2026-05-28 17:21:26 +02:00
import type { Page } from '@playwright/test' ;
import { test , expect } from './fixtures' ;
2026-07-07 10:50:24 +02:00
import { clickTreeItem , findAllTreeItems , waitUntil , stableShot } from '../e2e/utils/element-tracker' ;
2026-05-28 17:21:26 +02:00
/ * *
* PCB Calculator WASM E2E Tests
*
* The calculator is a wxFrame containing a wxTreebook with ~ 14 calculator
* panels grouped under four section pages . There ' s no GAL canvas , no
* toolbars - as - tested , and no setup wizard for the calculator itself .
*
2026-07-07 10:50:24 +02:00
* calculator . html seeds a default KiCad config in preRun ( like eeschema . html /
* pl_editor . html ) , so KiCad ' s first - run setup wizard never opens — the frame
* comes straight up and we wait deterministically for its panels to register .
* No wizard click - through , no fixed sleeps .
2026-05-28 17:21:26 +02:00
*
* Panel labels are sourced from pcb_calculator_frame.cpp :170 - 192 ( kicad fork ) .
* /
2026-07-07 10:50:24 +02:00
async function waitForCalculatorReady ( page : Page ) : Promise < void > {
2026-05-28 17:21:26 +02:00
await expect ( page . locator ( '#canvas' ) ) . toBeVisible ( { timeout : 90000 } ) ;
2026-07-07 10:50:24 +02:00
// "Calculate" is a unique button on the default Regulator panel — a reliable
// witness that the calculator frame is live and its panels have registered.
await waitUntil (
page ,
( ) = > {
const r = window . wxElementRegistry ;
return ! ! r && r . findByLabel ( 'Calculate' , { } ) . length > 0 ;
} ,
'calculator Regulator panel live (Calculate button registered)' ,
{ timeout : 90000 }
) ;
2026-05-28 17:21:26 +02:00
}
async function getRegistryLabels ( page : Page ) : Promise < string [ ] > {
return await page . evaluate ( ( ) = > {
2026-07-07 10:50:24 +02:00
const registry = window . wxElementRegistry ;
if ( ! registry ) return [ ] ;
return registry . findAll ( { } )
. map ( ( el ) = > ( el && el . label ? String ( el . label ) : '' ) )
2026-05-28 17:21:26 +02:00
. filter ( ( l : string ) = > l . length > 0 ) ;
} ) ;
}
test . describe ( 'PCB Calculator WASM' , ( ) = > {
test . beforeEach ( async ( { page } ) = > {
await page . goto ( '/kicad/calculator.html' ) ;
} ) ;
test ( 'loads calculator frame' , async ( { page , testLogger } ) = > {
void testLogger ;
2026-07-07 10:50:24 +02:00
await waitForCalculatorReady ( page ) ;
2026-05-28 17:21:26 +02:00
const labels = await getRegistryLabels ( page ) ;
const hasRegulatorPanel = labels . some ( l = > l === 'Calculate' ) ;
expect ( hasRegulatorPanel , ` expected the calculator's default Regulator panel to be live (Calculate button registered). Got: ${ JSON . stringify ( labels . slice ( 0 , 30 ) ) } ` ) . toBe ( true ) ;
2026-07-07 10:50:24 +02:00
await stableShot ( page , 'calculator-loaded.png' ) ;
2026-05-28 17:21:26 +02:00
} ) ;
test ( 'treebook lists expected panels' , async ( { page , testLogger } ) = > {
void testLogger ;
2026-07-07 10:50:24 +02:00
await waitForCalculatorReady ( page ) ;
2026-05-28 17:21:26 +02:00
const treeItems = await findAllTreeItems ( page ) ;
const treeLabels = treeItems . map ( i = > i . label ) . filter ( ( l ) : l is string = > typeof l === 'string' ) ;
const requiredSubset = [
'Regulators' ,
'Resistor Calculator' ,
'Via Size' ,
'Track Width' ,
'Color Code' ,
'RF Attenuators' ,
'Transmission Lines' ,
] ;
const missing = requiredSubset . filter ( req = > ! treeLabels . includes ( req ) ) ;
expect ( missing , ` treebook is missing expected panels: ${ JSON . stringify ( missing ) } (tree items: ${ JSON . stringify ( treeLabels ) } ) ` ) . toEqual ( [ ] ) ;
} ) ;
test ( 'switch to Color Code panel' , async ( { page , testLogger } ) = > {
void testLogger ;
2026-07-07 10:50:24 +02:00
await waitForCalculatorReady ( page ) ;
2026-05-28 17:21:26 +02:00
2026-07-07 10:50:24 +02:00
await stableShot ( page , 'calculator-before-switch.png' ) ;
2026-05-28 17:21:26 +02:00
const clicked = await clickTreeItem ( page , 'Color Code' ) ;
expect ( clicked , 'expected to find and click the Color Code tree item' ) . toBe ( true ) ;
2026-07-07 10:50:24 +02:00
// The Color Code panel exposes a unique "Tolerance" label the Regulator
// panel does not — wait for it as proof the panel swapped in (replaces
// waitForTimeout(800)).
await waitUntil (
page ,
( ) = > {
const r = window . wxElementRegistry ;
if ( ! r ) return false ;
return r . findAll ( { } ) . some ( ( el ) = > /Tolerance/i . test ( el . label || '' ) ) ;
} ,
'Color Code panel active (Tolerance label present)' ,
) ;
2026-05-28 17:21:26 +02:00
const labelsAfter = await getRegistryLabels ( page ) ;
const onColorCodePanel = labelsAfter . some ( l = > /Tolerance/i . test ( l ) ) ;
expect ( onColorCodePanel , ` expected Color Code panel to be active after click; labels: ${ JSON . stringify ( labelsAfter . slice ( 0 , 40 ) ) } ` ) . toBe ( true ) ;
2026-07-07 10:50:24 +02:00
await stableShot ( page , 'calculator-color-code.png' ) ;
2026-05-28 17:21:26 +02:00
} ) ;
} ) ;