mirror of https://github.com/coder/coder.git
83 lines
2.4 KiB
TypeScript
83 lines
2.4 KiB
TypeScript
import { Page } from "@playwright/test"
|
|
|
|
/**
|
|
* `timeout(x)` is a helper function to create a promise that resolves after `x` milliseconds.
|
|
*
|
|
* @param timeoutInMilliseconds Time to wait for promise to resolve
|
|
* @returns `Promise`
|
|
*/
|
|
export const timeout = (timeoutInMilliseconds: number): Promise<void> => {
|
|
return new Promise((resolve) => {
|
|
setTimeout(resolve, timeoutInMilliseconds)
|
|
})
|
|
}
|
|
|
|
/**
|
|
* `waitFor(f, timeout?)` waits for a predicate to return `true`, running it periodically until it returns `true`.
|
|
*
|
|
* If `f` never returns `true`, the function will simply return. In other words, the burden is on the consumer
|
|
* to check that the predicate is passing (`waitFor` does no validation).
|
|
*
|
|
* @param f A predicate that returns a `Promise<boolean>`
|
|
* @param timeToWaitInMilliseconds The total time to wait for the condition to be `true`.
|
|
* @returns
|
|
*/
|
|
export const waitFor = async (f: () => Promise<boolean>, timeToWaitInMilliseconds = 30000): Promise<void> => {
|
|
let elapsedTime = 0
|
|
const timeToWaitPerIteration = 1000
|
|
|
|
while (elapsedTime < timeToWaitInMilliseconds) {
|
|
const condition = await f()
|
|
|
|
if (condition) {
|
|
return
|
|
}
|
|
|
|
await timeout(timeToWaitPerIteration)
|
|
elapsedTime += timeToWaitPerIteration
|
|
}
|
|
}
|
|
|
|
interface WaitForClientSideNavigationOpts {
|
|
/**
|
|
* from is the page before navigation (the 'current' page)
|
|
*/
|
|
from?: string
|
|
/**
|
|
* to is the page after navigation (the 'next' page)
|
|
*/
|
|
to?: string
|
|
}
|
|
|
|
/**
|
|
* waitForClientSideNavigation waits for the url to change from opts.from to
|
|
* opts.to (if specified), as well as a network idle load state. This enhances
|
|
* a native playwright check for navigation or loadstate.
|
|
*
|
|
* @remark This is necessary in a client-side SPA world since playwright
|
|
* waitForNavigation waits for load events on the DOM (ex: after a page load
|
|
* from the server).
|
|
*
|
|
* @todo Better logging for this.
|
|
*/
|
|
export const waitForClientSideNavigation = async (page: Page, opts: WaitForClientSideNavigationOpts): Promise<void> => {
|
|
await Promise.all([
|
|
waitFor(() => {
|
|
const conditions: boolean[] = []
|
|
|
|
if (opts.from) {
|
|
conditions.push(page.url() !== opts.from)
|
|
}
|
|
|
|
if (opts.to) {
|
|
conditions.push(page.url() === opts.to)
|
|
}
|
|
|
|
const unmetConditions = conditions.filter((condition) => !condition)
|
|
|
|
return Promise.resolve(unmetConditions.length === 0)
|
|
}),
|
|
page.waitForLoadState("networkidle"),
|
|
])
|
|
}
|