Skip to content

Waiting for Async Updates ​

Problem ​

An interaction triggers an asynchronous update (a debounced handler, a reactive framework's next render, a fetch call) and you need to assert on the result without a fixed setTimeout in every test.

Solution ​

Use waitUntil() to poll an explicit boolean condition, or waitForEvent() when the code under test dispatches an event you can listen for instead.

ts
import { fireInput, fireSubmit, waitForEvent, waitUntil, within } from '@vielzeug/assay';

const form = document.querySelector('.search-form')!;
const view = within(form);

fireInput(view.get('input'));

// Debounced search — poll until the result list renders.
await waitUntil(() => (view.query('.results')?.children.length ?? 0) > 0);

// Or, if the component dispatches a 'search-complete' event once done:
const eventPromise = waitForEvent(form, 'search-complete');

fireSubmit(form);

await eventPromise;

With a Custom Timeout ​

Slow environments (CI, a debounce longer than the 1000ms default) need a longer window:

ts
await waitUntil(() => (view.query('.results')?.children.length ?? 0) > 0, { timeout: 5000, interval: 100 });

Pitfalls ​

  • waitUntil() requires a boolean result. Use eventually() for a retrying expect() assertion.
  • waitUntil() applies one hard deadline to polling and pending async predicates. Raise the default 1000ms only for intentionally longer workflows.
  • waitForEvent() only resolves on the next matching event — if the event may have already fired before listening starts, wait for resulting DOM state instead.