test: Avoid test flakiness by waiting for request count (#2740)
This commit is contained in:
@@ -14,6 +14,10 @@ const TEST_MEDIA_PATH = '/test-media';
|
||||
// page runs one test file, so nothing here is shared with another file.
|
||||
const requestCounts = new Map<string, number>();
|
||||
|
||||
// Tests waiting for a token to reach a request count, resolved by the worker
|
||||
// below as it counts.
|
||||
const requestWaiters = new Map<string, { count: number; resolve: () => void }[]>();
|
||||
|
||||
// Whether this page's tests asked for the worker. Recorded so that a URL only
|
||||
// the worker can answer cannot be built without it.
|
||||
let inUse = false;
|
||||
@@ -75,15 +79,49 @@ export const createUnansweredMediaURL = (): string => createTestMediaURL([]);
|
||||
export const createStallingMediaURL = (filename?: string): string =>
|
||||
createTestMediaURL([HTTP_OK], false, filename);
|
||||
|
||||
const getToken = (url: string): string | null =>
|
||||
new URL(url, window.location.href).searchParams.get('token');
|
||||
|
||||
/**
|
||||
* How many requests a media URL has been asked for, so a test can count what
|
||||
* the card actually fetched rather than only what it displayed.
|
||||
*/
|
||||
export const getTestMediaRequestCount = (url: string): number => {
|
||||
const token = new URL(url, window.location.href).searchParams.get('token');
|
||||
const token = getToken(url);
|
||||
return (token ? requestCounts.get(token) : null) ?? 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Wait until a media URL has been asked for the given number of times.
|
||||
*
|
||||
* A request is put on the page by the browser and answered by a service worker
|
||||
* on a thread of its own, so how long it takes to be counted is real time that
|
||||
* running the card's fake clock forward does not cover.
|
||||
*/
|
||||
export const waitForTestMediaRequestCount = async (
|
||||
url: string,
|
||||
count: number,
|
||||
): Promise<void> => {
|
||||
const token = getToken(url);
|
||||
if (!token) {
|
||||
throw new Error(
|
||||
'Requests are only counted for a media URL created by this file, ' +
|
||||
'e.g. createUnansweredMediaURL().',
|
||||
);
|
||||
}
|
||||
|
||||
if (getTestMediaRequestCount(url) >= count) {
|
||||
return;
|
||||
}
|
||||
|
||||
await new Promise<void>((resolve) => {
|
||||
requestWaiters.set(token, [
|
||||
...(requestWaiters.get(token) ?? []),
|
||||
{ count, resolve },
|
||||
]);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Serves a fixture at `/test-media/<file>`, behaving as the query asks:
|
||||
*
|
||||
@@ -120,7 +158,17 @@ const worker = setupWorker(
|
||||
.map(Number);
|
||||
|
||||
const answered = requestCounts.get(token) ?? 0;
|
||||
requestCounts.set(token, answered + 1);
|
||||
const counted = answered + 1;
|
||||
requestCounts.set(token, counted);
|
||||
|
||||
const waiters = requestWaiters.get(token) ?? [];
|
||||
requestWaiters.set(
|
||||
token,
|
||||
waiters.filter((waiter) => waiter.count > counted),
|
||||
);
|
||||
waiters
|
||||
.filter((waiter) => waiter.count <= counted)
|
||||
.forEach((waiter) => waiter.resolve());
|
||||
|
||||
const isPastEnd = answered >= responses.length;
|
||||
if (isPastEnd && url.searchParams.get('repeat') !== 'true') {
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
createUnansweredMediaURL,
|
||||
getTestMediaRequestCount,
|
||||
useTestMedia,
|
||||
waitForTestMediaRequestCount,
|
||||
} from '../../../browser/test-media';
|
||||
import {
|
||||
CAMERA_ENTITY,
|
||||
@@ -446,7 +447,8 @@ describe('MediaUnavailableIssue', () => {
|
||||
cameras: [createStillImageCameraConfig(CAMERA_ENTITY, mediaURL)],
|
||||
});
|
||||
|
||||
await card.waitForSelector('img');
|
||||
await waitForTestMediaRequestCount(mediaURL, 1);
|
||||
|
||||
await card.advanceSeconds(MEDIA_LOADING_TIMEOUT_SECONDS);
|
||||
expect(isIssueReported(card)).toBe(true);
|
||||
|
||||
@@ -460,6 +462,8 @@ describe('MediaUnavailableIssue', () => {
|
||||
// Past the grace period the attempt has had long enough, and the next retry
|
||||
// replaces it.
|
||||
await card.advanceSeconds(retrySeconds + 1);
|
||||
await waitForTestMediaRequestCount(mediaURL, 2);
|
||||
|
||||
expect(getTestMediaRequestCount(mediaURL)).toBeGreaterThan(1);
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user