From 6abf401a2f0ba191f9dd0d512a5fa1582d5ce1eb Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Wed, 8 Apr 2026 10:38:01 -0500 Subject: [PATCH] add self-tests for error collector fixture --- web/e2e/specs/_meta/error-collector.spec.ts | 112 ++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 web/e2e/specs/_meta/error-collector.spec.ts diff --git a/web/e2e/specs/_meta/error-collector.spec.ts b/web/e2e/specs/_meta/error-collector.spec.ts new file mode 100644 index 0000000000..7a888d4b22 --- /dev/null +++ b/web/e2e/specs/_meta/error-collector.spec.ts @@ -0,0 +1,112 @@ +/** + * Self-tests for the error collector fixture itself. + * + * These guard against future regressions in the safety net. Each test + * deliberately triggers (or avoids triggering) an error to verify the + * collector behaves correctly. Tests that expect to fail use the + * `expectedErrors` fixture parameter to allowlist their own errors. + */ + +import { test, expect } from "../../fixtures/frigate-test"; + +// test.use applies to a whole describe block in Playwright, so each test +// that needs a custom allowlist gets its own describe. + +test.describe("Error Collector — clean @meta", () => { + test("clean page passes", async ({ frigateApp }) => { + await frigateApp.goto("/"); + // No errors triggered. The fixture teardown should not throw. + }); +}); + +test.describe("Error Collector — unallowlisted console error fails @meta", () => { + test("console.error fails the test when not allowlisted", async ({ + page, + frigateApp, + }) => { + test.skip( + process.env.E2E_STRICT_ERRORS !== "1", + "Requires E2E_STRICT_ERRORS=1 to assert failure", + ); + test.fail(); // We expect the fixture teardown to throw + await frigateApp.goto("/"); + await page.evaluate(() => { + // eslint-disable-next-line no-console + console.error("UNEXPECTED_DELIBERATE_TEST_ERROR_xyz123"); + }); + }); +}); + +test.describe("Error Collector — allowlisted console error passes @meta", () => { + test.use({ expectedErrors: [/ALLOWED_DELIBERATE_TEST_ERROR_xyz123/] }); + + test("console.error is silenced when allowlisted via expectedErrors", async ({ + page, + frigateApp, + }) => { + await frigateApp.goto("/"); + await page.evaluate(() => { + // eslint-disable-next-line no-console + console.error("ALLOWED_DELIBERATE_TEST_ERROR_xyz123"); + }); + }); +}); + +test.describe("Error Collector — uncaught pageerror fails @meta", () => { + test("uncaught pageerror fails the test", async ({ page, frigateApp }) => { + test.skip( + process.env.E2E_STRICT_ERRORS !== "1", + "Requires E2E_STRICT_ERRORS=1 to assert failure", + ); + test.fail(); + await frigateApp.goto("/"); + await page.evaluate(() => { + setTimeout(() => { + throw new Error("UNCAUGHT_DELIBERATE_TEST_ERROR_xyz789"); + }, 0); + }); + // Wait a frame to let the throw propagate before fixture teardown. + // The marker below silences the e2e:lint banned-pattern check on this line. + await page.waitForTimeout(100); // e2e-lint-allow: deliberate; need to await async throw + }); +}); + +test.describe("Error Collector — 5xx fails @meta", () => { + test("same-origin 5xx response fails the test", async ({ + page, + frigateApp, + }) => { + test.skip( + process.env.E2E_STRICT_ERRORS !== "1", + "Requires E2E_STRICT_ERRORS=1 to assert failure", + ); + test.fail(); + await page.route("**/api/version", (route) => + route.fulfill({ status: 500, body: "boom" }), + ); + await frigateApp.goto("/"); + await page.evaluate(() => fetch("/api/version").catch(() => {})); + // Give the response listener a microtask to fire + await expect.poll(async () => true).toBe(true); + }); +}); + +test.describe("Error Collector — allowlisted 5xx passes @meta", () => { + // Use a single alternation regex so test.use() receives a 1-element array. + // Playwright's isFixtureTuple() treats any [value, object] pair as a fixture + // tuple, so a 2-element array whose second item is a RegExp would be + // misinterpreted as [defaultValue, options]. Both the request collector + // error ("500 … /api/version") and the browser console error + // ("Failed to load resource … 500") are matched by the alternation below. + test.use({ + expectedErrors: [/500.*\/api\/version|Failed to load resource.*500/], + }); + + test("allowlisted 5xx passes", async ({ page, frigateApp }) => { + await page.route("**/api/version", (route) => + route.fulfill({ status: 500, body: "boom" }), + ); + await frigateApp.goto("/"); + await page.evaluate(() => fetch("/api/version").catch(() => {})); + }); +});