| Filename | Latest commit message | Latest commit date |
|---|---|---|
The 3d-webgl merge (kicad eb13ff3bdc: the viewer now defaults to the real OpenGL renderer via wasm/gl1, and occ-split moves STEP parsing into the occ_service worker) made the raytracer-era orchestration on this branch moot — main's chromium-ci phase is green at 15-way parallelism (28666407570 / 28698861536). Drop what no longer earns its complexity, keep the diagnostics, fix main's live flake, and make the deadlock spec test what it was written for. - REVERT the chromium-ci-3d serial project, the two-phase test:kicad:ci, the SwiftShader GPU-process flags, and the resize-drag/models skips: config and package.json are byte-for-byte back to main's shape. The raytracer contention they guarded is no longer on the CI path. - FIX main's live flake: run 28698861536 is green only via retry (3d-viewer.spec:26 flaky) and 28666407570's deadlock red sampled an ALL-ZERO pixel signature — the viewer's first frame lags the canvas's creation on software WebGL under parallel load, and sampling too early reads an all-black backbuffer. New waitForThreeDRender() gates render assertions on actual pixels (1s-interval full-frame CPU reads) instead of fixed sleeps, used by 3d-viewer.spec:26 and the models render tail. - KEEP the storm-proofed samplers (one full-frame getImageData on a willReadFrequently canvas replacing 256 per-pixel GPU round-trips per sample — the "GPU stall due to ReadPixels" trigger) and the logThreeDDiag instrumentation: engine-independent, and they de-risk every remaining software-GL pixel read. - models spec: bridge assertions stay front-loaded (the protocol regression signal is independent of the render); the occ_service parse verdict is now POLLED — it lands async relative to the bridge ensures, so asserting it immediately raced the worker; the render tail runs again everywhere. (The pre-webgl raytracer+models renderer-death documented in a17f3be does not affect the OpenGL default path — the raytracer-toggle+models combination remains untested product surface, tracked outside this branch.) - deadlock spec: the deadlock it guards is raytracer-specific and the viewer now defaults to OpenGL — on the GL engine it either passes vacuously (fast renders make every liveness assertion trivial, 28698861536) or fails on the black first frame (28666407570). It now flips the engine via the "Use raytracing" toolbar toggle (loud assert if the toggle moved) and cross-checks engagement by requiring the canvas pixels to CHANGE after the flip with no input in between (the raytraced frame is lit differently; a GL re-render reproduces identical pixels; heap growth is unusable — mimalloc satisfies the raytracer from freed arena pages). That guard immediately caught a REAL defect: on the webgl-era wasm build the toggle is INERT (the click lands and "Reload time" updates, but the canvas never changes — suspects: DoRePaint's silent catch(runtime_error) freezing the canvas after a raytracer Redraw throw, or ToggleRaytracing writing m_boardAdapter.m_Cfg while RenderEngineChanged() reads GetAppSettings<…>(), possibly different instances in the merged bundle). The spec is therefore test.skip-annotated as a KNOWN ISSUE with the full engine-force machinery in place — unskipping it self-validates the product fix. The CI-skip also stays (raytracer liveness needs real-GPU pacing; the Worker-boot deadlock mechanism is covered on CI by the standalone wx harnesses). - 180s viewer-open waits kept as pure CI headroom (never slow a passing run). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
| .. | ||
| 3d-regression | ||
| apps | ||
| asyncify | ||
| baseline-screenshots | ||
| collab | ||
| e2e | ||
| fixtures/demo | ||
| gal-regression | ||
| kicad | ||
| scripts | ||
| tools/screenshots | ||
| web | ||
| find-hardcoded-coords.sh | ||
| GL_README.md | ||
| global-setup.ts | ||
| package-lock.json | ||
| package.json | ||
| playwright-asyncify.config.ts | ||
| playwright-coroutine.config.ts | ||
| playwright-kicad.config.ts | ||
| playwright-web.config.ts | ||
| playwright.config.ts | ||
| README.md | ||
| screenshot-manifest.json | ||
| serve.json | ||
| 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 # wx e2e specs + the asyncify race harness
KiCad application tests are a separate, heavier suite (they need the
docker-built KiCad WASM): npm run test:kicad. Run only the wx e2e specs with
npm run test:wx.
To run specific tests:
npx playwright test menu.spec.ts # Run menu tests only
npx playwright test --grep "wxTimer" # Run tests matching pattern
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/ # Screenshots (auto-generated)
├── baseline-screenshots/ # Reference screenshots for comparison
├── apps/ # Built WASM test applications
│ ├── minimal_test.html # Main test app
│ └── standalone/ # Individual component test apps
└── playwright.config.ts # Playwright configuration
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 screenshots to test-results/. Compare against baselines:
../scripts/compare-screenshots.sh
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? Two
scripts/common/inject-dyncall-shims.shfixes — the fiber trampoline self-heal (§3c) and the nested-Asyncify handleSleep save/restore (§3) — were written for the legacy-EH park-throw model. Under native wasm-EH the top loop is a per-frame-yield while-loop with no park-throw, so ablating either shim (SHIM_DISABLE_TRAMPOLINE_HEAL/SHIM_DISABLE_HANDLESLEEP, wired intests/apps/Makefile.wasm) no longer reproduces the disease it guarded — the old red "ablation pins" inasyncify/asyncify-races.spec.tshave been flipped to green "shim-redundancy pins" that now prove the native-EH path stays clean with the shim ablated. To do: sweep the real apps (modals, nested fibers, long sleeps, pthread pool) with each shim ablated; if all stay green, drop the shim injection and these pins. Until proven, they stay injected (belt-and-suspenders).