首页 > 解决方案 > 具有异步功能的有状态 React 组件未通过 Jest 测试

问题描述

我正在关注Pluralsight 的这个 Jest 测试教程。而且我写的代码和作者一模一样,但是由于某种原因我的测试没有通过。

我对作者仓库的拉取请求:https ://github.com/danielstern/isomorphic-react/pull/19

我有一个简单的 React 组件,它count通过对componentDidMount.

{this.state.count != -1 ? `${this.state.count} Notifications Awaiting` : 'Loading...'}

预期的

由于我已经模拟了 NotificationsService,并将 count 设置为42,因此测试应该通过组件内的文本"42 Notifications Awaiting!"

结果

文本保持为默认值Loading...

我已经正确地模拟了服务,并且count变量甚至被正确记录为42!然而this.state.count仍然-1如此,而不是显示:${this.state.count} Notifications Awaiting它仍然显示Loading...,因此测试失败。


我试过的

1)我尝试在延迟中添加 1000。

2) 尝试在测试中使用 setTimeout。

3)尝试jest.useFakeTimers();jest.runAllTimers();

但是没有任何效果,即使设置为 42,count组件的内部也会卡住。在我看来,我的测试在状态设置完成之前正在运行?-1count

在此处输入图像描述

NotificationsViewser.jsx 组件

import React from 'react';
import NotificationsService from '../services/NotificationsService';

export default class componentName extends React.Component {
  constructor(...args) {
    super(...args);

    this.state = {
      count: -1
    }
  }

  async componentDidMount () {
    let { count } = await NotificationsService.GetNotifications();
    console.log('count:', count);
    this.setState({
      count
    });
  }

  componentDidUpdate() {
    console.log('componentDidUpdate:', this.state);
  }

  render() {
    return (
      <div className="mt-3 mb-2">
        <div className="notifications">
          {this.state.count != -1 ? `${this.state.count} Notifications Awaiting` : `Loading...`}
        </div>
      </div>
    )
  }
}

NotificationsService.js

import { delay } from 'redux-saga';

export default {
  async GetNotifications() {
    console.warn("REAL NOTIFICATION SERVICE! CONTACTING APIS!");

    await delay(1000);
    return { count: 42 };
  }
}

模拟:NotificationsService.js

let count = 0;

export default {
  __setCount(_count) {
    count = _count;
  },
  async GetNotifications() {
    console.warn("GOOD JOB! USING MOCK SERVICE");
    return { count };
  }
}

最后...

考试

import React from 'react';
import renderer from 'react-test-renderer';
import delay from 'redux-saga';

import NotificationsViewer from '../NotificationsViewer';

jest.mock('../../services/NotificationsService');

const notificationService = require('../../services/NotificationsService').default;

describe('The notification viewer', () => {

  beforeAll(() => {
    notificationService.__setCount(42);
  });

  it('should display the correct number of notifications', async() => {
    const tree = renderer
      .create(
        <NotificationsViewer/>
      );

    await delay();

    const instance = tree.root;
    const component = instance.findByProps({className: `notifications`});
    const text = component.children[0];
    console.log('text is:', text);

    expect(text).toEqual('42 Notifications Awaiting!');
  });
})

标签: javascriptreactjsunit-testingtestingjestjs

解决方案


问题是让所有 React 生命周期方法(如实例化/被调用)await delay()都不起作用。componentDidMount

Enzyme即使由于许多未解决的错误问题,作者不推荐它,我也不得不使用它。

使用 Enzyme 我可以确保componentDidMount调用了 ,从而使用模拟服务设置countto的状态。42

我还需要安装以下软件包:

"enzyme": "^3.10.0",
"enzyme-adapter-react-16": "^1.14.0",

固定测试

import React from 'react';
import renderer from 'react-test-renderer';
import Adapter from 'enzyme-adapter-react-16';
import { shallow, configure } from 'enzyme';

configure({adapter: new Adapter()});

import NotificationsViewer from './NotificationsViewer';

jest.mock('../services/NotificationsService');

const notificationService = require('../services/NotificationsService').default;

notificationService.default = jest.fn();

describe('The notification viewer', () => {

  beforeAll(() => {
    notificationService.__setCount(42);
  });

  // it('pass', () => {});

  it('should display the correct number of notifications', async() => {
    const tree = renderer.create(<NotificationsViewer />);
    const wrapper = shallow(<NotificationsViewer />);
    const instance = tree.root;

    await wrapper.instance().componentDidMount();

    const component = instance.findByProps({className: `notifications`});
    const text = component.children[0];
    console.log('text is:', text);

    expect(text).toEqual('42 Notifications Awaiting');
  });
})

在此处输入图像描述


推荐阅读