The runtime is JSPI-only; this removes everything that still pretended otherwise. Three exhaustive sweeps (C++/JS+build+CI/tests+docs) drove the inventory; every deletion verified by grep closure + full gates. Broken-right-now fixes: - deploy-staging.yml passed the retired opt_level input — the workflow could not even start. Removed. - env.sh carried dead exports with a live -sASYNCIFY=1 inside (WASM_LDFLAGS/PTHREAD_LDFLAGS, zero consumers). Removed; the WASM_LEGACY_EXCEPTIONS rationale rewritten to the real reason. - docker/build.sh exported PCBJAM_ASYNC_BACKEND (read nowhere). Gone. Dead weight removed: - binaryen submodule (nothing builds or invokes it), wasm-opt-bench workflow + scripts/bench/, get-wasm-opt.sh, diagnostics.js (242 lines of Asyncify-API-only code), the KICAD_PIPELINE background-postprocess scaffolding (existed to parallelize the deleted wasm-opt phase; the postprocess is a seconds-long node script and now runs inline), build-monitor's dead asyncify rows, sched-context orphan build output, dead .gitignore entries, the .jspi-assets spike dir (the two wf-result research JSONs moved to docs/features/async/migration-evidence/). - bindings: fiber_park.h + its 12 embind registrations (broken-if- called under JSPI), the kicadOpenFileStart/OPEN_JOB starter route, main_stack_runner.h + 5 includes, the always-null context-sleep weak hook in nanosleep_yield.c. - shim: the backend field (installed-flag idempotency instead), noteContextWait (dead both sides), the __wxAsyncifyDump alias (+ the WasmTool fallback and string-dump normalize branch). - web: the emscripten-6-ignored mainScriptUrlOrBlob option in boot.ts (gerber-demo keeps it: it loads the deployed CDN release, which predates emscripten 6 — noted inline). Conditionals: all 'backend === jspi' checks reduced to scheduler- presence checks; races_quiescent re-keyed from Asyncify.state (vacuous) to real backlog quiescence (resumeReady/mutatorQueue — NOT _windowLive, which is the probing activation's own window by definition). Renames (identifiers only, no file renames): ASYNC_LINK_FLAGS→ JSPI_LINK_FLAGS and Makefile ASYNC_LDFLAGS→JSPI_LDFLAGS, kicadCollabFiberBusy→kicadCollabBusy (embind + web + tests), collab_common.h fiber*→apply*/coroutine naming, asyncifySignatures→ wasmTrapSignatures (lists byte-identical). Tests: the two remaining vacuous [wx-asyncify]/fiber-resume-refused asserts re-keyed to live JSPI beacons; eeschema-load's failure message no longer sends the developer to a deleted script; wait-beacons' dead families/parser deleted; lane-0 legacy-glue guards removed (lane 0 is unconstructible); the embind test.fail re-gated with the JSPI reason (plain embind invokers cannot suspend — verified still failing); lint-determinism now scans tests/jspi (166 files clean); eeschema-collab local-move gated to chromium (~50% flaky on FF even solo; pcbnew twin covers both engines). Docs: DEBUG.md rewritten as the JSPI debugging guide; build.md describes the single-phase build; docs/features/async/README.md banner-marked historical and repointed at the NEW 23-jspi-runtime.md (current architecture: export census, turnstile, libcontext ownership + refusal contract, embind call shapes, the em-pthread service-wrapper trick, exception policy, known gaps). Gates on the cleaned tree: test:e2e 725 passed / 0 failed (after the quiescence-probe fix; the 3 other reds were verified contention flakes solo-green or the documented FF gate), web 76/0, jspi 18/18 both engines, vitest 295/295 + 17/17, all lints green, live-app census clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016X9eh1s5sTx1o9Em9KBuwR
93 lines
4 KiB
TypeScript
93 lines
4 KiB
TypeScript
import { test, expect, type Page } from '@playwright/test';
|
|
import { clickMenuBarItem, clickMenuItemByText } from '../e2e/utils/element-tracker';
|
|
|
|
/**
|
|
* File → Quit after a tool switch: quitting must land on the project overview.
|
|
*
|
|
* A tool switch (Tools → "Switch to PCB Editor", ExecuteFile →
|
|
* window.kicadWebOpenTool) is a hard location.assign that pushes a history
|
|
* entry. Quit therefore cannot rely on stepping history back: after
|
|
* project → schematic → switch-to-pcb, one history step back is the schematic
|
|
* editor, not the project page. Quit must navigate to the project overview
|
|
* explicitly (WasmTool installQuitHook), wherever the session wandered first.
|
|
*
|
|
* URL + project-page DOM assertions — no screenshots.
|
|
*/
|
|
|
|
/** Scope segment for the demo project (the reference backend serves it for any). */
|
|
const SCOPE = 'default';
|
|
|
|
const SCH_URL_RE = /\/default\/projects\/demo\/demo\.kicad_sch/;
|
|
const PCB_URL_RE = /\/default\/projects\/demo\/demo\.kicad_pcb/;
|
|
// Project overview: path ends at /projects/demo (optionally a query string).
|
|
const PROJECT_URL_RE = /\/default\/projects\/demo\/?(\?.*)?$/;
|
|
|
|
async function waitForToolReady(page: Page, titleRe: RegExp): Promise<void> {
|
|
await expect(page.locator('#canvas')).toBeVisible({ timeout: 120000 });
|
|
await expect
|
|
.poll(() => page.title(), {
|
|
message: `editor never reached title ${titleRe}`,
|
|
timeout: 120000,
|
|
intervals: [1000],
|
|
})
|
|
.toMatch(titleRe);
|
|
// The menu helpers drive the rendered-element registry.
|
|
await page.waitForFunction(
|
|
() =>
|
|
!!(window as unknown as { wxElementRegistry?: { findAllRendered?: unknown } })
|
|
.wxElementRegistry,
|
|
null,
|
|
{ timeout: 30000 }
|
|
);
|
|
// The boot and eager-library overlays (WasmTool, `absolute inset-0 z-30`)
|
|
// cover the whole editor including the menubar — synthetic menu clicks land
|
|
// on them until they clear (eeschema hydrates the full symbol set post-boot).
|
|
await expect(page.locator("div.absolute.inset-0.z-30")).toHaveCount(0, {
|
|
timeout: 180000,
|
|
});
|
|
}
|
|
|
|
async function quitViaFileMenu(page: Page): Promise<void> {
|
|
expect(await clickMenuBarItem(page, 'File'), 'File menubar item clickable').toBe(true);
|
|
await clickMenuItemByText(page, 'Quit');
|
|
}
|
|
|
|
test.describe('web app — File → Quit after a tool switch', () => {
|
|
test('quit after switching sch → pcb lands on the project page, not the previous editor', async ({
|
|
page,
|
|
}) => {
|
|
test.setTimeout(480000); // two full wasm boots (schematic, then pcbnew)
|
|
|
|
// Enter the editor the way a user does: the project page's "Open in …"
|
|
// link is a hard navigation.
|
|
await page.goto(`/${SCOPE}/projects/demo`);
|
|
await page
|
|
.getByRole('link', { name: /Open in Schematic Editor/i })
|
|
.first()
|
|
.click();
|
|
await page.waitForURL(SCH_URL_RE, { timeout: 30000 });
|
|
await waitForToolReady(page, /demo — Schematic Editor/i);
|
|
|
|
// Switch to the PCB editor — a hard navigation that stacks a second
|
|
// editor history entry on top of the schematic one.
|
|
expect(await clickMenuBarItem(page, 'Tools'), 'Tools menubar item clickable').toBe(true);
|
|
await clickMenuItemByText(page, 'Switch to PCB Editor');
|
|
await page.waitForURL(PCB_URL_RE, { timeout: 30000 });
|
|
await waitForToolReady(page, /demo — PCB Editor/i);
|
|
|
|
await quitViaFileMenu(page);
|
|
|
|
// Must land on the project overview — not back in the schematic editor.
|
|
// Poll the URL instead of waitForURL: the quit flow can supersede its own
|
|
// navigation while the wasm tears down, and Firefox then kills a pending
|
|
// waitForURL with NS_BINDING_ABORTED even though the final URL is right.
|
|
await expect
|
|
.poll(() => page.url(), { timeout: 30000 })
|
|
.toMatch(PROJECT_URL_RE);
|
|
// And the overview must actually render (guards a URL-push-without-render
|
|
// regression, which a URL-only assertion would miss).
|
|
await expect(
|
|
page.getByRole('link', { name: /Open in Schematic Editor/i }).first()
|
|
).toBeVisible({ timeout: 30000 });
|
|
});
|
|
});
|