我有一个应用程序组件,负责呈现子输入组件,它还负责通过名为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
,或者至少通过说"channelSearch
由componentDidMount()
调用"来描述它)会很有帮助
我遇到了这个状态未定义的问题。
这是因为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功能。