pcbjam/tests
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Viktor Vaczi 9a04217788 wip: nested-asyncify fix, wxAuiToolBar registration, tests, research docs
Main-repo side of a multi-part WIP covering the KiCad WASM tool-selection
and nested-Asyncify work. Submodule commits are in kicad@f6e9239aaa
(libcontext hygiene) and wxwidgets@bb80f91e8b (auibar registration +
dialog diagnostics).

## scripts/common/inject-dyncall-shims.sh

Wrap Asyncify.handleSleep / allocateData to save-and-restore Asyncify.currData
around each EM_ASYNC_JS sleep. This fixes the nested Asyncify collision where
a fiber swap that fired during a modal's event loop clobbered currData, and
the modal's later doRewind used the fiber's buffer and hit "RuntimeError:
index out of bounds". Root cause documented as Emscripten Issue #9153
(wontfix upstream).

Diagnostic-rewind logging (forcedBottomOfCallStack, callStack traces) is
retained to help future debugging of Asyncify state corruption.

## tests/

- tests/playwright-kicad.config.ts: add `channel: 'chrome'` for the
  chromium project so --project=chromium --headed uses system Chrome
  (real GPU) instead of SwiftShader on ARM Mac. Also switch trace to
  retain-on-failure + screenshot on-failure for easier E2E debugging.
- tests/kicad/pcbnew.spec.ts: replace `tool.checked` assertions with a
  label-suffix check (`[checked]`) since our auibar registration encodes
  checked state in the label (no schema change to the registry).
- tests/apps/Makefile.wasm: add `coroutine-nested` build target + include
  it in the all: list.
- tests/apps/standalone/coroutine/: kicad_coroutine_harness.h + test app
  reproducing KiCad COROUTINE semantics against real libcontext.
- tests/apps/standalone/coroutine-nested/: nested_test.cpp reproduces the
  EM_ASYNC_JS-modal + fiber-swap nesting bug in isolation. 8 scenarios
  from baseline_modal_alone through nested_fibers_inside_modal.
- tests/e2e/coroutine.spec.ts + coroutine-nested.spec.ts: Playwright specs
  that load the standalone apps and assert all case cases pass via
  [COROUTINE_TEST] SUMMARY log parsing.

## research/ and features/browser-tools/

Three background docs capturing the investigation trajectory:

- features/browser-tools/0001-kicad-wasm-tool-activation-investigation.md
  Early investigation: why tools don't activate; initial dynCall-empty-
  callback hypothesis.
- features/browser-tools/0002-wasm-coroutine-deep-dive.md
  Deep dive on Asyncify internals, fiber API, QEMU's coroutine-wasm
  reference implementation.
- features/browser-tools/0003-wxauitoolbar-registration-fix.md
  The narrow fix: why wxAuiToolBar needs a registration block, where to
  add it, what the fallback plan is.
- research/threading_1.md: corrected root-cause analysis after reading
  runtime logs — nested-Asyncify currData collision, Emscripten #9153.
- research/threading_2.md: extended research on alternative approaches
  (JSPI/WasmFX/state-machines) and why they don't help here.

## Submodule pointer updates

kicad: f6e9239aaa (wip: libcontext WASM hygiene cleanup)
wxwidgets: bb80f91e8b (wip: wxAuiToolBar element-registry registration +
            dialog diagnostics)

## Open threads not yet in scope

- Firefox/Chrome divergent behavior: "indirect call signature mismatch"
  traps in Firefox vs renderer crash in system Chrome (tracked in
  plans/peaceful-hugging-pnueli.md and the research docs).
- E2E pixel-diff for Draw Lines fails because the test's diff region does
  not cover where the line is actually drawn; tool activation works, the
  line is visible in test-results/pcbnew-draw-lines-02-after-drawing.png.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 13:58:16 +02:00
..
apps wip: nested-asyncify fix, wxAuiToolBar registration, tests, research docs 2026-04-21 13:58:16 +02:00
baseline-screenshots Fix Asyncify and improve build process 2025-12-14 11:59:50 +01:00
e2e wip: nested-asyncify fix, wxAuiToolBar registration, tests, research docs 2026-04-21 13:58:16 +02:00
gal-regression feat(webgl): Migrate to pure WebGL 2.0 and fix GL canvas layering 2026-03-20 12:38:24 +01:00
kicad wip: nested-asyncify fix, wxAuiToolBar registration, tests, research docs 2026-04-21 13:58:16 +02:00
scripts wasm: validate kicad hi-dpi scaling 2026-03-22 12:48:05 +01:00
find-hardcoded-coords.sh Extend element registry and migrate all tests to semantic selectors 2025-12-30 14:17:51 +01:00
GL_README.md feat(test): Update wizard test to use dynamic button labels 2026-01-12 15:17:03 +01:00
global-setup.ts Organize test logs into separate directories by test suite and file 2025-12-27 16:35:40 +01:00
package-lock.json Add TypeScript configuration for Playwright tests 2025-11-29 12:39:30 +01:00
package.json wasm: validate kicad hi-dpi scaling 2026-03-22 12:48:05 +01:00
playwright-kicad.config.ts wip: nested-asyncify fix, wxAuiToolBar registration, tests, research docs 2026-04-21 13:58:16 +02:00
playwright.config.ts Clean up test infrastructure and fix test assertions 2026-01-01 20:18:19 +01:00
README.md Clean up test infrastructure and fix test assertions 2026-01-01 20:18:19 +01:00
serve.json Add KiCad PCBnew WASM test infrastructure 2025-12-12 15:34:15 +01:00
tsconfig.json Add TypeScript configuration for Playwright tests 2025-11-29 12:39:30 +01:00
WHATWORKS.md Reorganize project structure for clarity 2025-12-27 14:06:23 +01:00
wizard-04-finish-headless.png wasm: validate kicad hi-dpi scaling 2026-03-22 12:48:05 +01:00

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

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
│   ├── opengl.spec.ts      # OpenGL tab 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, OpenGL
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
opengl.spec.ts OpenGL GL tests (immediate mode, vertex arrays)
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:

  • -g for DWARF debug info
  • -gsource-map for browser source maps
  • -O0 for 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

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 buttons
  • dialog.spec.ts - Info, Yes/No, Error, Custom dialog buttons
  • timer.spec.ts - Start, Stop, Reset buttons
  • filedialog.spec.ts - Open, Save, Open Multiple buttons
  • logerror.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