1

我有一个 App 组件负责渲染子输入组件,它还负责通过名为channelSearch. 我已尝试遵守此处概述的建议的最佳实践,以使用 React 使用 ajax/fetch。

该方法通过 props 向下传递并通过回调调用。

注意 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方法编写测试。我目前正在对 DOM 中mount的整个<App>组件使用酶和 jsdom。找到带有回调的子节点,模拟单击(应该触发回调)并检查组件的状态是否已更改。但是,这似乎不起作用。

我也尝试过直接调用该方法,但是,我遇到了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();
});

这似乎仍然没有改变组件的状态。

4

3 回答 3

1

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

nock在这里可能对你有用。

于 2016-04-21T15:21:40.240 回答
0

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

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

我遇到了 this.state 未定义的问题。

这是因为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,我会看看。

于 2016-06-01T05:39:03.577 回答
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 功能。

于 2018-06-20T12:57:34.060 回答