claude-toolkit 0.1.12 → 0.1.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,168 @@
1
+ ---
2
+ name: ct-playwright-patterns
3
+ description: Playwright E2E testing patterns -- Page Objects, fixtures, auth, network mocking, and CI/CD
4
+ ---
5
+
6
+ # Playwright E2E Patterns
7
+
8
+ E2E tests sit at the top of the testing pyramid. They exercise full user journeys in real browsers. Write fewer, make each one count.
9
+
10
+ ## Project Structure
11
+
12
+ ```
13
+ e2e/
14
+ fixtures/ # Custom Playwright fixtures
15
+ index.ts # Extended test with page objects
16
+ pages/ # Page Object classes
17
+ components/ # Component Object classes (reusable fragments)
18
+ specs/ # Test files organized by feature
19
+ helpers/ # Utilities (data factories, API helpers)
20
+ .auth/ # storageState files (gitignored)
21
+ ```
22
+
23
+ ## Page Object Model + Fixtures
24
+
25
+ Combine Page Objects with custom fixtures. Tests receive pre-built page objects:
26
+
27
+ ```typescript
28
+ // e2e/pages/LoginPage.ts
29
+ export class LoginPage {
30
+ private readonly emailInput: Locator;
31
+ private readonly submitButton: Locator;
32
+
33
+ constructor(private readonly page: Page) {
34
+ this.emailInput = page.getByLabel("Email");
35
+ this.submitButton = page.getByRole("button", { name: "Sign in" });
36
+ }
37
+
38
+ async goto() { await this.page.goto("/login"); }
39
+ async login(email: string, password: string) {
40
+ await this.emailInput.fill(email);
41
+ await this.submitButton.click();
42
+ }
43
+ }
44
+
45
+ // e2e/fixtures/index.ts
46
+ export const test = base.extend<Fixtures>({
47
+ loginPage: async ({ page }, use) => { await use(new LoginPage(page)); },
48
+ });
49
+ ```
50
+
51
+ Fixtures are lazy (created on demand) and composable (can depend on each other).
52
+
53
+ ## Authentication
54
+
55
+ Use project dependencies with `storageState` to authenticate once and reuse:
56
+
57
+ ```typescript
58
+ // e2e/auth.setup.ts
59
+ setup("authenticate", async ({ page }) => {
60
+ await page.goto("/login");
61
+ await page.getByLabel("Email").fill("test@example.com");
62
+ await page.getByRole("button", { name: "Sign in" }).click();
63
+ await page.waitForURL("/dashboard");
64
+ await page.context().storageState({ path: "e2e/.auth/user.json" });
65
+ });
66
+ ```
67
+
68
+ Config: `dependencies: ["setup"]` + `storageState: "e2e/.auth/user.json"`. Add `e2e/.auth/` to `.gitignore`.
69
+
70
+ For multi-role testing, create separate setup files per role.
71
+
72
+ ## Locator Priority
73
+
74
+ 1. `getByRole()` -- accessibility semantics, survives refactors
75
+ 2. `getByLabel()` -- form elements
76
+ 3. `getByPlaceholder()` -- input hints
77
+ 4. `getByText()` -- visible text
78
+ 5. `getByTestId()` -- stable but less semantic
79
+ 6. CSS/XPath -- **avoid**
80
+
81
+ ## Web-First Assertions
82
+
83
+ Always use auto-retrying assertions:
84
+
85
+ ```typescript
86
+ // GOOD
87
+ await expect(page.getByRole("alert")).toBeVisible();
88
+ await expect(page).toHaveURL("/dashboard");
89
+
90
+ // BAD -- checks once, no retry
91
+ expect(await page.getByRole("alert").isVisible()).toBeTruthy();
92
+ ```
93
+
94
+ Key assertions: `toBeVisible()`, `toBeEnabled()`, `toHaveText()`, `toHaveURL()`, `toHaveCount()`, `toHaveScreenshot()`, `toMatchAriaSnapshot()`.
95
+
96
+ ## Network Mocking
97
+
98
+ ```typescript
99
+ // Mock API
100
+ await page.route("**/api/users", async (route) => {
101
+ await route.fulfill({ status: 200, contentType: "application/json", body: JSON.stringify([{ name: "Alice" }]) });
102
+ });
103
+
104
+ // Block analytics
105
+ await page.route("**/analytics/**", (route) => route.abort());
106
+ ```
107
+
108
+ Mock ~80% of API calls for speed; keep ~20% hitting real endpoints. Always call `route.continue()`, `route.fulfill()`, or `route.abort()`. Use `page.unrouteAll()` in cleanup.
109
+
110
+ ## WebSocket Mocking (v1.53+)
111
+
112
+ ```typescript
113
+ await page.routeWebSocket("wss://example.com/ws", (ws) => {
114
+ ws.onMessage((message) => { ws.send("mocked response"); });
115
+ });
116
+ ```
117
+
118
+ ## Accessibility Testing
119
+
120
+ ```typescript
121
+ import AxeBuilder from "@axe-core/playwright";
122
+
123
+ test("WCAG 2.1 AA", async ({ page }) => {
124
+ await page.goto("/");
125
+ const results = await new AxeBuilder({ page }).withTags(["wcag2a", "wcag2aa", "wcag21aa"]).analyze();
126
+ expect(results.violations).toEqual([]);
127
+ });
128
+ ```
129
+
130
+ Aria snapshots (v1.52+): `await expect(nav).toMatchAriaSnapshot(...)`.
131
+
132
+ ## Parallelization
133
+
134
+ - File-level parallel (default) -- start here
135
+ - In-file: `test.describe.configure({ mode: "parallel" })`
136
+ - Full: `fullyParallel: true` in config
137
+
138
+ Each worker gets its own `BrowserContext` (isolated cookies/storage). Use `mode: "serial"` sparingly.
139
+
140
+ ## CI/CD
141
+
142
+ - Use official Playwright Docker image (`mcr.microsoft.com/playwright:v1.58.0-noble`)
143
+ - Upload reports + traces as artifacts
144
+ - Use `--shard` for suites exceeding 5 minutes
145
+ - `retries: process.env.CI ? 2 : 0`
146
+ - Traces: `trace: "on-first-retry"`
147
+
148
+ ## Flaky Test Prevention
149
+
150
+ | Cause | Fix |
151
+ |---|---|
152
+ | `waitForTimeout()` | Web-first assertions or `waitForResponse` |
153
+ | Brittle selectors | `getByRole`, `getByLabel`, `getByTestId` |
154
+ | Shared state | Fresh `BrowserContext` per test |
155
+ | External API flakiness | Mock with `page.route()` |
156
+ | Animation timing | `--force-prefers-reduced-motion` |
157
+ | Missing `await` | #1 source of false-passing tests. Lint for it. |
158
+
159
+ ## Anti-Patterns
160
+
161
+ 1. **Using `waitForTimeout()`** -- Use web-first assertions or explicit wait conditions.
162
+ 2. **Fragile CSS/XPath selectors** -- Use role-based and semantic locators.
163
+ 3. **Using `{ force: true }`** -- Masks real actionability problems.
164
+ 4. **Missing `await` on assertions** -- #1 source of false-passing tests.
165
+ 5. **Tests without assertions** -- A test that clicks without asserting is just a script.
166
+ 6. **Using Playwright for unit tests** -- Use Vitest for pure logic.
167
+ 7. **Committing raw codegen output** -- Always refactor into Page Objects.
168
+ 8. **Not cleaning up route handlers** -- Use `page.unrouteAll()`.
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "ct-playwright-patterns",
3
+ "description": "Playwright E2E testing patterns with Page Objects, fixtures, and CI/CD",
4
+ "defaultMappings": {
5
+ "e2e": "ct-playwright-patterns",
6
+ "playwright.config.ts": "ct-playwright-patterns"
7
+ },
8
+ "fileExtensions": ["spec.ts"],
9
+ "skillRules": {
10
+ "ct-playwright-patterns": {
11
+ "description": "Playwright E2E testing with Page Objects, fixtures, auth, and network mocking",
12
+ "priority": 7,
13
+ "triggers": {
14
+ "keywords": [
15
+ "playwright",
16
+ "e2e",
17
+ "end-to-end",
18
+ "page object",
19
+ "browser test",
20
+ "storageState"
21
+ ],
22
+ "keywordPatterns": ["\\bplaywright\\b", "\\be2e\\b", "\\bpage\\s*object\\b"],
23
+ "pathPatterns": ["**/e2e/**", "**/*.spec.ts", "**/playwright.config.*"],
24
+ "intentPatterns": [
25
+ "(?:create|write|add).*(?:e2e|end.to.end|playwright).*(?:test)",
26
+ "(?:page object|fixture|browser test)"
27
+ ],
28
+ "contentPatterns": [
29
+ "@playwright/test",
30
+ "page.goto",
31
+ "page.getByRole",
32
+ "storageState",
33
+ "base.extend"
34
+ ]
35
+ },
36
+ "relatedSkills": ["ct-storybook-patterns", "ct-testing-patterns", "ct-vite-vitest-patterns"]
37
+ }
38
+ }
39
+ }
@@ -46,7 +46,13 @@
46
46
  "<Switch"
