diff --git a/apps/desktop/e2e/fix-electron-tracing.ts b/apps/desktop/e2e/fix-electron-tracing.ts index a59825e98444..1c2a9825dad5 100644 --- a/apps/desktop/e2e/fix-electron-tracing.ts +++ b/apps/desktop/e2e/fix-electron-tracing.ts @@ -21,6 +21,12 @@ * so the test runner's willStartTest doesn't throw "already started". * * Imported from playwright.config.ts so it runs before any test. + * + * Pinned dependency: this file reaches into Playwright internals (_playwright, + * _allContexts, _context) that have no public contract. @playwright/test is + * pinned exact (=1.58.2 in package.json) so a bump can't silently break the + * monkeypatch. When bumping, re-verify these private symbols still exist on + * the Electron / PlaywrightInternal classes and that tracing still merges. */ import { _electron as electron, type BrowserContext } from '@playwright/test' @@ -31,13 +37,13 @@ const originalLaunch = electron.launch.bind(electron) electron.launch = async (options: any) => { const app = await originalLaunch(options) - const ctx = app._context as BrowserContext + const ctx = (app as any)._context as BrowserContext electronContexts.add(ctx) ctx.once('close', () => electronContexts.delete(ctx)) // Patch _allContexts so the test runner sees the electron context // (didFinishTest cleanup → _stopTracing → stopChunk → merge into trace.zip). - const pw = electron._playwright as any + const pw = (electron as any)._playwright as any if (pw && !pw.__electronTracingPatched) { pw.__electronTracingPatched = true const original = pw._allContexts.bind(pw) diff --git a/apps/desktop/electron/main.ts b/apps/desktop/electron/main.ts index fb60adbf1bf9..b24decc00815 100644 --- a/apps/desktop/electron/main.ts +++ b/apps/desktop/electron/main.ts @@ -7622,9 +7622,9 @@ function createWindow() { // Under Playright testing, instantly show the window. // `ready-to-show` doesn't fire in some testing envs. if (process.env.TEST_WORKER_INDEX !== undefined) { - if (mainWindow && !mainWindow.isDestroyed() && !mainWindow.isVisible()) { - mainWindow.show() - } + if (mainWindow && !mainWindow.isDestroyed() && !mainWindow.isVisible()) { + mainWindow.show() + } } mainWindow.on('will-enter-full-screen', () => sendWindowStateChanged(true)) diff --git a/apps/desktop/package.json b/apps/desktop/package.json index b6fc344cd80e..743269c10476 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -41,7 +41,7 @@ "test:desktop:nsis": "node scripts/test-desktop.mjs nsis", "test:desktop:existing": "node scripts/test-desktop.mjs existing", "test:desktop:fresh": "node scripts/test-desktop.mjs fresh", - "typecheck": "tsc -p . --noEmit && tsc -p tsconfig.electron.json --noEmit", + "typecheck": "tsc -p . --noEmit && tsc -p tsconfig.electron.json --noEmit && tsc -p tsconfig.e2e.json --noEmit", "lint": "eslint src/ electron/", "lint:fix": "eslint src/ electron/ --fix", "fmt": "prettier --write 'src/**/*.{ts,tsx}' 'electron/**/*.ts' 'vite.config.ts'", diff --git a/apps/desktop/playwright.config.ts b/apps/desktop/playwright.config.ts index 9a661e5fadd0..dc06c59fe786 100644 --- a/apps/desktop/playwright.config.ts +++ b/apps/desktop/playwright.config.ts @@ -45,7 +45,9 @@ export default defineConfig({ // overlay, DecodeText). Without this, screenshots capture the loading bar // or overlay at a transient opacity because the text-content check fires // before the visual transition finishes. - reducedMotion: 'reduce', + contextOptions: { + reducedMotion: 'reduce', + }, }, expect: { toHaveScreenshot: { diff --git a/apps/desktop/src/components/gateway-connecting-overlay.tsx b/apps/desktop/src/components/gateway-connecting-overlay.tsx index d2050f11fed4..0268755d5632 100644 --- a/apps/desktop/src/components/gateway-connecting-overlay.tsx +++ b/apps/desktop/src/components/gateway-connecting-overlay.tsx @@ -83,29 +83,17 @@ export function GatewayConnectingOverlay() { return } - if(reduce) { - // Under reduced motion, skip straight to gone — no text-out, no hold, - // no overlay fade. The overlay unmounts immediately. - setPhase('gone') - } - - if (previewing) { - // Under reduced motion, skip straight to gone — no text-out, no hold, - // no overlay fade. The overlay unmounts immediately. - if(reduce) { - setPhase('gone') - - return - } - + if (previewing) { const id = window.setTimeout(() => setPhase('text-out'), PREVIEW_CONNECT_MS) return () => window.clearTimeout(id) } if (gatewayState === 'open' && shownRef.current) { - // Under reduced motion, skip straight to gone — no text-out, no hold, - // no overlay fade. The overlay unmounts immediately. + // Under reduced motion, skip the multi-phase exit choreography + // (text-out → hold → overlay fade) and jump straight to gone so the + // overlay unmounts the instant the gateway opens. E2E screenshots + // rely on this to avoid catching the overlay mid-fade. setPhase(reduce ? 'gone' : 'text-out') } }, [phase, previewing, gatewayState, reduce]) diff --git a/apps/desktop/tsconfig.e2e.json b/apps/desktop/tsconfig.e2e.json new file mode 100644 index 000000000000..e0beb8961941 --- /dev/null +++ b/apps/desktop/tsconfig.e2e.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "types": ["node", "@playwright/test"], + "composite": true + }, + "include": ["e2e", "playwright.config.ts"], + "exclude": ["src", "electron"] +}