Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TypeError: (0 , _component.default) is not a function mock tests #854

Open
tejpowar opened this issue Nov 23, 2021 · 20 comments
Open

TypeError: (0 , _component.default) is not a function mock tests #854

tejpowar opened this issue Nov 23, 2021 · 20 comments

Comments

@tejpowar
Copy link

💬 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?

@open-collective-bot
Copy link

Hey @tejpowar 👋,
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 ❤️.

@theKashey
Copy link
Collaborator

  • what you want to do
  • what is the real error? Callstack is important.

@tejpowar
Copy link
Author

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

@stale
Copy link

stale bot commented Apr 16, 2022

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.

@stale stale bot added the wontfix label Apr 16, 2022
@stale stale bot closed this as completed Apr 27, 2022
@tara-singh-danu
Copy link

Did anyone found any solution?

@nathanmillar16
Copy link

I'm also looking for a solution. Any help would be appreciated!

@tara-singh-danu did you find a solution?

@tara-singh-danu
Copy link

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.

@nathanmillar16
Copy link

@tejpowar how did you mock the loadable import?

@HebleV
Copy link

HebleV commented Oct 11, 2022

I faced a similar issue and included the function definition in a try catch block and it fixed the related failing test cases.

@santicalvo
Copy link

Hi @HebleV can you expand a little in the solution?

@santicalvo
Copy link

santicalvo commented Dec 8, 2022

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
  };
});

@theKashey
Copy link
Collaborator

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

@theKashey theKashey reopened this Dec 8, 2022
@stale stale bot removed the wontfix label Dec 8, 2022
@santicalvo
Copy link

santicalvo commented Dec 9, 2022

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 :-)

@theKashey
Copy link
Collaborator

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)

@santicalvo
Copy link

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.

timarney/react-app-rewired#328 (comment).

@stale
Copy link

stale bot commented Apr 2, 2023

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.

@stale stale bot added the wontfix label Apr 2, 2023
@felixcatto
Copy link

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(...)).

2023-05-27_06-58

2023-05-27_06-55

2023-05-27_06-56

I fixed it by writing

import rawLoadable from '@loadable/component';
const loadable = typeof rawLoadable === 'function' ? rawLoadable : rawLoadable.default;

@stale stale bot removed the wontfix label May 27, 2023
@stale
Copy link

stale bot commented Aug 13, 2023

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.

@stale stale bot added the wontfix label Aug 13, 2023
@revenokanton
Copy link

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;

@vladkostevich
Copy link

@revenokanton dude, it's amazing!!!

@stale stale bot removed the wontfix label Oct 4, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

9 participants