9

I have this component:

import React from 'react';

const UploadAsync = Loadable({
  loader: () => import('components/Upload'),
  loading: () => <LoadingComponent full />
});

const Component = () => {
  return <UploadAsync />
}

export default Component

And the test:

import React from 'react';
import Component from './index';

describe('Component', () => {
  it('should render correctly with upload component', () => {
    const tree = create(<Component />).toJSON();

    expect(tree).toMatchSnapshot();
  });
});

How I can see the Upload component and not the Loading component in the snapshot?

exports[`Content should render correctly with form component 1`] = `
  <div>
    <Loading
      full={true}
    />
  </div>
`;

So far I have tried setTimeOut and Promises.

Albert Olivé Corbella
  • 4,061
  • 7
  • 48
  • 66

7 Answers7

11

Use Loadable.preloadAll() before the tests then you can access the Component you need.

Docs

Simple example:

all imports here

Loadable.preloadAll()

describe('TestName', () => {
 //tests
})

  • Loadable.preloadAll() is returning a promise, so this does not seem like it's the correct solution. – ggwzrd May 26 '21 at 13:20
3

I haven't been able to figure this out either, but here are a couple of workarounds that, alone or together, may work reasonably well:

Snapshot test the components that are passed to Loadable

In your case, the test would look something like this:

import React from 'react';
import Component from './components/Upload';

describe('Component', () => {
  it('should render correctly with upload component', () => {
    const tree = create(<Component />).toJSON();

    expect(tree).toMatchSnapshot();
  });
});

You could also test <LoadingComponent full /> in a similar fashion. No, this doesn't assure you that the Loadable component is working, but you may find it satisfactory to assume that the react-loadable library is well tested and will work as long as you pass to it your own, properly tested components.

End-to-end browser testing

Using a framework such as Selenium or TestCafe you can write tests that run against your site as it runs in a real browser.

fagerbua
  • 406
  • 2
  • 9
1

I'm using @testing-library/react and jest. Using the preloadReady() function found in the docs here -> https://github.com/jamiebuilds/react-loadable#preloading-ready-loadable-components-on-the-client

Importantly, I call it after rendering.

import { waitFor, render } from "@testing-library/react";

it("should match snapshot with all valid props", async () => {
  const { asFragment } = render(<Component />);

  // wait to load components after rendering
  await waitFor(() => Loadable.preloadReady());

  expect(asFragment()).toMatchSnapshot();
}
Parker Tailor
  • 1,290
  • 13
  • 12
0

It seems like there is no proper solution but if your test is actually rendering the component in browser inside iframe then you can get your react component by Jquery contentDocument

$('#component-iframe')[0].contentDocument

you can find for some specific element in your component by class or id using

$('#component-iframe')[0].contentDocument.getElementById('componentID')
0

I have a solution, which I found accidentally, but I don't understand how it works (maybe if we could figure out, we could solve this problem). For now, it's good for a workaround.

If you call mount once outside the test, the dynamic module will load magically:

function mountApp() {
  return mount(
    <ApolloProvider client={apolloClient}>
      <MemoryRouter initialEntries={['/']}>
        <App />
      </MemoryRouter>
    </ApolloProvider>
  );
}

mountApp();

// Tests
test('react-loadable module loads', () => {
  const wrapper = mountApp();
  console.log(wrapper.debug());
});

Here, the App, which contains react-loadable modules loads correctly with all its content available. When I remove the first mountApp, it doesn't work anymore (it loads only the loading string).

Edit: Actually it works inside the test too, but this way you only need to do this once for every test to work.

András Geiszl
  • 966
  • 2
  • 16
  • 36
0

I was trying to test a component which had Loadable-components inside of it, and run into a similar problem. I managed to mock those components and that made the parent-component mount (enzyme) as I wanted it to.

I'm leaving out the mocked store and props, as they aren't relevant to the solution

const component = () => {
  return mount(
    <Provider store={store}>
      <DoubleMatrix {...props} />
    </Provider>
  )
}

// These are the Loadable-components, import { Grid, GridColumn } from 'App/Components/Tables/Grid' in the parent component which I am testing

jest.mock('App/Components/Tables/Grid', () => ({
  Grid: () => <div />, // eslint-disable-line
  GridColumn: () => <div />, // eslint-disable-line
}))

it('renders', () => {
  const wrapper = component()
  expect(wrapper).toMatchSnapshot()
})
-1

Here is how you test the loaded component:

import {LoadableFoo} from './loadable-foo';
import {Foo} from './Foo';

it('should load the Foo component', async () => {
  // usual shallow render
  const component = shallow(<LoadableFoo/>);  

  // prerender the Loadable component
  const loadedComponent = await component.preload();

  expect(loadedComponent.Foo).toEqual(Foo);
});
Gopikrishna S
  • 2,221
  • 4
  • 25
  • 39