test(engine): browser tests kill a Chrome whose close hangs instead of timing out (#5898)

This commit is contained in:
Miguel Ángel
2026-10-19 18:12:50 +00:00
committed by GitHub
parent 44bbc5885f
commit 0ce14d6443
5 changed files with 53 additions and 13 deletions
@@ -0,0 +1,25 @@
import { describe, expect, it, vi } from "vitest";
import type { Browser } from "puppeteer-core";
import { closeTestChrome } from "./loopback.js";
const fakeBrowser = (close: () => Promise<void>) => {
const kill = vi.fn();
const disconnect = vi.fn(async () => undefined);
const browser = { close, disconnect, process: () => ({ kill }) } as unknown as Browser;
return { browser, kill, disconnect };
};
describe("closeTestChrome", () => {
it("kills a Chrome whose close never finishes", async () => {
const { browser, kill, disconnect } = fakeBrowser(() => new Promise(() => undefined));
await closeTestChrome(browser, 0);
expect(kill).toHaveBeenCalledWith("SIGKILL");
expect(disconnect).toHaveBeenCalledOnce();
});
it("leaves a Chrome that closed alone", async () => {
const { browser, kill } = fakeBrowser(async () => undefined);
await closeTestChrome(browser, 60_000);
expect(kill).not.toHaveBeenCalled();
});
});
@@ -16,3 +16,23 @@ export function launchTestChrome(executablePath: string | undefined): Promise<Br
args: ["--no-sandbox", "--disable-dev-shm-usage"],
});
}
/** Closes a test Chrome, killing it when close hangs (seen on Windows runners) so afterAll never times out. */
export async function closeTestChrome(
browser: Browser | undefined,
timeoutMs = 5_000,
): Promise<void> {
if (!browser) return;
let timer: ReturnType<typeof setTimeout> | undefined;
const closed = await Promise.race([
browser.close().then(
() => true,
() => false,
),
new Promise<boolean>((resolve) => (timer = setTimeout(resolve, timeoutMs, false))),
]);
clearTimeout(timer);
if (closed) return;
browser.process()?.kill("SIGKILL");
await browser.disconnect().catch(() => undefined);
}
@@ -8,7 +8,7 @@ import {
releasableVideoIds,
releaseInjectedVideoMedia,
} from "./frameCapture.js";
import { listenOnLoopback, launchTestChrome } from "./__fixtures__/loopback.js";
import { closeTestChrome, listenOnLoopback, launchTestChrome } from "./__fixtures__/loopback.js";
const chromePath = resolveHeadlessShellPath();
const hasBrowser = chromePath !== undefined && spawnSync(chromePath, ["--version"]).status === 0;
@@ -50,7 +50,7 @@ describe.skipIf(!hasBrowser)("releaseInjectedVideoMedia in Chrome", () => {
});
afterAll(async () => {
for (const res of openMedia) res.destroy();
await browser?.close();
await closeTestChrome(browser);
await new Promise<void>((resolve) => server.close(() => resolve()));
});
@@ -1,8 +1,9 @@
import { spawnSync } from "node:child_process";
import { afterAll, beforeAll, describe, expect, it } from "vitest";
import puppeteer, { type Browser } from "puppeteer-core";
import type { Browser } from "puppeteer-core";
import { resolveHeadlessShellPath } from "./browserManager.js";
import { applyVideoMetadataHints } from "./frameCapture.js";
import { closeTestChrome, launchTestChrome } from "./__fixtures__/loopback.js";
const chromePath = resolveHeadlessShellPath();
const hasBrowser = chromePath !== undefined && spawnSync(chromePath, ["--version"]).status === 0;
@@ -23,15 +24,9 @@ describe.skipIf(!hasBrowser)("applyVideoMetadataHints in Chrome", () => {
let browser: Browser;
beforeAll(async () => {
browser = await puppeteer.launch({
executablePath: chromePath,
headless: true,
args: ["--no-sandbox", "--disable-dev-shm-usage"],
});
});
afterAll(async () => {
await browser?.close();
browser = await launchTestChrome(chromePath);
});
afterAll(() => closeTestChrome(browser));
it("lays out a video without loaded metadata as it would with it", async () => {
const page = await browser.newPage();
@@ -4,7 +4,7 @@ import { afterAll, beforeAll, beforeEach, describe, expect, it } from "vitest";
import type { Browser, Page } from "puppeteer-core";
import { resolveHeadlessShellPath } from "./browserManager.js";
import { injectVideoFramesBatch } from "./screenshotService.js";
import { listenOnLoopback, launchTestChrome } from "./__fixtures__/loopback.js";
import { closeTestChrome, listenOnLoopback, launchTestChrome } from "./__fixtures__/loopback.js";
const chromePath = resolveHeadlessShellPath();
const hasBrowser = chromePath !== undefined && spawnSync(chromePath, ["--version"]).status === 0;
@@ -45,7 +45,7 @@ describe.skipIf(!hasBrowser)("video frame transport in Chrome", () => {
unexpectedFrameRequests = 0;
});
afterAll(async () => {
await browser?.close();
await closeTestChrome(browser);
server.closeAllConnections();
await new Promise<void>((resolve) => server.close(() => resolve()));
});