【问题标题】:How to test a Async function in Component Life Cycle?如何在组件生命周期中测试异步功能?
【发布时间】:2017-07-01 11:29:35
【问题描述】:

我尝试在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);
}; 

用户.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:
      {}

【问题讨论】:

    标签: javascript unit-testing reactjs jestjs enzyme


    【解决方案1】:

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

    将这些函数作为道具传递可以让您轻松地模拟它们以用于测试目的,特别是用于单元测试。如果您想要一个您真正在此处编写的集成测试,那么您可能需要使用 fetch-mock for fetchmoxios(https://github.com/mzabriskie/moxios) 之类的东西来模拟与网络相关的调用,因为您'正在使用 axios。

    您在调用之前使用模拟库定义预期的“服务器响应”,然后进行断言。

    【讨论】:

    • 但是在我的代码重构之后,仍然弹出错误,还有其他可能的原因吗?
    • 如果你重构了你的代码,就不需要调用真正的API,传递一个模拟函数作为prop!
    猜你喜欢
    • 2020-05-10
    • 1970-01-01
    • 1970-01-01
    • 2018-10-19
    • 2021-01-18
    • 1970-01-01
    • 2017-11-29
    • 2016-04-24
    • 1970-01-01
    相关资源
    最近更新 更多