| Filename | Latest commit message | Latest commit date |
|---|---|---|
Same FOOTPRINT_EDIT_FRAME and the same wx-layer focus rule; opening a second editor from a board session never became ready on CI (Chromium 180 s, Firefox footprint load >60 s). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012Wd1r3ewftpV1DBSEArpRa |
||
| .. | ||
| 3d-regression | ||
| apps | ||
| collab | ||
| e2e | ||
| fixtures/demo | ||
| gal-regression | ||
| jspi | ||
| kicad | ||
| scripts | ||
| tools | ||
| web | ||
| .gitignore | ||
| find-hardcoded-coords.sh | ||
| GL_README.md | ||
| global-setup.ts | ||
| package-lock.json | ||
| package.json | ||
| playwright-web.config.ts | ||
| playwright.config.ts | ||
| README.md | ||
| serve.json | ||
| TESTING.md | ||
| tsconfig.json | ||
| WHATWORKS.md | ||
| wizard-04-finish-headless.png | ||
KiCad WASM Tests
Playwright tests for verifying the wxWidgets WASM port.
Prerequisites
- Node.js 18+
- Emscripten SDK (for building)
Building the Test App
../scripts/build-wasm-test.sh
This builds apps/minimal_test.{html,js,wasm} and standalone test apps.
Running Tests
npm install
npm test # setup:kicad + the full merged run (same projects as CI)
One merged config (playwright.config.ts) drives every wasm suite as
Playwright projects; npm run test:e2e runs the CI set: wx-chromium,
kicad-firefox, kicad-chromium, jspi-firefox, coroutine-firefox.
The KiCad specs (heavier — they need the docker-built KiCad WASM) run on BOTH
engines; npm run test:kicad is the firefox-only shortcut. The React web app
suite is separate: npm run test:web (see playwright-web.config.ts).
To run a subset, pick a project (and optionally a spec):
npx playwright test --project=wx-chromium menu.spec.ts # wx menu tests only
npx playwright test --project=kicad-firefox kicad/pcbnew.spec.ts
npx playwright test --project=wx-chromium --grep "wxTimer"
Test Structure
tests/
├── e2e/ # Playwright test specs
│ ├── utils/ # Shared test utilities
│ │ ├── fixtures.ts # Playwright fixtures with auto-logging
│ │ ├── element-tracker.ts # Element registry utilities (clickByLabel, etc.)
│ │ └── test-utils.ts # Logging and helper functions
│ ├── menu.spec.ts # wxMenuBar tests
│ ├── timer.spec.ts # wxTimer tests
│ ├── dialog.spec.ts # wxDialog/wxMessageBox tests
│ ├── tree.spec.ts # wxTreeCtrl tests
│ ├── grid.spec.ts # wxGrid/wxSpinCtrl/wxSearchCtrl tests
│ ├── wxwidgets.spec.ts # Comprehensive UI interaction tests
│ └── ...
├── logs/ # Test logs (auto-generated)
├── test-results/{chromium,firefox}/ # Screenshots per engine (auto-generated)
├── baseline-screenshots/{chromium,firefox}/ # Reference screenshots per engine — gitignored cache of the R2 bucket (npm run screenshots:fetch)
├── .baseline-manifest.json # Gitignored copy of the R2-hosted baseline manifest (npm run screenshots:fetch-manifest)
├── apps/ # Built WASM test applications
│ ├── minimal_test.html # Main test app
│ └── standalone/ # Individual component test apps
├── playwright.config.ts # THE merged config (wx / kicad / jspi / coroutine / perf projects)
└── playwright-web.config.ts # React web-app suite (own server stack)
Logging
Each test automatically captures:
- Console logs with timestamps and log levels
- Page errors with full stack traces
Log files are written to logs/ after each test:
<test-name>.log- All console output<test-name>.errors.log- Errors only (created if errors occurred)
Example log format:
[2025-11-29T19:39:42.165Z] [LOG] [EVENT] Application started
[2025-11-29T19:39:42.733Z] [WARNING] GPU stall due to ReadPixels
[2025-11-29T19:39:42.801Z] [ERROR] Some error message
Screenshots
Tests capture raw PNGs to test-results/<engine>/ (engine-scoped via
stableShot/shotPath). The offline gate compares them against the per-engine
baselines pinned by the R2-hosted manifest:
npm run screenshots:fetch-manifest && npm run screenshots:fetch
npm run screenshots:check
CI's Linux render is the source of truth — update baselines by promoting a CI
run in the morelli review app
(https://pcbjam-morelli-staging.pcbjam-staging.workers.dev), never by copying
local renders. Rules and details: TESTING.md.
Viewing the App Directly
Start a local server in the apps directory:
cd apps
npx serve .
Then open http://localhost:3000/minimal_test.html in your browser.
Alternative using Python:
cd apps
python3 -m http.server 8000
Then open http://localhost:8000/minimal_test.html
Test Categories
| Spec File | Tests | Description |
|---|---|---|
wxwidgets.spec.ts |
Comprehensive | Full UI interaction, stability |
menu.spec.ts |
wxMenuBar | Menu bar visibility and interactions |
timer.spec.ts |
wxTimer | Timer start/stop/reset functionality |
dialog.spec.ts |
wxDialog | Message boxes and custom dialogs |
tree.spec.ts |
wxTreeCtrl | Tree control with expand/collapse |
grid.spec.ts |
wxGrid | Grid, SpinCtrl, SearchCtrl |
aui.spec.ts |
wxAuiManager | Dockable panels |
clipboard.spec.ts |
wxClipboard | Copy/paste operations |
dataview.spec.ts |
wxDataViewCtrl | List and tree data views (Zone Manager-like) |
filedialog.spec.ts |
wxFileDialog | File open/save dialogs |
htmlwin.spec.ts |
wxHtmlWindow | HTML rendering (About dialogs, error formatting) |
layout.spec.ts |
wxSplitter | Splitter and scrolled windows |
toolbar.spec.ts |
wxToolBar | Toolbar buttons and status bar |
Debugging WASM Crashes
When a test fails with a WASM crash (e.g., "memory access out of bounds"), you can build with debug symbols to get meaningful stack traces:
Debug Build
# Build test apps with DWARF symbols and source maps
../scripts/build-wasm-test.sh --debug
This enables:
-gfor DWARF debug info-gsource-mapfor browser source maps-O0for no optimization (preserves debugging context)
Reading Stack Traces
With a debug build, WASM stack traces show actual function names:
Before (release build):
RuntimeError: memory access out of bounds
at wasm-function[102]:0xfdf8
at wasm-function[99]:0xe6e0
After (debug build):
RuntimeError: memory access out of bounds
at grid_test.wasm.GridTestFrame::LogEvent(wxString const&)
at grid_test.wasm.GridTestFrame::OnGridCellSelect(wxGridEvent&)
at grid_test.wasm.wxEventFunctorMethod<...>::operator()
Using LLVM Tools
For deeper analysis, use Emscripten's LLVM tools:
LLVM_DIR="/opt/homebrew/Cellar/emscripten/4.0.20/libexec/llvm/bin"
# Check if WASM has DWARF info
$LLVM_DIR/llvm-dwarfdump --debug-info apps/standalone/grid/grid_test.wasm
# Disassemble with function names
$LLVM_DIR/llvm-objdump -d grid_test.wasm | head -200
Element Registry (Recommended)
The wxWidgets WASM port includes an element registry that tracks all wxWindow instances with their positions, labels, and types. This enables tests to find UI elements by semantic identifiers instead of hardcoded pixel coordinates.
Usage
import { waitForRegistry, clickByLabel, findByLabel, findByType } from './utils/fixtures';
// Wait for registry to be available
await waitForRegistry(page);
// Click buttons by label text
await clickByLabel(page, 'Copy to Clipboard');
await clickByLabel(page, 'Save File...');
// Find elements for inspection
const button = await findByLabel(page, 'OK');
if (button) {
console.log(`Button at (${button.centerX}, ${button.centerY})`);
}
// Find all elements of a type
const buttons = await findByType(page, 'wxButton');
Available Functions
| Function | Description |
|---|---|
waitForRegistry(page) |
Wait for element registry to initialize |
findByLabel(page, label, options?) |
Find element by label text |
findByName(page, name, options?) |
Find element by wxWindow name |
findByType(page, typeName, options?) |
Find all elements of a type (e.g., 'wxButton') |
clickByLabel(page, label, options?) |
Click element by label |
clickByName(page, name, options?) |
Click element by name |
Options
interface FindOptions {
visible?: boolean; // Filter by visibility (default: true)
enabled?: boolean; // Filter by enabled state
exact?: boolean; // Exact label match (default: substring)
type?: string; // Filter by type name
}
When to Use
Use the element registry for tests that click on wxButton and other wxWindow-based controls. The registry tracks:
- wxButton, wxTextCtrl, wxStaticText, wxPanel, wxFrame, etc.
Not trackable (use pixel coordinates instead):
- wxToolBar tool items (rendered by toolbar)
- wxMenuBar menu items (rendered by menu system)
- wxAuiManager panel controls (title bars, close buttons)
- wxGrid cells (rendered by grid)
- wxSplitterWindow sash (rendered by splitter)
Migrated Tests
These tests use the element registry:
clipboard.spec.ts- Copy, Paste, Check, Clear buttonsdialog.spec.ts- Info, Yes/No, Error, Custom dialog buttonstimer.spec.ts- Start, Stop, Reset buttonsfiledialog.spec.ts- Open, Save, Open Multiple buttonslogerror.spec.ts- Trigger Error, Flush Log buttons
Available Test Apps
| App URL | Description |
|---|---|
/standalone/clipboard/clipboard_test.html |
Copy, Paste, Check, Clear buttons |
/standalone/dataview/dataview_test.html |
wxDataViewListCtrl and wxDataViewTreeCtrl (Zone Manager-like data) |
/standalone/dialog/dialog_test.html |
Info, Yes/No, Error, Custom dialog buttons |
/standalone/htmlwin/htmlwin_test.html |
wxHtmlWindow with various HTML content |
/standalone/tree/tree_test.html |
Expand All, Collapse All, etc. |
/standalone/menu/menu_test.html |
Menu bar testing |
/standalone/grid/grid_test.html |
Grid controls |
/standalone/aui/aui_test.html |
AUI panel controls |
/standalone/toolbar/toolbar_test.html |
Toolbar buttons |
/standalone/timer/timer_test.html |
Timer controls |
/standalone/filedialog/filedialog_test.html |
File dialog buttons |
/standalone/layout/layout_test.html |
Layout controls |
Environment Variables
| Variable | Default | Description |
|---|---|---|
APP_URL |
(required) | URL path to scan |
STEP |
10 |
Pixel step size for scanning (smaller = more accurate but slower) |
START_X |
0 |
X coordinate to start scanning |
END_X |
canvas width | X coordinate to end scanning |
START_Y |
0 |
Y coordinate to start scanning |
END_Y |
canvas height | Y coordinate to end scanning |
Output
The utility outputs:
- Button positions with labels (from console log keywords)
- Generated test code snippets
- Results JSON file at
test-results/button-finder-results.json
Example output:
RESULTS: Found 4 buttons
Button positions (relative to canvas):
Copy at (352, 196)
Log: [CLIPBOARD_EVENT] Attempting to copy text to clipboard...
Paste at (600, 196)
Log: [CLIPBOARD_EVENT] Attempting to paste from clipboard...
Known Issues
- Timer tests: May fail due to timing sensitivity
- Tree tests: Button click positions may vary
Open tasks
Research: are the Asyncify fiber shims still needed under native-EH?Resolved at doc 20 D-1, then mooted by the JSPI migration (2026-08): the ablation builds (races_test_noheal/races_test_nosleepfix) and their shim-redundancy pins (in the since-deletedasyncify/asyncify-races.spec.ts) pinned a runtime that no longer exists, and the asyncify scheduler shim they were measured against retired with the backend. The semantic race battery lives on injspi/suspend-races.spec.tsagainst the JSPI runtime.
Collab e2e — legacy vs v2 bundles, and repro markers
Two esbuild bundles (npm run build:collab, rebuilt by the specs' beforeAll):
apps/kicad/collab-bundle.js— the LEGACY scalar wire (startCollab/kicadCollabSnapshot/Apply/onDelta). Dead in production (nothing registersonDelta); driven by the pre-existing*-collab.spec.tstwo-tab tests. Kept only until the scalar wire is deleted.apps/kicad/collab-bundle-v2.js— the PRODUCTION v2 "items" stack (bindKicadCollaboverkicadCollabSnapshotItems/ApplyItems/onItems, Y keyskdoc_*), fromcollab/browser-entry-v2.ts. Driven bykicad/ysync-two-tab.spec.ts. The build aliasesyjsto ONE copy (the two web pnpm workspaces otherwise bundle two, and Y types are instanceof-checked).
ysync repro tests
kicad/ysync-two-tab.spec.ts, kicad/ysync-repros-{pcbnew,eeschema}.spec.ts reproduce
the bugs of the 2026-07-02 Yjs⇄KiCad sync review (docs/features/ysync-review/ on the
ysync-review branch; unit-level repros live in
web/pcbjam-shared/test/ysync-repros.test.ts and
web/standalone/src/wasm/collab/ysync-repros.test.ts).
Convention: a repro asserts the CORRECT behavior and is marked expected-fail
(test.fail() / vitest it.fails) with a comment naming the bug doc. The suite stays
green while the bug is open; fixing the bug flips the repro to "unexpected pass",
forcing the marker's removal — the repro becomes the regression test. Green companion
tests pin each repro's preconditions (harness, apply path, emit path) so an expected
failure can only come from the bug itself. The "local move emits" controls double as
the headless-emit probes gating the emit-dependent repros.
Follow-up (tracked in review miss 11): once the v2 specs are trusted, un-skip/retire the legacy two-tab specs together with the legacy wire.