Add Electron E2E harness launcher
This commit is contained in:
1 parent
fa8c52b239
commit
00ee563311
4 files changed
+47
-6
No files matched your search
+18
-3
@@ -10,6 +10,7 @@ const { validateRenderRequest } = require('../shared/renderValidation.cjs') as {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const isDev = !app.isPackaged
|
const isDev = !app.isPackaged
|
||||||
|
const isE2E = process.env.RUWIO_E2E === '1'
|
||||||
const devServerUrl = process.env.VITE_DEV_SERVER_URL ?? 'http://localhost:5200'
|
const devServerUrl = process.env.VITE_DEV_SERVER_URL ?? 'http://localhost:5200'
|
||||||
const devServerOrigin = new URL(devServerUrl).origin
|
const devServerOrigin = new URL(devServerUrl).origin
|
||||||
const appIconPath = isDev
|
const appIconPath = isDev
|
||||||
@@ -43,6 +44,12 @@ function sendAppCommand(command: string): void {
|
|||||||
mainWindow.webContents.send('ruwio:menu-command', command)
|
mainWindow.webContents.send('ruwio:menu-command', command)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
// Playwright's Electron runner can evaluate in the main process and call this
|
||||||
|
// env-gated hook without expanding the preload bridge surface.
|
||||||
|
var __ruwioTestMenuCommand: ((command: string) => void) | undefined
|
||||||
|
}
|
||||||
|
|
||||||
function sendRenderProgress(
|
function sendRenderProgress(
|
||||||
target: Electron.WebContents,
|
target: Electron.WebContents,
|
||||||
event: { jobId: string; progress: number; done: boolean; error?: string },
|
event: { jobId: string; progress: number; done: boolean; error?: string },
|
||||||
@@ -101,9 +108,14 @@ async function runRenderMp4(event: IpcMainInvokeEvent, payload: RenderMp4Payload
|
|||||||
defaultPath: sanitizeMp4Name(payload?.suggestedName),
|
defaultPath: sanitizeMp4Name(payload?.suggestedName),
|
||||||
filters: [{ name: 'MP4 Video', extensions: ['mp4'] }],
|
filters: [{ name: 'MP4 Video', extensions: ['mp4'] }],
|
||||||
}
|
}
|
||||||
const saveResult = window
|
const e2eSavePath = isE2E
|
||||||
? await dialog.showSaveDialog(window, saveOptions)
|
? process.env.RUWIO_E2E_SAVE_PATH || path.join(app.getPath('temp'), saveOptions.defaultPath)
|
||||||
: await dialog.showSaveDialog(saveOptions)
|
: ''
|
||||||
|
const saveResult = e2eSavePath
|
||||||
|
? { canceled: false, filePath: e2eSavePath }
|
||||||
|
: window
|
||||||
|
? await dialog.showSaveDialog(window, saveOptions)
|
||||||
|
: await dialog.showSaveDialog(saveOptions)
|
||||||
if (saveResult.canceled || !saveResult.filePath) return null
|
if (saveResult.canceled || !saveResult.filePath) return null
|
||||||
|
|
||||||
const jobId = randomUUID()
|
const jobId = randomUUID()
|
||||||
@@ -379,6 +391,9 @@ app.setName('RUWIO')
|
|||||||
app.whenReady().then(() => {
|
app.whenReady().then(() => {
|
||||||
ipcMain.handle('ruwio:render-mp4', handleRenderMp4)
|
ipcMain.handle('ruwio:render-mp4', handleRenderMp4)
|
||||||
ipcMain.handle('ruwio:render-cancel', handleRenderCancel)
|
ipcMain.handle('ruwio:render-cancel', handleRenderCancel)
|
||||||
|
if (isE2E) {
|
||||||
|
globalThis.__ruwioTestMenuCommand = (command: string) => sendAppCommand(command)
|
||||||
|
}
|
||||||
createMenu()
|
createMenu()
|
||||||
createMainWindow()
|
createMainWindow()
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -19,7 +19,7 @@
|
|||||||
"test:render-server": "node --test server/server.smoke.test.cjs",
|
"test:render-server": "node --test server/server.smoke.test.cjs",
|
||||||
"test:render-server:e2e": "node --test server/render.e2e.test.cjs",
|
"test:render-server:e2e": "node --test server/render.e2e.test.cjs",
|
||||||
"test:render-desktop": "tsc -p tsconfig.electron.json && node scripts/verify-desktop-render.cjs",
|
"test:render-desktop": "tsc -p tsconfig.electron.json && node scripts/verify-desktop-render.cjs",
|
||||||
"test:capture-fidelity": "tsc -p tsconfig.electron.json && electron scripts/verify-capture-fidelity.cjs",
|
"test:capture-fidelity": "tsc -p tsconfig.electron.json && node scripts/run-electron-harness.cjs scripts/verify-capture-fidelity.cjs",
|
||||||
"stage:ffmpeg": "node scripts/stage-ffmpeg.cjs"
|
"stage:ffmpeg": "node scripts/stage-ffmpeg.cjs"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
const { spawnSync } = require('node:child_process')
|
||||||
|
|
||||||
|
const electron = require('electron')
|
||||||
|
const args = process.argv.slice(2)
|
||||||
|
|
||||||
|
if (!args.length) {
|
||||||
|
console.error('usage: node scripts/run-electron-harness.cjs <script> [args...]')
|
||||||
|
process.exit(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
const env = { ...process.env }
|
||||||
|
delete env.ELECTRON_RUN_AS_NODE
|
||||||
|
env.ELECTRON_DISABLE_SANDBOX = '1'
|
||||||
|
|
||||||
|
const res = spawnSync(electron, ['--no-sandbox', ...args], {
|
||||||
|
stdio: 'inherit',
|
||||||
|
env,
|
||||||
|
argv0: electron,
|
||||||
|
})
|
||||||
|
|
||||||
|
process.exit(res.status ?? 1)
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// Runs the desktop-render verification harnesses (Phase A/B of
|
// Runs the desktop-render verification harnesses (Phase A/B of
|
||||||
// electron-rendering-integration-plan_2.md) under Electron and aggregates the
|
// 05_electron-rendering-integration-plan_2.md) under Electron and aggregates the
|
||||||
// results. Each harness exits 0 on PASS, non-zero on FAIL.
|
// results. Each harness exits 0 on PASS, non-zero on FAIL.
|
||||||
//
|
//
|
||||||
// npm run test:render-desktop (compiles electron TS first, then runs this)
|
// npm run test:render-desktop (compiles electron TS first, then runs this)
|
||||||
@@ -11,6 +11,10 @@ const { spawnSync } = require('node:child_process')
|
|||||||
const path = require('node:path')
|
const path = require('node:path')
|
||||||
|
|
||||||
const electron = require('electron') // resolves to the electron binary path
|
const electron = require('electron') // resolves to the electron binary path
|
||||||
|
const electronEnv = { ...process.env }
|
||||||
|
delete electronEnv.ELECTRON_RUN_AS_NODE
|
||||||
|
electronEnv.ELECTRON_DISABLE_SANDBOX = '1'
|
||||||
|
|
||||||
const harnesses = [
|
const harnesses = [
|
||||||
['capture', 'verify-capture.cjs', 'hidden-window capturePage produces advancing, non-blank frames (#1/#2)'],
|
['capture', 'verify-capture.cjs', 'hidden-window capturePage produces advancing, non-blank frames (#1/#2)'],
|
||||||
['capture-fidelity', 'verify-capture-fidelity.cjs', 'capturePage matches render.html canvas pixels'],
|
['capture-fidelity', 'verify-capture-fidelity.cjs', 'capturePage matches render.html canvas pixels'],
|
||||||
@@ -26,8 +30,9 @@ const harnesses = [
|
|||||||
let failures = 0
|
let failures = 0
|
||||||
for (const [name, file, desc] of harnesses) {
|
for (const [name, file, desc] of harnesses) {
|
||||||
process.stdout.write(`\n=== ${name}: ${desc} ===\n`)
|
process.stdout.write(`\n=== ${name}: ${desc} ===\n`)
|
||||||
const res = spawnSync(electron, [path.join(__dirname, file)], {
|
const res = spawnSync(electron, ['--no-sandbox', path.join(__dirname, file)], {
|
||||||
stdio: ['ignore', 'inherit', 'ignore'], // drop Electron's chatty stderr
|
stdio: ['ignore', 'inherit', 'ignore'], // drop Electron's chatty stderr
|
||||||
|
env: electronEnv,
|
||||||
})
|
})
|
||||||
if (res.status !== 0) {
|
if (res.status !== 0) {
|
||||||
failures += 1
|
failures += 1
|
||||||
|
|||||||
Reference in new issue
Block a user