105 lines
5.1 KiB
JavaScript
105 lines
5.1 KiB
JavaScript
const test = require("node:test");
|
|
const assert = require("node:assert/strict");
|
|
const fs = require("node:fs/promises");
|
|
const os = require("node:os");
|
|
const path = require("node:path");
|
|
const { ChromiumFallback } = require("../build/ChromiumFallback");
|
|
|
|
const waitFor = async (predicate) => {
|
|
const deadline = Date.now() + 3000;
|
|
while (Date.now() < deadline) {
|
|
if (await predicate()) return;
|
|
await new Promise((resolve) => setTimeout(resolve, 20));
|
|
}
|
|
throw new Error("timed out waiting for subprocess fixture");
|
|
};
|
|
|
|
test("uses isolated profile and safe argv; stop kills only its process and cleans profile", async () => {
|
|
const fixture = await fs.mkdtemp(path.join(os.tmpdir(), "queuecube-test-"));
|
|
const argsFile = path.join(fixture, "argv.json");
|
|
const executable = path.join(fixture, "fake-chrome.js");
|
|
await fs.writeFile(executable, `#!/usr/bin/env node\nconst fs=require('fs'); fs.writeFileSync(${JSON.stringify(argsFile)}, JSON.stringify(process.argv.slice(2))); setInterval(()=>{},1000);\n`);
|
|
await fs.chmod(executable, 0o700);
|
|
const browser = new ChromiumFallback(() => undefined, executable);
|
|
const url = "https://example.test/?x=1; touch /tmp/should-not-exist";
|
|
|
|
try {
|
|
assert.equal(await browser.start(url, () => true), true);
|
|
await waitFor(async () => { try { await fs.access(argsFile); return true; } catch { return false; } });
|
|
const args = JSON.parse(await fs.readFile(argsFile, "utf8"));
|
|
assert.equal(args.at(-1), url);
|
|
assert.ok(args.some((arg) => arg.startsWith("--user-data-dir=")));
|
|
assert.ok(args.includes("--kiosk"));
|
|
assert.ok(!args.some((arg) => /no-sandbox|disable-web-security|ignore-certificate/i.test(arg)));
|
|
const profilePath = args.find((arg) => arg.startsWith("--user-data-dir=")).split("=", 2)[1];
|
|
await browser.stop();
|
|
assert.equal(browser.isRunning, false);
|
|
await assert.rejects(fs.access(profilePath));
|
|
} finally {
|
|
await browser.stop();
|
|
await fs.rm(fixture, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
test("discovers chromium-browser when that is the installed executable", async () => {
|
|
const fixture = await fs.mkdtemp(path.join(os.tmpdir(), "queuecube-browser-path-test-"));
|
|
const argsFile = path.join(fixture, "argv.json");
|
|
const executable = path.join(fixture, "chromium-browser");
|
|
const previousPath = process.env.PATH;
|
|
const previousOverride = process.env.QUEUECUBE_CHROME_BIN;
|
|
await fs.writeFile(executable, `#!/usr/bin/env node\nconst fs=require('fs'); fs.writeFileSync(${JSON.stringify(argsFile)}, JSON.stringify(process.argv.slice(2))); setInterval(()=>{},1000);\n`);
|
|
await fs.chmod(executable, 0o700);
|
|
await fs.symlink(process.execPath, path.join(fixture, "node"));
|
|
|
|
try {
|
|
process.env.PATH = fixture;
|
|
delete process.env.QUEUECUBE_CHROME_BIN;
|
|
const browser = new ChromiumFallback();
|
|
assert.equal(await browser.start("https://example.test/browser-discovery", () => true), true);
|
|
await waitFor(async () => { try { await fs.access(argsFile); return true; } catch { return false; } });
|
|
assert.equal(JSON.parse(await fs.readFile(argsFile, "utf8")).at(-1), "https://example.test/browser-discovery");
|
|
await browser.stop();
|
|
} finally {
|
|
process.env.PATH = previousPath;
|
|
if (previousOverride === undefined) delete process.env.QUEUECUBE_CHROME_BIN;
|
|
else process.env.QUEUECUBE_CHROME_BIN = previousOverride;
|
|
await fs.rm(fixture, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
test("canceled startup cleans its profile without spawning", async () => {
|
|
const browser = new ChromiumFallback(() => undefined, "/bin/false");
|
|
assert.equal(await browser.start("https://example.test/", () => false), false);
|
|
assert.equal(browser.isRunning, false);
|
|
});
|
|
|
|
test("cancellation during process startup stops the late process and removes its profile", async () => {
|
|
const fixture = await fs.mkdtemp(path.join(os.tmpdir(), "queuecube-race-test-"));
|
|
const executable = path.join(fixture, "fake-chrome.js");
|
|
await fs.writeFile(executable, "#!/usr/bin/env node\nsetInterval(()=>{},1000);\n");
|
|
await fs.chmod(executable, 0o700);
|
|
const browser = new ChromiumFallback(() => undefined, executable);
|
|
const cleanedProfiles = [];
|
|
const removeProfile = browser.removeProfile.bind(browser);
|
|
browser.removeProfile = async (profile) => { cleanedProfiles.push(profile); await removeProfile(profile); };
|
|
let checks = 0;
|
|
try {
|
|
assert.equal(await browser.start("https://example.test/race", () => ++checks === 1), false);
|
|
assert.equal(checks, 2, "the request became stale after process startup");
|
|
await waitFor(async () => {
|
|
if (!cleanedProfiles.length) return false;
|
|
try { await fs.access(cleanedProfiles[0]); return false; } catch { return true; }
|
|
});
|
|
assert.equal(browser.isRunning, false);
|
|
} finally {
|
|
await browser.stop();
|
|
await fs.rm(fixture, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
test("missing browser executable reports startup failure and clears ownership", async () => {
|
|
const browser = new ChromiumFallback(() => undefined, "/definitely/missing/queuecube-chrome");
|
|
await assert.rejects(browser.start("https://example.test/", () => true), /ENOENT/);
|
|
assert.equal(browser.isRunning, false);
|
|
});
|