Files
buzz/desktop/scripts/check-e2e-bootstrap.test.mjs
Logan Johnson 091670ff77 fix(e2e): close bootstrap checker receiver gaps
Preserve unsafe bootstrap events through supported parenthesized forms and grant loop bootstrap credit only when syntax proves an enumerable runtime iteration.

Co-authored-by: Larry <larry@buzz.local>
Co-authored-by: Brother Darryl <darryl@buzz.local>
Signed-off-by: Logan Johnson <loganj@squareup.com>
2026-08-21 00:34:00 +00:00

1343 lines
54 KiB
JavaScript

import assert from "node:assert/strict";
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
import test from "node:test";
const projects = [
["desktop", "../scripts/check-e2e-bootstrap.mjs"],
["web", "../scripts/check-e2e-bootstrap.mjs"],
];
const imports = 'import { test, bootstrapE2ePage } from "../helpers/test";';
const spec = (body) =>
`${imports}\ntest("x", async ({ page }) => { ${body} });`;
for (const [project, checkerPath] of projects) {
const { checkSource, runCheck } = await import(checkerPath);
const accepts = (source) => assert.equal(checkSource(source), undefined);
const rejects = (source) => assert.notEqual(checkSource(source), undefined);
test(`${project}: accepts direct, hook, and beforeNavigate bootstrap patterns`, () => {
accepts(spec("await bootstrapE2ePage(page);"));
accepts(
`${imports}\ntest.beforeEach(async ({ page }) => { await bootstrapE2ePage(page); });\ntest("x", async ({ page }) => { await page.title(); });`,
);
accepts(
spec(
"await bootstrapE2ePage(page, { beforeNavigate: async () => page.addInitScript(() => {}) });",
),
);
});
test(`${project}: accepts module helpers and ratified containers`, () => {
accepts(
`${imports}\nasync function open(page) { return await bootstrapE2ePage(page); }\ntest("x", async ({ page }) => { const response = await open(page); void response; });`,
);
accepts(
spec(
"try { await bootstrapE2ePage(page); } finally { await page.title(); }",
),
);
accepts(
spec(
"try { await page.title(); } finally { await bootstrapE2ePage(page); }",
),
);
accepts(
spec("for (const attempt of [0, 1]) { await bootstrapE2ePage(page); }"),
);
accepts(
spec(
"for (let attempt = 0; attempt < 2; attempt += 1) { await bootstrapE2ePage(page); }",
),
);
});
test(`${project}: classifies indirect page fixture access and requires bootstrap`, () => {
const cases = [
[
"whole fixture object",
"fixtures",
"await fixtures.page.title();",
"const { page } = fixtures; await bootstrapE2ePage(page);",
],
[
"object rest",
"{ ...rest }",
"await rest.page.title();",
"const { page } = rest; await bootstrapE2ePage(page);",
],
[
"body destructuring",
"fixtures",
"const { page } = fixtures; await page.title();",
"const { page } = fixtures; await bootstrapE2ePage(page);",
],
];
for (const [name, parameter, body, bootstrap] of cases) {
const source = `${imports}\ntest("${name}", async (${parameter}) => { ${body} });`;
assert.equal(
checkSource(source),
"must structurally await bootstrapE2ePage for every test, directly or through an applicable ancestor test.beforeEach",
);
accepts(
`${imports}\ntest("${name}", async (${parameter}) => { ${bootstrap} ${body} });`,
);
}
});
test(`${project}: follows bounded fixture-object aliases and element access`, () => {
const cases = [
"const alias = fixtures; await alias.page.title();",
'await fixtures["page"].title();',
"const first = fixtures; const second = first; const { page } = second; await page.title();",
];
for (const body of cases) {
const source = `${imports}\ntest("x", async (fixtures) => { ${body} });`;
assert.equal(
checkSource(source),
"must structurally await bootstrapE2ePage for every test, directly or through an applicable ancestor test.beforeEach",
);
accepts(
`${imports}\ntest("x", async (fixtures) => { const { page } = fixtures; await bootstrapE2ePage(page); ${body} });`,
);
}
});
test(`${project}: requires bootstrap for each created page receiver`, () => {
const unsafe = `${imports}
test("x", async ({ page, context }) => {
await bootstrapE2ePage(page);
const second = await context.newPage();
await second.goto("/");
});`;
assert.equal(
checkSource(unsafe),
"must structurally await bootstrapE2ePage for every test, directly or through an applicable ancestor test.beforeEach",
);
rejects(`${imports}
test("x", async ({ page, context }) => {
const second = await context.newPage();
await bootstrapE2ePage(second, "/");
await page.title();
});`);
accepts(`${imports}
test("x", async ({ page, context }) => {
const second = await context.newPage();
await bootstrapE2ePage(page, "/");
await bootstrapE2ePage(second, "/");
await page.title();
});`);
rejects(`${imports}
test("x", async ({ context }) => {
const second = await context.newPage();
await second.goto("/");
});`);
rejects(`${imports}
test("x", async ({ context }) => {
const second = await context.newPage();
await second.goto("/");
await bootstrapE2ePage(second, "/");
});`);
rejects(`${imports}
test("x", async ({ page, context }) => {
await bootstrapE2ePage(page);
const second = await context.newPage();
bootstrapE2ePage(second, "/");
await second.goto("/");
});`);
accepts(`${imports}
test("x", async ({ page, context }) => {
await bootstrapE2ePage(page);
const second = await context.newPage();
await bootstrapE2ePage(second, "/");
});`);
rejects(`${imports}
test("x", async ({ context }) => {
const second = await context.newPage();
await second.goto("/");
await bootstrapE2ePage(second, "/");
await second.goto("/later");
});`);
accepts(`${imports}
test("x", async ({ context }) => {
const second = await context.newPage();
await bootstrapE2ePage(second, "/");
await second.goto("/");
await bootstrapE2ePage(second, "/later");
await second.goto("/later");
});`);
rejects(`${imports}
async function navigate(target) { await target.goto("/"); }
test("fixture navigation before bootstrap", async ({ page }) => {
await navigate(page);
await bootstrapE2ePage(page, "/");
});`);
rejects(`${imports}
async function readStorage(target) { await target.evaluate(() => localStorage.getItem("x")); }
test("fixture storage before bootstrap", async ({ page }) => {
await readStorage(page);
await bootstrapE2ePage(page, "/");
});`);
accepts(`${imports}
test("fixture setup before bootstrap", async ({ page }) => {
await page.addInitScript(() => {});
await bootstrapE2ePage(page, "/");
});`);
for (const body of [
'const second = await context.newPage(); if (false) await bootstrapE2ePage(second); await second.goto("/");',
'const second = await context.newPage(); async function never() { await bootstrapE2ePage(second); } await second.goto("/");',
'let second; second = await context.newPage(); await second.goto("/");',
'const second = await context.newPage(); second.goto("/");',
])
rejects(
`${imports}\n test("x", async ({ context }) => { ${body} });`,
);
});
test(`${project}: preserves helper event order and actual-argument mapping`, () => {
rejects(`${imports}
async function unsafeThenBootstrap(target) {
await target.goto("/");
await bootstrapE2ePage(target);
}
test("x", async ({ page }) => { await unsafeThenBootstrap(page); });`);
accepts(`${imports}
async function bootstrapThenUnsafe(target) {
await bootstrapE2ePage(target);
await target.goto("/");
}
test("x", async ({ page }) => { await bootstrapThenUnsafe(page); });`);
rejects(`${imports}
async function inner(safeTarget, unsafeTarget) {
await bootstrapE2ePage(safeTarget);
await unsafeTarget.goto("/");
}
async function outer(unsafeTarget, other) { await inner(other, unsafeTarget); }
test("x", async ({ page }) => {
const other = {};
await outer(page, other);
});`);
accepts(`${imports}
async function inner(target) { await bootstrapE2ePage(target); }
async function outer(unused, target) { await inner(target); }
test("x", async ({ page }) => { await outer(undefined, page); });`);
});
test(`${project}: conservatively checks executable conditional branches`, () => {
rejects(
spec(
'if (condition) await page.goto("/"); await bootstrapE2ePage(page);',
),
);
rejects(
spec(
'switch (mode) { case "go": await page.goto("/"); break; default: break; } await bootstrapE2ePage(page);',
),
);
accepts(
spec(
'await bootstrapE2ePage(page); if (condition) await page.goto("/");',
),
);
accepts(
spec(
'await bootstrapE2ePage(page); switch (mode) { case "go": await page.goto("/"); break; default: break; }',
),
);
rejects(
spec(
'if (condition) await bootstrapE2ePage(page); await page.goto("/");',
),
);
accepts(
spec('if (false) await page.goto("/"); await bootstrapE2ePage(page);'),
);
});
test(`${project}: keeps hook coverage receiver-aware`, () => {
rejects(`${imports}
test.beforeEach(async ({ page }) => { await bootstrapE2ePage(page); });
test("x", async ({ context }) => {
const second = await context.newPage();
await second.goto("/");
});`);
accepts(`${imports}
test.beforeEach(async ({ page }) => { await bootstrapE2ePage(page); });
test("x", async ({ page }) => { await page.title(); });`);
accepts(`${imports}
test.beforeEach(async ({ page }) => { await bootstrapE2ePage(page); });
test("x", async ({ context }) => {
const second = await context.newPage();
await bootstrapE2ePage(second);
await second.goto("/");
});`);
});
test(`${project}: conservatively checks catch work`, () => {
rejects(
spec(
'try { await page.title(); } catch { await page.goto("/"); } await bootstrapE2ePage(page);',
),
);
accepts(
spec(
'await bootstrapE2ePage(page); try { await page.title(); } catch { await page.goto("/"); }',
),
);
rejects(
spec(
'try { await page.title(); } catch { await bootstrapE2ePage(page); } await page.goto("/");',
),
);
});
test(`${project}: propagates unawaited helper unsafe events`, () => {
rejects(
`${imports} async function read(target) { await target.evaluate(() => localStorage.getItem("x")); } test("x", async ({ page }) => { read(page); await bootstrapE2ePage(page); });`,
);
rejects(
`${imports} async function go(target) { await target.goto("/"); } test("x", async ({ page }) => { go(page); await bootstrapE2ePage(page); });`,
);
rejects(
`${imports} async function boot(target) { await bootstrapE2ePage(target); } test("x", async ({ page }) => { boot(page); await page.goto("/"); });`,
);
accepts(
`${imports} async function go(target) { await target.goto("/"); } test("x", async ({ page }) => { await bootstrapE2ePage(page); await go(page); });`,
);
accepts(
`${imports} async function setup(target) { await target.addInitScript(() => {}); } test("x", async ({ page }) => { setup(page); await bootstrapE2ePage(page); });`,
);
});
test(`${project}: preserves safety events through parenthesized helper calls`, () => {
for (const call of ["(go(page));", "await (go(page));"])
rejects(
`${imports} async function go(target) { await target.goto("/"); } test("x", async ({ page }) => { ${call} await bootstrapE2ePage(page); });`,
);
for (const call of ["(go(page));", "await (go(page));"])
accepts(
`${imports} async function go(target) { await target.goto("/"); } test("x", async ({ page }) => { await bootstrapE2ePage(page); ${call} });`,
);
});
test(`${project}: preserves safety events through parenthesized helper callees`, () => {
for (const call of ["(go)(page);", "await (go)(page);"])
rejects(
`${imports} async function go(target) { await target.goto("/"); } test("x", async ({ page }) => { ${call} await bootstrapE2ePage(page); });`,
);
rejects(
`${imports} async function go(target) { await target.goto("/"); } test("x", async ({ page }) => { await (go(page)); await bootstrapE2ePage(page); });`,
);
accepts(
`${imports} async function setup(target) { await target.addInitScript(() => {}); } test("x", async ({ page }) => { await (setup)(page); await (bootstrapE2ePage)(page); });`,
);
});
test(`${project}: preserves supported operations through member parentheses`, () => {
for (const operation of [
'await (page.goto)("/");',
'await (page).goto("/");',
'await ((page)["goto"])("/");',
'await (page.evaluate)(() => localStorage.getItem("x"));',
])
rejects(spec(`${operation} await bootstrapE2ePage(page);`));
for (const operation of [
'await (target.goto)("/");',
'await (target).goto("/");',
'await (target.evaluate)(() => localStorage.getItem("x"));',
])
rejects(
`${imports} async function unsafe(target) { ${operation} } test("x", async ({ page }) => { await unsafe(page); await bootstrapE2ePage(page); });`,
);
accepts(spec('await bootstrapE2ePage(page); await (page.goto)("/");'));
});
test(`${project}: recognizes parenthesized created-page operations`, () => {
for (const creation of [
"await (context.newPage)()",
"await (context).newPage()",
'await ((context)["newPage"])()',
"await ((context.newPage)())",
])
rejects(
`${imports} test("x", async ({ context }) => { const second = ${creation}; await second.goto("/"); });`,
);
accepts(
`${imports} test("x", async ({ context }) => { const second = await (context.newPage)(); await bootstrapE2ePage(second); await (second.goto)("/"); });`,
);
});
test(`${project}: grants loop bootstrap credit only for guaranteed iterations`, () => {
for (const loop of [
"for (const value of values) await bootstrapE2ePage(page);",
"for (const key in values) await bootstrapE2ePage(page);",
"for (const value of [...[]]) await bootstrapE2ePage(page);",
"for (const value of [...values]) await bootstrapE2ePage(page);",
"for (const key in { ...{} }) await bootstrapE2ePage(page);",
"for (const key in { ...values }) await bootstrapE2ePage(page);",
"for (const key in { __proto__: null }) await bootstrapE2ePage(page);",
'for (const key in { "__proto__": null }) await bootstrapE2ePage(page);',
"for (const key in { [Symbol()]: 1 }) await bootstrapE2ePage(page);",
"for (const key in { [Symbol.iterator]: 1 }) await bootstrapE2ePage(page);",
"for (const key in { [key]: 1 }) await bootstrapE2ePage(page);",
"for (const key in { [getKey()]: 1 }) await bootstrapE2ePage(page);",
"for (const key in { [Symbol.iterator]() {} }) await bootstrapE2ePage(page);",
"for (const key in { get [Symbol.iterator]() { return 1 } }) await bootstrapE2ePage(page);",
"for (const key in { set [Symbol.iterator](value) {} }) await bootstrapE2ePage(page);",
"for (const key in { [key]() {} }) await bootstrapE2ePage(page);",
"for (const key in { get [key]() { return 1 } }) await bootstrapE2ePage(page);",
"for (const key in { set [key](value) {} }) await bootstrapE2ePage(page);",
"while (condition) await bootstrapE2ePage(page);",
"for (; condition;) await bootstrapE2ePage(page);",
])
rejects(spec(`${loop} await page.goto("/");`));
rejects(
spec(
'let values = []; for (const value of values) await bootstrapE2ePage(page); values = [1]; await page.goto("/");',
),
);
accepts(
spec(
'const values = [1]; for (const value of values) await bootstrapE2ePage(page); await page.goto("/");',
),
);
rejects(
spec(
'const values = [...[]]; for (const value of values) await bootstrapE2ePage(page); await page.goto("/");',
),
);
for (const loop of [
"for (const value of [1]) await bootstrapE2ePage(page);",
"for (const value of [...[], 1]) await bootstrapE2ePage(page);",
"for (const key in { ...{}, x: 1 }) await bootstrapE2ePage(page);",
'for (const key in { ["__proto__"]: null }) await bootstrapE2ePage(page);',
"for (const key in { [`x`]: 1 }) await bootstrapE2ePage(page);",
"for (const key in { [1]: 1 }) await bootstrapE2ePage(page);",
'for (const key in { ["x"]() {} }) await bootstrapE2ePage(page);',
'for (const key in { get ["x"]() { return 1 } }) await bootstrapE2ePage(page);',
'for (const key in { set ["x"](value) {} }) await bootstrapE2ePage(page);',
"for (const key in { __proto__: null, x: 1 }) await bootstrapE2ePage(page);",
'for (const value of "x") await bootstrapE2ePage(page);',
"for (const key in { x: 1 }) await bootstrapE2ePage(page);",
"for (;;) { await bootstrapE2ePage(page); break; }",
"while (true) { await bootstrapE2ePage(page); break; }",
"do { await bootstrapE2ePage(page); } while (condition);",
])
accepts(spec(`${loop} await page.goto("/");`));
rejects(
spec(
'for (const value of values) await page.goto("/"); await bootstrapE2ePage(page);',
),
);
});
test(`${project}: invalidates unsafe events born on unmapped helper receivers`, () => {
for (const operation of [
'const alias = target; await alias.goto("/");',
'const alias = target; await alias.evaluate(() => localStorage.getItem("x"));',
'const unrelated = {}; await unrelated.goto("/");',
])
rejects(
`${imports} async function unsafe(target) { ${operation} } test("x", async ({ page }) => { await unsafe(page); await bootstrapE2ePage(page); });`,
);
rejects(
`${imports} async function unsafe(target) { await target.goto("/"); } test("x", async ({ page }) => { await unsafe(page); await bootstrapE2ePage(page); });`,
);
accepts(
`${imports} async function setup(target) { const alias = target; await alias.addInitScript(() => {}); } test("x", async ({ page }) => { await setup(page); await bootstrapE2ePage(page); });`,
);
});
test(`${project}: fails closed when callback helper events cannot map to receivers`, () => {
for (const actual of ["alias", "unrelated"])
rejects(
`${imports} async function go(target) { await target.goto("/"); } test("x", async ({ page }) => { const alias = page; const unrelated = {}; await go(${actual}); await bootstrapE2ePage(page); });`,
);
rejects(
`${imports} async function go(target) { await target.goto("/"); } test("x", async ({ page }) => { await go(page); await bootstrapE2ePage(page); });`,
);
accepts(
`${imports} async function setup(target) { await target.addInitScript(() => {}); } test("x", async ({ page }) => { const alias = page; await setup(alias); await bootstrapE2ePage(page); });`,
);
});
test(`${project}: classifies bounded element-access operations`, () => {
rejects(spec('await page["goto"]("/"); await bootstrapE2ePage(page);'));
rejects(
spec(
'await page["evaluate"](() => localStorage.getItem("x")); await bootstrapE2ePage(page);',
),
);
rejects(
`${imports} test("x", async ({ context }) => { const second = await context["newPage"](); await second.goto("/"); });`,
);
accepts(spec('await bootstrapE2ePage(page); await page["goto"]("/");'));
accepts(
`${imports} test("x", async ({ context }) => { const second = await context["newPage"](); await bootstrapE2ePage(second); await second["goto"]("/"); });`,
);
});
test(`${project}: fails closed for recursive and unmapped helpers`, () => {
rejects(
`${imports} async function setup(target) { await bootstrapE2ePage(target); await setup(target); } test("x", async ({ page }) => { await setup(page); });`,
);
rejects(
`${imports} async function a(target) { await bootstrapE2ePage(target); await b(target); } async function b(target) { await a(target); } test("x", async ({ page }) => { await a(page); });`,
);
rejects(
`${imports} async function go(target) { await target.goto("/"); } test("x", async ({ page }) => { go(page as any); await bootstrapE2ePage(page); });`,
);
rejects(
`${imports} async function go(target) { await target.goto("/"); } test("x", async ({ page }) => { go((page)); await bootstrapE2ePage(page); });`,
);
rejects(
`${imports} async function go(target) { await target.goto("/"); } test("x", async (fixtures) => { go(fixtures.page); const { page } = fixtures; await bootstrapE2ePage(page); });`,
);
accepts(
`${imports} async function inner(target) { await bootstrapE2ePage(target); } async function outer(target) { await inner(target); } test("x", async ({ page }) => { await outer(page); });`,
);
accepts(
`${imports} async function setup(target) { await target.addInitScript(() => {}); } test("x", async ({ page }) => { setup(page as any); await bootstrapE2ePage(page); });`,
);
});
test(`${project}: rejects nested safety events mapped through local identifiers`, () => {
rejects(
`${imports} async function inner(target) { await target.goto("/"); } async function outer(target) { const alias = target; await inner(alias); } test("x", async ({ page }) => { await outer(page); await bootstrapE2ePage(page); });`,
);
rejects(
`${imports} async function inner(target) { await target.goto("/"); } async function outer(target) { await inner(target); } test("x", async ({ page }) => { await outer(page); await bootstrapE2ePage(page); });`,
);
accepts(
`${imports} async function inner(target) { await target.addInitScript(() => {}); } async function outer(target) { const alias = target; await inner(alias); } test("x", async ({ page }) => { await outer(page); await bootstrapE2ePage(page); });`,
);
});
test(`${project}: applies created-page receiver enforcement in whole-file checks`, () => {
const root = fs.mkdtempSync(
path.join(os.tmpdir(), "e2e-bootstrap-created-page-"),
);
try {
fs.mkdirSync(path.join(root, "tests/e2e"), { recursive: true });
fs.mkdirSync(path.join(root, "tests/helpers"), { recursive: true });
fs.writeFileSync(
path.join(root, "tests/helpers/test.ts"),
"export {};\n",
);
for (const [name, body] of [
[
"wrong-fixture-receiver.spec.ts",
'const second = await context.newPage(); await bootstrapE2ePage(second, "/"); await page.title();',
],
[
"safe-fixture-receiver.spec.ts",
'const second = await context.newPage(); await bootstrapE2ePage(page, "/"); await bootstrapE2ePage(second, "/"); await page.title();',
],
[
"fixture-navigation-before-bootstrap.spec.ts",
'await page.goto("/"); await bootstrapE2ePage(page, "/");',
],
[
"fixture-storage-before-bootstrap.spec.ts",
'await page.evaluate(() => localStorage.getItem("x")); await bootstrapE2ePage(page, "/");',
],
[
"fixture-setup-before-bootstrap.spec.ts",
'await page.addInitScript(() => {}); await bootstrapE2ePage(page, "/");',
],
[
"dead.spec.ts",
'const second = await context.newPage(); if (false) await bootstrapE2ePage(second); await second.goto("/");',
],
[
"nested.spec.ts",
'const second = await context.newPage(); async function never() { await bootstrapE2ePage(second); } await second.goto("/");',
],
[
"assigned.spec.ts",
'let second; second = await context.newPage(); await second.goto("/");',
],
[
"unawaited-navigation.spec.ts",
'const second = await context.newPage(); second.goto("/");',
],
[
"initial-navigation.spec.ts",
'const second = await context.newPage(); await second.goto("/"); await bootstrapE2ePage(second, "/"); await second.goto("/later");',
],
[
"conditional-unsafe.spec.ts",
'if (condition) await page.goto("/"); await bootstrapE2ePage(page);',
],
[
"conditional-safe.spec.ts",
'await bootstrapE2ePage(page); if (condition) await page.goto("/");',
],
[
"switch-unsafe.spec.ts",
'switch (mode) { case "go": await page.goto("/"); break; default: break; } await bootstrapE2ePage(page);',
],
[
"switch-safe.spec.ts",
'await bootstrapE2ePage(page); switch (mode) { case "go": await page.goto("/"); break; default: break; }',
],
[
"initial-bootstrap.spec.ts",
'await bootstrapE2ePage(page, "/"); const second = await context.newPage(); await bootstrapE2ePage(second, "/"); await second.goto("/"); await bootstrapE2ePage(second, "/later"); await second.goto("/later");',
],
])
fs.writeFileSync(
path.join(root, "tests/e2e", name),
`${imports} test("x", async ({ page, context }) => { ${body} });`,
);
fs.writeFileSync(
path.join(root, "tests/e2e/helper-order-unsafe.spec.ts"),
`${imports} async function open(target) { await target.goto("/"); await bootstrapE2ePage(target); } test("x", async ({ page }) => { await open(page); });`,
);
fs.writeFileSync(
path.join(root, "tests/e2e/helper-order-safe.spec.ts"),
`${imports} async function open(target) { await bootstrapE2ePage(target); await target.goto("/"); } test("x", async ({ page }) => { await open(page); });`,
);
fs.writeFileSync(
path.join(root, "tests/e2e/helper-mapping-unsafe.spec.ts"),
`${imports} async function inner(safeTarget, unsafeTarget) { await bootstrapE2ePage(safeTarget); await unsafeTarget.goto("/"); } async function outer(unsafeTarget, other) { await inner(other, unsafeTarget); } test("x", async ({ page }) => { const other = {}; await outer(page, other); });`,
);
fs.writeFileSync(
path.join(root, "tests/e2e/helper-mapping-safe.spec.ts"),
`${imports} async function inner(target) { await bootstrapE2ePage(target); } async function outer(unused, target) { await inner(target); } test("x", async ({ page }) => { await outer(undefined, page); });`,
);
assert.equal(runCheck(root).length, 12);
} finally {
fs.rmSync(root, { recursive: true, force: true });
}
});
test(`${project}: enforces helper-call boundaries in whole-file checks`, () => {
const root = fs.mkdtempSync(
path.join(os.tmpdir(), "e2e-bootstrap-helper-boundaries-"),
);
try {
fs.mkdirSync(path.join(root, "tests/e2e"), { recursive: true });
fs.mkdirSync(path.join(root, "tests/helpers"), { recursive: true });
fs.writeFileSync(
path.join(root, "tests/helpers/test.ts"),
"export {};\n",
);
const cases = [
[
"parenthesized-awaited-unsafe.spec.ts",
"await (go(page)); await bootstrapE2ePage(page);",
],
[
"parenthesized-unawaited-unsafe.spec.ts",
"(go(page)); await bootstrapE2ePage(page);",
],
[
"parenthesized-awaited-safe.spec.ts",
"await bootstrapE2ePage(page); await (go(page));",
],
[
"parenthesized-unawaited-safe.spec.ts",
"await bootstrapE2ePage(page); (go(page));",
],
[
"callback-alias-unsafe.spec.ts",
"const alias = page; await go(alias); await bootstrapE2ePage(page);",
],
[
"callback-unrelated-unsafe.spec.ts",
"const unrelated = {}; await go(unrelated); await bootstrapE2ePage(page);",
],
[
"callback-direct-unsafe.spec.ts",
"await go(page); await bootstrapE2ePage(page);",
],
[
"callback-setup-alias-safe.spec.ts",
"const alias = page; await setup(alias); await bootstrapE2ePage(page);",
],
];
for (const [name, body] of cases)
fs.writeFileSync(
path.join(root, "tests/e2e", name),
`${imports} async function go(target) { await target.goto("/"); } async function setup(target) { await target.addInitScript(() => {}); } test("x", async ({ page }) => { ${body} });`,
);
assert.deepEqual(
runCheck(root)
.map((entry) => entry.split(":")[0])
.sort(),
[
"callback-alias-unsafe.spec.ts",
"callback-direct-unsafe.spec.ts",
"callback-unrelated-unsafe.spec.ts",
"parenthesized-awaited-unsafe.spec.ts",
"parenthesized-unawaited-unsafe.spec.ts",
],
);
} finally {
fs.rmSync(root, { recursive: true, force: true });
}
});
test(`${project}: enforces event birth and callee parentheses in whole files`, () => {
const root = fs.mkdtempSync(
path.join(os.tmpdir(), "e2e-bootstrap-event-accounting-"),
);
try {
fs.mkdirSync(path.join(root, "tests/e2e"), { recursive: true });
fs.mkdirSync(path.join(root, "tests/helpers"), { recursive: true });
fs.writeFileSync(
path.join(root, "tests/helpers/test.ts"),
"export {};\n",
);
const cases = [
[
"callee-awaited-unsafe.spec.ts",
"await (go)(page); await bootstrapE2ePage(page);",
],
[
"callee-unawaited-unsafe.spec.ts",
"(go)(page); await bootstrapE2ePage(page);",
],
[
"whole-call-control.spec.ts",
"await (go(page)); await bootstrapE2ePage(page);",
],
[
"birth-alias-goto.spec.ts",
"await aliasGoto(page); await bootstrapE2ePage(page);",
],
[
"birth-alias-storage.spec.ts",
"await aliasStorage(page); await bootstrapE2ePage(page);",
],
[
"birth-unrelated-goto.spec.ts",
"await unrelatedGoto(page); await bootstrapE2ePage(page);",
],
[
"birth-direct-control.spec.ts",
"await go(page); await bootstrapE2ePage(page);",
],
[
"setup-control.spec.ts",
"await (setup)(page); await (bootstrapE2ePage)(page);",
],
];
const helpers = `
async function go(target) { await target.goto("/"); }
async function aliasGoto(target) { const alias = target; await alias.goto("/"); }
async function aliasStorage(target) { const alias = target; await alias.evaluate(() => localStorage.getItem("x")); }
async function unrelatedGoto(target) { const unrelated = {}; await unrelated.goto("/"); }
async function setup(target) { const alias = target; await alias.addInitScript(() => {}); }
`;
for (const [name, body] of cases)
fs.writeFileSync(
path.join(root, "tests/e2e", name),
`${imports} ${helpers} test("x", async ({ page }) => { ${body} });`,
);
assert.deepEqual(
runCheck(root)
.map((entry) => entry.split(":")[0])
.sort(),
[
"birth-alias-goto.spec.ts",
"birth-alias-storage.spec.ts",
"birth-direct-control.spec.ts",
"birth-unrelated-goto.spec.ts",
"callee-awaited-unsafe.spec.ts",
"callee-unawaited-unsafe.spec.ts",
"whole-call-control.spec.ts",
],
);
} finally {
fs.rmSync(root, { recursive: true, force: true });
}
});
test(`${project}: enforces member parentheses and loop accounting in whole files`, () => {
const root = fs.mkdtempSync(
path.join(os.tmpdir(), "e2e-bootstrap-conservative-accounting-"),
);
try {
fs.mkdirSync(path.join(root, "tests/e2e"), { recursive: true });
fs.mkdirSync(path.join(root, "tests/helpers"), { recursive: true });
fs.writeFileSync(
path.join(root, "tests/helpers/test.ts"),
"export {};\n",
);
const cases = [
[
"member-callee.spec.ts",
'await (page.goto)("/"); await bootstrapE2ePage(page);',
],
[
"member-receiver.spec.ts",
'await (page).goto("/"); await bootstrapE2ePage(page);',
],
[
"member-storage.spec.ts",
'await (page.evaluate)(() => localStorage.getItem("x")); await bootstrapE2ePage(page);',
],
[
"helper-member.spec.ts",
"await unsafe(page); await bootstrapE2ePage(page);",
],
[
"created-member.spec.ts",
'const second = await (context.newPage)(); await second.goto("/");',
],
[
"created-safe.spec.ts",
'await bootstrapE2ePage(page); const second = await (context).newPage(); await bootstrapE2ePage(second); await (second.goto)("/");',
],
[
"dynamic-for-of.spec.ts",
'for (const value of values) await bootstrapE2ePage(page); await page.goto("/");',
],
[
"dynamic-while.spec.ts",
'while (condition) { await bootstrapE2ePage(page); break; } await page.goto("/");',
],
[
"spread-array.spec.ts",
'for (const value of [...[]]) await bootstrapE2ePage(page); await page.goto("/");',
],
[
"spread-object.spec.ts",
'for (const key in { ...{} }) await bootstrapE2ePage(page); await page.goto("/");',
],
[
"temporal-loop.spec.ts",
'let values = []; for (const value of values) await bootstrapE2ePage(page); values = [1]; await page.goto("/");',
],
[
"proto-identifier.spec.ts",
'for (const key in { __proto__: null }) await bootstrapE2ePage(page); await page.goto("/");',
],
[
"proto-string.spec.ts",
'for (const key in { "__proto__": null }) await bootstrapE2ePage(page); await page.goto("/");',
],
[
"proto-computed-safe.spec.ts",
'for (const key in { ["__proto__"]: null }) await bootstrapE2ePage(page); await page.goto("/");',
],
[
"computed-number-safe.spec.ts",
'for (const key in { [1]: 1 }) await bootstrapE2ePage(page); await page.goto("/");',
],
[
"computed-symbol.spec.ts",
'for (const key in { [Symbol()]: 1 }) await bootstrapE2ePage(page); await page.goto("/");',
],
[
"computed-symbol-member.spec.ts",
'for (const key in { [Symbol.iterator]: 1 }) await bootstrapE2ePage(page); await page.goto("/");',
],
[
"computed-bound.spec.ts",
'const key = Symbol(); for (const item in { [key]: 1 }) await bootstrapE2ePage(page); await page.goto("/");',
],
[
"computed-call.spec.ts",
'for (const key in { [getKey()]: 1 }) await bootstrapE2ePage(page); await page.goto("/");',
],
[
"computed-symbol-method.spec.ts",
'for (const key in { [Symbol.iterator]() {} }) await bootstrapE2ePage(page); await page.goto("/");',
],
[
"computed-symbol-getter.spec.ts",
'for (const key in { get [Symbol.iterator]() { return 1 } }) await bootstrapE2ePage(page); await page.goto("/");',
],
[
"computed-symbol-setter.spec.ts",
'for (const key in { set [Symbol.iterator](value) {} }) await bootstrapE2ePage(page); await page.goto("/");',
],
[
"computed-dynamic-method.spec.ts",
'for (const key in { [dynamicKey]() {} }) await bootstrapE2ePage(page); await page.goto("/");',
],
[
"computed-dynamic-getter.spec.ts",
'for (const key in { get [dynamicKey]() { return 1 } }) await bootstrapE2ePage(page); await page.goto("/");',
],
[
"computed-dynamic-setter.spec.ts",
'for (const key in { set [dynamicKey](value) {} }) await bootstrapE2ePage(page); await page.goto("/");',
],
[
"computed-static-method-safe.spec.ts",
'for (const key in { ["x"]() {} }) await bootstrapE2ePage(page); await page.goto("/");',
],
[
"computed-static-getter-safe.spec.ts",
'for (const key in { get ["x"]() { return 1 } }) await bootstrapE2ePage(page); await page.goto("/");',
],
[
"computed-static-setter-safe.spec.ts",
'for (const key in { set ["x"](value) {} }) await bootstrapE2ePage(page); await page.goto("/");',
],
[
"proto-mixed-safe.spec.ts",
'for (const key in { __proto__: null, x: 1 }) await bootstrapE2ePage(page); await page.goto("/");',
],
[
"literal-loop-safe.spec.ts",
'for (const value of [1]) await bootstrapE2ePage(page); await page.goto("/");',
],
[
"concrete-spread-array-safe.spec.ts",
'for (const value of [...[], 1]) await bootstrapE2ePage(page); await page.goto("/");',
],
[
"concrete-spread-object-safe.spec.ts",
'for (const key in { ...{}, x: 1 }) await bootstrapE2ePage(page); await page.goto("/");',
],
[
"do-loop-safe.spec.ts",
'do { await bootstrapE2ePage(page); } while (condition); await page.goto("/");',
],
];
for (const [name, body] of cases)
fs.writeFileSync(
path.join(root, "tests/e2e", name),
`${imports} async function unsafe(target) { await (target.evaluate)(() => localStorage.getItem("x")); } test("x", async ({ page, context }) => { ${body} });`,
);
assert.deepEqual(
runCheck(root)
.map((entry) => entry.split(":")[0])
.sort(),
[
"computed-bound.spec.ts",
"computed-call.spec.ts",
"computed-dynamic-getter.spec.ts",
"computed-dynamic-method.spec.ts",
"computed-dynamic-setter.spec.ts",
"computed-symbol-getter.spec.ts",
"computed-symbol-member.spec.ts",
"computed-symbol-method.spec.ts",
"computed-symbol-setter.spec.ts",
"computed-symbol.spec.ts",
"created-member.spec.ts",
"dynamic-for-of.spec.ts",
"dynamic-while.spec.ts",
"helper-member.spec.ts",
"member-callee.spec.ts",
"member-receiver.spec.ts",
"member-storage.spec.ts",
"proto-identifier.spec.ts",
"proto-string.spec.ts",
"spread-array.spec.ts",
"spread-object.spec.ts",
"temporal-loop.spec.ts",
],
);
} finally {
fs.rmSync(root, { recursive: true, force: true });
}
});
test(`${project}: applies receiver-aware hooks and catch checks in whole files`, () => {
const root = fs.mkdtempSync(
path.join(os.tmpdir(), "e2e-bootstrap-hook-catch-"),
);
try {
fs.mkdirSync(path.join(root, "tests/e2e"), { recursive: true });
fs.mkdirSync(path.join(root, "tests/helpers"), { recursive: true });
fs.writeFileSync(
path.join(root, "tests/helpers/test.ts"),
"export {};\n",
);
const cases = [
[
"hook-created-unsafe.spec.ts",
'test.beforeEach(async ({ page }) => { await bootstrapE2ePage(page); }); test("x", async ({ context }) => { const second = await context.newPage(); await second.goto("/"); });',
],
[
"hook-fixture-safe.spec.ts",
'test.beforeEach(async ({ page }) => { await bootstrapE2ePage(page); }); test("x", async ({ page }) => { await page.title(); });',
],
[
"hook-created-safe.spec.ts",
'test.beforeEach(async ({ page }) => { await bootstrapE2ePage(page); }); test("x", async ({ context }) => { const second = await context.newPage(); await bootstrapE2ePage(second); await second.goto("/"); });',
],
[
"catch-unsafe.spec.ts",
'test("x", async ({ page }) => { try { await page.title(); } catch { await page.goto("/"); } await bootstrapE2ePage(page); });',
],
[
"catch-safe.spec.ts",
'test("x", async ({ page }) => { await bootstrapE2ePage(page); try { await page.title(); } catch { await page.goto("/"); } });',
],
[
"catch-bootstrap.spec.ts",
'test("x", async ({ page }) => { try { await page.title(); } catch { await bootstrapE2ePage(page); } await page.goto("/"); });',
],
];
for (const [name, body] of cases)
fs.writeFileSync(
path.join(root, "tests/e2e", name),
`${imports} ${body}`,
);
assert.deepEqual(
runCheck(root)
.map((entry) => entry.split(":")[0])
.sort(),
[
"catch-bootstrap.spec.ts",
"catch-unsafe.spec.ts",
"hook-created-unsafe.spec.ts",
],
);
} finally {
fs.rmSync(root, { recursive: true, force: true });
}
});
test(`${project}: applies unawaited and element-access checks in whole files`, () => {
const root = fs.mkdtempSync(
path.join(os.tmpdir(), "e2e-bootstrap-unawaited-element-"),
);
try {
fs.mkdirSync(path.join(root, "tests/e2e"), { recursive: true });
fs.mkdirSync(path.join(root, "tests/helpers"), { recursive: true });
fs.writeFileSync(
path.join(root, "tests/helpers/test.ts"),
"export {};\n",
);
const cases = [
[
"unawaited-storage.spec.ts",
'async function read(target) { await target.evaluate(() => localStorage.getItem("x")); } test("x", async ({ page }) => { read(page); await bootstrapE2ePage(page); });',
],
[
"unawaited-goto.spec.ts",
'async function go(target) { await target.goto("/"); } test("x", async ({ page }) => { go(page); await bootstrapE2ePage(page); });',
],
[
"unawaited-safe.spec.ts",
'async function setup(target) { await target.addInitScript(() => {}); } test("x", async ({ page }) => { setup(page); await bootstrapE2ePage(page); });',
],
[
"element-goto.spec.ts",
'test("x", async ({ page }) => { await page["goto"]("/"); await bootstrapE2ePage(page); });',
],
[
"element-created.spec.ts",
'test("x", async ({ context }) => { const second = await context["newPage"](); await second.goto("/"); });',
],
[
"element-safe.spec.ts",
'test("x", async ({ page }) => { await bootstrapE2ePage(page); await page["goto"]("/"); });',
],
];
for (const [name, body] of cases)
fs.writeFileSync(
path.join(root, "tests/e2e", name),
`${imports} ${body}`,
);
assert.deepEqual(
runCheck(root)
.map((x) => x.split(":")[0])
.sort(),
[
"element-created.spec.ts",
"element-goto.spec.ts",
"unawaited-goto.spec.ts",
"unawaited-storage.spec.ts",
],
);
} finally {
fs.rmSync(root, { recursive: true, force: true });
}
});
test(`${project}: applies recursion and unmapped guards in whole files`, () => {
const root = fs.mkdtempSync(
path.join(os.tmpdir(), "e2e-bootstrap-recursion-unmapped-"),
);
try {
fs.mkdirSync(path.join(root, "tests/e2e"), { recursive: true });
fs.mkdirSync(path.join(root, "tests/helpers"), { recursive: true });
fs.writeFileSync(
path.join(root, "tests/helpers/test.ts"),
"export {};\n",
);
const cases = [
[
"direct.spec.ts",
'async function setup(target){await bootstrapE2ePage(target);await setup(target);} test("x",async({page})=>{await setup(page);});',
],
[
"mutual.spec.ts",
'async function a(target){await bootstrapE2ePage(target);await b(target);} async function b(target){await a(target);} test("x",async({page})=>{await a(page);});',
],
[
"as.spec.ts",
'async function go(target){await target.goto("/");} test("x",async({page})=>{go(page as any);await bootstrapE2ePage(page);});',
],
[
"paren.spec.ts",
'async function go(target){await target.goto("/");} test("x",async({page})=>{go((page));await bootstrapE2ePage(page);});',
],
[
"property.spec.ts",
'async function go(target){await target.goto("/");} test("x",async(fixtures)=>{go(fixtures.page);const {page}=fixtures;await bootstrapE2ePage(page);});',
],
[
"safe.spec.ts",
'async function inner(target){await bootstrapE2ePage(target);} test("x",async({page})=>{await inner(page);});',
],
];
for (const [n, b] of cases)
fs.writeFileSync(path.join(root, "tests/e2e", n), `${imports} ${b}`);
assert.equal(runCheck(root).length, 5);
} finally {
fs.rmSync(root, { recursive: true, force: true });
}
});
test(`${project}: applies local-identifier mapping guards in whole files`, () => {
const root = fs.mkdtempSync(
path.join(os.tmpdir(), "e2e-bootstrap-local-map-"),
);
try {
fs.mkdirSync(path.join(root, "tests/e2e"), { recursive: true });
fs.mkdirSync(path.join(root, "tests/helpers"), { recursive: true });
fs.writeFileSync(
path.join(root, "tests/helpers/test.ts"),
"export {};\n",
);
const cases = [
[
"alias.spec.ts",
'async function inner(target){await target.goto("/");} async function outer(target){const alias=target;await inner(alias);} test("x",async({page})=>{await outer(page);await bootstrapE2ePage(page);});',
],
[
"direct.spec.ts",
'async function inner(target){await target.goto("/");} async function outer(target){await inner(target);} test("x",async({page})=>{await outer(page);await bootstrapE2ePage(page);});',
],
[
"setup.spec.ts",
'async function inner(target){await target.addInitScript(()=>{});} async function outer(target){const alias=target;await inner(alias);} test("x",async({page})=>{await outer(page);await bootstrapE2ePage(page);});',
],
];
for (const [n, b] of cases)
fs.writeFileSync(path.join(root, "tests/e2e", n), `${imports} ${b}`);
assert.equal(runCheck(root).length, 2);
} finally {
fs.rmSync(root, { recursive: true, force: true });
}
});
test(`${project}: ignores destructuring property keys with different bound locals`, () => {
accepts(
spec(
"const { test: localTest, bootstrapE2ePage: localBootstrap } = helpers; void localTest; void localBootstrap; await bootstrapE2ePage(page);",
),
);
});
for (const [name, source] of [
[
".ts helper suffix",
'import { test, bootstrapE2ePage } from "../helpers/test.ts"; test("x", async () => {});',
],
[
"import alias",
'import { test as e2eTest, bootstrapE2ePage } from "../helpers/test"; e2eTest("x", async () => { await bootstrapE2ePage(); });',
],
[
"re-export",
'import { test, bootstrapE2ePage } from "./reexport"; test("x", async () => { await bootstrapE2ePage(); });',
],
[
"dynamic import",
'const { test, bootstrapE2ePage } = await import("../helpers/test"); test("x", async () => { await bootstrapE2ePage(); });',
],
[
"dead-code call",
`${imports}\nasync function never(page) { await bootstrapE2ePage(page); } test("x", async () => {});`,
],
[
"comment",
`${imports}\n// await bootstrapE2ePage(page)\ntest("x", async () => {});`,
],
[
"string",
`${imports}\nconst hint = "await bootstrapE2ePage(page)"; test("x", async () => {});`,
],
[
"mixed safe and unsafe tests",
`${imports}\ntest("safe", async ({ page }) => { await bootstrapE2ePage(page); }); test("unsafe", async ({ page }) => { await page.title(); });`,
],
["missing bootstrap receiver", spec("await bootstrapE2ePage();")],
["non-identifier bootstrap receiver", spec('await bootstrapE2ePage("/");')],
["if-wrapped call", spec("if (true) { await bootstrapE2ePage(page); }")],
[
"catch-only call",
spec(
"try { await page.title(); } catch { await bootstrapE2ePage(page); }",
),
],
[
"zero-iteration false loop",
spec("for (; false;) { await bootstrapE2ePage(page); }"),
],
[
"zero-iteration empty iterable",
spec("for (const value of []) { await bootstrapE2ePage(page); }"),
],
[
"uncalled nested function",
spec("async function setup() { await bootstrapE2ePage(page); }"),
],
[
"unawaited helper",
`${imports}\nasync function open(page) { await bootstrapE2ePage(page); }\ntest("x", async ({ page }) => { open(page); });`,
],
[
"fake test.extend",
`${imports}\ntest.extend("x", async ({ page }) => { await bootstrapE2ePage(page); });`,
],
[
"misplaced describe hook",
`${imports}\ntest.describe("inside", () => { test.beforeEach(async ({ page }) => { await bootstrapE2ePage(page); }); test("covered", async () => {}); }); test("outside", async () => {});`,
],
[
"shadowed bootstrap",
`${imports}\ntest("x", async ({ page }) => { const bootstrapE2ePage = async () => {}; await bootstrapE2ePage(page); });`,
],
[
"object shorthand binding shadow",
spec(
"const { bootstrapE2ePage } = helpers; await bootstrapE2ePage(page);",
),
],
[
"nested object alias binding shadow",
spec(
"const { bootstrap: { run: bootstrapE2ePage } } = helpers; await bootstrapE2ePage(page);",
),
],
[
"nested array default binding shadow",
spec("const [[test = fallback]] = values; await bootstrapE2ePage(page);"),
],
[
"object rest binding shadow",
spec(
"const { ignored, ...bootstrapE2ePage } = helpers; await bootstrapE2ePage(page);",
),
],
[
"destructured function parameter shadow",
spec(
"function configure({ nested: [bootstrapE2ePage] }) {} await bootstrapE2ePage(page);",
),
],
[
"destructured arrow parameter shadow",
spec(
"const configure = ([{ test }]) => {}; await bootstrapE2ePage(page);",
),
],
[
"destructured method parameter shadow",
spec(
"class Harness { configure({ helper: { bootstrapE2ePage = fallback } }) {} } await bootstrapE2ePage(page);",
),
],
[
"parenthesized false condition",
spec("while (((false))) { await bootstrapE2ePage(page); }"),
],
[
"parenthesized empty array iterable",
spec("for (const value of (([]))) { await bootstrapE2ePage(page); }"),
],
[
"parenthesized empty string iterable",
spec('for (const value of ((""))) { await bootstrapE2ePage(page); }'),
],
[
"parenthesized empty object for-in",
spec("for (const key in (({}))) { await bootstrapE2ePage(page); }"),
],
]) {
test(`${project}: rejects ${name}`, () => rejects(source));
}
test(`${project}: classifies non-browser harnesses structurally`, () => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), "e2e-bootstrap-"));
try {
fs.mkdirSync(path.join(root, "tests/e2e"), { recursive: true });
fs.mkdirSync(path.join(root, "tests/helpers"), { recursive: true });
fs.writeFileSync(
path.join(root, "tests/helpers/test.ts"),
"export {};\n",
);
fs.writeFileSync(
path.join(root, "tests/e2e/agents-everywhere.live.spec.ts"),
'import { test } from "../helpers/test"; test("relay", async () => {});',
);
fs.writeFileSync(
path.join(root, "tests/e2e/renamed-cli-harness.spec.ts"),
'import { test } from "../helpers/test"; test("relay", async () => {});',
);
fs.writeFileSync(
path.join(root, "tests/e2e/agents-everywhere.live.perf.ts"),
'import { test } from "../helpers/test"; test("browser", async ({ page }) => { await page.title(); });',
);
assert.deepEqual(runCheck(root), [
"agents-everywhere.live.perf.ts: must directly import unaliased test and bootstrapE2ePage from the canonical tests/helpers/test module",
]);
} finally {
fs.rmSync(root, { recursive: true, force: true });
}
});
test(`${project}: discovers nested specs with a canonical relative import`, () => {
const root = fs.mkdtempSync(path.join(os.tmpdir(), "e2e-bootstrap-"));
try {
fs.mkdirSync(path.join(root, "tests/e2e/nested"), { recursive: true });
fs.mkdirSync(path.join(root, "tests/helpers"), { recursive: true });
fs.writeFileSync(
path.join(root, "tests/helpers/test.ts"),
"export {};\n",
);
fs.writeFileSync(
path.join(root, "tests/e2e/nested/example.spec.ts"),
'import { test, bootstrapE2ePage } from "../../helpers/test"; test("x", async ({ page }) => { await bootstrapE2ePage(page); });',
);
assert.deepEqual(runCheck(root), []);
} finally {
fs.rmSync(root, { recursive: true, force: true });
}
});
}
for (const [project, checkerPath] of projects) {
const { checkSource } = await import(checkerPath);
test(`${project}: traverses canonical parameterized registration containers only`, () => {
assert.equal(
checkSource(`${imports}
for (const name of ["one", "two"]) test(name, async ({ page }) => { await bootstrapE2ePage(page); });
["three"].forEach((name) => test(name, async ({ page }) => { await bootstrapE2ePage(page); }));
["four"].map((name) => test(name, async ({ page }) => { await bootstrapE2ePage(page); }));`),
undefined,
);
assert.notEqual(
checkSource(`${imports}
function registerLater() { test("hidden", async ({ page }) => { await bootstrapE2ePage(page); }); }
test("unsafe", async ({ page }) => { await page.title(); });`),
undefined,
);
});
}