pcbjam/tests/web/tool-switch.spec.ts
Istvan Matejcsok 2652d6fa81 tool-switch: create the missing counterpart file instead of silently no-opping
Tools → "Switch to PCB Editor" in a project with no .kicad_pcb (e.g. created
from a lone schematic) did nothing: the nav hook found no file for the target
tool and returned false. Now a session that can persist (ToolPage passes the
new createFile prop) writes the templated counterpart via
createProjectFileIfMissing — no download fallback, and it re-checks existence
so a collaborator's file is never clobbered — then navigates to it, matching
native KiCad (pcbnew opens a new board at the derived path). Sessions that
can't persist (read-only viewers, scratch/local-folder) keep the logged no-op.

Also latch the quit dispatcher off before every deliberate tool-switch
navigation (markDeliberateNavigation): the wx port's UnloadCallback runs on
BEFOREUNLOAD and closes the top frame the moment the navigation starts, so
the quit hook history.back()'d over the in-flight navigation — the pagehide
latch is too late (it only fires at commit time).

e2e: new tests/web/tool-switch-missing-file.spec.ts reproduces the flow via a
browser-local (IDB) project created from the home page; playwright-web config
gains VITE_LOCAL_PROJECTS=idb and derives STANDALONE_PORT/CORS_ORIGIN from
WEB_APP_URL (runs the suite past a squatted :3048); both vars declared in
web/turbo.json globalEnv (turbo strict-env strips undeclared vars). Includes
the previously-uncommitted tool-switch spec repairs (URL grammar + z-30
boot-overlay wait).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 14:19:47 +02:00

86 lines
3 KiB
TypeScript

import { test, expect, type Page } from '@playwright/test';
import { clickMenuBarItem, clickMenuItemByText, stableShot } from '../e2e/utils/element-tracker';
/**
* Tool-switch e2e: eeschema Tools → "Switch to PCB Editor" (and the reverse)
* must navigate the browser to the other tool's URL.
*
* Native KiCad spawns a process for this via ExecuteFile (common/gestfich.cpp);
* the WASM build delegates to window.kicadWebOpenTool (WasmTool.tsx), which
* maps the MEMFS file path to the project-relative file and calls
* location.assign(/:scope/projects/:name/<file>) — the tool is inferred from
* the file extension. Each direction is a full page navigation followed by a
* fresh wasm boot — hence the generous timeouts.
*/
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 switchTool(
page: Page,
menuLabel: string,
expectedUrl: RegExp,
expectedTitle: RegExp
): Promise<void> {
expect(await clickMenuBarItem(page, 'Tools'), 'Tools menubar item clickable').toBe(true);
await clickMenuItemByText(page, menuLabel);
await page.waitForURL(expectedUrl, { timeout: 30000 });
await waitForToolReady(page, expectedTitle);
}
test.describe('web app — tool switching', () => {
test('eeschema → Switch to PCB Editor navigates to pcbnew', async ({ page }) => {
test.setTimeout(420000); // two full wasm boots
await page.goto('/default/projects/demo/demo.kicad_sch');
await waitForToolReady(page, /demo — Schematic Editor/i);
await switchTool(
page,
'Switch to PCB Editor',
/\/default\/projects\/demo\/demo\.kicad_pcb/,
/demo — PCB Editor/i
);
await stableShot(page, 'web-switch-sch-to-pcb.png');
});
test('pcbnew → Switch to Schematic Editor navigates to eeschema', async ({ page }) => {
test.setTimeout(420000);
await page.goto('/default/projects/demo/demo.kicad_pcb');
await waitForToolReady(page, /demo — PCB Editor/i);
await switchTool(
page,
'Switch to Schematic Editor',
/\/default\/projects\/demo\/demo\.kicad_sch/,
/demo — Schematic Editor/i
);
await stableShot(page, 'web-switch-pcb-to-sch.png');
});
});