loadable-components
loadable-components copied to clipboard
TypeError: (0 , _component.default) is not a function mock tests
💬 Questions and Help
Hi,
We are using the loadable/component function to load components but are having issues with the mocking tests and running into the following error:
TypeError: (0 , _component.default) is not a function
Within our test we have just created a mock like so
jest.mock('@loadable/component', () => ({
loadable: jest.fn()
}));
Also tried
jest.mock('@loadable/component', () => {
const original = jest.requireActual('@loadable/component');
return {
...original,
__esModule: true,
default: () => {},
loadableReady: callback => callback(),
};
});
But this still errors.
Any ideas on how we can mock it?
Hey @tejpowar :wave:, Thank you for opening an issue. We'll get back to you as soon as we can. Please, consider supporting us on Open Collective. We give a special attention to issues opened by backers. If you use Loadable at work, you can also ask your company to sponsor us :heart:.
- what you want to do
- what is the real error? Callstack is important.
Hi,
We basically need to update unit tests whereby we are using loadable and need to mock it.
The error is:
Test suite failed to run
TypeError: (0 , _component.default) is not a function
18 |
> 19 | export const agreement = loadable(
| ^
20 | () => import(/* webpackChunkName: "agreement" */ './agreement'),
21 | { fallback: <Spinner overlay="clear" alignCenter /> }
22 | );
So the error is actually failing in our component when we run our unit tests.
Basically we need to mock out the above code within our unit test
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Did anyone found any solution?
I'm also looking for a solution. Any help would be appreciated!
@tara-singh-danu did you find a solution?
I'm also looking for a solution. Any help would be appreciated!
@tara-singh-danu did you find a solution?
I am using these libraries now
"@testing-library/jest-dom": "5.16.2", "@testing-library/react": "12.1.5", "@testing-library/user-event": "^14.2.1",
In which I am not getting the above issue.
@tejpowar how did you mock the loadable import?
I faced a similar issue and included the function definition in a try catch block and it fixed the related failing test cases.
Hi @HebleV can you expand a little in the solution?
I have found a very hacky and ugly solution... It would be nice to know the proper way to do this.
Let's assume we import a component (with classes) called Dummy:
import loadable, { lazy } from '@loadable/component';
const Dummy = lazy(() => import('../components/Dummy'));
...
// lazyLoaded is a state variable to force Suspense
class SomeClass {
render() {
return (<>
{this.state.lazyLoaded && <Suspense fallback={<div>loading in suspense</div>}><Dummy /></Suspense>
< />)
}
}
We can use the following super ugly code in jest to mock it.
jest.mock('react', () => {
const React = jest.requireActual('react');
const Suspense = ({children, fallback}) => {
console.log('Suspense called children!!', typeof children, children.toString());
console.log('Suspense called fallback!!', typeof fallback, fallback.toString());
return children;
};
return {
...React,
Suspense
};
});
jest.mock('@loadable/component', () => {
const loadable = jest.requireActual('@loadable/component');
// The trick is to convert the async dynamic import we do not have in node, to a syncronous require!!!!!!
const lazy = (importer) => {
const matchCondition = `${importer?.toString()}`.match('Dummy');
if(matchCondition) {
return require('../components/Dummy').default;
}
return importer;
};
loadable.lazy = lazy;
return {
__esModule: true,
default: (children) => {
return children;
},
loadable,
lazy
};
});
Note - you do mock @loadable/component
in the same way, and in your case default export is working 🤷♂️
However, I should ask other questions
- why you need to mock loadable/component?
- why you
require('../components/Dummy')
- is loadable babel plugin applied? Because it should handle this out of the box
Hello @theKashey, I mock @loadable/component
because I need to mock lazy. Also, I have loadable babel plugin, injected with react-app-rewired
, but not working with jest. How should it work with jest? Do you know any example to mock properly @loadable/component
, Suspense
and lazy
?
I manage to get this working on React 17, even though it is not supported. It might work on 16, but no idea...
I would love to know the proper way to do this :-)
How should it work with jest?
Follow Jest babel's configuration (usually just .babelrc
)
Do you know any example to mock
You cannot mock loadable, as you need "something" to transform import
into require
to make your code "sync". Or you might not want that and keep stuff dynamic. If you use Jest with RTL - that should work out of the box, you just need to wait a little for components to load (wait for content inside lazy loaded regions or just wait for a promise)
You cannot mock loadable, as you need "something" to transform import into require to make your code "sync". Or you might not want that and keep stuff dynamic. If you use Jest with RTL - that should work out of the box, you just need to wait a little for components to load (wait for content inside lazy loaded regions or just wait for a promise)
Well, the whole point is to deal with @loadable/component
, Suspense
and lazy
with dynamic imports. We are using enzyme
. I see that the very ugly example above works, I override Lazy and transform import
to require
.
I will take a look to the following example to see if I can make it working. Otherwise, I'll go with the ugly solution. Thanks for your help.
https://github.com/timarney/react-app-rewired/issues/328#issuecomment-498836392.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
There is something wrong with this package export. Seems it provides different exports in ESM and CJS. In ESM default
is loadable function, but in CJS default
is an object with another default prop. So you need to write loadable.default(() => import(...))
.
I fixed it by writing
import rawLoadable from '@loadable/component';
const loadable = typeof rawLoadable === 'function' ? rawLoadable : rawLoadable.default;
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Finally found rather simple solution which works for me without mocking:
import { render,screen } from '@testing-library/react';
import LoadableComponent from './LoadableComponent';
test('it renders', async () => {
const name = "LoadableComponent"
render(<LoadableComponent name={name} />);
expect(await screen.findByText(name)).toBeInTheDocument();
});
LoadableComponent file:
import loadable from '@loadable/component';
const LoadableComponent = loadable(
() => import('your-library-path'),
);
export default LoadableComponent;
@revenokanton dude, it's amazing!!!