Tam*_*lyn 7 jestjs react-testing-library testing-library
我想断言一个条件,我知道该条件不会立即为真,但在异步操作之后可能为真,此时测试应该失败。
假设我正在测试这个计数器组件:
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>
</>
);
}
Run Code Online (Sandbox Code Playgroud)
我可以编写此测试来检查该值不应低于零:
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 -1")).not.toBeInTheDocument();
// !!! wrong !!!
Run Code Online (Sandbox Code Playgroud)
但是最后两个断言总是会通过,即使组件有一个错误,这意味着它将异步更新以显示“值是-1”。
处理这种情况的推荐方法是什么?
Tam*_*lyn 14
我想出的最好的办法是:
await expect(
screen.findByText("Value is -1", {}, { timeout: 100 })
).rejects.toThrow();
Run Code Online (Sandbox Code Playgroud)
它尝试查找文本,等待超时(从默认的 1 秒减少到 100 毫秒以加快测试速度),然后拒绝 捕获的文本expect。如果文本存在,则findByText调用将解析,因此将expect拒绝并且测试将失败(不要忘记await)expect。
该模式可以使用以下方法扩展到其他断言waitFor:
await expect(
waitFor(
() => { expect(screen.getByRole('input')).toHaveValue(-1); },
{ timeout: 100 }
)
).rejects.toThrow();
Run Code Online (Sandbox Code Playgroud)
虽然这可行,但有点复杂,尤其是waitFor形式。我觉得这仍然可以改进,所以如果您有任何建议,请提出。
采用Tamlyn 出色的自我回答中提出的概念,我将其推断为一个名为的实用程序,该实用程序具有与测试库verifyNeverOccurs相同的签名,但只有在您发送给它的回调断言通过时才会失败:waitFor
import { waitFor, waitForOptions } from '@testing-library/react';
/**
* Inverse of RTL's `waitFor`; used to verify that a thing does *not* occur.
* Useful for situations in which verifying that some effect did occur would
* require using `await waitFor()` and you need to test that the effect does
* not occur. Like `waitFor`, it must be `await`ed.
* @param {function} negativeAssertionFn - a callback function that expects a thing you do _not_ expect will occur
* @param {Object} options - options object with same shape as `waitFor`'s options argument (ultimately just passed through to `waitFor`)
* @return {void}
*/
const verifyNeverOccurs = async (negativeAssertionFn: () => unknown, options?: waitForOptions) => {
await expect(
waitFor(negativeAssertionFn, options),
).rejects.toThrow();
};
export default verifyNeverOccurs;
Run Code Online (Sandbox Code Playgroud)
(这是在 TypeScript 中,但如果你想在 vanilla JS 中使用,你可以随时删除类型)。
用法示例:
// fails if `element` ever contains the text "oh no"
verifyNeverOccurs(() => expect(element).toHaveTextContent('oh no'));
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2793 次 |
| 最近记录: |