Run the Playwright fixture smoke harness to prove a real generated crouton app still boots, authenticates, and does CRUD after a dependency bump or package change. Use when asked to "smoke test", "run e2e", "verify against a fixture", or to check that a packages/ change doesn't break consuming apps.
Scanned 9/12/2026
Install to Claude Code
npx -y skills add FriendlyInternet/nuxt-crouton --skill e2e-smoke --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of E2e Smoke?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/friendlyinternet-e2e-smoke)More formats (shields.io, HTML) on the badges page.
---
name: e2e-smoke
layer: stack
description: Run the Playwright fixture smoke harness to prove a real generated crouton app still boots, authenticates, and does CRUD after a dependency bump or package change. Use when asked to "smoke test", "run e2e", "verify against a fixture", or to check that a packages/ change doesn't break consuming apps.
allowed-tools: Bash, Read, Grep, Glob, AskUserQuestion
---
# E2E Smoke — fixture harness runner
Boots a **real generated crouton app** (`fixtures/<name>`) and runs the
Playwright smoke (login/register → create team → per-collection CRUD → optional
package surfaces). This is the "did a packages/ change or dep bump break a
consuming app" check.
> **Reference, not this file:** the harness internals (manifest format, auth
> realities, adding a fixture, gotchas) live in **`e2e/CLAUDE.md`**. This skill
> is only about *running* it and reading the result. Read `e2e/CLAUDE.md` before
> editing the harness or a manifest.
## When to use
- After changing anything in `packages/` (especially `crouton-core`, `crouton-cli`, `crouton-pages`, `crouton-bookings`, `crouton-auth`).
- After a dependency bump / `pnpm.overrides` change (this is exactly what it's for — e.g. the tiptap 3.20 bump).
- When the user says "smoke test", "run the e2e", "check the fixtures", "verify nothing broke".
## Step 1 — Pick the fixture that exercises the change
One fixture per run (they all use port 3000). Match the change to the fixture
whose packages actually mount the affected code — booting `minimal` won't touch
pages/editor code.
| Fixture | Exercises | Use when you changed… |
|---------|-----------|------------------------|
| `minimal` | core + auth + i18n, one `items` collection | crouton-core, crouton-auth, crouton-i18n, generator core, generic CRUD |
| `with-pages` | + `@fyit/crouton-pages` → transitively `@fyit/crouton-editor`; surface = pages workspace (mounts `CroutonEditorBlocks` → the real tiptap editor) | crouton-pages, **crouton-editor**, tiptap deps |
| `with-bookings` | + `@fyit/crouton-bookings` (locations/settings/slots); surface = bookings admin | crouton-bookings, heavy domain-package scaffolding |
| `with-assets` | + `@fyit/crouton-assets`; surface = the optional `CroutonAssetsPicker` mounts (not the core stub) | crouton-assets, the stub/`hasApp` system |
| `with-collab` | + `@fyit/crouton-collab`; surface = realtime collab UI mounts single-client (spike) | crouton-collab |
| `with-maps` | + `@fyit/crouton-maps`; a `venues` collection with address+coordinate fields — MapLibre map mounts in the generated form, `/api/maps/geocode` proxies live Nominatim | crouton-maps |
| `with-sales` | + `@fyit/crouton-sales` + `@fyit/crouton-printing`; two-tier POS smoke — order placed, print job pending→done against an in-test fake `:9100` ESC/POS printer | crouton-sales, crouton-printing |
| `with-devtools` | + `@fyit/crouton-devtools` + `@fyit/crouton-feedback`; surface = the feedback "glasses" launcher mounts via devtools `installModule` | crouton-devtools, crouton-feedback |
If unsure which fixture covers the change, grep the fixtures for the affected
component/package (`grep -rl '<Component>' fixtures/`) before guessing. If none
cover it, say so — the honest answer may be "no fixture exercises this; add one
(see `e2e/CLAUDE.md` → Adding a new fixture) or smoke a real app instead."
Use `AskUserQuestion` to confirm the fixture only if the change spans several or
the mapping is ambiguous; otherwise pick the obvious one and state it.
## Step 2 — Build the fixture's workspace deps (fresh checkout/worktree only)
The dev server loads the dist-consumed `@fyit/*` packages; on a clean tree they
aren't built yet. Build the fixture's transitive deps first (the `^...` excludes
the fixture app itself):
```bash
pnpm --filter "e2e-fixture-<name>^..." build
```
Skip this if you've been building/typechecking these packages this session and
they're already current. If the dev server errors with `Could not load '@fyit/crouton'`, this build is the fix.
## Step 2.5 — Browser binary in a sandbox (remote/CI env without the matching Chromium)
In a remote/sandboxed env the run can fail at the `setup` project with
`browserType.launch: Executable doesn't exist at /opt/pw-browsers/chromium…` and
`pnpm exec playwright install` then **fails too** —
`403 … Host not in allowlist: playwright.download.prss.microsoft.com` (the egress
policy blocks the download). The cause is a version skew: the installed
`@playwright/test` pins a browser build (e.g. 1200) that isn't on disk, while the
sandbox ships a slightly older one (e.g. 1194). You can't download the exact build.
**Fix — launch the build that *is* installed, via `PW_EXECUTABLE_PATH`** (the
config honours it → `launchOptions.executablePath`):
```bash
ls /opt/pw-browsers # find the installed build, e.g. chromium-1194
# full binary: /opt/pw-browsers/chromium-<build>/chrome-linux/chrome
E2E_FIXTURE=<name> BETTER_AUTH_SECRET=dev BETTER_AUTH_URL=http://localhost:3000 \
PW_EXECUTABLE_PATH=/opt/pw-browsers/chromium-<build>/chrome-linux/chrome \
pnpm test:e2e
```
A one-build skew (1194 vs 1200) launches fine for a smoke. `PW_EXECUTABLE_PATH`
is a committed escape hatch in `playwright.config.ts` — no source edit per run.
Watch out: a piped `… | tail` masks the real failure (tail exits 0), so check the
tail content for `Executable doesn't exist`, not just the exit code.
## Step 3 — Run
**`BETTER_AUTH_SECRET` and `BETTER_AUTH_URL` are required** — without the secret,
crouton-auth refuses to mint sessions and `auth.setup.ts` fails with "Could not
authenticate test user." Any value works locally.
```bash
E2E_FIXTURE=<name> \
BETTER_AUTH_SECRET=dev \
BETTER_AUTH_URL=http://localhost:3000 \
pnpm test:e2e
```
- The config's `webServer` boots `pnpm --filter e2e-fixture-<name> dev` on `:3000`, or **reuses a server already running there** (so if a dev server is up on 3000, kill it or expect it to be reused).
- First run is slow: cold `nuxt dev` compiles routes/auth-modal on demand (timeouts are deliberately high — 240s per test / 30s per expect / 180s webServer boot; `e2e/playwright.config.ts`). Don't lower them; give the run several minutes before suspecting a hang.
- Run in the background if it's long, and report when it returns.
## Faster runs (the cold-compile tax)
A run is slow (~5+ min for `with-pages`) almost entirely because it boots
`nuxt dev`, which **compiles each route on first hit** — and a fresh
checkout/remote container pays that cold every time. Levers, by payoff:
- **Reuse a warm server (biggest win when iterating).** `webServer.reuseExistingServer`
is on, so start the fixture's dev server **once** and leave it up; every
subsequent `pnpm test:e2e` reuses it and the routes stay compiled (runs 2..N
are seconds, not minutes):
```bash
# leave this running in the background:
pnpm --filter e2e-fixture-<name> dev
# then re-run the smoke as many times as you like — it attaches to :3000
```
- **Run only the specs the change touches.** A render/CRUD change doesn't need
the auth-smoke trio (logout/re-login/team-switch). `setup` must always run:
```bash
pnpm test:e2e e2e/collection.smoke.spec.ts e2e/surface.smoke.spec.ts # + setup runs automatically
```
- **Don't chase the font errors.** The `Could not initialize provider bunny/google`
lines are an instant egress 403 (fail-fast), not a timeout — log noise, not a
time sink. Disabling remote fonts cleans logs but won't speed the smoke.
- **The structural fix (tens of seconds, not minutes): #246** — boot a *prebuilt*
app (`nuxt preview`) instead of `nuxt dev` so routes compile once. Blocked by a
prod-SSR auth-cookie 500; tracked there.
## Step 4 — Read the result
- **Pass:** all `setup` + `*.smoke.spec.ts` projects green. Report which fixture, which collections/surfaces ran.
- **Fail:** Playwright writes a report to `playwright-report/` and traces/screenshots to `test-results/` (both gitignored). Open the report or read the failing spec's error. Distinguish:
- *Auth/setup failure* → usually missing `BETTER_AUTH_SECRET`, or a stale `e2e/.auth/` (delete it and rerun).
- *List/CRUD failure* → the generated collection or a package surface regressed — that's a real signal, investigate the app, not the harness.
- *Boot failure* (`Could not load '@fyit/...'`) → Step 2 build was skipped/stale.
- If you captured any screenshot manually, it goes in `screenshots/` (repo root), never the app or root dir.
## Scope notes (set expectations honestly)
- The smoke proves **boot + auth + CRUD + surface render**. It does **not** deeply
drive package UIs — e.g. `with-pages` confirms the editor *workspace mounts*
under the current tiptap, but doesn't type into the editor. Say what a pass does
and doesn't prove.
- A **type-only** fix (e.g. `ref`→`shallowRef`) is validated by `pnpm typecheck`,
not by this smoke — don't claim the smoke covers it. The smoke's value for that
PR is catching **runtime** fallout from the accompanying dep bump.
- To drive a surface deeper (type a block, assert content), extend the fixture's
`e2e.manifest.json` `surfaces` or add a fixture — see `e2e/CLAUDE.md`. Editing
the manifest/fixture is fine (they're in `fixtures/`, not `packages/`); editing
the harness specs in `e2e/` is also outside the packages gate.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!