Files
clide/tools/ui/tests/smoke.spec.ts
T
jpmschweitzerandClaude c8d019e630 add web WASM Playwright harness for UI driving
tools/ui/ — scripts + Playwright config that let Claude Code (and
humans) drive the Flutter WASM build in a real browser. The point is
to avoid screenshot round-trips: every interactive widget in clide
ships a Semantics wrapper anyway (a11y requirement), so the automation
layer just queries the `flt-semantics[aria-label]` DOM.

  * build.sh — `flutter build web --wasm` from app/
  * serve.sh — `python3 -m http.server 4280` in the background.
    Before binding, kills any stale listener on the port (orphans
    from earlier failed runs no longer accumulate).
  * stop.sh — port-based kill; escalates to SIGKILL after 300ms.
    The pidfile is now advisory — port ownership is the source of
    truth.
  * driver.ts — `ClideDriver` class with `byLabel`, `click`, `type`,
    `readText`, `screenshot`, `dumpSemanticsTree`, and
    `waitUntilReady` that auto-clicks the `flt-semantics-placeholder`
    so the semantic tree is populated before queries.
  * tests/smoke.spec.ts — first driver test; asserts welcome +
    disconnected labels surface in the Semantics DOM.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-04-21 15:48:07 +02:00

24 lines
959 B
TypeScript

import { test, expect } from '@playwright/test';
import { ClideDriver } from '../driver';
/**
* Browser smoke: boot the WASM bundle and verify the Welcome view +
* statusbar indicator + daemon-disconnected label all render. This is
* the "app actually works in a real browser" regression gate — the web
* counterpart of `integration_test/app_starts_test.dart`.
*/
test('clide boots in the browser, welcome + statusbar visible', async ({ page }) => {
const clide = new ClideDriver(page);
await clide.goto('/');
// Semantics nodes are attached even when their rendered canvas is
// visually covered by the Flutter glass-pane; assert "attached" for
// the automation contract — we're reading the tree, not asserting
// rendering.
const openProject = clide.byLabel('Open project');
await expect(openProject).toHaveCount(1);
const disconnected = clide.byLabel('disconnected');
await expect(disconnected.first()).toBeAttached();
});