Skip to main content

Waiting and synchronisation

Serenity/JS helps you model your test scenarios from the perspective of actors performing activities to accomplish their goals. Waiting for a condition to occur follows this same consistent approach, with any synchronisation statements assertions expressed using the interaction to Wait.until.

The anatomy of a synchronisation statement​

Wait.until follows the same consistent pattern as Ensure.eventually and accepts two arguments:

An example Serenity/JS synchronisation statement might look like this:

import { actorCalled, Wait } from '@serenity-js/core'
import { and, startsWith, endsWith } from '@serenity-js/assertions'

await actorCalled('Edna').attemptsTo(
Wait.until('Hello world', and(startsWith('Hello'), endsWith('world'))),
// actual value --^ ^-- expectation
)

Wait vs Ensure​

Same as the interaction to Ensure.eventually, Wait.until allows for the "actual value" to be determined dynamically and resolved in the context of the actor performing the assertion.

<span class="spinner">Loading...</span>
import { actorCalled, Wait } from '@serenity-js/core'
import { not, isPresent } from '@serenity-js/assertions'
import { PageElement, By } from '@serenity-js/web'

const spinner = () =>
PageElement.located(By.css('.spinner')).describedAs('spinner')

await actorCalled('Edna').attemptsTo(
Wait.until(spinner(), not(isPresent())),
)

Again, same as the interaction to Ensure.eventually, the maximum interaction timeout of Wait.until can be set globally via Serenity/JS configuration, or per interaction:

import { actorCalled, Duration, Wait } from '@serenity-js/core'
import { not, isPresent } from '@serenity-js/assertions'

await actorCalled('Edna').attemptsTo(
Wait.upTo(Duration.ofSeconds(2))
.until(spinner(), not(isPresent())),
)

However, unlike Ensure.eventually which uses an exponential backoff algorithm to reduce the frequency of evaluation calls over time, Wait.until instructs the actor to resolve the actual value at a consistent time interval between the evaluation calls:

Example web scenario interacting with the widget
import { actorCalled, Duration, Wait } from '@serenity-js/core'
import { not, isPresent } from '@serenity-js/assertions'

await actorCalled('Edna').attemptsTo(
Wait.until(spinner(), not(isPresent()))
.pollingEvery(Duration.ofSeconds(1)),
)

Implementing custom expectations​

Serenity/JS assertions and web modules provide expectations you'll need to implement even the most sophisticated test scenarios.

However, you can also implement custom expectations when needed. To do that, consult the examples in Expectation API docs and the Serenity/JS code base on GitHub.