document test layers and Claude's UI workflow
Three docs under docs/testing/:
* README.md — layer-by-layer reference (what each covers, the
runner, how to invoke, local vs CI flow). Points at the load-
bearing startup gate and the client-side-only constraint so a
macOS clone runs the same suite as Linux.
* a11y-manual.md — 15-minute manual checklist run at every tier
cut. Orca on Linux, VoiceOver on macOS. Catches prose drift
automation can't judge.
* claude-ui-workflow.md — how Claude Code drives the WASM build
through Playwright, including the `flt-semantics-placeholder`
quirk (semantics are opt-in in Flutter web; the driver
auto-clicks the placeholder to enable them).
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
# How Claude Code uses clide
|
||||
|
||||
Claude Code needs to *actually use* the app while building features.
|
||||
The pipeline:
|
||||
|
||||
1. **Flutter builds the app to WASM.** `flutter build web --wasm` ships
|
||||
a CanvasKit/Skwasm bundle under `app/build/web/`.
|
||||
2. **A local server serves it.** `tools/ui/serve.sh` starts
|
||||
`http://localhost:4280` in the background with a pidfile.
|
||||
3. **Playwright drives a headless Chromium.** Instead of click-by-pixel
|
||||
— which is brittle on a CanvasKit `<canvas>` — the driver queries
|
||||
Flutter's semantic tree (`flt-semantics[aria-label=…]`), the same
|
||||
tree screen readers use. This is only reliable because every
|
||||
interactive widget in clide already ships `Semantics(label:, hint:)`
|
||||
wrappers for a11y — the automation surface is a free side-benefit.
|
||||
|
||||
## Claude's one-liners
|
||||
|
||||
```bash
|
||||
# Bring the app up (builds wasm, starts server)
|
||||
make ui-dev
|
||||
|
||||
# Run an ad-hoc probe
|
||||
cd tools/ui && npx playwright test ...
|
||||
|
||||
# Everything in one shot (build + serve + smoke + stop)
|
||||
make ui-smoke
|
||||
|
||||
# Bring it down
|
||||
make ui-stop
|
||||
```
|
||||
|
||||
## Writing a driver script
|
||||
|
||||
```ts
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { ClideDriver } from '../driver';
|
||||
|
||||
test('opens the theme picker and selects summer-night', async ({ page }) => {
|
||||
const clide = new ClideDriver(page);
|
||||
await clide.goto('/');
|
||||
|
||||
// Keyboard shortcut that invokes `theme.pick`:
|
||||
await page.keyboard.press('Control+K');
|
||||
|
||||
// Pick via semantic label.
|
||||
await clide.click('summer-night');
|
||||
|
||||
// Dump the whole tree to inspect state after an interaction.
|
||||
const tree = await clide.dumpSemanticsTree();
|
||||
console.log(JSON.stringify(tree, null, 2));
|
||||
|
||||
// Screenshot into out/ (Claude reads the PNG via the Read tool).
|
||||
await clide.screenshot('out/theme-picker.png');
|
||||
});
|
||||
```
|
||||
|
||||
## Prerequisites (one-time per machine)
|
||||
|
||||
```bash
|
||||
cd tools/ui
|
||||
npm install
|
||||
npx playwright install chromium
|
||||
```
|
||||
|
||||
## Known quirks
|
||||
|
||||
- **Labels are merged.** Flutter web concatenates sibling Semantics
|
||||
labels into a single `aria-label` separated by newlines. `byLabel`
|
||||
uses substring match for that reason. When two Semantics nodes share
|
||||
a substring, narrow with `.filter()` on the returned locator.
|
||||
- **The placeholder button.** Flutter web ships semantics disabled by
|
||||
default, behind an invisible `<flt-semantics-placeholder>` button.
|
||||
`ClideDriver.waitUntilReady()` clicks it automatically.
|
||||
- **No daemon on web.** The WASM build has no unix socket; the status
|
||||
indicator always says `disconnected`. That's honest — a web-hosted
|
||||
clide has no local daemon to talk to. The Playwright flow is for
|
||||
UI-only verification.
|
||||
|
||||
## When Playwright is overkill
|
||||
|
||||
If all I need is "does the extension register its contributions," a
|
||||
widget test (`test/builtin/*/widget_test.dart`) is faster and cheaper.
|
||||
Reach for Playwright when the question is about the real rendering
|
||||
pipeline, keyboard behavior, or multi-widget interactions that mirror
|
||||
a user workflow.
|
||||
Reference in New Issue
Block a user