7

I'm new to React and to React unit testing. I have a component which loads some divs based on state set with useState. Inside useEffect, if a rejected promise is returned from a function then an error div should be shown instead. I want to test this scenario, but because initial state is set as error = false, the original divs are still shown instead.

My question is, how can I do this so that the test registers updated divs? I'm using Enzyme's mount(), but I've also tried it with shallow(). I've also verified that it's actually going into .catch() with some console.logs.

component:

export const Main = (props) => { 
  const [showLoadError, setShowLoadError] = useState(false);
  const [loadError, setLoadError] = useState('');

  React.useEffect(() => {
    const { categories, actions } = props;

    // retrieve categories from Db if they don't exist in state
    if (categories.length === 0) {
      actions.loadCategories().catch(err => {
        setShowLoadError(true);
        setLoadError(err.message);
      })
    } else {
      setShowLoadError(false);
      setLoadError('');
    }
  }, []);

  return (

    <>
      {/* conditional show for error container if loading failed */}
      {showLoadError &&
        <div className="load-error">
          Error loading categories. {loadError}
        </div>
      }
      {/* conditional show for no Load error */}
      {!showLoadError &&
        <div className="grid-container grid-container--fit">
          <div><CategoryContainer /></div>
          <div><ItemContainer /></div>
          <div><FileAssociationsContainer /></div>
        </div>
      }
    </>
  );
}

test:

import React from 'react';
import ConnectedApp, { Main } from './Main';
import { shallow, mount } from 'enzyme';

jest.mock("../category/CategoryContainer");
jest.mock("../item/ItemContainer");
jest.mock("../fileAssociations/FileAssociationsContainer");

describe("Main component", () => {

  beforeEach(() => {
    fetch.resetMocks()
  });

  test('should render error div after loadCategories fail',  () => {
    const categories = [];
    const errMessage = {message: 'test error'}
    const actions = {
      loadCategories: jest.fn(() => {
        return Promise.reject(errMessage);
      })
    };

    const wrapper = mount(<Main categories={categories} actions={actions} />);

    wrapper.setProps(); // rerenders

    // expect there to be a load-error div
    expect(wrapper.find('div').hasClass('load-error')).toBe(true)

    // expect loadCategories to be called because component was passed in empty categories
    expect(actions.loadCategories).toBeCalled();

  });



});

I've tried wrapper.setProps(), wrapper.update() before my expects with no luck.

Additionally, this unit test gives a jest warning that An update to Main inside a test was not wrapped in act(...). This only happens if actions.loadCategories() returns a rejected promise. It does not do this when it returns a resolved promise. I've tried moving code into act() with no luck in removing the error, like such:

act(() => {
      actions = {
        loadCategories: jest.fn(() => {
          return Promise.reject(errMessage);
        })
      };
      wrapper = mount(<Main categories={categories} actions={actions} />);
      wrapper.setProps(); // rerenders
    });
skyboyer
  • 22,209
  • 7
  • 57
  • 64
user1779418
  • 455
  • 1
  • 7
  • 22
  • Does this answer your question? [Testing React components that fetches data using Hooks](https://stackoverflow.com/questions/55047535/testing-react-components-that-fetches-data-using-hooks) – Varun Sharma Apr 18 '20 at 15:41

0 Answers0