diff --git a/tests/kicad/pcbnew.html b/tests/kicad/pcbnew.html
deleted file mode 100644
index 88d12b9..0000000
--- a/tests/kicad/pcbnew.html
+++ /dev/null
@@ -1,318 +0,0 @@
-
-
-
-
-
- KiCad PCBnew - WASM
-
-
-
-
-
-
Loading PCBnew...
-
-
-
-
-
KiCad PCBnew (WASM)
-
-
-
-
-
-
-
-
-
-
-
- X: 0.00mm Y: 0.00mm
- Ready
- Memory: --
-
-
-
-
-
diff --git a/tests/kicad/pcbnew.spec.ts b/tests/kicad/pcbnew.spec.ts
index e0dc8f0..1ac9cc4 100644
--- a/tests/kicad/pcbnew.spec.ts
+++ b/tests/kicad/pcbnew.spec.ts
@@ -1,115 +1,33 @@
import { test, expect } from '@playwright/test';
-import path from 'path';
/**
* PCBnew WASM E2E Tests
*
* These tests verify that the KiCad PCBnew application runs correctly in the browser.
- * They test the basic UI functionality and WASM module loading.
+ * The WASM files are served from apps/kicad/ via the web server.
*/
test.describe('PCBnew WASM', () => {
test.beforeEach(async ({ page }) => {
- // Navigate to PCBnew test page
- const htmlPath = path.join(__dirname, 'pcbnew.html');
- await page.goto(`file://${htmlPath}`);
-
- // Wait for loading overlay to disappear
- await page.waitForSelector('#loading-overlay.hidden', { timeout: 30000 });
+ // Navigate to PCBnew via web server (apps/kicad/pcbnew.html)
+ await page.goto('/kicad/pcbnew.html');
});
- test('should load the PCBnew interface', async ({ page }) => {
- // Check that the toolbar is visible
- await expect(page.locator('#toolbar h1')).toHaveText('KiCad PCBnew (WASM)');
-
- // Check that toolbar buttons exist
- await expect(page.locator('#btn-new')).toBeVisible();
- await expect(page.locator('#btn-open')).toBeVisible();
- await expect(page.locator('#btn-save')).toBeVisible();
- await expect(page.locator('#btn-zoom-in')).toBeVisible();
- await expect(page.locator('#btn-zoom-out')).toBeVisible();
- await expect(page.locator('#btn-fit')).toBeVisible();
+ test('should load PCBnew WASM module', async ({ page }) => {
+ // Wait for WASM to initialize (look for canvas or status indicator)
+ // This is a basic smoke test - expand as PCBnew integration matures
+ await expect(page.locator('canvas')).toBeVisible({ timeout: 60000 });
});
- test('should have a working canvas', async ({ page }) => {
- const canvas = page.locator('#canvas');
- await expect(canvas).toBeVisible();
+ test('should render without JavaScript errors', async ({ page }) => {
+ const errors: string[] = [];
+ page.on('pageerror', err => errors.push(err.message));
- // Check that canvas has proper dimensions
- const box = await canvas.boundingBox();
- expect(box?.width).toBeGreaterThan(0);
- expect(box?.height).toBeGreaterThan(0);
- });
+ await page.goto('/kicad/pcbnew.html');
+ await page.waitForTimeout(5000); // Give time for WASM to load
- test('should track mouse coordinates', async ({ page }) => {
- const canvas = page.locator('#canvas');
- const statusCoords = page.locator('#status-coords');
-
- // Move mouse over canvas
- await canvas.hover({ position: { x: 100, y: 100 } });
-
- // Check that coordinates are updated
- const coordText = await statusCoords.textContent();
- expect(coordText).toMatch(/X: \d+\.\d+mm Y: \d+\.\d+mm/);
- });
-
- test('should log UI interactions', async ({ page }) => {
- const logPanel = page.locator('#log-panel');
-
- // Click New button
- await page.click('#btn-new');
-
- // Check that action was logged
- await expect(logPanel).toContainText('New project');
- });
-
- test('should have status bar with info', async ({ page }) => {
- await expect(page.locator('#status-info')).toHaveText('Ready');
- });
-
- test('should show sidebar with log panel', async ({ page }) => {
- const sidebar = page.locator('#sidebar');
- const logPanel = page.locator('#log-panel');
-
- await expect(sidebar).toBeVisible();
- await expect(logPanel).toBeVisible();
- });
-
- // Screenshot test for visual regression
- test('should match visual snapshot', async ({ page }) => {
- await page.screenshot({
- path: path.join(__dirname, 'screenshots', 'pcbnew-initial.png'),
- fullPage: true
- });
- });
-});
-
-test.describe('PCBnew File Operations', () => {
- test.beforeEach(async ({ page }) => {
- const htmlPath = path.join(__dirname, 'pcbnew.html');
- await page.goto(`file://${htmlPath}`);
- await page.waitForSelector('#loading-overlay.hidden', { timeout: 30000 });
- });
-
- test('should have file open button that triggers file picker', async ({ page }) => {
- const openBtn = page.locator('#btn-open');
- await expect(openBtn).toBeVisible();
-
- // Click should trigger file input (we can't fully test file selection in Playwright)
- // but we can verify the button is clickable
- await openBtn.click();
- });
-});
-
-test.describe('PCBnew WASM Module', () => {
- test('WASM module loading (placeholder)', async ({ page }) => {
- // This test will be expanded once the WASM module is built
- const htmlPath = path.join(__dirname, 'pcbnew.html');
- await page.goto(`file://${htmlPath}`);
-
- // Check for expected warning when module is not built
- const logPanel = page.locator('#log-panel');
- await page.waitForSelector('#loading-overlay.hidden', { timeout: 30000 });
- await expect(logPanel).toContainText('Note: PCBnew WASM module not yet built');
+ // Filter out known acceptable errors if any
+ const criticalErrors = errors.filter(e => !e.includes('ResizeObserver'));
+ expect(criticalErrors).toHaveLength(0);
});
});
diff --git a/tests/package.json b/tests/package.json
index b0135d2..6251262 100644
--- a/tests/package.json
+++ b/tests/package.json
@@ -9,8 +9,8 @@
"build-wasm": "cd apps && make -f Makefile.wasm",
"serve": "npx serve apps -p 8080 -c ../serve.json",
"setup:kicad": "./scripts/setup-kicad-wasm.sh",
- "test:kicad": "playwright test kicad/",
- "test:kicad:headed": "playwright test kicad/ --headed"
+ "test:kicad": "npm run setup:kicad && playwright test --config=playwright-kicad.config.ts",
+ "test:kicad:headed": "npm run setup:kicad && playwright test --config=playwright-kicad.config.ts --headed"
},
"devDependencies": {
"@playwright/test": "^1.40.0",
diff --git a/tests/playwright-kicad.config.ts b/tests/playwright-kicad.config.ts
new file mode 100644
index 0000000..9eb837d
--- /dev/null
+++ b/tests/playwright-kicad.config.ts
@@ -0,0 +1,68 @@
+import { defineConfig, devices } from '@playwright/test';
+import { execSync } from 'child_process';
+import * as fs from 'fs';
+import * as path from 'path';
+
+const PORT_FILE = path.join(__dirname, '.test-port');
+
+// Get existing port from file or find a new one
+function getOrFindPort(): number {
+ try {
+ const stat = fs.statSync(PORT_FILE);
+ const age = Date.now() - stat.mtimeMs;
+ if (age < 60000) {
+ const port = parseInt(fs.readFileSync(PORT_FILE, 'utf-8').trim());
+ if (port > 0 && port < 65536) {
+ return port;
+ }
+ }
+ } catch {
+ // File doesn't exist or can't be read
+ }
+
+ const port = findFreePort();
+ fs.writeFileSync(PORT_FILE, port.toString());
+ return port;
+}
+
+function findFreePort(): number {
+ try {
+ const result = execSync(
+ 'python3 -c "import socket; s=socket.socket(); s.bind((\'\',0)); print(s.getsockname()[1]); s.close()"',
+ { encoding: 'utf-8' }
+ );
+ return parseInt(result.trim());
+ } catch {
+ return 9000 + Math.floor(Math.random() * 1000);
+ }
+}
+
+const port = getOrFindPort();
+
+export default defineConfig({
+ testDir: './kicad',
+ fullyParallel: true,
+ forbidOnly: !!process.env.CI,
+ retries: process.env.CI ? 2 : 0,
+ workers: process.env.CI ? 1 : undefined,
+ reporter: 'html',
+ timeout: 120000, // KiCad WASM needs more time to load
+
+ use: {
+ baseURL: `http://localhost:${port}`,
+ trace: 'on-first-retry',
+ },
+
+ projects: [
+ {
+ name: 'chromium',
+ use: { ...devices['Desktop Chrome'] },
+ },
+ ],
+
+ webServer: {
+ command: `npx serve apps -p ${port} -c ../serve.json`,
+ port: port,
+ reuseExistingServer: !process.env.CI,
+ },
+});