Jest require '#material-ui/icons' gives undefined - reactjs

When ever I try to use require or require.requireActual in jest, to import '#material-ui/icons', jest claims it to be undefined.
I'm guessing this is a bug/issue, as I cant imagine any export to be undefined for require. The file being referenced by this ('#material-ui/icons/index.js') uses code like this to define its exports:
Object.defineProperty(exports, "AccessAlarm", {
enumerable: true,
get: function get() {
return _AccessAlarm.default;
}
});
I know jest does do funky stuff with the base require, perhaps this method of export definition is tripping jest up?
Does anyone have any insight into this, solutions or workarounds, etc?
Also does anybody know of a way to get a list of icons in '#material-ui/icons' given this restriction (get a list of the icons is all I'm trying to do in the first place), and no, I do not want to use a file reader.
To be clear, this is on a simple test file with no mocking.

So I am now using the following solution (automock all material-ui icons) since it looks like jest cant handle them to begin with, so no harm in just permanently automocking them:
const mockIconsList = new Map();
jest.mock('#material-ui/icons', () => new Proxy({__esModule: true}, {
get: (target, prop) => {
if (prop in target)
return target[prop];
if (!mockIconsList.has(prop))
mockIconsList.set(prop, mockComponent(`mockMaterialIcon${prop}`));
return mockIconsList.get(prop);
},
}));
I am still however curious about the above issue and any information regarding it.

Related

Is it possible to disable specific React warnings from Jest (using Create React App)

Recently, React started giving depreciation warnings for componentWillReceiveProps lifecycle method. I am using a library that utilized this function and the maintainers haven't updated their codebase yet.
Currently, any time I run my tests, whether it is in development or in CI, I keep getting ~30 lines of depreciation warnings for each component that the maintainer provides.
Is there a way to suppress these warnings (at least in development)?
EDIT:
I am willing to add certain comments in my files to disable warnings from a specific package if there is a chance:
// some line to disable warnings for this package
import { DateRangePicker } from 'react-dates';
If you want to disable all warnings that meet some condition, keeping all other warnings, for all tests:
const originalWarn = console.warn.bind(console.warn)
beforeAll(() => {
console.warn = (msg) =>
!msg.toString().includes('componentWillReceiveProps') && originalWarn(msg)
})
afterAll(() => {
console.warn = originalWarn
})
React codebase also contains expect(render(...)).toWarnDev(...), but that's not included in Jest documentation, you might need to investigate more if you want to use that feature.
Similar in concept to a previous answer, but a bit easier would be:
jest.spyOn(global.console, 'warn').mockImplementationOnce((message) => {
if (!message.includes('componentWillReceiveProps')) {
global.console.warn(message);
}
});
If you wanted to do it across tests you could do:
let consoleSpy;
beforeAll(() => {
consoleSpy = jest.spyOn(global.console, 'warn').mockImplementation((message) => {
// same implementation as above
});
afterAll(() => consoleSpy.mockRestore());
A variation on #Aprillion's answer...
I wanted to suppress certain error messages in all tests (in a create-react-app application).
I added this to my setupTests.js:
// This error is a bug fixed in React 18: https://github.com/facebook/react/pull/22114.
// Suppress it for all tests.
const BOGUS_UNMOUNTED_ERROR = (
"Can't perform a React state update on an unmounted component."
);
const originalError = console.error.bind(console.error);
console.error = (...args) => !args.toString().includes(BOGUS_UNMOUNTED_ERROR)
&& originalError(...args);
I guess the most important difference is that I replaced (msg) with (...args) in two places, so that all arguments to console.error() were passed through. Without this, I was getting %s's in my console error messages that should have been filled in with other arguments.
So I found a way to fix these warnings for any library using react-codemod.
Since this library does not work inside node_modules so have to do a little hack.
Run:
yarn add -D react-codemod
open ./node_modules/react-codemod/bin/cli.js
Remove/comment line (72) > + // args.push('--ignore-pattern=/node_modules/');
Run:
./node_modules/.bin/react-codemod rename-unsafe-lifecycles
To this question answer with the path of the library, you want to fix...
“On which files or directory should the codemods be applied?”
./node_modules/react-dates/lib/** // or any library with issue
This could be a temporary fix till react-codemod support node_modules libraries.
You can also fork the library and remove the line for yourself and use it like this inside your CI pipeline to not get any warnings like this anymore.
You can just add this line above whatever is showing the warning. I have tried this in VScode so i'm not sure if it works with others. This disables whatever warning that will be displayed in the next line.
// eslint-disable-next-line

CommonJS require vs. ES6 import discrepancy

So, I am new to React. Apologies if I am missing something obvious, I'm wrestling with a weird issue with my ES6 imports.
I'm using the #typeform/embed module (0.12.1), which oddly links to a GitHub repo on npm but that repo doesn't exist. So I haven't been able to look into potentially related issues.
Anyways, whenever I do the following:
import typeformEmbed from '#typeform/embed'
My text editor shows that the type of typeformEmbed is a string, and when I go to invoke a function on it, it is always undefined. Gives me the 'ole cannot invoke property X on undefined TypeError. It almost looks as if it is trying to import the README?
But, then I opened up my Node REPL and could write:
const typeformEmbed = require('#typeform/embed')
and it works like a charm.
Is there some discrepancy between the two that I am missing?
Edit: I know that this question is pretty text-heavy, let me know if there is crucial information that I'm missing. I should mention that I built this project with create-react-app.
import * as typeformEmbed from '#typeform/embed';
const popUpHandler = () => {
typeformEmbed.makePopup(
'https://admin.typeform.com/to/PlBzgL',
{
mode: 'drawer_left',
autoOpen: true,
autoClose: 3,
hideScrollbars: true,
onSubmit: function () {
console.log('Typeform successfully submitted')
}
}
)}
Should work for you

How do i mock and customise the values of a function imported from a npm package using Jest?

I use isMobileOnly from "react-device-detect" npm package in my React component say(SampleComponent.js).
I would like to customize the return value of isMobileOnly in my jest unit tests.
I have tried Jest manual mocks as mentioned in the link below:
https://jestjs.io/docs/en/manual-mocks
But it does not seem to work for me.
I have also tried:
jest's mockImplementation
jest's mockImplementationOnce
jest's spyOn
import {isMobileOnly} from 'react-device-detect;
In my jest unit tests, i would like to mock the function isMobileOnly in such a way that i should be able to customize its return value to "true". The default value is "false".
This worked for me.
In your test file, add this: import * as deviceDetect from 'react-device-detect';
then you can change things like: deviceDetect.isMobileOnly = true;
eg.
import * as deviceDetect from 'react-device-detect'; //<--important
it.only('clicking on myAccount redirects to /user/myAccount', () => {
///make sure this is before mount or shallow
deviceDetect.isMobileOnly = true; //<--important
component = mount(<Provider store={store}><Sidebar history={mockedHistory} /></Provider>);
component.find('[test-id="myAccount"]').first().simulate('click');
expect(mockedHistory.push).toHaveBeenCalledWith('/user/myAccount');
});
Finally! I figured it out myself after hours of struggle. Here is what i did:
Created __mocks__ folder in the same level as node_modules directory where the package "react-device-detect" is available. Note: smaller case is important for __mocks__.
Created a file named "react-device-detect.js" within the __mocks__ folder.
Added the following code in it:
const deviceDetect = jest.genMockFromModule('react-device-detect');
deviceDetect.isMobileOnly = true;
module.exports = deviceDetect;
Within the test file, i imported the "isMobileOnly" as i did in the original
component:
import { isMobileOnly } from 'react-device-detect';
Now, i can change value of "deviceDetect.isMobileOnly" to true or false in the
mocked file as per the unit test case's need .
For more details, refer the official documentation here https://jestjs.io/docs/en/manual-mocks
Thanks #Roman for reaching out!
I use the " import * as deviceDetect" answer, it worked but I ran into an issue because of typescript and the readonly property of isMobile.
So this solution worked for me :
Object.defineProperty(reactDeviceDetect, 'isIOS', { get: () => true });
as describe here
I hope that help!
You can possibly override the User Agent for testing purposes so react-device-detect package will identify it like You need, here's how to do that.
This topic should also be helpful.

How to use getReactively with find all helper in Angular Meteor?

I am working through Angular Meteor tutorial and got deprecation warning on
this.helpers({
parties: () => {
return Parties.find({}); //deprecation warning. Use getReactively
}
});
But I am not quite sure how to get all records reactively. I do not have any queries to say return Parties.find({field: this.getReactively(query)}). I just want all records/everything similar to Collection.find({}) or Parties.find({}) but without deprecation warning.
Im often use parties: ()=> Parties.find() and I'm has no error or deprecated warning. You maybe should try it.
Beside, sometime I need handle data fetch from query. Im used a temp variable for save data before handle it.
You can try (some code is pseudo code)
parties: () {
this.temp = Parties.find().fetch();
if(this.temp) {
//handle data, adjust property like format string, format date....
return this.temp
}
}
Its work, no deprecated, no error. You can try it.

How to catch React propTypes warnings on server?

While rendering React components on server all of the propTypes warning messages are falling to general output or process.stdout. For example, this is visible only in terminal or in general application log:
Warning: Failed propType: Required prop `title` was not specified in `Page`.
Is there any way to catch this warnings and transform them or pipe them into another direction? For instance, I want to separate application log and React (as template engine) log. How can I do it?
Like #m01, I wanted to make sure that any react errors (and in fact any js errors) cause my unit tests to fail, but I found a much simpler way to do it. At the top level of your tests, put this:
beforeAll(() => {
console.error = (error) => {
throw new Error(error);
};
});
I needed the same thing, but for a different use case. I wanted to make sure that all my unit tests pass without any React warnings.
I use this in my test utils:
expectNoConsoleErrors: function() {
var savedErrors;
beforeEach(function () {
savedErrors = [];
spyOn(console, 'error').and.callFake(function () {
var stack = new Error(_.map(arguments).join(' ')).stack;
// if you need workarounds for come components, put them here
savedErrors.push(stack);
});
});
afterEach(function () {
if (savedErrors.length > 0) {
fail(savedErrors.join('\n'));
}
});
},
Then in describe block I put
myTestUtils.expectNoConsoleErrors()
And it works like a charm.
This is not very clean because it will also catch all other calls to console.error, but I don't want them during test anyway, so this seems ok for me.
Also, when I have some misbehaving component producing unnecessary warnings, like e.g. react-input-autosize I can ignore it using:
// Workaround for https://github.com/JedWatson/react-select/issues/371
if (_.contains(stack, 'react-input-autosize')) {
return;
}
Btw, note that before v0.14, React was using console.warn instead of console.error to produce these warnings.
I tried looking into the React src how they print those output messages, but then I realized that it should only be printing those messages in development mode. If your node/iojs runtime is set to the "production" env, React should not even be doing those checks and that's what you want for a real app running. Those warnings are meant just for devs running locally.

Resources