ADR-010: E2E UI Smoke Test with the Real WASM Engine
Status: Accepted Date: 2026-07-05
Context
ADR-009 added orca-wasm/scripts/smoke-test.mjs, a Node script that loads
slicer.js/slicer.wasm directly and calls _orc_init/_orc_slice to catch
an engine that compiles but traps on a real slice. It only runs in
build-wasm.yml, which is path-filtered to orca-wasm/** — a normal UI PR
never triggers it, and it never touches the actual app path a real user
exercises: FileUpload → App.tsx's queue state machine →
worker-singleton.ts → slicer.worker.ts's message protocol → the WASM
module. A regression in that glue code (a broken postMessage payload, a
worker that never spawns, a UI state that gets stuck on loading-wasm) would
compile fine, pass the Node-level smoke test, and still ship broken.
Decision
Add a Playwright E2E test (e2e/slice.spec.ts) that drives the real browser
UI end-to-end against a real compiled engine:
- Load the app, upload the real Voron Design Cube v7 STL
(
e2e/fixtures/voron-design-cube-v7.stl, vendored, GPL-3.0 — see below andNOTICE.md) — the exact model that historically triggered two production crashes in the Arachne wall generator (orca-wasm/patches/apply.pysections 8/8c–8f; also referenced in ADR-009's context). Using this real, previously-crash-triggering mesh is a stronger regression guard for the UI path than a trivial synthetic primitive would be. - Navigate to the Slice tab and click "Slice All".
- Wait for the queue item to reach
Done(cold engine load + a real slice, generous timeout) and assert the download button appears. - Assert no browser console errors occurred during the whole flow.
data-testid attributes were added to the file input, tab buttons, slice
button, queue item status, and download button (src/components/FileUpload.tsx,
src/App.tsx) so the test doesn't depend on copy text.
Wired into a new .github/workflows/e2e-smoke.yml, triggered on every
pull_request (no path filter, unlike build-wasm.yml) — a UI-only change is
exactly what this test exists to catch. It downloads the latest published
engine release via npm run setup (the same script local dev uses) rather
than building from source: engine-source correctness is already gated by
build-wasm.yml's own smoke test before anything is ever published, so this
test only needs a real, working binary to drive the UI against, not the one
the current PR might be building.
Runs against npm run dev (not vite preview) because the required
COOP/COEP headers (vite.config.ts) are configured under server, not
preview.
Why vendoring this file is safe (unlike ADR-009's synthetic mesh)
ADR-009 deliberately avoided vendoring a third-party STL for
orca-wasm/scripts/smoke-test.mjs, to "sidestep any question about
redistributing someone else's model." For this E2E test we vendor the real
Voron Design Cube v7 (e2e/fixtures/voron-design-cube-v7.stl) instead,
because the actual blocker was provenance/attribution, not license
incompatibility:
- Voron Design's hardware repos (including
VoronDesign/Voron-2, which hosts this file) are licensed GPL-3.0. - This repository is AGPL-3.0-or-later. GPLv3 and AGPLv3 both contain a clause (§13 in each) that the FSF added specifically so GPLv3-covered and AGPLv3-covered works can be combined — they are not in conflict.
- Attribution is recorded in
NOTICE.md(source URL pinned to the commit the file was fetched from, license, copyright), satisfying GPL-3.0's notice requirement.
orca-wasm/scripts/smoke-test.mjs itself is unchanged and still defaults to
a synthetic mesh — this doesn't reopen or reverse ADR-009, it only settles
that vendoring a compatible-licensed, properly-attributed fixture is
different from vendoring an unknown/incompatible one.
Consequences
- Positive: Catches breakage in the worker/UI integration layer that the
Node-level smoke test structurally cannot see, on every PR rather than only
ones touching
orca-wasm/**. - Positive: Runs against a real engine binary, not a mock — closer to what a user's browser actually does.
- Negative / accepted scope: Tests against the latest published engine
release, not a WASM change made in the same PR (that PR's
build-wasm.ymlrun validates the engine itself; the two checks are complementary, not redundant). - Negative: Adds a Chromium download + a dev-server boot + one slice to
every PR's CI — a few minutes, not the multi-hour cost of
build-wasm.yml. - Negative: Adds a ~170 KB third-party binary (
voron-design-cube-v7.stl) to the repository, with an attribution obligation tracked inNOTICE.md.