| 1 | import assert from "node:assert/strict"; |
| 2 | import { copyFile, mkdtemp, rm } from "node:fs/promises"; |
| 3 | import { createRequire } from "node:module"; |
| 4 | import { tmpdir } from "node:os"; |
| 5 | import { createServer } from "vite"; |
| 6 | import path from "node:path"; |
| 7 | import { fileURLToPath } from "node:url"; |
| 8 | const frontendDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); |
| 9 | process.env.PLAYWRIGHT_BROWSERS_PATH = !process.env.PLAYWRIGHT_BROWSERS_PATH || process.env.PLAYWRIGHT_BROWSERS_PATH === ".pw-browsers" |
| 10 | ? path.join(frontendDir, ".pw-browsers") |
| 11 | : process.env.PLAYWRIGHT_BROWSERS_PATH; |
| 12 | const { chromium, _electron } = await import("playwright"); |
| 13 | const electronEngine = process.argv.includes("--electron"); |
| 14 | const electronHome = electronEngine ? await mkdtemp(path.join(tmpdir(), "reasonix-dock-electron-")) : ""; |
| 15 | |
| 16 | const server = await createServer({ root: frontendDir, server: { host: "127.0.0.1", port: 0, hmr: false }, logLevel: "error", plugins: [{ |
| 17 | name: "dock-navigation-fixture", |
| 18 | configureServer(server) { server.middlewares.use(async (req, res, next) => { |
| 19 | if (req.url !== "/dock-navigation-fixture") return next(); |
| 20 | res.setHeader("Content-Type", "text/html"); |
| 21 | res.end(await server.transformIndexHtml(req.url, '<html><head><link rel="icon" href="data:,"></head><body><div id="root"></div><script type="module" src="/bench/dock-navigation-fixture.tsx"></script></body></html>')); |
| 22 | }); }, |
| 23 | }] }); |
| 24 | await server.listen(); |
| 25 | let browser; |
| 26 | let electronApp; |
| 27 | try { |
| 28 | const address = server.httpServer.address(); |
| 29 | const url = `http://127.0.0.1:${address.port}/dock-navigation-fixture`; |
| 30 | let page; |
| 31 | if (electronEngine) { |
| 32 | const main = path.join(electronHome, "main.cjs"); |
| 33 | await copyFile(path.join(frontendDir, "bench/transcript-layout-electron.cjs"), main); |
| 34 | const electronRequire = createRequire(path.join(frontendDir, "../electron/package.json")); |
| 35 | electronApp = await _electron.launch({ |
| 36 | executablePath: electronRequire("electron"), |
| 37 | args: [main], |
| 38 | env: { ...process.env, REASONIX_LAYOUT_URL: url }, |
| 39 | }); |
| 40 | page = await electronApp.firstWindow(); |
| 41 | } else { |
| 42 | browser = await chromium.launch({ headless: true, executablePath: process.env.CHROME_EXECUTABLE }); |
| 43 | page = await browser.newPage(); |
| 44 | } |
| 45 | await page.addInitScript(() => localStorage.setItem("reasonix-lang", "en")); |
| 46 | const errors = []; |
| 47 | page.on("pageerror", error => { errors.push(error.message); console.error(error.message); }); |
| 48 | page.on("console", message => { if (message.type() === "error") { errors.push(message.text()); console.error(message.text()); } }); |
| 49 | await page.goto(url); |
| 50 | for (const host of ["local", "remote"]) { |
| 51 | if (host === "remote") await page.locator("#switch-host").click(); |
| 52 | const card = page.locator(".presented-file"); |
| 53 | await card.locator(".presented-file__main").click(); |
| 54 | await page.getByText(`NAVIGATION CONTENT ${host}.txt`, { exact: false }).first().waitFor(); |
| 55 | for (const action of [/source|源码|原始碼/i, /tree|文件树|檔案樹/i]) { |
| 56 | await card.locator(".presented-file__more").click(); |
| 57 | await page.getByRole("menuitem", { name: action }).click(); |
| 58 | await page.getByText(`NAVIGATION CONTENT ${host}.txt`, { exact: false }).first().waitFor(); |
| 59 | } |
| 60 | console.log(`PASS ${electronEngine ? "Electron" : "browser"} ${host}: preview, source, reveal-tree`); |
| 61 | } |
| 62 | await page.getByRole("treeitem", { name: "a.txt", exact: true }).click(); |
| 63 | await page.locator(".remote-file-view__toolbar button").click(); |
| 64 | await page.locator(".remote-file-view textarea").fill("DRAFT A"); |
| 65 | await page.locator(".remote-file-view__toolbar button").click(); |
| 66 | await page.getByRole("treeitem", { name: "b.txt", exact: true }).click(); |
| 67 | await page.getByText("NAVIGATION CONTENT b.txt", { exact: false }).first().waitFor(); |
| 68 | await page.locator("#finish-save").click(); |
| 69 | assert.match(await page.locator(".remote-file-view").innerText(), /NAVIGATION CONTENT b.txt/); |
| 70 | assert.doesNotMatch(await page.locator(".remote-file-view").innerText(), /DRAFT A/); |
| 71 | console.log(`PASS ${electronEngine ? "Electron" : "browser"} old save receipt cannot overwrite replacement file`); |
| 72 | assert.deepEqual(errors, []); |
| 73 | } finally { |
| 74 | await browser?.close(); |
| 75 | await electronApp?.close(); |
| 76 | await server.close(); |
| 77 | if (electronHome) await rm(electronHome, { recursive: true, force: true }); |
| 78 | } |
| 79 |