测试React组件内部的fetch()方法

Testing fetch() method inside React component

本文关键字:方法 fetch React 组件 内部 测试      更新时间:2023-09-26

我有一个应用程序组件,负责呈现子输入组件,它还负责通过名为channelSearch的方法处理对Twitch API的提取请求。我试着遵循这里列出的使用ajax/fetch和React的最佳实践。

该方法通过props传递,并通过回调进行调用。

注意,fetch方法实际上是同构的fetch。

channelSearch (searchReq, baseUrl="https://api.twitch.tv/kraken/channels/") {
  fetch(baseUrl + searchReq)
  .then(response => {
    return response.json();
  })
  .then(json => {
    this.setState({newChannel:json});
  })
  .then( () => {
    if (!("error" in this.state.newChannel) && this.channelChecker(this.state.newChannel._id, this.state.channelList) ) {
      this.setState(
        {channelList: this.state.channelList.concat([this.state.newChannel])}
      );
    }
  })
  .catch(error => {
    return error;
  });
}

我目前正在尝试为channelSearch方法编写一个测试。我目前正在使用酶和jsdom来mount DOM中的整个<App>组件。找到带有回调的子节点,模拟单击(应该会触发回调),然后检查组件的状态是否已更改。然而,这似乎并不奏效。

我也尝试过直接调用该方法,但是遇到了this.state未定义的问题。

test('channel search method should change newChannel state', t => {
  const wrapper = mount(React.createElement(App));
  wrapper.find('input').get(0).value = "test";
  console.log(wrapper.find('input').get(0).value);
  wrapper.find('input').simulate("change");
  wrapper.find('button').simulate("click");
  console.log(wrapper.state(["newChannel"]));

});

我真的很失落,我不确定是方法本身写得不好,还是我没有使用正确的工具来完成工作。任何指导都将不胜感激。

更新#1:

我在评论中推荐了nock,测试现在看起来是这样的:

test('channel search method should change newChannel state', t => {
  // Test object setup
  var twitch = nock('https://api.twitch.tv')
                .log(console.log)
                .get('/kraken/channels/test')
                .reply(200, {
                  _id: '001',
                  name: 'test',
                  game: 'testGame'
                });
  function checker() {
    if(twitch.isDone()) {
      console.log("Done!");
      console.log(wrapper.state(["newChannel"]));
    }
    else {
      checker();
    }
  }
  const wrapper = mount(React.createElement(App));
  wrapper.find('input').get(0).value = "test";
  wrapper.find('input').simulate("change");
  wrapper.find('button').simulate("click");
  checker();
});

这似乎仍然不会改变组件的状态。

fetch是异步的,但您正在同步测试,您需要使用同步mock来模拟fetch,或者使测试异步。

诺克可能在这里为你工作。

我建议您使用plnkr创建一个测试样本。

我同意汤姆的看法,你正在同步测试。当然,展示你的实际组件代码(所有相关部分,比如channelSearch,或者至少通过说"channelSearchcomponentDidMount()调用"来描述它)会很有帮助

我遇到了这个状态未定义的问题。

这是因为this.setState()是异步的。这是出于性能原因,以便React可以批量更改。

我怀疑您需要更改当前的代码:

.then(json => {
    this.setState({newChannel:json});
})

到:

.then(json => {
  return new Promise(function(resolve, reject) {
    this.setState({newChannel:json}, resolve);
  })
})

请注意,您的checker()方法不起作用。它是循环的,但twitch.isDone()永远不会是真的,因为它从来没有机会运行。Javascript是单线程的,所以您的检查器代码将连续运行,不允许在两者之间进行任何其他操作。

如果你设置了plnkr,我会看一看。

从组件中重构fetch代码,然后将其作为属性中的回调函数传递给组件。

export class Channel extends React.Component {
  componentDidMount() {
    this.props.searchFunction().then(data => this.setState(data));
  }
  render() {
    return <div>{this.state}</div>;
  }
}

Uage:

function channelSearch(name) {
  return fetch(`https://api.twitch.tv/kraken/search/channels?query=${name}`);
}
<Channel searchFunction={channelSearch} />

现在,您可以独立于组件测试API功能。