agentleFS
JoviDeCroockJoviDeCroock/pracht/skills/scaffold-e2e/SKILL.md

scaffold-e2e

Skill106 starsChanged 7 months agoMITView on GitHub

Set up Playwright for a pracht app with a config that boots `pracht dev` or `pracht preview`, plus a smoke test per route for status, title, console errors, and navigation. Use for "scaffold E2E", "set up Playwright", "add browser tests", "smoke test my routes".

  • Reads credentials
  • Installs packages

The file

We split this skill into the rules it gives an agent

10 rules. About 0 are common, 1 is distinctive, and 9 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈1

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 9

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Ask the user (default: dev):

    line 27
  2. Very specific:

    Add firefox and webkit only if the user requests them.

    line 46
  3. Very specific:

    If playwright.config.ts already exists, merge — do not clobber.

    line 79
  4. Very specific:

    If any route is render: "ssr" or "ssg"/"isg":

    line 132
  5. Very specific:

    If an e2e script already exists in the project, confirm before overwriting.

    line 155
  6. Distinctive:

    If specs fail on first run, report.

    line 165
  7. Very specific:

    Never overwrite an existing playwright.config.ts without diffing first.

    line 175
  8. Very specific:

    If the app uses typed routes, run pracht typegen --check before generating specs and prefer imported href() for test URLs in app-owned …

    line 176
  9. Very specific:

    Use webServer to boot pracht dev or pracht preview so CI works out-of-the-box.

    line 177
  10. Very specific:

    Wait for window.__PRACHT_ROUTER_READY__ before interacting with the page in any spec that relies on client-side navigation.

    line 181

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Pracht Scaffold E2E

Generate a Playwright suite that exercises the live app. Aligns with https://pracht.resynapse.dev/docs/recipes/testing.md.

Step 1: Decide which build the tests run against

Ask the user (default: dev):

  1. pracht dev — fast, HMR, but can mask production-only bugs (different bundling, different SSG/ISG flow).
  2. Production runtime — pracht preview: purpose-built, it builds and serves the production output locally for both Node and Cloudflare targets (Vercel prints guidance instead). Use pracht preview --skip-build to serve an existing build after an explicit pracht build. Prefer this over hand-rolling node dist/server/server.js, which is Node-adapter-only and skips the build.
  3. External URL — user provides BASE_URL; tests do not boot the server.

Step 2: Install

pnpm add -D @playwright/test
pnpm exec playwright install chromium

Add firefox and webkit only if the user requests them.

Step 3: Write playwright.config.ts

import { defineConfig, devices } from "@playwright/test";

const PORT = Number(process.env.PORT ?? 3000);

export default defineConfig({
  testDir: "./e2e",
  fullyParallel: true,
  retries: process.env.CI ? 2 : 0,
  reporter: process.env.CI ? "github" : "list",
  use: {
    baseURL: process.env.BASE_URL ?? `http://localhost:${PORT}`,
    trace: "on-first-retry",
    screenshot: "only-on-failure",
  },
  webServer: process.env.BASE_URL
    ? undefined
    : {
        command: "pnpm dev", // or "pracht preview" for the production runtime — choose at scaffold time
        url: `http://localhost:${PORT}`,
        reuseExistingServer: !process.env.CI,
        timeout: 120_000,
      },
  projects: [
    { name: "chromium", use: devices["Desktop Chrome"] },
  ],
});

If playwright.config.ts already exists, merge — do not clobber.

Step 4: Generate per-route smoke tests

MCP: if pracht dev-mcp is registered, prefer its inspect_*, generate_*, doctor, and verify tools to the CLI.

pracht inspect routes --json

For every route entry, generate one spec under e2e/smoke/. Skip routes with dynamic segments unless the user provides example params (ask via AskUserQuestion).

Per-route template:

import { test, expect } from "@playwright/test";

test.describe("smoke: <path>", () => {
  test("loads with 200 and a title", async ({ page }) => {
    const errors: string[] = [];
    page.on("console", (msg) => {
      if (msg.type() === "error") errors.push(msg.text());
    });
    page.on("pageerror", (err) => errors.push(err.message));

    const response = await page.goto("<path>");
    expect(response?.status(), "HTTP status").toBeLessThan(400);
    await expect(page).toHaveTitle(/.+/);
    expect(errors, "no console errors").toEqual([]);
  });
});

Step 5: Generate a navigation crawl

A single e2e/navigation.spec.ts that:

  1. Visits the home route.
  2. Waits for hydration with the documented readiness idiom before touching anything — otherwise the crawl races hydration and clicks fall through to full page loads:
    await page.waitForFunction(() => (window as any).__PRACHT_ROUTER_READY__);
  3. Collects every same-origin <a href>.
  4. Clicks each in turn, asserts no console errors, no 4xx/5xx.

This catches client-router intercept regressions and broken links.

Step 6: Generate a hydration check (optional)

If any route is render: "ssr" or "ssg"/"isg":

test("server HTML matches client render", async ({ page }) => {
  const errors: string[] = [];
  page.on("console", (m) => m.type() === "error" && errors.push(m.text()));
  await page.goto("<path>");
  await page.waitForLoadState("networkidle");
  expect(errors.filter((e) => /Hydration|hydrat/i.test(e))).toEqual([]);
});

Step 7: Wire package.json

{
  "scripts": {
    "e2e": "playwright test",
    "e2e:ui": "playwright test --ui"
  }
}

If an e2e script already exists in the project, confirm before overwriting.

Step 8: Run

pnpm e2e
pracht verify --json

If specs fail on first run, report. Common first-run failures:

  • Port collision (already-running dev server).
  • Missing browser binary (playwright install chromium).
  • Strict CSP blocking inline test scripts (rare).

Rules

  1. Source of routes is pracht inspect routes --json. Do not glob src/routes/**.
  2. Skip dynamic-segment routes unless example params are provided.
  3. Never overwrite an existing playwright.config.ts without diffing first.
  4. If the app uses typed routes, run pracht typegen --check before generating specs and prefer imported href() for test URLs in app-owned route fixtures.
  5. Use webServer to boot pracht dev or pracht preview so CI works out-of-the-box.
  6. Console-error capture is mandatory — silent JS errors are the most common pracht hydration regression.
  7. Wait for window.__PRACHT_ROUTER_READY__ before interacting with the page in any spec that relies on client-side navigation.

$ARGUMENTS

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.