Home > Enterprise >  Testing react component when state changes
Testing react component when state changes

Time:07-22

This is my code. I want to test the text in the component once the state is updated. But In the console It's showing loading component.

I'm using Jest and Enzyme.

This is App.js code

import logo from "./logo.svg";
import "./App.css";
import React, { useEffect } from "react";

function App() {
  const [isLoading, setIsLoading] = React.useState(true);
  const [isDataLoaded, setIsDataLoaded] = React.useState(false);

  useEffect(() => {
    if (isDataLoaded) {
      setIsLoading(false);
    }
  }, [isDataLoaded]);

  useEffect(() => {
    setTimeout(() => setIsDataLoaded(true), 4000);
  }, []);

  return (
    <div className="App">
      {isLoading && <div>Loading....</div>}
      {!isLoading && (
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <p>
            Edit <code>src/App.js</code> and save to reload.
          </p>
          <a
            className="App-link"
            href="https://reactjs.org"
            target="_blank"
            rel="noopener noreferrer"
          >
            Learn React
          </a>
        </header>
      )}
    </div>
  );
}

export default App;

This is App.test.js code

import React from "react";
import { mount } from "enzyme";
import App from "./App";

let wrapper;

const setup = (state = {}) => {
  const mockUseState = jest.fn().mockReturnValue([{ ...state }, jest.fn()]);
  React.useState = mockUseState;
  return mount(<App />);
};

// beforeEach(() => {
//   wrapper = setup();
// });

// afterEach(() => {
//   wrapper.unmount();
// });

describe("App", () => {
  test("renders without error", () => {
    wrapper = setup();
    expect(wrapper.find("App").exists()).toBe(true);
  });

  test("renders learn react link", () => {
    wrapper = setup({ isLoading: false });
    wrapper.setProps();
    console.log(wrapper.debug(), "console output")
    expect(wrapper.find("App-link").text()).toBe("Learn React");
  });
});

CodePudding user response:

You mocked React.useState which will breaks the real function of useState. Keep using the real React.useState and use faker timers to mock the timer for setTimeout.

E.g.

App.tsx:

import React, { useEffect } from 'react';

function App() {
  const [isLoading, setIsLoading] = React.useState(true);
  const [isDataLoaded, setIsDataLoaded] = React.useState(false);

  useEffect(() => {
    if (isDataLoaded) {
      setIsLoading(false);
    }
  }, [isDataLoaded]);

  useEffect(() => {
    setTimeout(() => setIsDataLoaded(true), 4000);
  }, []);

  return (
    <div className="App">
      {isLoading && <div>Loading....</div>}
      {!isLoading && (
        <header className="App-header">
          <a className="App-link" href="https://reactjs.org" target="_blank" rel="noopener noreferrer">
            Learn React
          </a>
        </header>
      )}
    </div>
  );
}

export default App;

App.test.tsx:

import React from 'react';
import { mount } from 'enzyme';
import App from './App';
import { act } from 'react-dom/test-utils';

describe('App', () => {
  test('renders without error', () => {
    const wrapper = mount(<App />);
    expect(wrapper.find('.App').exists()).toBe(true);
  });

  test('renders learn react link', () => {
    jest.useFakeTimers();
    const wrapper = mount(<App />);
    act(() => {
      jest.advanceTimersByTime(4000);
    })
    wrapper.update();
    console.log(wrapper.debug());
    expect(wrapper.find('.App-link').text()).toBe('Learn React');
  });
});

Test result:

 PASS  stackoverflow/73051795/App.test.tsx (11.204 s)
  App
    ✓ renders without error (38 ms)
    ✓ renders learn react link (21 ms)

  console.log
    <App>
      <div className="App">
        <header className="App-header">
          <a className="App-link" href="https://reactjs.org" target="_blank" rel="noopener noreferrer">
            Learn React
          </a>
        </header>
      </div>
    </App>

      at Object.<anonymous> (stackoverflow/73051795/App.test.tsx:19:13)

Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        11.704 s

package version:

"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.5",
"react": "^16.14.0",
"react-dom": "^16.14.0",
"jest": "^26.6.3",
  • Related