Reputation: 3461
We now use lazy-loading through loadable.lib
for about 20 new files which used to load the npm module react-toastify
synchronously. The changes are waiting in a draft PR but it seems that the unit tests are broken because they do not wait for the loadable.lib
-passed module to be loaded.
Be able to mock loadable.lib
so that it works exactly like before but loads the given library synchronously and in the unit test this is seen as the children of loadable.lib
resulted Component have access to that library and a first render does this successfully.
The old snapshot (full of tags and nested things and props) and the new one (null
) are not matching. These do not work:
// TODO: not working because loadable is used in many places
// and children are not always enough to render to avoid crashes,
// and even just with children there can be crashes
jest.mock('@loadable/component', (loadfn) => ({
lib: jest.fn(() => {
return { toast: {} };
}),
}));
If it is possible to mock the loadable.lib
function to render its children instead of wait for some library to be loaded, I don't know how I can fill the undefined variables that the code uses because I have loadables that use loadables that use loadables and so on.
I've read that there are some WebPack hints such as webpackPrefetch
and webpackPreload
but I am not sure if it is a good road to go.
The code I am working on (and there are 19 other files like this one): https://github.com/silviubogan/volto/blob/1d015c145e562565ecfa058629ae3d7a9f3e39e4/src/components/manage/Actions/Actions.jsx (I am currently working on loading react-toastify
through loadable.lib
always.)
https://medium.com/pixel-and-ink/testing-loadable-components-with-jest-97bfeaa6da0b - I tried to do a similar thing like the code in that article but it is not working:
jest.mock('@loadable/component', async (loadfn) => {
const val = await loadfn();
return {
lib: () => val,
};
});
Taken from the link above, this is how I currently use react-toastify (named LoadableToast
):
/**
* Render method.
* @method render
* @returns {string} Markup for the component.
*/
render() {
return (
<LoadableToast>
{({ default: toast }) => {
this.toast = toast;
return (
<Dropdown
item
id="toolbar-actions"
To put it in other words, how can I mock a dynamic import? How can I make jest go over lazy loading and provide a value instead of making the test wait to receive a value?
Thank you!
With the following new code, still not working:
jest.mock('@loadable/component', (load) => {
return {
lib: () => {
let Component;
const loadPromise = load().then((val) => (Component = val.default));
const Loadable = (props) => {
if (!Component) {
throw new Error(
'Bundle split module not loaded yet, ensure you beforeAll(() => MyLazyComponent.load()) in your test, import statement: ' +
load.toString(),
);
}
return <Component {...props} />;
};
Loadable.load = () => loadPromise;
return Loadable;
},
};
});
Upvotes: 1
Views: 2470
Reputation: 116
A better solution is to mock the Loadable components module. We can do this simply by using Jest mock capabilities (https://jestjs.io/docs/manual-mocks#mocking-node-modules) and Loadable itself in the following way:
export default function (load) {
return load.requireSync();
}
That's it, now you should be able to run your unit tests as normal.
Upvotes: 4
Reputation: 21
We did it by
jest.mock('@loadable/component', () => ({
lib: () => {
const MegadraftEditor = () => {} // Name of your import
return ({ children }) => children({ default: { MegadraftEditor } })
},
}))
In case there is only one default export it could also be
jest.mock('@loadable/component', () => ({
lib: () => {
const HotTable = () => {} // Name of your import
return ({ children }) => children({ default: HotTable })
},
}))
Then in the test you just need to dive() and use childAt() until you have the correct location of the component you want to lazy-load. Note that this will then not have any of your wrappers around the lazy-loaded component in the snapshot.
it('renders correct', () => {
const component = shallow(
<View
data={}
/>
)
.dive()
.childAt(0)
.dive()
expect(component).toMatchSnapshot()
})
Upvotes: 2