/** * @description Listens for one event and resolves with this event object after it was fired. * * @example * setTimeout(() => el.fireDone()); * await oneEvent(el, 'done'); * expect(el.done).to.be.true; * @returns Promise to await until the event has been fired */ export function oneEvent(eventTarget: HTMLElement, eventName: string) { return new Promise(resolve => { function listener(ev: Event) { resolve(ev) eventTarget.removeEventListener(eventName, listener) } eventTarget.addEventListener(eventName, listener) }) } type WaitUtilOptions = { interval?: number timeout?: number } /** * Waits until the given predicate returns a truthy value. Calls and awaits the predicate * function at the given interval time. Can be used to poll until a certain condition is true. * * @example * ```js * import { fixture, waitUntil } from '@open-wc/testing-helpers'; * * const element = await fixture(html``); * * await waitUntil(() => element.someAsyncProperty, 'element should become ready'); * ``` * */ export function waitUntil( predicate: () => unknown | Promise, message: string, options: WaitUtilOptions = {}, ) { const { interval = 50, timeout = 1000 } = options return new Promise((resolve, reject) => { let timeoutId: NodeJS.Timeout setTimeout(() => { clearTimeout(timeoutId) reject(new Error(message ? `Timeout: ${message}` : `waitUntil timed out after ${timeout}ms`)) }, timeout) async function nextInterval() { try { if (await predicate()) { resolve(undefined) } else { timeoutId = setTimeout(() => { nextInterval() }, interval) } } catch (error) { reject(error) } } nextInterval() }) }