Context & Problem Statement
FloCafe is an offline-first hybrid Electron desktop POS with capability detection (window.electronAPI), platform title bar overlays (native-overlay on macOS, fallback controls on Windows/Linux), window focus/blur dimming, and custom layout rails.
Currently, automated E2E tests run primarily inside standard headless Chromium browsers. Because standard browser sessions lack window.electronAPI and native desktop OS window lifecycle events:
- Ad-Hoc Mock Fragility: Tests that need to test desktop chrome must invent inline mocks with
page.addInitScript(...). These ad-hoc mocks often miss subtle platform flags, window event bindings (data-flo-window-focused), or IPC subscriptions.
- Lack of Native OS Verification: Native desktop presentation (macOS traffic lights clearance, window focus state transitions, titlebar dragging) cannot be tested in a pure headless browser without real Electron windowing.
- Execution Overhead & Timeouts: Re-building the frontend and re-inventing mocks in separate tests creates test setup drift, flakiness, and long test execution times.
Goals & Target Architecture
Implement the Dual-Layer Testing Architecture (the modern industry standard for Electron + Playwright apps):
- Layer 1: Typed Capability Fixtures (Fast Browser/LAN Tests)
- Provide a shared, type-safe Playwright fixture (
frontend/e2e/helpers/electron-fixture.ts) that standardizes window.electronAPI injection across browser tests in 1 line.
- Layer 2: Native Desktop E2E Project (True Electron Window Tests)
- Configure a dedicated Playwright Electron test project using
playwright._electron.launch() to run end-to-end tests against real Electron desktop binaries without mocks.
Step-by-Step Implementation Guide
Step 1: Create Centralized Browser Fixture (frontend/e2e/helpers/electron-fixture.ts)
Create a helper that extends Playwright's test or provides an injectElectronMock function matching frontend/src/types/electron.d.ts:
import type { Page } from '@playwright/test';
export interface ElectronMockOptions {
platform?: 'darwin' | 'win32' | 'linux';
status?: 'ready' | 'loading' | 'error';
focused?: boolean;
}
/**
* Injects a fully compliant, typed window.electronAPI mock into the page
* before application scripts execute.
*/
export async function injectElectronMock(page: Page, options: ElectronMockOptions = {}) {
const { platform = 'darwin', status = 'ready', focused = true } = options;
await page.addInitScript(({ platform, status, focused }) => {
(window as any).electronAPI = {
platform,
getStatus: () => Promise.resolve({ status }),
onStatusChange: (callback: (status: any) => void) => {
return () => {};
},
windowAction: (action: string) => Promise.resolve(),
};
// Simulate initial window focus state
if (focused) {
document.documentElement.setAttribute('data-flo-window-focused', 'true');
}
}, { platform, status, focused });
}
Step 2: Configure Native Electron Project in Playwright (frontend/playwright.config.ts)
Add a dedicated Electron project configuration that points to the compiled Electron main process:
// Add project definition in frontend/playwright.config.ts
{
name: 'electron-desktop',
testMatch: /.*\.electron\.spec\.ts/,
use: {
// Desktop-specific viewport and settings
viewport: { width: 1280, height: 800 },
},
}
Step 3: Create Native Electron Test Suite (frontend/e2e/desktop/title-bar.electron.spec.ts)
Create a real Electron E2E test utilizing _electron.launch:
import { test, expect, _electron as electron } from '@playwright/test';
import path from 'path';
test.describe('Electron Native Window Chrome', () => {
test('launches desktop app with native titlebar and window controls', async () => {
const electronApp = await electron.launch({
args: [path.join(__dirname, '../../../dist/main/main.js')],
});
const window = await electronApp.firstWindow();
await window.waitForLoadState('domcontentloaded');
// Verify true native runtime flags
const platform = await window.evaluate(() => window.electronAPI?.platform);
expect(platform).toBeDefined();
// Verify titlebar rendering in real Electron
await expect(window.locator('[data-testid="desktop-title-bar"]')).toBeVisible();
await electronApp.close();
});
});
Step 4: Add NPM Script Shortcuts (package.json)
Add dedicated scripts for developer convenience:
"test:e2e:browser": "playwright test --project=chromium",
"test:e2e:electron": "playwright test --project=electron-desktop",
"test:e2e": "playwright test"
Verification Gates & Exit Criteria
To mark this issue complete, the implementation must meet the following criteria:
Exit Strategy & Rollback Plan
- The fixture helper is strictly additive in
frontend/e2e/helpers/ and does not mutate application runtime logic in src/ or main/.
- If native Electron tests encounter CI runner platform limitations (e.g. headless Linux xvfb requirements), the native Electron project can be gated to local runs while browser fixture tests run on all CI workflows.
References & Documentation
Context & Problem Statement
FloCafe is an offline-first hybrid Electron desktop POS with capability detection (
window.electronAPI), platform title bar overlays (native-overlayon macOS, fallback controls on Windows/Linux), window focus/blur dimming, and custom layout rails.Currently, automated E2E tests run primarily inside standard headless Chromium browsers. Because standard browser sessions lack
window.electronAPIand native desktop OS window lifecycle events:page.addInitScript(...). These ad-hoc mocks often miss subtle platform flags, window event bindings (data-flo-window-focused), or IPC subscriptions.Goals & Target Architecture
Implement the Dual-Layer Testing Architecture (the modern industry standard for Electron + Playwright apps):
frontend/e2e/helpers/electron-fixture.ts) that standardizeswindow.electronAPIinjection across browser tests in 1 line.playwright._electron.launch()to run end-to-end tests against real Electron desktop binaries without mocks.Step-by-Step Implementation Guide
Step 1: Create Centralized Browser Fixture (
frontend/e2e/helpers/electron-fixture.ts)Create a helper that extends Playwright's
testor provides aninjectElectronMockfunction matchingfrontend/src/types/electron.d.ts:Step 2: Configure Native Electron Project in Playwright (
frontend/playwright.config.ts)Add a dedicated Electron project configuration that points to the compiled Electron main process:
Step 3: Create Native Electron Test Suite (
frontend/e2e/desktop/title-bar.electron.spec.ts)Create a real Electron E2E test utilizing
_electron.launch:Step 4: Add NPM Script Shortcuts (
package.json)Add dedicated scripts for developer convenience:
Verification Gates & Exit Criteria
To mark this issue complete, the implementation must meet the following criteria:
npm run lintpasses with 0 type errors oranyviolations in the new fixture helper.title-bar-platform.spec.ts, etc.) successfully refactored to useinjectElectronMock()with 100% pass rate.npm run test:e2e:electronlaunches the Electron window, tests the titlebar, and cleanly exits without leaving zombie background processes or port locks (lsof -i :3001returns empty).Exit Strategy & Rollback Plan
frontend/e2e/helpers/and does not mutate application runtime logic insrc/ormain/.References & Documentation