test/profile/launch-test.ts (view raw)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
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";
describe("openProfileWindow's failure reporting", () => {
let root: string;
before(() => {
root = mkdtempSync(join(tmpdir(), "pi-launch-"));
});
after(() => {
rmSync(root, { recursive: true, force: true });
});
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()));
});
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"));
});
});
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" });
assert.ok(!r.success);
},
);
describe("L3", () => {
let before_: string | undefined;
before(() => {
before_ = process.env["TMPDIR"];
process.env["TMPDIR"] = root;
});
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);
});
});
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 });
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);
await r.data.cleanup();
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();
}
});
});
});
|