'Mocking dot notation React components in Jest

I have a component that, depending on data being loaded, renders either a component or a loading component:

// components/example

import Component from 'components/component';


const Example = ({loaded}) => (
  <>
    {loaded ? <Component/> : <Component.Loading/>}
  </>
)

The loading component is written as dot notation, because I feel like it makes it easier to read and use. Is there any way to mock <Component.Loading/> in my unit tests?

This was my best guess, but it didn't work:

// components/example.test

import Example from './example'

const mockedComponent = jest.fn();

jest.mock('components/component', () => ({
  __esModule: true,
  default: () => mockedComponent(),
}));

const setup = () => {
  const utils = render(<Example loading={false} />);
  return {
    ...utils,
  };
};

it('Renders correctly', () => {
    const component = () => <>Main component</>;
    component.Loading = () => <>Loading component</>;
    mockedComponent.mockReturnValue(component);
    setup();  
});

Jest doesn't like this, and tells me that <Component.Loading/> is undefined.

  console.error
    Warning: React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.


Solution 1:[1]

Right so this while doing this I was going off how you usually mock react components:

jest.mock('component/something', () => ({
 __esModule: true,
  default: () => <>Mocked component</>,
}));

This usually works, but for dot-notation component the syntax is different:


const component = () => <>Main component</>;
component.Loading = () => <>Loading</>;

jest.mock('components/component', () => ({
  __esModule: true,
  default: component,
}));

If you want to go a step further you can mock with a jest.fn():

const mockedItemStatus = jest.fn();
const mockedItemStatusSkeleton = jest.fn();

const component = () => mockedItemStatus();
component.Loading = () => mockedItemStatusSkeleton();

jest.mock('components/component', () => ({
  __esModule: true,
  default: component,
}));

Then in your tests you can make the mock return the specific component you need:

  it('Renders correctly', () => {
    mockedItemStatusSkeleton.mockImplementation(() => <>Loading</>);
    render(<Component/>)
    expect(mockedItemStatusSkeleton).toHaveBeenCalled();
  });

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1