Why doesn't the loader show on the second test when I run the same test twice in jest, using react testing library, react.lazy, and suspense?

Viewed 614

Here is a sample of my code

// App.js

import React, { Suspense, lazy } from "react";

const Loader = () => <div data-testid="loader">Loading...</div>

const Login = lazy(() => import("./Login"));

function App() {
  return (
    <Suspense fallback={<Loader />}>
      <Login />
    </Suspense>
  );
}

export default App;

// Login.js

import React from 'react';

const Login = () => <div data-testid="login">Login</div>

export default Login
// App.test.js

import React from 'react';
import { render, waitForElementToBeRemoved, cleanup } from '@testing-library/react';
import App from './App';


describe('App when user is not signed in', () => {
  it("should redirect to login page", async () => {
    beforeEach(() => jest.resetAllMocks())
    const { getByTestId, getByText } = render(<App />);
    await waitForElementToBeRemoved(() => getByTestId('loader'))
    const linkElement = getByText(/Login/i);
  
    expect(linkElement).toBeInTheDocument();
  });
})

describe('App with User Logged in as Admin', () => {
  it("redirect to login page", async () => {
    beforeEach(() => {
      // will set local storage for auth token
      // for a logged in user
    })
    let container = document.createElement('div')
    const { getByTestId, getByText } = render(<App />, {
      container
    });
  
    await waitForElementToBeRemoved(() => getByTestId('loader'))
    const linkElement = getByText(/Login/i);
  
    expect(linkElement).toBeInTheDocument();
  });
})

The issue I am having is that I expect to have the loader when I run the second test but it is not there thus throwing an error.

I would like to know why the loader is not rendered in the second test which renders the login page straight away. I suspect the first test is affecting the second test but the question is why.

I created a repl to this issue here. https://repl.it/@tibetegya/Create-React-App

1 Answers

toBeInTheDocument asserts that the element exists in the document, as the name suggests:

The jest-dom utility library provides the .toBeInTheDocument() matcher, which can be used to assert that an element is in the body of the document, or not. This can be more meaningful than asserting a query result is null.

The component was rendered to detached container element in the second test and doesn't exist in document DOM, so the test fails.

Instead, basic Jest assertions can be used, as the documentation suggests:

expect(linkElement).not.toBeNull()

There may be no reason to use custom container, unless there's a need to test how the component works in detached elements.

Related