Files
bun.sh/test/scripts/browser.js
2023-01-31 17:55:16 -08:00

177 lines
4.7 KiB
JavaScript

const puppeteer = require("puppeteer");
const http = require("http");
const path = require("path");
const url = require("url");
const fs = require("fs");
const child_process = require("child_process");
const snippetsDir = path.resolve(__dirname, "../snippets");
const serverURL = process.env.TEST_SERVER_URL || "http://localhost:8080";
const USE_EXISTING_PROCESS = process.env.USE_EXISTING_PROCESS || false;
const DISABLE_HMR = !!process.env.DISABLE_HMR;
const bunFlags = ["dev", `--origin=${serverURL}`, DISABLE_HMR && "--disable-hmr"].filter(Boolean);
const bunExec = process.env.BUN_BIN || "bun";
var bunProcess;
var waitSpawn;
if (!USE_EXISTING_PROCESS) {
bunProcess = child_process.spawn(bunExec, bunFlags, {
cwd: snippetsDir,
stdio: "pipe",
env: {
...process.env,
DISABLE_BUN_ANALYTICS: "1",
},
shell: false,
});
console.log("$", bunExec, bunFlags.join(" "));
bunProcess.stderr.pipe(process.stderr);
bunProcess.stdout.pipe(process.stdout);
var rejecter;
bunProcess.once("error", err => {
console.error("❌ bun error", err);
process.exit(1);
});
if (!process.env.CI) {
waitSpawn = new Promise((resolve, reject) => {
bunProcess.once("spawn", code => {
console.log("Spawned");
resolve();
});
});
}
process.on("beforeExit", () => {
bunProcess && bunProcess.kill(0);
});
}
const isDebug = bunExec.endsWith("-debug");
function writeSnapshot(name, code) {
let file = path.join(__dirname, "../snapshots", name);
if (!DISABLE_HMR) {
file = file.substring(0, file.length - path.extname(file).length) + ".hmr" + path.extname(file);
}
if (!fs.existsSync(path.dirname(file))) {
fs.mkdirSync(path.dirname(file), { recursive: true });
}
fs.writeFileSync(
isDebug ? file.substring(0, file.length - path.extname(file).length) + ".debug" + path.extname(file) : file,
code,
);
}
const baseOptions = {
dumpio: !!process.env.CI_DEBUG,
args: [
"--disable-gpu",
"--disable-dev-shm-usage",
"--disable-setuid-sandbox",
"--no-sandbox",
"--ignore-certificate-errors",
"--use-fake-ui-for-media-stream",
"--use-fake-device-for-media-stream",
"--disable-sync",
],
executablePath: process.env.BROWSER_EXECUTABLE,
headless: true,
};
async function main() {
const launchOptions = USE_EXISTING_PROCESS ? { ...baseOptions, devtools: !process.env.CI } : baseOptions;
const browser = await puppeteer.launch(launchOptions);
const promises = [];
let allTestsPassed = true;
if (waitSpawn) await waitSpawn;
var canRetry = true;
async function runPage(key) {
var page;
try {
page = await browser.newPage();
if (USE_EXISTING_PROCESS) {
await page.evaluate(`
globalThis.BUN_DEBUG_MODE = true;
`);
}
var shouldClose = true;
page.on("console", obj => console.log(`[console.${obj.type()}] ${obj.text()}`));
page.exposeFunction("testFail", error => {
console.log(`${error}`);
allTestsPassed = false;
});
let testDone = new Promise(resolve => {
page.exposeFunction("testDone", resolve);
});
try {
await page.goto(`${serverURL}/`, {
waitUntil: "domcontentloaded",
});
await page.evaluate(`
globalThis.runTest("${key}");
`);
await testDone;
} catch (err) {
if (canRetry) {
console.log(
`${key} failed once (incase it's still booting on universal binary for the first time). Retrying...`,
);
canRetry = false;
return await runPage(key);
}
throw err;
}
console.log(`${key}`);
} catch (e) {
if (USE_EXISTING_PROCESS) shouldClose = false;
allTestsPassed = false;
console.log(`${key}: ${(e && e.message) || e}`);
} finally {
try {
const code = await page.evaluate(`
globalThis.getModuleScriptSrc("${key}");
`);
writeSnapshot(key, code);
} catch (exception) {
console.warn(`Failed to update snapshot: ${key}`, exception);
}
}
canRetry = false;
if (shouldClose) await page.close();
}
const tests = require("./snippets.json");
tests.reverse();
for (let test of tests) {
await runPage(test);
}
if (!USE_EXISTING_PROCESS || (USE_EXISTING_PROCESS && allTestsPassed)) {
bunProcess && bunProcess.kill(0);
if (!allTestsPassed) {
console.error(`❌ browser test failed`);
process.exit(1);
} else {
console.log(`✅ browser test passed`);
bunProcess && bunProcess.kill(0);
process.exit(0);
}
await browser.close();
}
}
main().catch(error =>
setTimeout(() => {
throw error;
}),
);