使用异步setState调用来响应测试功能

时间:2018-03-08 19:38:51

标签: javascript reactjs asynchronous testing mocha

我的React组件中有以下功能

changeProject(project) {
    const buildProjectValues = [];
    BambooService.GetBuilds(project).then((res) => {
      res.map(build => {
        buildProjectValues.push({'label':build.searchEntity.planName, 'value':build.searchEntity.id});
      });
      this.setState({buildValues:buildProjectValues})
    })
  }

通过相关测试:

it('should set buildValues state property to returned array from API call', () => {
    const wrapper = mount(<RepoForm projectValues={projectOptions} />);
    const instance = wrapper.instance();

    nock('https://myurl.api.com')
      .get('/builds?projectKey=KEY')
      .reply(200, buildMock)

    instance.changeProject('KEY');
    expect(instance.state.buildValues).to.equal(buildMock);
  })

问题是我的测试完成,失败,在我的代码中的promise解析之前,以及setState无论如何都是异步的!

我尝试使用setImmediate如下,但结果相同;

it('should set buildValues state property to returned array from API call', () => {
    const wrapper = mount(<RepoForm projectValues={projectOptions} />);
    const instance = wrapper.instance();

    nock('https://myurl.api.com')
      .get('/builds?projectKey=KEY')
      .reply(200, buildMock)

    instance.changeProject('KEY');
    setImmediate(() => {
      expect(instance.state.buildValues).to.equal(buildMock);
    });

  })

有没有什么方法可以重写我的代码来避免这种情况?或者是否有其他模式我可以用于此方案来测试我的异步代码?谢谢!

2 个答案:

答案 0 :(得分:0)

首先编辑changeProject()以返回在测试中使用它的承诺:

changeProject(project) {
    const buildProjectValues = [];
    return BambooService.GetBuilds(project).then((res) => {
      res.map(build => {
        buildProjectValues.push({
           'label':build.searchEntity.planName,
           'value':build.searchEntity.id
        });
      });
      this.setState({buildValues:buildProjectValues})
    })
  }

然后在测试中,将您的断言添加到then()

it('should set buildValues state property to returned array from API call', () => {
    const wrapper = mount(<RepoForm projectValues={projectOptions} />);
    const instance = wrapper.instance();

    nock('https://myurl.api.com')
      .get('/builds?projectKey=KEY')
      .reply(200, buildMock)

    instance.changeProject('KEY')
       .then(() => {
            expect(instance.state.buildValues).to.equal(buildMock);
       });    
  })

您也可以使用await代替then()

await instance.changeProject('KEY');     
expect(instance.state.buildValues).to.equal(buildMock);

答案 1 :(得分:0)

修改changeProject()以返回承诺:

changeProject(project) {
    const buildProjectValues = [];
    return BambooService.GetBuilds(project).then((res) => {
      res.map(build => {
        buildProjectValues.push({'label':build.searchEntity.planName, 'value':build.searchEntity.id});
      });
      this.setState({buildValues:buildProjectValues})
    })
}

现在,您可以在测试中获得承诺,并允许Jest在您致电expect()之前解决它:

it('should set buildValues state property to returned array from API call', () => {
    const wrapper = mount(<RepoForm projectValues={projectOptions} />);
    const instance = wrapper.instance();

    nock('https://myurl.api.com')
      .get('/builds?projectKey=KEY')
      .reply(200, buildMock)

    return instance.changeProject('KEY')
        .then(() => {
          expect(instance.state.buildValues).to.equal(buildMock);
        });
})

当你从Jest测试中返回一个promise时,Jest会尝试解决它。如果成功解决了承诺,将调用then()