如何在组件生命周期中测试异步功能?

时间:2017-06-27 09:05:57

标签: javascript unit-testing reactjs jestjs enzyme

我尝试在ComponentDidMount中测试一个异步函数,在搜索之后,我推出了测试函数,但它似乎不起作用?

referring to this anwser

我的测试功能出了什么问题?

api.js

export const fetchPopularRepos = (lang: string) => {
  var encodedURI: string = window.encodeURI(
    "https://api.github.com/search/repositories?q=stars:>1 + language:" +
      lang +
      "&sort=stars&order=desc&type=Repositories"
  );
  return axios.get(encodedURI).then(response => response.data.items);
}; 

user.js的

import React from "react";
import { Card } from "antd";
import { fetchPopularRepos } from "./api";

class TestUser extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      text: "initialize",
      item: {}
    };
  }

  componentDidMount() {
    fetchPopularRepos("all")
      .then(item => {
        this.setState({
          items
        });
      })
      .catch(error => console.log(error))  
  }

  handleClick() {
    this.setState({
      text: "You clicked it"
    });
  }

  render() {
    return (
      <div>
        <button onClick={this.handleClick.bind(this)}>{this.state.text}</button>
        <div className="wrapper">
          <Card />
          <Card />
          <Card />
        </div>
      </div>
    );
  }
}

export default TestUser;

User.test.js

import React from "react";
import TestUser from "./User";
import { shallow, mount } from "enzyme";
import renderer from "react-test-renderer";
import { Card } from "antd";


  it("should render right after click the button", async () => {
  const expectedItems = [{ id: 2 }];
  const p = Promise.resolve(expectedItems);
  const fetchPopularRepos = str => p;
  const component = mount(<TestUser />);
  await p;

  expect(component.state().item).toEqual(expectedItems); 
});

日志

{ Error: Network Error
          at createError (/Users/next/Documents/react-master/react-ant/node_modules/axios/lib/core/createError.js:16:15)
          at XMLHttpRequest.handleError [as onerror] (/Users/next/Documents/react-master/react-ant/node_modules/axios/lib/adapters/xhr.js:87:14)
          at XMLHttpRequest.callback.(anonymous function) (/Users/next/Documents/react-master/react-ant/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:289:32)
          at invokeEventListeners (/Users/next/Documents/react-master/react-ant/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:219:27)
          at invokeInlineListeners (/Users/next/Documents/react-master/react-ant/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:166:7)
          at EventTargetImpl._dispatch (/Users/next/Documents/react-master/react-ant/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:122:7)
          at EventTargetImpl.dispatchEvent (/Users/next/Documents/react-master/react-ant/node_modules/jsdom/lib/jsdom/living/events/EventTarget-impl.js:87:17)
          at XMLHttpRequest.dispatchEvent (/Users/next/Documents/react-master/react-ant/node_modules/jsdom/lib/jsdom/living/generated/EventTarget.js:61:35)
          at XMLHttpRequest.abort (/Users/next/Documents/react-master/react-ant/node_modules/jsdom/lib/jsdom/living/xmlhttprequest.js:405:16)
          at Object.abort (/Users/next/Documents/react-master/react-ant/node_modules/jsdom/lib/jsdom/living/xhr-utils.js:315:13)
          at RequestManager.close (/Users/next/Documents/react-master/react-ant/node_modules/jsdom/lib/jsdom/living/nodes/Document-impl.js:146:21)
          at Window.close (/Users/next/Documents/react-master/react-ant/node_modules/jsdom/lib/jsdom/browser/Window.js:362:29)
          at JSDOMEnvironment.dispose (/Users/next/Documents/react-master/react-ant/node_modules/jest-environment-jsdom/build/index.js:44:19)
          at Promise.resolve.then (/Users/next/Documents/react-master/react-ant/node_modules/jest-cli/build/runTest.js:102:17)
          at process._tickCallback (internal/process/next_tick.js:103:7)
        config:
         { adapter: [Function: xhrAdapter],
           transformRequest: { '0': [Function: transformRequest] },
           transformResponse: { '0': [Function: transformResponse] },
           timeout: 0,
           xsrfCookieName: 'XSRF-TOKEN',
           xsrfHeaderName: 'X-XSRF-TOKEN',
           maxContentLength: -1,
           validateStatus: [Function: validateStatus],
           headers: { Accept: 'application/json, text/plain, */*' },
           method: 'get',
           url: 'https://api.github.com/search/repositories?q=stars:%3E1%20+%20language:all&sort=stars&order=desc&type=Repositories',
           data: undefined },
        request:
         XMLHttpRequest {
           onabort: null,
           onerror: [Function: handleError],
           onload: null,
           onloadend: null,
           onloadstart: null,
           onprogress: null,
           ontimeout: [Function: handleTimeout],
           upload:
            XMLHttpRequestUpload {
              onabort: null,
              onerror: null,
              onload: null,
              onloadend: null,
              onloadstart: null,
              onprogress: null,
              ontimeout: null,
              _ownerDocument: [Object] },
           onreadystatechange: [Function: handleLoad] },
        response: undefined }

  ● should render right after click the button

    expect(received).toEqual(expected)

    Expected value to equal:
      [{"id": 2}]
    Received:
      {}

1 个答案:

答案 0 :(得分:0)

与您所指的答案的不同之处在于,您的API调用函数fetchRepos在您的案例中的组件中是硬编码的,而在答案中它是作为prop收到的。

将这些功能作为道具传递,可以轻松模拟它们以进行测试,特别是用于单元测试。如果你想要一个你在这里写的集成测试,那么你可能需要使用fetch-mock fetchmoxios来模拟与网络相关的调用( https://github.com/mzabriskie/moxios)因为您正在使用axios。

您可以定义预期的&#34;服务器响应&#34;在调用之前使用模拟库,然后执行断言。