1

Here is the mini react project: https://codesandbox.io/s/shy-monad-n32vv

I try my best to make it as small as I can. To let tailwindcss open dark mode, we need to add "dark" to the document.documentElement's classList. So the mini project will add or remove (aka, toggle) the class name "dark" to classList after we click the button.

It works really well. But the Jest test failed.

Here is the test file in the mini project:

import { render, fireEvent } from "@testing-library/react";
import App from "./App.js";

test("<App />", () => {
  const { getByText } = render(<App />);
  const darkToggle = getByText("Toggle");
  document.documentElement.classList.remove("dark");
  expect(document.documentElement.classList.contains("dark")).toBe(false);

  fireEvent.click(darkToggle);
  expect(document.documentElement.classList.contains("dark")).toBe(true);
  fireEvent.click(darkToggle);

  // it failed here!!!!
  expect(document.documentElement.classList.contains("dark")).toBe(false);

  fireEvent.click(darkToggle);
  expect(document.documentElement.classList.contains("dark")).toBe(true);
});

I read a lot but cannot find something useful. Mocking DOM by JSDOM looks do not work -- Looks like that the new version Jest's default env is JSDOM. I also failed to test localStorage(I remove those in the mini project), I hope those failed because the same bug.

My guess: after use Redux, the test failed. I think the test failed because of createAsyncThunk. But I still have no idea.

EDITED: I find this will help: https://stackoverflow.com/a/51045733/13031497

EDITED: I resolve it. But looks like the codesandbox still raise error?

Peterlits Zo
  • 476
  • 1
  • 4
  • 17

1 Answers1

0

After try, I find await new Promise(process.nextTick); does well.

I think because createAsyncThunk's function will change the data after test -- really bad. If there is some function that can sleep some time after the data has already changed, it will be the BEST!!! I find this page: https://stackoverflow.com/a/51045733/13031497, it tell my change the test file like:

  import { render, fireEvent } from "@testing-library/react";
  import App from "./App.js";
  
  test("<App />", () => {
    const { getByText } = render(<App />);
    const darkToggle = getByText("Toggle");
    document.documentElement.classList.remove("dark");
    expect(document.documentElement.classList.contains("dark")).toBe(false);
  
    fireEvent.click(darkToggle);
 +  await new Promise(process.nextTick);
    expect(document.documentElement.classList.contains("dark")).toBe(true);
 +
    fireEvent.click(darkToggle);
- 
-   // it failed here!!!!
 +  await new Promise(process.nextTick);
    expect(document.documentElement.classList.contains("dark")).toBe(false);
  
    fireEvent.click(darkToggle);
 +  await new Promise(process.nextTick);
    expect(document.documentElement.classList.contains("dark")).toBe(true);
  });

Then the test pass.

Peterlits Zo
  • 476
  • 1
  • 4
  • 17