用于axios提取的集成测试,当我用笑话在`it`函数中将`done`作为回调应用时,它将失败

时间:2019-09-05 00:30:28

标签: reactjs redux jestjs moxios

我正在尝试在集成测试中为网络获取运行Jest测试。它使用beforeEach来创建伪造的网络获取响应,并且应返回长度为2的响应。当我从以下代码中删除完成时,测试进行得很好,但是只要我使用done作为回调和看来测试失败了,错误提示返回的长度只有1,而预期的长度应该是2。

它使用酶和完整的dom来测试3个组件的集成,当我不使用done时,测试进行得很好,但是当我使用done时,它通过了测试。

beforeEach(() => {
    moxios.install();
    moxios.stubRequest('http://jsonplaceholder.typicode.com/comments', {
        status: 200,
        response: [ { name: 'Fetch #1' }, { name: 'Fetch #2' } ]
    });
});

afterEach(() => {
    moxios.uninstall();
});

it('can fetch a list of comments and display them', (done) => {
    // Attempt to render the *entire* app
    const wrapped = mount(
        <Root>
            <App />
        </Root>
    );
    // find the 'fetchComments' button and click it
    wrapped.find('.fetch_comments').simulate('click');

    // setTimeout is used because moxio introduces a little delay fetching the data.
    // so setTimeout makes Jest to have a little delay so it won't throw error.
    //  Expect to find a list of comments!
    //
    setTimeout(() => {
        wrapped.update();
        console.log(wrapped.find('li').length);
        expect(wrapped.find('li').length).toEqual(2);

        wrapped.unmount();
        done();
    }, 3300);

});
      1
    console.error node_modules/jsdom/lib/jsdom/virtual-console.js:29
      Error: Uncaught [Error: expect(received).toEqual(expected) // deep equality

      Expected: 2
      Received: 1]
          at reportException (/Users/dmml/Documents/Developer/reactPractice/testing/testing-stephen-grider/node_modules/jsdom/lib/jsdom/living/helpers/runtime-script-errors.js:66:24)
          at Timeout.callback [as _onTimeout] (/Users/dmml/Documents/Developer/reactPractice/testing/testing-stephen-grider/node_modules/jsdom/lib/jsdom/browser/Window.js:680:7)
          at listOnTimeout (internal/timers.js:531:17)
          at processTimers (internal/timers.js:475:7) JestAssertionError: expect(received).toEqual(expected) // deep equality

      Expected: 2
      Received: 1
          at toEqual (/Users/dmml/Documents/Developer/reactPractice/testing/testing-stephen-grider/src/__tests__/integrations.test.js:36:37)
          at Timeout.callback [as _onTimeout] (/Users/dmml/Documents/Developer/reactPractice/testing/testing-stephen-grider/node_modules/jsdom/lib/jsdom/browser/Window.js:678:19)
          at listOnTimeout (internal/timers.js:531:17)
          at processTimers (internal/timers.js:475:7) {
        matcherResult: {
          actual: 1,
          expected: 2,
          message: [Function],
          name: 'toEqual',
          pass: false
        }
      }

  ● can fetch a list of comments and display them

    expect(received).toEqual(expected) // deep equality

    Expected: 2
    Received: 1

      34 |              wrapped.update();
      35 |              console.log(wrapped.find('li').length);
    > 36 |              expect(wrapped.find('li').length).toEqual(2);
         |                                                ^
      37 | 
      38 |              wrapped.unmount();
      39 |              done();

      at toEqual (src/__tests__/integrations.test.js:36:37)
      at Timeout.callback [as _onTimeout] (node_modules/jsdom/lib/jsdom/browser/Window.js:678:19)

Test Suites: 1 failed, 2 passed, 3 total
Tests:       1 failed, 5 passed, 6 total
Snapshots:   0 total
Time:        5.028s
Ran all test suites related to changed files.

1 个答案:

答案 0 :(得分:0)

moxios我从来没有取得过成功。因此,我更喜欢mock-axios-adapter。如果您使用的是thenables,则可以在类字段中返回axios调用并返回await。否则,如果您使用async/await,则可以简单地Promise.resolve()类字段实例。另外,我尽量避免使用setTimeout,因为它会增加总体测试运行时间。

例如(thenables):

class Example extends Component {
  state = {
    data: [],
    hasError: "",
    isLoading: true
  };

  componentDidMount = () => {
    window.setTimeout(() => {
      this.fetchData("users");
    }, 1500);
  };

