diff options
| author | amankumarsingh77 <amankumarsingh7702@gmail.com> | 2026-07-27 00:27:08 +0530 |
|---|---|---|
| committer | Aman Kumar <145339995+amankumarsingh77@users.noreply.github.com> | 2026-08-02 19:12:46 +0530 |
| commit | 15a537a99efba614e6e108722462bcb78ec6c3c4 (patch) | |
| tree | 2ff20907fee8ace7a071470d491fe7808dce6a63 /test/profile/launch-test.ts | |
| parent | ce5d808cb4cc3581d85b829656d1d478dc43e3a6 (diff) | |
test: port remaining suites to node:test
Mechanical port of the hand-rolled check() harness. Import-after-env
ordering preserved so suites still read their sandbox dirs.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'test/profile/launch-test.ts')
| -rw-r--r-- | test/profile/launch-test.ts | 167 |
1 files changed, 103 insertions, 64 deletions
diff --git a/test/profile/launch-test.ts b/test/profile/launch-test.ts index 0061273..70ca8af 100644 --- a/test/profile/launch-test.ts +++ b/test/profile/launch-test.ts @@ -7,89 +7,128 @@ * "couldn't open a window in <profile> automatically". These tests pin the * failure to its real cause instead. * - * Run: npx tsx test/profile/launch-test.ts + * Run: npm test */ +import { test, before, after, describe } from "node:test"; +import assert from "node:assert/strict"; import { existsSync, mkdtempSync, readdirSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { fileURLToPath } from "node:url"; import { openProfileWindow } from "../../src/profile/launch"; -let passed = 0; -let failed = 0; -const check = (cond: boolean, label: string): void => { - if (cond) { - passed++; - console.log(` ✓ ${label}`); - } else { - failed++; - console.error(` ✗ ${label}`); - } -}; - -async function main(): Promise<void> { - const root = mkdtempSync(join(tmpdir(), "pi-launch-")); - try { - // L1: a nonexistent binary — the shape of an in-place browser upgrade, - // where /proc/<pid>/exe still names the unlinked file. - { - const missing = join(root, "chrome (deleted)"); - const r = await openProfileWindow({ exePath: missing, profileDir: "Default" }); - check(!r.success, "L1: a missing executable fails the launch"); - if (!r.success) { - check(r.error.includes(missing), "L1: the error names the path that could not be launched"); - check(r.error.includes("ENOENT"), "L1: the error carries spawn's own cause"); - } - } +describe("openProfileWindow's failure reporting", () => { + let root: string; + + before(() => { + root = mkdtempSync(join(tmpdir(), "pi-launch-")); + }); + + after(() => { + rmSync(root, { recursive: true, force: true }); + }); + + // L1: a nonexistent binary — the shape of an in-place browser upgrade, + // where /proc/<pid>/exe still names the unlinked file. + describe("L1", () => { + const missing = (): string => join(root, "chrome (deleted)"); + + test("L1: a missing executable fails the launch", async () => { + const r = await openProfileWindow({ exePath: missing(), profileDir: "Default" }); + assert.ok(!r.success); + }); + + test("L1: the error names the path that could not be launched", async () => { + const r = await openProfileWindow({ exePath: missing(), profileDir: "Default" }); + assert.ok(!r.success); + assert.ok(r.error.includes(missing())); + }); - // L2: a file that exists but is not executable — same async 'error' path, - // different errno (EACCES). Skipped where the check is meaningless. - if (process.platform !== "win32" && process.getuid?.() !== 0) { + test("L1: the error carries spawn's own cause", async () => { + const r = await openProfileWindow({ exePath: missing(), profileDir: "Default" }); + assert.ok(!r.success); + assert.ok(r.error.includes("ENOENT")); + }); + }); + + // L2: a file that exists but is not executable — same async 'error' path, + // different errno (EACCES). Skipped where the check is meaningless. + test( + "L2: a non-executable file fails the launch", + { skip: process.platform === "win32" || process.getuid?.() === 0 }, + async () => { const notExec = join(root, "not-executable"); writeFileSync(notExec, "#!/bin/sh\n", { mode: 0o644 }); const r = await openProfileWindow({ exePath: notExec, profileDir: "Default" }); - check(!r.success, "L2: a non-executable file fails the launch"); - } + assert.ok(!r.success); + }, + ); + + // L3: a failed launch leaves no sentinel file behind. The caller only calls + // cleanup() on the success path, so the failure path owns its own tidying. + describe("L3", () => { + let before_: string | undefined; - // L3: a failed launch leaves no sentinel file behind. The caller only calls - // cleanup() on the success path, so the failure path owns its own tidying. - { - const before = process.env["TMPDIR"]; + before(() => { + before_ = process.env["TMPDIR"]; process.env["TMPDIR"] = root; - try { - const r = await openProfileWindow({ exePath: join(root, "absent"), profileDir: "Default" }); - check(!r.success, "L3: launch failed as set up"); - const leftovers = readdirSync(root).filter((n) => n.startsWith("pi-harness-")); - check(leftovers.length === 0, "L3: no handshake page is left on disk after a failed launch"); - } finally { - if (before === undefined) delete process.env["TMPDIR"]; - else process.env["TMPDIR"] = before; - } - } + }); + + after(() => { + if (before_ === undefined) delete process.env["TMPDIR"]; + else process.env["TMPDIR"] = before_; + }); + + test("L3: launch failed as set up", async () => { + const r = await openProfileWindow({ exePath: join(root, "absent"), profileDir: "Default" }); + assert.ok(!r.success); + }); + + test("L3: no handshake page is left on disk after a failed launch", async () => { + await openProfileWindow({ exePath: join(root, "absent"), profileDir: "Default" }); + const leftovers = readdirSync(root).filter((n) => n.startsWith("pi-harness-")); + assert.equal(leftovers.length, 0); + }); + }); - // L4: a launcher that starts succeeds, and the sentinel it advertises is a - // real, readable file — the page the browser is asked to open. - { + // L4: a launcher that starts succeeds, and the sentinel it advertises is a + // real, readable file — the page the browser is asked to open. + describe("L4", () => { + let r: Awaited<ReturnType<typeof openProfileWindow>>; + + before(async () => { const stub = join(root, "stub-browser"); writeFileSync(stub, "#!/bin/sh\nexit 0\n", { mode: 0o755 }); - const r = await openProfileWindow({ exePath: stub, profileDir: "Default" }); - check(r.success, "L4: a startable binary yields a handle"); + r = await openProfileWindow({ exePath: stub, profileDir: "Default" }); + }); + + test("L4: a startable binary yields a handle", () => { + assert.ok(r.success); + }); + + test("L4: the sentinel page exists before the browser is polled", () => { + assert.ok(r.success); + if (r.success) { + const sentinel = fileURLToPath(r.data.sentinelUrl); + assert.ok(existsSync(sentinel)); + } + }); + + test("L4: cleanup removes the sentinel page", async () => { + assert.ok(r.success); if (r.success) { const sentinel = fileURLToPath(r.data.sentinelUrl); - check(existsSync(sentinel), "L4: the sentinel page exists before the browser is polled"); await r.data.cleanup(); - check(!existsSync(sentinel), "L4: cleanup removes the sentinel page"); + assert.ok(!existsSync(sentinel)); + } + }); + + test("L4: kill is safe to call twice", () => { + assert.ok(r.success); + if (r.success) { r.data.kill(); r.data.kill(); - check(true, "L4: kill is safe to call twice"); } - } - } finally { - rmSync(root, { recursive: true, force: true }); - } - - console.log(`\n${passed} passed, ${failed} failed`); - process.exit(failed === 0 ? 0 : 1); -} - -void main(); + }); + }); +}); |