47
47
  ]
48
48
  },
49
- "relatedSkills": ["ct-vanilla-extract-patterns", "ct-testing-patterns"]
49
+ "relatedSkills": [
50
+ "ct-vanilla-extract-patterns",
51
+ "ct-testing-patterns",
52
+ "ct-vite-vitest-patterns",
53
+ "ct-storybook-patterns",
54
+ "ct-playwright-patterns"
55
+ ]
50
56
  }
51
57
  }
52
58
  }
@@ -0,0 +1,166 @@
1
+ ---
2
+ name: ct-storybook-patterns
3
+ description: Storybook interaction testing, CSF 3 stories, play functions, a11y, and visual regression for SolidJS components
4
+ ---
5
+
6
+ # Storybook Patterns
7
+
8
+ Storybook is the middle layer of the testing pyramid: component interaction testing, visual regression, and accessibility auditing in a real browser.
9
+
10
+ ## SolidJS Integration
11
+
12
+ Uses community packages: `storybook-solidjs` (renderer) + `storybook-solidjs-vite` (builder).
13
+
14
+ **Critical:** Always use `createJSXDecorator` for JSX decorators. Standard decorators cause duplicate DOM elements with SolidJS.
15
+
16
+ ```tsx
17
+ import { createJSXDecorator } from "storybook-solidjs";
18
+
19
+ const ThemeDecorator = createJSXDecorator((Story) => (
20
+ <ThemeProvider><Story /></ThemeProvider>
21
+ ));
22
+ ```
23
+
24
+ ## CSF 3 Stories
25
+
26
+ Use CSF 3 (not CSF Factories -- React-only as of Storybook 10.3).
27
+
28
+ ```tsx
29
+ import type { Meta, StoryObj } from "storybook-solidjs";
30
+
31
+ const meta = {
32
+ title: "Components/Button",
33
+ component: Button,
34
+ tags: ["autodocs"],
35
+ } satisfies Meta<typeof Button>;
36
+
37
+ export default meta;
38
+ type Story = StoryObj<typeof meta>;
39
+
40
+ export const Primary: Story = {
41
+ args: { variant: "primary", children: "Click me" },
42
+ };
43
+ ```
44
+
45
+ ### Coverage Checklist
46
+
47
+ Every component needs stories for: all visual states (default, hover, focus, active, disabled, loading, error, empty), viewport sizes where layout differs, theme variants, edge cases (long text, missing data).
48
+
49
+ ## Interaction Testing
50
+
51
+ Import everything from `@storybook/test` (instrumented versions). Never import from `@testing-library/dom` directly.
52
+
53
+ ```tsx
54
+ import { expect, fn, userEvent, within } from "@storybook/test";
55
+
56
+ export const SubmitForm: Story = {
57
+ args: { onSubmit: fn() },
58
+ play: async ({ canvasElement, args, step }) => {
59
+ const canvas = within(canvasElement);
60
+ await step("Fill form", async () => {
61
+ await userEvent.type(canvas.getByLabelText("Email"), "user@example.com");
62
+ });
63
+ await step("Submit", async () => {
64
+ await userEvent.click(canvas.getByRole("button", { name: "Sign in" }));
65
+ });
66
+ await expect(args.onSubmit).toHaveBeenCalledOnce();
67
+ },
68
+ };
69
+ ```
70
+
71
+ **Key rules:**
72
+ 1. Always `await` expect calls (enables Interactions panel logging).
73
+ 2. Use `step()` to organize complex interactions.
74
+ 3. Use `fn()` for spying (auto-restored between stories).
75
+
76
+ ## Running in CI (Vitest Addon)
77
+
78
+ Use `@storybook/addon-vitest` (replaces old test-runner). No running Storybook instance needed.
79
+
80
+ Required dependencies: `@storybook/addon-vitest`, `@vitest/browser`, `@vitest/browser-playwright`, `@vitest/coverage-v8`.
81
+
82
+ Add as an inline project in your main Vite config using `test.projects`:
83
+
84
+ ```typescript
85
+ // vite.config.ts
86
+ import { storybookTest } from "@storybook/addon-vitest/vitest-plugin";
87
+ import { playwright } from "@vitest/browser-playwright";
88
+
89
+ export default defineConfig({
90
+ plugins: [/* ...app plugins */],
91
+ test: {
92
+ projects: [
93
+ {
94
+ extends: true,
95
+ test: { name: "unit", environment: "jsdom", setupFiles: ["./tests/setup.ts"] },
96
+ },
97
+ {
98
+ extends: true,
99
+ plugins: [storybookTest({ configDir: ".storybook" })],
100
+ test: {
101
+ name: "storybook",
102
+ browser: { enabled: true, headless: true, provider: playwright(), instances: [{ browser: "chromium" }] },
103
+ setupFiles: [".storybook/vitest.setup.ts"],
104
+ },
105
+ },
106
+ ],
107
+ },
108
+ });
109
+ ```
110
+
111
+ ## Accessibility
112
+
113
+ Built on axe-core. Set globally in `.storybook/preview.ts`:
114
+
115
+ ```typescript
116
+ export default {
117
+ parameters: { a11y: { test: "error" } }, // "error" | "todo" | "off"
118
+ tags: ["a11y-test"],
119
+ };
120
+ ```
121
+
122
+ ## MSW for API Components
123
+
124
+ ```typescript
125
+ // .storybook/preview.ts
126
+ import { initialize, mswLoader } from "msw-storybook-addon";
127
+ initialize();
128
+ export default { loaders: [mswLoader] };
129
+ ```
130
+
131
+ Per-story handlers via `parameters.msw.handlers`. Keep success handlers in shared `mocks/handlers.ts`, override with error/edge-case at story level.
132
+
133
+ ## Module Mocking (Storybook 10)
134
+
135
+ `sb.mock` for internal module replacement. Register in `.storybook/preview.ts` only:
136
+
137
+ ```typescript
138
+ import { sb } from "@storybook/test";
139
+ sb.mock("../src/api/client", () => ({ fetchUser: async () => ({ name: "Mock" }) }));
140
+ ```
141
+
142
+ MSW for network-level; `sb.mock` for internal modules.
143
+
144
+ ## Portable Stories
145
+
146
+ Reuse stories in Vitest with `composeStories`:
147
+
148
+ ```tsx
149
+ import { composeStories } from "storybook-solidjs";
150
+ import * as stories from "./Button.stories";
151
+ const { Primary } = composeStories(stories);
152
+
153
+ test("renders primary", () => {
154
+ const { getByRole } = render(() => <Primary />);
155
+ expect(getByRole("button")).toBeInTheDocument();
156
+ });
157
+ ```
158
+
159
+ ## Anti-Patterns
160
+
161
+ 1. **Destructuring SolidJS props in stories** -- Pass props via `args`; use `createJSXDecorator` for decorators.
162
+ 2. **Importing from `@testing-library/dom`** -- Use `@storybook/test` for instrumented versions.
163
+ 3. **Not awaiting `expect()` in play functions** -- Always `await expect(...)`.
164
+ 4. **Skipping error/edge-case stories** -- Always include loading, error, empty, boundary states.
165
+ 5. **Using `@storybook/test-runner`** -- Use `@storybook/addon-vitest` instead.
166
+ 6. **Registering `sb.mock` in story files** -- Register in `.storybook/preview.ts` only.
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "ct-storybook-patterns",
3
+ "description": "Storybook interaction testing, CSF 3 stories, and visual regression for SolidJS",
4
+ "defaultMappings": {
5
+ ".storybook": "ct-storybook-patterns",
6
+ "src/**/*.stories.tsx": "ct-storybook-patterns"
7
+ },
8
+ "fileExtensions": ["stories.tsx", "stories.ts"],
9
+ "skillRules": {
10
+ "ct-storybook-patterns": {
11
+ "description": "Storybook CSF 3 stories, play functions, a11y testing, and visual regression",
12
+ "priority": 7,
13
+ "triggers": {
14
+ "keywords": [
15
+ "storybook",
16
+ "story",
17
+ "stories",
18
+ "csf",
19
+ "play function",
20
+ "interaction test",
21
+ "visual regression",
22
+ "chromatic"
23
+ ],
24
+ "keywordPatterns": ["\\bstorybook\\b", "\\bstories\\b", "\\bplay\\s+function\\b"],
25
+ "pathPatterns": ["**/*.stories.tsx", "**/*.stories.ts", "**/.storybook/**"],
26
+ "intentPatterns": [
27
+ "(?:create|write|add).*(?:story|stories|storybook)",
28
+ "(?:interaction|visual|a11y).*(?:test|testing)"
29
+ ],
30
+ "contentPatterns": [
31
+ "satisfies Meta",
32
+ "StoryObj",
33
+ "@storybook/test",
34
+ "createJSXDecorator",
35
+ "storybook-solidjs"
36
+ ]
37
+ },
38
+ "relatedSkills": [
39
+ "ct-solidjs-patterns",
40
+ "ct-testing-patterns",
41
+ "ct-vite-vitest-patterns",
42
+ "ct-playwright-patterns"
43
+ ]
44
+ }
45
+ }
46
+ }