Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/468.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript React-Test`componentDidMount`异步调用_Javascript_Reactjs_Enzyme - Fatal编程技术网

Javascript React-Test`componentDidMount`异步调用

Javascript React-Test`componentDidMount`异步调用,javascript,reactjs,enzyme,Javascript,Reactjs,Enzyme,各位 在componentDidMount中发生异步调用后,我在测试状态更新时遇到了奇怪的问题 以下是我的组件代码: 'use strict'; import React from 'react'; import UserComponent from './userComponent'; const request = require('request'); class UsersListComponent extends React.Component { constructor(

各位

componentDidMount
中发生异步调用后,我在测试状态更新时遇到了奇怪的问题

以下是我的组件代码:

'use strict';


import React from 'react';
import UserComponent from './userComponent';
const request = require('request');


class UsersListComponent extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      usersList: []
    };
  }

  componentDidMount() {
    request('https://api.github.com/users', (err, res) => {
      if (!err && res.statusCode === 200) {
        this.setState({
          usersList: res.slice(0)
        });
      }
      else {
        console.log(err);
      }
    });
  }

  render() {
    if (!this.state.usersList.length) {
      return null;
    }

    return (
      <div className="users-list">
        { this._constructUsersList() }
      </div>
    );
  }

  _constructUsersList() {
    return this.state.usersList.map((user, index) => {
      return (
        <UserComponent
              key={ index }
              name={ user.name }
              age={ user.age } />
      );
    });
  }
};


export default UsersListComponent;
“严格使用”;
从“React”导入React;
从“./UserComponent”导入UserComponent;
const request=require('request');
类UsersListComponent扩展了React.Component{
建造师(道具){
超级(道具);
此.state={
用户列表:[]
};
}
componentDidMount(){
请求('https://api.github.com/users“,(错误,结果)=>{
如果(!err&&res.statusCode==200){
这是我的国家({
usersList:res.slice(0)
});
}
否则{
控制台日志(err);
}
});
}
render(){
if(!this.state.usersList.length){
返回null;
}
返回(
{this.\u constructUsersList()}
);
}
_constructUsersList(){
返回此.state.usersList.map((用户,索引)=>{
返回(
);
});
}
};
导出默认UsersListComponent;
现在,我在我的测试文件中所做的工作(我有一个由摩卡+柴+西农组成的设置,所有这些都在工作):