  fetchData = url => {
    return app
      .get(`${url}`)
      .then(res => {
        this.setState({ isLoading: false, data: res.data });
      })
      .catch(err =>
        this.setState({ isLoading: false, hasError: err.toString() })
      );
  }

  handleClick = () => {
    this.setState({ isLoading: true, data: [] }, () => {
      this.fetchData("todos");
    });
  };

  render = () => (
    <div className="app-container">
      {this.state.isLoading ? (
        <ShowLoading />
      ) : this.state.hasError ? (
        <ShowError error={this.state.hasError} />
      ) : (
        <ShowData data={this.state.data} handleClick={this.handleClick} />
      )}
    </div>
  );
}

例如(async/await):

class Example extends Component {
  state = {
    data: [],
    hasError: "",
    isLoading: true
  };

  componentDidMount = () => {
    window.setTimeout(() => {
      this.fetchData("users");
    }, 1500);
  };

  fetchData = async url => {
    try {
      const res = await app.get(`${url}`);
      this.setState({ isLoading: false, data: res.data });
    } catch (err) {
      this.setState({ isLoading: false, hasError: err.toString() });
    }
  };

  handleClick = () => {
    this.setState({ isLoading: true, data: [] }, () => {
      this.fetchData("todos");
    });
  };

  render = () => (
    <div className="app-container">
      {this.state.isLoading ? (
        <ShowLoading />
      ) : this.state.hasError ? (
        <ShowError error={this.state.hasError} />
      ) : (
        <ShowData data={this.state.data} handleClick={this.handleClick} />
      )}
    </div>
  );
}

然后在您的测试中调用并解析fetchData(适用于两个示例-我使用单词implementation来指代伪造的API请求如何与组件和integration来指代真实的API 如何与组件进行交互-但这都是主观的:

import React from "react";
import MockAdapter from "axios-mock-adapter";
import { shallow } from "enzyme"; // I use shallow, but you can use mount
import Users from "../index.js";
import app from "../../../utils/axiosConfig";

const mockAxios = new MockAdapter(app);

const data = [
  {
    id: 1,
    name: "Leanne Graham",
    username: "Bret",
    email: "Sincere@april.biz",
    address: {
      street: "Kulas Light",
      suite: "Apt. 556",
      city: "Gwenborough",
      zipcode: "92998-3874",
      geo: {
        lat: "-37.3159",
        lng: "81.1496"
      }
    },
    phone: "1-770-736-8031 x56442",
    website: "hildegard.org",
    company: {
      name: "Romaguera-Crona",
      catchPhrase: "Multi-layered client-server neural-net",
      bs: "harness real-time e-markets"
    }
  }
];

describe("App", () => {
  let wrapper;
  beforeEach(() => {
    mockAxios.reset();
    wrapper = shallow(<Users />);
  });

  afterAll(() => {
    wrapper.unmount();
  });

  it("renders without errors", () => {
    expect(wrapper.find("div.app-container")).toHaveLength(1);
  });

  it("initally shows that it's loading", () => {
    expect(wrapper.state("isLoading")).toBeTruthy();
    expect(wrapper.find("ShowLoading")).toHaveLength(1);
  });

  describe("API Implementation", () => {
    it("renders data and shows an Update button", async () => {
      mockAxios.onGet("users").reply(200, data);
      await Promise.resolve(wrapper.instance().fetchData("users"));

      expect(wrapper.state("isLoading")).toBeFalsy();
      expect(
        wrapper
          .find("ShowData")
          .dive()
          .find("div.data")
      ).toHaveLength(1);
      expect(
        wrapper
          .find("ShowData")
          .dive()
          .find("button.update")
      ).toHaveLength(1);
      mockAxios.restore();
    });
  });

  describe("API Integration", () => {
    it("retrieves real data from API, renders data, and shows an Update button", async () => {
      await Promise.resolve(wrapper.instance().fetchData("users"));

      expect(wrapper.state("isLoading")).toBeFalsy();
      expect(
        wrapper
          .find("ShowData")
          .dive()
          .find("div.data")
      ).toHaveLength(10);
      expect(
        wrapper
          .find("ShowData")
          .dive()
          .find("button.update")
      ).toHaveLength(1);
    });
  });
});

运行位于Tests旁边的Browser标签。

工作示例(主题):

Edit API Example w/ Axios Mock Testing (thenables)

工作示例(异步/等待):

Edit API Example w/ Axios Mock Testing (async/await)