findElectron() probed exactly one path, and got three things wrong at once for anyone not on a hoisted POSIX install: * It looked only under the REPO ROOT. This is an npm workspaces repo and npm hoists a dependency only when nothing conflicts, so `electron` installing into apps/desktop/node_modules is an ordinary outcome, not a broken tree. * It joined a bare `electron`. On Windows the dist file is `electron.exe`, so the probe could never match there. * Its PATH fallback spawned `which`, which is not a command on Windows, so the fallback failed for a reason unrelated to whether electron is on PATH. The three combine into a misleading error: the suite refuses to start with 'Run "npm install" from the repo root' on a tree that has electron installed. Reproduced on Windows 11 against this repo, where apps/desktop/node_modules/electron/dist/electron.exe exists and the old body throws that message; the reporter on #88036 hit the same thing on Linux and had to hand-symlink the package before the suite would run. Resolution now asks the installed `electron` package for its own path first (its main export IS the absolute executable, resolved from path.txt and honouring ELECTRON_OVERRIDE_DIST_PATH), then falls back to explicit dist probes for each root, then to PATH with the platform's lookup command. The error message lists what was searched. The rules live in e2e/electron-binary.ts so they can be unit-tested without importing the Playwright runner, with the platform passed in rather than read from process.platform: reading it would leave every Windows rule untested on the Linux CI runner. Wiring: the vitest `electron` project picks up e2e/**/*.unit.test.ts and Playwright ignores the same pattern, so helper unit tests run in exactly one runner and the specs are untouched. Verified: 5 unit tests pass; mutation-checked one rule at a time (hardcoding the binary name fails 2, reversing the probe order fails 1, hardcoding `which` fails 1). tsc -p . and tsc -p tsconfig.e2e.json clean. This is the environment blocker called out in #88036, not its rendering bug, so it is deliberately a subset. Refs #88036
68 lines
2.6 KiB
TypeScript
68 lines
2.6 KiB
TypeScript
import './e2e/fix-electron-tracing'
|
|
|
|
import { defineConfig, type ReporterDescription } from '@playwright/test'
|
|
|
|
/**
|
|
* Visual regression testing config.
|
|
*
|
|
* Screenshots are compared against baselines. On `main`, baselines are
|
|
* generated with `--update-snapshots` and cached. On PRs, the cached
|
|
* baselines are restored and screenshots are compared — but tests DON'T
|
|
* fail on visual diffs (see `expectVisualSnapshot` in visual-snapshot.ts).
|
|
* Instead, diffs are surfaced in the CI step summary and uploaded as
|
|
* artifacts for human review.
|
|
*
|
|
* To update baselines after an intentional UI change:
|
|
* npx playwright test --update-snapshots
|
|
*/
|
|
const reporters: ReporterDescription[] = [
|
|
['list'],
|
|
['html', { open: 'never', outputFolder: 'playwright-report' }],
|
|
]
|
|
|
|
if (process.env.CI) {
|
|
reporters.push(['json', { outputFile: 'playwright-report/results.json' }])
|
|
}
|
|
|
|
export default defineConfig({
|
|
/* Test files live under e2e/ so they never collide with the vitest suite
|
|
* under src/ or the node:test files under electron/. */
|
|
testDir: './e2e',
|
|
/* ...except `*.unit.test.ts`, which covers the e2e HELPERS (no Electron, no
|
|
* app) and is owned by the vitest `electron` project. Without this the
|
|
* default testMatch would claim those files too and run them twice. */
|
|
testIgnore: '**/*.unit.test.ts',
|
|
/* The desktop app can take a while to bootstrap on cold CI runners — 90 s
|
|
* per test gives us headroom without masking real hangs. */
|
|
timeout: 90_000,
|
|
retries: process.env.CI ? 1 : 0,
|
|
/* Each test gets its own worker so the Electron process is fully isolated. */
|
|
fullyParallel: false,
|
|
reporter: reporters,
|
|
use: {
|
|
screenshot: 'on',
|
|
trace: { mode: 'on', screenshots: true, snapshots: true, sources: true },
|
|
// Emulate prefers-reduced-motion: reduce so all CSS transitions and
|
|
// animations resolve instantly. This prevents boot/connecting overlays
|
|
// from being mid-fade when a screenshot fires, and skips JS-driven exit
|
|
// choreography in components that check matchMedia (onboarding, connecting
|
|
// 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.
|
|
contextOptions: {
|
|
reducedMotion: 'reduce',
|
|
},
|
|
},
|
|
expect: {
|
|
toHaveScreenshot: {
|
|
// 1% of pixels may differ — absorbs sub-pixel font rendering variance
|
|
// between local and CI environments.
|
|
maxDiffPixelRatio: 0.01,
|
|
animations: 'disabled',
|
|
caret: 'hide',
|
|
// Per-channel threshold for "close enough" — anti-aliasing differences.
|
|
threshold: 0.2,
|
|
},
|
|
},
|
|
})
|