3

我想断言一个我知道不会立即成立的条件,但在异步操作之后可能是真的,在这种情况下测试应该失败。

假设我正在测试这个计数器组件:

function Counter() {
  const [value, setValue] = useState(1);
  function decrement() {
    if (value >= 0) { // <- off by one bug
      someAsyncAction().then(() => setValue(value - 1));
    }
  }
  return (
    <>
      Value is {value}
      <button onClick={decrement}>Decrement</button>
    </>
  );
}

我可以编写这个测试来检查该值是否不应低于零:

const button = screen.getByRole("button", { name: "Decrement" });
expect(screen.getByText("Value is 1")).toBeInTheDocument();

userEvent.click(button);
expect(await screen.findByText("Value is 0")).toBeInTheDocument();

userEvent.click(button);
// !!! wrong !!!
expect(screen.getByText("Value is 0")).toBeInTheDocument();
expect(screen.queryByText("Value is -0")).not.toBeInTheDocument();
// !!! wrong !!!

但是最后两个断言总是会通过,即使组件有一个错误,这意味着它将异步更新以显示“Value is -1”。

处理这种情况的推荐方法是什么?

4

1 回答 1

5

我想出的最好的是:

await expect(screen.findByText("Value is -0", {}, {timeout: 100})).rejects.toThrow();

这试图找到文本,等待超时(从默认的 1 秒减少到 100 毫秒以加快测试速度)然后拒绝被expect. 如果文本存在,则findByText呼叫将解决,因此将拒绝并且测试将expect失败(不要忘记)。awaitexpect

可以使用以下方法将此模式扩展到其他断言waitFor

await expect(waitFor(() => {
  expect(screen.getByRole('input')).toHaveValue(-1);
}, { timeout: 100 })).rejects.toThrow();

虽然这可行,但它有点复杂,尤其是waitFor表单。我觉得这仍然可以改进,所以如果您有任何建议,请加入。

于 2021-07-09T14:00:16.383 回答