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.
Expected results
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.
Actual results
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.
Relevant links on what I have tried
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
throughloadable.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,
};
});
A little bit of code
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"
Conclusion
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!
Update 1
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;
},
};
});