diff options
Diffstat (limited to 'test/scripts/browser.js')
-rw-r--r-- | test/scripts/browser.js | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/test/scripts/browser.js b/test/scripts/browser.js new file mode 100644 index 000000000..479a55c9c --- /dev/null +++ b/test/scripts/browser.js @@ -0,0 +1,190 @@ +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 = [ + `--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; + }) +); |