pcbjam/tests/web/tool-switch-missing-file.spec.ts

79 lines
3.8 KiB
TypeScript
Raw Normal View History

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 13:56:27 +02:00
import { test, expect, type Page } from '@playwright/test';
import { clickMenuBarItem, clickMenuItemByText, stableShot } from '../e2e/utils/element-tracker';
/**
* Tool-switch with a MISSING counterpart: eeschema Tools "Switch to PCB
* Editor" in a project that has no .kicad_pcb must CREATE the templated board
* and navigate to it (native KiCad opens pcbnew on a new board at the derived
* path) not silently no-op (the old behavior: the WasmTool nav hook logged
* "[nav] no project file found" and returned false).
*
* The backend demo fixture carries both files, so this spec builds a
* schematic-only project the way a user does: home page Tools grid
* "Schematic Editor" NewFileDialog (project "Untitled" slug "untitled",
* file "main.kicad_sch") a browser-local IndexedDB project under the @local
* scope. That flow only renders when the standalone runs with
* VITE_LOCAL_PROJECTS=idb (playwright-web.config.ts sets it for cold starts;
* a hand-started stack must set it too the dialog assertion below names the
* flag so a mis-configured stack fails self-diagnosingly). A fresh Playwright
* context has an empty IDB, so the slug is deterministically "untitled".
*/
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,
});
}
test.describe('web app — tool switch creates the missing counterpart', () => {
test('eeschema → Switch to PCB Editor creates and opens main.kicad_pcb', async ({ page }) => {
test.setTimeout(420000); // two full wasm boots
// Home → Tools grid: with the local store on, launching a document tool
// opens the new-file dialog (HomePage onLaunch → setNewFileTool).
await page.goto('/');
await page.getByRole('button', { name: 'Schematic Editor', exact: true }).click();
await expect(
page.locator('#newfile-projectname'),
'new-file dialog must open — is the stack running with VITE_LOCAL_PROJECTS=idb?'
).toBeVisible();
// The defaults are what the URL assertions below rely on (and their
// presence doubles as a dialog-hydrated wait).
await expect(page.locator('#newfile-projectname')).toHaveValue('Untitled');
await expect(page.locator('#newfile-name')).toHaveValue('main.kicad_sch');
await page.getByRole('button', { name: 'Create & open' }).click();
// NewFileDialog persists to IDB, then hard-navigates to the file route.
await page.waitForURL(/\/@local\/projects\/untitled\/main\.kicad_sch/, { timeout: 30000 });
await waitForToolReady(page, /main — Schematic Editor/i);
// The switch. Before the fix nothing happens (no navigation, no dialog),
// so the waitForURL below is where this spec fails.
expect(await clickMenuBarItem(page, 'Tools'), 'Tools menubar item clickable').toBe(true);
await clickMenuItemByText(page, 'Switch to PCB Editor');
await page.waitForURL(/\/@local\/projects\/untitled\/main\.kicad_pcb/, { timeout: 30000 });
await waitForToolReady(page, /main — PCB Editor/i);
await stableShot(page, 'web-switch-missing-pcb-created.png');
});
});