super-productivity/e2e/playwright.config.ts
Johannes Millan 77f83c5687
test(e2e): harden failure signals and provider gates (#7753)
* test: harden e2e failure signals

Fail otherwise-passing E2E tests on browser runtime errors, keep Playwright retries disabled, preserve Docker E2E exit codes, and make plugin/WebDAV setup failures hard failures instead of logged or skipped conditions.

* test: harden provider e2e runners

Make WebDAV and SuperSync runner scripts require provider readiness, preserve cleanup and argument forwarding, and fail manual sync clients on uncaught page errors.

* ci: require providers for scheduled e2e

Set required-provider flags in scheduled WebDAV and SuperSync jobs, and remove the duplicate provider runner scripts while keeping local npm aliases inline.

* test: catch e2e teardown pageerrors and tighten fixture

- closeClient now asserts runtime errors AFTER context.close() so
  pageerrors emitted during teardown (Angular destroy hooks, late RxJS
  errors) are captured instead of dropped. Matches the pattern in
  guardContextCloseWithRuntimeErrorCheck.
- test.fixture.ts isolatedContext now spreads Playwright's merged
  contextOptions instead of destructuring 23 fields by hand. Future
  option additions propagate automatically; the page fixture uses the
  shared attachPageErrorCollector and only fails on pageerror (not
  console.error, which is too noisy). Guards against a configured 0
  timeout being treated as undefined.
- plugin-loading.spec.ts second test now hard-asserts that the plugin
  menu entry reappears after re-enable, matching the first test instead
  of silently logging when not visible.

* test(sync): stabilize ImmediateUploadService spec

Two complementary fixes for flaky failures observed under full-suite
random-order runs where the upload pipeline silently never fires:

- Pin navigator.onLine = true in beforeEach (restored in afterEach).
  isOnline() inside _canUpload reads navigator.onLine directly. The
  keyboard-layout spec replaces the whole navigator and the is-online
  spec spies on it; if order or restoration ever drifts, every "should
  fire upload" test fails trivially while the "should NOT" tests pass.
- Replace tick(2100) with tick(2000); flush(). The await chain inside
  withSession() (provider.isReady, withSession entry, uploadPendingOps,
  optional LWW re-upload) requires more microtask drain than tick's
  fixed-time window reliably provides under load. flush() drains the
  pipeline regardless.

* test(e2e): guard skipOnboarding init script against data: frames

The new page-error collector started failing plugin specs because
addInitScript runs in every frame — including the empty data:text/html
iframe that plugin-index swaps in on destroy — and localStorage access
in a data: URL throws SecurityError. Wrap the four setItem calls in
try/catch so the helper noops in storage-less frames.
2026-05-23 20:33:04 +02:00

174 lines
5.2 KiB
TypeScript

import { defineConfig, devices } from '@playwright/test';
import path from 'path';
import os from 'os';
/**
* See https://playwright.dev/docs/test-configuration.
*/
export default defineConfig({
testDir: path.join(__dirname, 'tests'),
/* Global setup */
globalSetup: require.resolve(path.join(__dirname, 'global-setup')),
/* Run tests in files in parallel */
fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI,
/*
* Keep retries disabled so E2E failures expose determinism problems instead
* of being hidden by a later passing attempt.
*/
retries: 0,
// Reduce worker count to avoid resource contention causing flakiness
// Lower worker count improves stability by reducing parallel execution stress
workers:
(process.env.CI
? Math.min(3, os.cpus().length)
: Math.min(12, os.cpus().length - 1)) || 1,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: process.env.CI
? [
[
'html',
{
outputFolder: path.join(
__dirname,
'..',
'.tmp',
'e2e-test-results',
'playwright-report',
),
open: 'never',
},
],
[
'junit',
{
outputFile: path.join(
__dirname,
'..',
'.tmp',
'e2e-test-results',
'results.xml',
),
},
],
]
: process.env.PLAYWRIGHT_HTML_REPORT
? [
[
'html',
{
outputFolder: path.join(
__dirname,
'..',
'.tmp',
'e2e-test-results',
'playwright-report',
),
open: 'always',
},
],
]
: 'line',
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
/* Base URL to use in actions like `await page.goto('/')`. */
baseURL: process.env.E2E_BASE_URL || 'http://localhost:4242',
/*
* Pin the browser locale so navigator.language is deterministic across
* machines. The app's "System default" date/time locale follows
* navigator.language, and many tests assume en-GB (DD/MM/YYYY, 24h).
*/
locale: 'en-GB',
/* Configure downloads to go to test output directory, not ~/Downloads */
downloadsPath: path.join(__dirname, '..', '.tmp', 'e2e-test-results', 'downloads'),
/* Collect trace on failure for better debugging. See https://playwright.dev/docs/trace-viewer */
trace: 'retain-on-failure',
/* Take screenshot on failure */
screenshot: 'only-on-failure',
/* Video on failure */
video: 'retain-on-failure',
/* Browser options */
userAgent: 'PLAYWRIGHT',
/* Navigation timeout - increased for stability */
navigationTimeout: 30000,
/* Action timeout - increased for stability with Angular */
actionTimeout: 15000,
},
/* Configure projects for major browsers */
projects: [
{
name: 'chromium',
use: {
...devices['Desktop Chrome'],
contextOptions: {
permissions: ['geolocation', 'notifications'],
geolocation: { longitude: 0, latitude: 0 },
},
launchOptions: {
args: [
'--disable-dev-shm-usage',
'--disable-browser-side-navigation',
'--no-sandbox',
'--disable-setuid-sandbox',
'--disable-extensions',
'--disable-gpu', // Disable GPU for more stable headless execution
'--disable-software-rasterizer',
'--disable-background-timer-throttling', // Prevent timer throttling
'--disable-backgrounding-occluded-windows',
'--disable-renderer-backgrounding',
],
},
},
},
// Optionally test against other browsers
// {
// name: 'firefox',
// use: { ...devices['Desktop Firefox'] },
// },
// {
// name: 'webkit',
// use: { ...devices['Desktop Safari'] },
// },
],
/* Run your local dev server before starting the tests */
/* When E2E_BASE_URL is set (e.g., when using Docker), skip starting the server */
webServer: process.env.E2E_BASE_URL
? undefined
: {
command: process.env.CI
? 'npm run serveFrontend:e2e:prod'
: 'npm run startFrontend:e2e',
url: 'http://localhost:4242',
reuseExistingServer: false,
timeout: 2 * 60 * 1000,
stdout: 'ignore', // Reduce log noise
stderr: 'pipe',
},
/* Folder for test artifacts such as screenshots, videos, traces, etc. */
outputDir: path.join(__dirname, '..', '.tmp', 'e2e-test-results', 'test-results'),
/* Global timeout for each test - increased for Angular app stability
* and mandatory encryption handling overhead in SuperSync tests */
timeout: 180 * 1000,
/* Global timeout for each assertion - increased for slow rendering */
expect: {
timeout: 20 * 1000,
},
/* Maximum test failures before stopping */
maxFailures: process.env.CI ? undefined : 5,
});