Retryable assertions
When testing asynchronous code, your system often arrives at the expected state eventually. That is why you often express your intentions in tests as "wait for X to happen" instead of claiming "X must happen immediately".
In Promise-based APIs, that expectation is neatly abstracted behind the
async
/await
keywords to keep your tests clean:const response = await fetch('/api/songs')
await expect(response.json()).resolves.toEqual(favoriteSongs)
While fetching the list of songs takes time, that eventuality is represented as a Promise that you canawait
. This guaratees that your test will not continue until the data is fetched. Quite the same applies to reading the response body stream.
But not all systems are designed like that. And even the systems that are designed like that may not expose you the right Promises to await.
In those situations, you likely reach to utilities like
waitFor()
to help you express the expected eventual state of your tested code.api.sideEffect()
await vi.waitFor(() => {
expect(api.state).toEqual(expectedState)
})
And this works great. But today, I'd like to show you a different approach to expressing eventual expectations.