Loading
Current section: Assertions 7 exercises
solution

Retryable Assertions Solution

Replace vi.waitFor() with Vitest’s expect.poll() to write clearer retryable assertions for eventual async states in tests.

Loading solution

Transcript

00:00 Let's take a look at the test first. Here I'm testing this client class that implements a client-server communication. So here it requests some fruits and attaches the response listener that will be called once the server responds with some data. As any network communication, it's asynchronous. So this response may arrive immediately or in a second or in 50 milliseconds.

00:19 We don't know, but we need to account for that asynchronicity in the test. So to do that, I'm introducing this wait for utility, I'm awaiting this promise, and I express my expectation here that response listener should be called with this exact payload of apples, bananas, and cherries. What I can do instead though is use a retriable assertion.

00:38 Let me show you how that works. Let's take this existing assertion and refactor it. First, I will drop the wait for because we're not going to need it anymore. And the next thing I will do, I will call expect.pull. This expect.pull will introduce a new kind of assertion which will automatically retry itself until it reaches a certain timeout. To make it work, I need to make sure

00:59 that this received argument to this assertion is not the value I'm trying to test, it is the function that returns that value. By introducing this getter, you're eliminating the out-of-date, basically stale values here. So every time Vetus retries this assertion, it will pull this new value

01:15 and thus assert on the up-to-date state of that value. And then for the rest of it, this remainder of the assertion, this matcher remains absolutely the same. And now the only thing I have to do is to await this assertion because similar to wait for, using retriable assertions returns you a promise, something to await. So once I save this, let's run this test.

01:35 I'm going to open my terminal, run npm test, and I will see this test passing. So what's happening here is we are accounting for this client-server asynchronicity by introducing a retriable assertion using expect.pull. This assertion will pull the latest response listener value and will retry this to have been called with assertion,

01:55 making sure that it has been called with the correct payload. And only when it will, this return promise here will resolve and we will see our test passing. Similar to using wait for, you can customize your polling logic by introducing things like interval or timeout in the second argument to this poll function. This will be your options for this assertion.

02:14 And you can also configure timeout and interval globally to apply to all tests. If you go to your vitas-config, go to this test key, introduce expect here, then poll, and then you can provide the same options like interval and timeout to have a consistent values across your entire test suite.

02:31 The choice between expect.pull and wait for is really simple. It just so happened that wait for utility was never meant to be used with assertions. If you provide those expect calls in the callback to that function, when they throw, those errors are not always picked up by vitas correctly, and they may result in degrading developer experience overall.

02:50 So whenever you have to express some expectations towards your system that should happen eventually, you should always reach for expect.pull for retrieval assertions. So does it make the wait for utility obsolete? Well, not really. You should still use it to await different side effects, but the ones that are not directly related to your expectations, not related to the thing

03:09 that you're trying to test. For example, maybe your system transitions to a state and then you want to express some expectation. Maybe your page should change the URL, and then you want to make sure that a particular element is visible on the page. This is where you reach out to wait for instead. I've been dreaming about an API like expect something eventually to be something else for years now,

03:29 and I can finally use it built in in vitas in this nice form factor of expect.pull.