Files
QueueCube/web/backend/test/ChromiumFallback.test.cjs

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);
});