从“React”导入React;
从“chai”导入{expect};
从“酶”导入{shall,mount,render};
从“sinon”进口sinon;
从“../src/UsersListComponent”导入UsersListComponent;
描述('UsersListComponent的测试套件',()=>{
它('在发出'componentDidMount'中的AJAX调用后正确更新状态',()=>{
const server=sinon.fakeServer.create();
server.respondWith('GET','https://api.github.com/users', [
200,
{
“内容类型”:“应用程序/json”,
“内容长度”:2
},
“[{”姓名“:”统治“,”年龄“:26}”
]);
让wrapper=mount();
server.respond();
server.restore();
expect(wrapper.update().state().usersList).to.be.instanceof(数组);
log(wrapper.update().state().usersList.length);
});
});
即使我在包装器上调用
update()
,状态也不会得到更新。长度仍然是0。我是不是遗漏了什么?我是否需要以另一种方式模拟服务器响应

谢谢你的帮助

我查看了一下,发现回调中缺少了“body”参数

应该是这样的

...
request('https://api.github.com/users', (err, res, body) => {
    if (!err && res.statusCode === 200) {
      this.setState({
        usersList: body.slice(0)
      });
    }
...

您可以通过传递一个返回承诺的函数,将用户列表检索从react组件中抽象出来,以便

  componentDidMount() {
    request('https://api.github.com/users', (err, res) => {
      if (!err && res.statusCode === 200) {
        this.setState({
          usersList: res.slice(0)
        });
      }
      else {
        console.log(err);
      }
    });
  }
换成

  componentDidMount() {
     var comp = this;
     this.props.getUsers()
        .then(function(usersList) {
          comp.setState({
            usersList: usersList
          });
        })
        .catch(function (err) {
            console.log(err);
        });
  }
在您的模拟测试中,
getUsers
函数:

    it('Correctly updates the state after AJAX call in `componentDidMount` was made', (done) => {

      let resolveGetUsers;

      let getUsers = function() {
        return new Promise(function (resolve, reject) {
                  resolveGetUsers = resolve;
                });
      }

      let wrapper = mount(<UsersListComponent getUsers={getUsers} />);

      resolveGetUsers([{ "name": "Reign", "age": 26 }]);


      // promise resolve happens in a subsequent event loop turn so move assertions inside setImmediate
      setImmediate(() => {

        expect(wrapper.update().state().usersList).to.be.instanceof(Array);
        ...

        done();
      });
    }
it('componentDidMount`was'中的AJAX调用后正确更新状态),(完成)=>{
让我们的用户;
让getUsers=function(){
返回新承诺(功能(解决、拒绝){
resolveGetUsers=resolve;
});
}
让wrapper=mount();
resolveGetUsers([{“姓名”:“统治”、“年龄”:26}]);
//承诺解析发生在随后的事件循环中,因此将断言移动到setImmediate中
setImmediate(()=>{
expect(wrapper.update().state().usersList).to.be.instanceof(数组);
...
完成();
});
}
请注意,我已经完成了这项工作,它对我来说很有用(即使没有wrapper.update()部分),在这里,我尝试在不运行它的情况下将其应用到您的代码示例中

还请注意,它应该在componentDidMount以外的情况下也能工作-例如,在单击按钮后触发异步操作。

给出我的解决方案:

  • 酶3.9.0
  • 酶-适配器-反应-16 1.9.1
  • 反应16.8.0
  • 开玩笑
1-模拟数据服务

您必须模拟数据服务(通常类似于axios或其他HTTP库)

文件:
\uuuuumocks\uuuu/LogDataService.js

let searchData = {}

const LogDataService = {
    search: () => new Promise((resolve, reject) =>
        process.nextTick(() => resolve(searchData))
    ),
    setSearchData: (data) => searchData = data
}

export default LogDataService
jest.mock('services/LogDataService')

import LogDataService from 'services/LogDataService';

// Declare a super promise that will synchro all promises
function flushPromises() {
    return new Promise(resolve => setImmediate(resolve));
}

it('renders without data', async () => {
    // Set dummy data
    LogDataService.setSearchData([])
    // The component we want to test that use
    // LogDataService.search method we just mock up
    const component = mount(<JobsExecutionTimeline />);
    // wait
    await flushPromises();
    // re-build the render
    component.update()
    // Compare to snapshot
    expect(toJson(component)).toMatchSnapshot();
});
2-测试

文件:
\uuuuu测试/toto.test.js

let searchData = {}

const LogDataService = {
    search: () => new Promise((resolve, reject) =>
        process.nextTick(() => resolve(searchData))
    ),
    setSearchData: (data) => searchData = data
}

export default LogDataService
jest.mock('services/LogDataService')

import LogDataService from 'services/LogDataService';

// Declare a super promise that will synchro all promises
function flushPromises() {
    return new Promise(resolve => setImmediate(resolve));
}

it('renders without data', async () => {
    // Set dummy data
    LogDataService.setSearchData([])
    // The component we want to test that use
    // LogDataService.search method we just mock up
    const component = mount(<JobsExecutionTimeline />);
    // wait
    await flushPromises();
    // re-build the render
    component.update()
    // Compare to snapshot
    expect(toJson(component)).toMatchSnapshot();
});
jest.mock('services/LogDataService'))
从“服务/LogDataService”导入LogDataService;
//声明将同步所有承诺的超级承诺
函数flushPromises(){
返回新承诺(resolve=>setImmediate(resolve));
}
它('无数据呈现',异步()=>{
//设置虚拟数据
LogDataService.setSearchData([])
//我们要测试的组件使用
//我们刚刚模拟的LogDataService.search方法
const component=mount();
//等等
等待flushPromises();
//重新构建渲染
component.update()
//与快照相比
expect(toJson(component)).toMatchSnapshot();
});

确实是这样。我肯定有这个问题,但它并没有解决真正的问题。所以我最终解决了。结果证明,由于setState的异步性质,我不得不在超时时检查它。这里的最终实现-(我还切换到了
superagent
,只是个人喜好)。还使用了
nock
来模拟服务器响应。sinon中的假服务器出现了奇怪的问题。请求没有被捕获。我可能需要更深入地了解这一点(可能我在那里做了一些古怪的事情)。请注意,如果在
beforeach()
中使用此选项,
setImmediate()
部分可能会导致错误,因为其内容的执行被延迟。您的测试可能会在
setImmediate()
块完成之前开始执行。要解决此问题,请将
setImmediate()
块包装在
new Promise()中
只有当块中的所有语句都完成时才会解析。将
beforeach()
函数设为异步,并在其中包含一行内容,例如:
等待新承诺((解析,拒绝)=>{/*setImmediateBlock在这里;不要忘记将resolve()放在它的末尾。*/})
非常好,您可以将其缩短为
等待新承诺(setImmediate)
,如果愿意,可以删除helper函数。