Rob
Rob

Reputation: 1

Appropriate Architecture of Asynchronous Tests with React Testing Library to avoid hanging tests

Am trying to run asynchronous tests for a React page which uses mock api data but they are hanging for as long as you set the Jest timeout to. Am using mock service worker (msw) to provide the page data which is working fine in dev, and Redux. Am following the recommendation from the Redux team of not mocking Redux so that you can do proper integration testing and see how the page actually runs. A Redux action calls the fetch which is then populated by msw and the data is then populated in the Redux store. However the test always times out on the await WaitFor.

test('displays position page', async () => {
    const container = document.createElement('div'); 
    const root = createRoot(container!);
    root.render(
    <ReduxProvider store={store} key="redux">
        <MemoryRouter initialEntries={['/']}>
            <PositionPage />
        </MemoryRouter>
    </ReduxProvider>
    )
  await waitFor(async () => {
    expect(await screen.getByText("XXXX", { exact: false })).toBeInTheDocument();
  })
});

For msw I have setupTests.ts

import '@testing-library/jest-dom';
import { getServer } from './core/mocks/server';

const server = getServer();
beforeAll(() => {
  server.listen()
});
afterEach(() => {
  server.resetHandlers()
})
afterAll(() => {
  server.close()
})

and in server.ts:

import { setupServer } from 'msw/node';
import type { SetupServer } from 'msw/node';
import { handlers } from './handlers';

// eslint-disable-next-line @typescript-eslint/init-declarations
let server: SetupServer | undefined;
export const getServer = (): SetupServer => {
  if (!server) {
    server = setupServer(...handlers);
  }
  return server;
};

What am I doing wrong here? Is it because Redux is the real Redux here rather than being mocked? Is there a way to get this to work without having to lose all the "real world" testing elements that using proper Redux gives you?

Upvotes: 0

Views: 131

Answers (1)

Mister_CK
Mister_CK

Reputation: 1073

Bit of a shot in the dark, but are you using fakeTimers? You can also have set them in the jest.config.js:

const config = {
  fakeTimers: {
    enableGlobally: true,
  },
};

They don't always work well with async/await tests. And you would get the behaviour you are describing.

Otherwise it might be helpful to also share the code under test, i.e. your PositionPage.

Update Waitfor doesn't need to contain an async function. probably not what is causing the issue. But screen.getByText("XXXX", { exact: false })).toBeInTheDocument(); doesn't return a promise, so you shouldn't await it:

  await waitFor(() => {
    expect(screen.getByText("XXXX", { exact: false 
  })).toBeInTheDocument();
  })

What are you using for store? it should be the same as your actual store, but you should create a new instance for every test. I do this by exporting my createStore function from store.ts

Upvotes: 0

Related Questions