在React组件

时间:2016-04-20 17:42:34

标签: javascript reactjs jsdom enzyme

我有一个负责渲染子输入组件的App组件,它还负责通过一个名为channelSearch的方法处理对Twitch API的提取请求。我尝试遵循建议的here概述的最佳做法,以便使用React进行ajax / fetch。

该方法通过道具传递,并通过回调调用。

请注意,fetch方法实际上是isomorphic-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();
});

这似乎仍未改变组件的状态。

3 个答案:

答案 0 :(得分:1)

fetch是异步的,但是你要进行同步测试,你需要使用同步模拟进行模拟获取或者使测试异步。

nock可能适合您。

答案 1 :(得分:0)

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

我同意汤姆你正在同步测试。展示您的实际组件代码(所有相关部分,例如调用channelSearch,或者至少通过说“channelSearch调用{{1}来描述它当然会很有帮助你说:

  

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

这是因为this.setState() is asynchronous。这是出于性能原因,因此React可以批量更改。

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

componentDidMount()

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

请注意,您的.then(json => { return new Promise(function(resolve, reject) { this.setState({newChannel:json}, resolve); }) }) 方法无效。它正在循环,但checker()将永远不会成为现实,因为它永远不会有机会运行。 Javascript是单线程的,因此您的检查器代码将连续运行,不允许其他任何内容。

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

答案 2 :(得分:0)

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

export class Channel extends React.Component {
  componentDidMount() {
    this.props.searchFunction().then(data => this.setState(data));
  }

  render() {
    return <div>{this.state}</div>;
  }
}

用法:

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

<Channel searchFunction={channelSearch} />

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