具有异步功能的状态化React组件无法进行Jest测试

时间:2019-06-17 19:41:39

标签: javascript reactjs unit-testing testing jestjs

我将继续关注此Jest test tutorial on Pluralsight here。而且我写的代码与作者完全一样,但是由于某种原因,我的测试没有通过。

我对作者回购请求的请求: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();

无论什么都不起作用,即使count设置为42,组件内部的-1仍停留在count处。在我看来,我的测试在状态设置完毕?

enter image description here

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

3 个答案:

答案 0 :(得分:1)

问题是await delay()无法让所有componentDidMount之类的React生命周期方法实例化/被调用。

尽管由于很多开放的bug问题,笔者不推荐使用Enzyme,我还是不得不使用它。

使用酶,我可以确保调用componentDidMount,并通过模拟服务将count的状态设置为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');
  });
})

enter image description here

答案 1 :(得分:1)

实际上,真正的问题出在isomorphic-react/src/components/__tests__/NotificationsViewer.js文件中。 delay的导入方式错误,导致测试出错。

如果像这样导入delayimport { delay } from 'redux-saga'可解决问题。 = D

答案 2 :(得分:0)

也许您的describe还需要是一个异步函数? await语句需要在async范围内声明,不是吗?