玩笑测试:在连接组件中等待多个承诺

gyl*_*laz 2 javascript asynchronous reactjs jestjs redux

我有一个连接组件(HOC),可以在 中获取一些数据componentDidMount,例如:

function setData(data) {
  return { type: "SET_DATA", data: data };
}

function fetchData() {
  return axios.get("http://echo.jsontest.com/key/value/one/two");
}

function getData(dispatch) {
  return () => fetchData().then(response => dispatch(setData(response.data)));
}

class Welcome extends Component {
  componentDidMount() {
    this.props.getData();
  }

  render() {
    if (this.props.data) {
      return <div>We have data!</div>;
    } else {
      return <div>Waiting for data...</div>;
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

完整代码可以在这里看到:https://github.com/gylaz/react-integration-test-example/blob/eb3238c0a8aa4b15331a031d7d2d3a0aa97ef9c7/src/App.js

我的测试看起来像:

it("renders without crashing", async () => {
  axios.get = jest.fn(() => {
    return Promise.resolve({ data: { one: 1, two: 2 } });
  });
  const div = document.createElement("div");
  const component = await ReactDOM.render(<App />, div);

  expect(div.textContent).toEqual("We have data!");
});
Run Code Online (Sandbox Code Playgroud)

完整测试代码在这里:https://github.com/gylaz/react-integration-test-example/blob/eb3238c0a8aa4b15331a031d7d2d3a0aa97ef9c7/src/App.test.js

测试顺利通过!

但是,当我对方法进行修改fetchData以从响应中提取实际数据(通过 Promise)时,例如:

function fetchData() {
  return axios
    .get("http://echo.jsontest.com/key/value/one/two")
    .then(response => response.data);
}

function getData(dispatch) {
  return () => fetchData().then(data => dispatch(setData(data)));
}
Run Code Online (Sandbox Code Playgroud)

测试将失败,直到我await在第一个之前添加另一个await

it("renders without crashing", async () => {
  axios.get = jest.fn(() => {
    return Promise.resolve({ data: { one: 1, two: 2 } });
  });
  const div = document.createElement("div");
  const component = await await ReactDOM.render(<App />, div);

  expect(div.textContent).toEqual("We have data!");
});
Run Code Online (Sandbox Code Playgroud)

这是显示上述内容的 PR:https://github.com/gylaz/react-integration-test-example/pull/1

我的调用链中的 s越多,我需要添加的then就越多,这看起来很麻烦。awaits

是否有更好的方法在测试中立即等待所有内容,或者其他解决方案?

gyl*_*laz 5

await我发现最好的方法是将期望包裹在setImmediateor中,而不是使用多个s process.nextTick。而且您不需要使用async/await.

例如:

it("renders without crashing", () => {
  axios.get = jest.fn(() => {
    return Promise.resolve({ data: { one: 1, two: 2 } });
  });
  const div = document.createElement("div");
  const component = ReactDOM.render(<App />, div);

  setImmediate(() => {
    expect(div.textContent).toEqual("We have data!");
  });
});
Run Code Online (Sandbox Code Playgroud)

关于承诺和事件外观的解释可以在这篇文章中找到。

这种方法的一个缺点是,如果期望失败,Jest 将使测试运行器崩溃(而不是显示失败但不崩溃)。目前有一个 bug,可以在 GitHub 上的这个问题中关注。