简体   繁体   中英

How to test async data fetching react component using jest and enzyme?

I have a react component using useEffect hook for data fetching and setting loading, success and failure state accordingly.

import React, { useState, useEffect } from "react";
import { fetchData } from "./api";

function App({ id }) {
  const [data, setData] = useState(null);
  const [isFetching, setIsFetching] = useState(false);
  const [error, setError] = useState(null);
  useEffect(() => {
    setIsFetching(true);
    fetchData(id)
      .then(
        response => {
          setData(response.data);
          setIsFetching(false);
        },
        err => {
          setError(err);
          setIsFetching(false);
        }
      )
      .catch(err => {
        setError(err);
        setIsFetching(false);
      });
  }, [id]);

  if (data) {
    return <pre>{JSON.stringify(data)}</pre>;
  }
  if (isFetching) {
    return <div>fetching...</div>;
  }
  if (error) {
    return <pre>{JSON.stringify(error)}</pre>;
  }
  return <div>null</div>;
}

export default App;

I am trying to test this component using jest and enzyme.

Here is a sandbox https://codesandbox.io/s/jest-enzyme-re41k

I am getting a weird error Cannot read property 'isTTY' of undefined

Could someone help fix the test?

Here is the unit test solution:

app.jsx :

import React, { useState, useEffect } from 'react';
import { fetchData } from './api';

function App({ id }) {
  const [data, setData] = useState(null);
  const [isFetching, setIsFetching] = useState(false);
  const [error, setError] = useState(null);
  useEffect(() => {
    setIsFetching(true);
    fetchData(id)
      .then(
        (response) => {
          setData(response.data);
          setIsFetching(false);
        },
        (err) => {
          setError(err);
          setIsFetching(false);
        },
      )
      .catch((err) => {
        setError(err);
        setIsFetching(false);
      });
  }, [id]);

  if (data) {
    return <pre>{JSON.stringify(data)}</pre>;
  }
  if (isFetching) {
    return <div>fetching...</div>;
  }
  if (error) {
    return <pre>{JSON.stringify(error)}</pre>;
  }
  return <div>null</div>;
}

export default App;

api.js :

export function fetchData() {
  // real implementation
}

app.test.jsx :

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

jest.mock('./api.js', () => {
  return {
    fetchData: jest.fn(),
  };
});

describe('59586141', () => {
  afterEach(() => {
    jest.clearAllMocks();
  });
  it('should fetch data correctly', async () => {
    const mResponse = { data: { id: 1 } };
    const mProps = { id: 1 };
    fetchData.mockResolvedValueOnce(mResponse);
    const wrapper = mount(<App {...mProps}></App>);
    expect(wrapper.exists).toBeTruthy();
    expect(wrapper.find('div').text()).toBe('fetching...');
    await act(async () => {
      await new Promise((resolve) => setTimeout(resolve, 0));
    });
    wrapper.update();
    expect(wrapper.find('pre').text()).toBe(JSON.stringify(mResponse.data));
    expect(fetchData).toBeCalledWith(1);
  });

  it('should handle error if fetch data failure', async () => {
    const mError = new Error('some network error');
    const mProps = { id: 1 };
    fetchData.mockRejectedValueOnce(mError);
    const wrapper = mount(<App {...mProps}></App>);
    expect(wrapper.exists).toBeTruthy();
    expect(wrapper.find('div').text()).toBe('fetching...');
    await act(async () => {
      await new Promise((resolve) => setTimeout(resolve, 0));
    });
    wrapper.update();
    expect(wrapper.find('pre').text()).toBe(JSON.stringify(mError));
    expect(fetchData).toBeCalledWith(1);
  });
});

Unit test result with coverage report:

 PASS  src/stackoverflow/59586141/api.test.jsx (9.079s)
  59586141
    ✓ should fetch data correctly (119ms)
    ✓ should handle error if fetch data failure (12ms)

----------|----------|----------|----------|----------|-------------------|
File      |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
----------|----------|----------|----------|----------|-------------------|
All files |     93.1 |      100 |       80 |     91.3 |                   |
 app.jsx  |     93.1 |      100 |       80 |     91.3 |             22,23 |
----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests:       2 passed, 2 total
Snapshots:   0 total
Time:        10.458s

Source code: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/59586141

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM