I want to assert on a condition which I know will not be true immediately, but might be true after an async action, in which the test should fail.
Say I'm testing this counter component:
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>
</>
);
}
I can write this test to check that the value should not go below zero:
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 !!!
But the last two assertions will always pass, even though the component has a bug which means it will asynchronously update to show "Value is -1".
What is the recommended way to deal with this kind of situation?