javascript - 如何使用 Jest 和 enzyme 测试异步数据获取 react 组件?

标签 javascript reactjs unit-testing jestjs enzyme

我有一个 React 组件,它使用 useEffect 钩子(Hook)来获取数据并相应地设置加载、成功和失败状态。

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;

我正在尝试使用 jest 和 enzyme 测试这个组件。

这是一个沙箱 https://codesandbox.io/s/jest-enzyme-re41k

我收到一个奇怪的错误 Cannot read property 'isTTY' of undefined

有人可以帮助修复测试吗?

最佳答案

这是单元测试解决方案:

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);
  });
});

带有覆盖率报告的单元测试结果:

 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

源代码:https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/59586141

关于javascript - 如何使用 Jest 和 enzyme 测试异步数据获取 react 组件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59586141/

相关文章:

javascript - 如何使用 es6 过滤对象值

unit-testing - Grails:如何在使用 Spock 进行单元测试时将值保存到 transient 字段?

unit-testing - 用 Jest 模拟 redux saga 中间件

javascript - $ ("#id option").隐藏();不在 safari/chrome 上工作?

javascript - jQuery 选择器,用于查找文本不以某些内容开头的链接

reactjs - 您无权使用阻塞 webRequest 监听器。请务必在 list 中声明 webRequestBlocking 权限

node.js - 如何测试 Connect/Express 中间件?

javascript - 浏览器是真正逐行读取 JavaScript 还是多次通过?

javascript - 如何在每次点击按钮时将数字相加

reactjs - 如何让 ant-design Drawer 组件宽度响应