stably 4.9.0 → 4.10.0

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.
Files changed (47) hide show
  1. package/dist/index.mjs +1 -1
  2. package/dist/stably-plugin-cli/.claude-plugin/plugin.json +5 -0
  3. package/dist/stably-plugin-cli/skills/bash-commands/SKILL.md +65 -0
  4. package/dist/stably-plugin-cli/skills/browser-interaction-guide/SKILL.md +144 -0
  5. package/dist/stably-plugin-cli/skills/bulk-test-handling/SKILL.md +104 -0
  6. package/dist/stably-plugin-cli/skills/debugging-test-failures/SKILL.md +146 -0
  7. package/dist/{stably-plugin → stably-plugin-cli}/skills/playwright-best-practices/SKILL.md +11 -5
  8. package/dist/stably-plugin-cli/skills/playwright-config-auth/SKILL.md +217 -0
  9. package/dist/stably-plugin-cli/skills/stably-sdk-reference/SKILL.md +307 -0
  10. package/dist/stably-plugin-cli/skills/test-creation-workflow/SKILL.md +311 -0
  11. package/package.json +2 -2
  12. package/dist/stably-plugin/.claude-plugin/plugin.json +0 -5
  13. package/dist/stably-plugin/skills/playwright-best-practices/references/accessibility.md +0 -359
  14. package/dist/stably-plugin/skills/playwright-best-practices/references/annotations.md +0 -526
  15. package/dist/stably-plugin/skills/playwright-best-practices/references/assertions-waiting.md +0 -361
  16. package/dist/stably-plugin/skills/playwright-best-practices/references/browser-apis.md +0 -391
  17. package/dist/stably-plugin/skills/playwright-best-practices/references/browser-extensions.md +0 -506
  18. package/dist/stably-plugin/skills/playwright-best-practices/references/canvas-webgl.md +0 -493
  19. package/dist/stably-plugin/skills/playwright-best-practices/references/ci-cd.md +0 -407
  20. package/dist/stably-plugin/skills/playwright-best-practices/references/clock-mocking.md +0 -364
  21. package/dist/stably-plugin/skills/playwright-best-practices/references/component-testing.md +0 -500
  22. package/dist/stably-plugin/skills/playwright-best-practices/references/console-errors.md +0 -420
  23. package/dist/stably-plugin/skills/playwright-best-practices/references/debugging.md +0 -491
  24. package/dist/stably-plugin/skills/playwright-best-practices/references/electron.md +0 -509
  25. package/dist/stably-plugin/skills/playwright-best-practices/references/error-testing.md +0 -360
  26. package/dist/stably-plugin/skills/playwright-best-practices/references/file-operations.md +0 -375
  27. package/dist/stably-plugin/skills/playwright-best-practices/references/fixtures-hooks.md +0 -417
  28. package/dist/stably-plugin/skills/playwright-best-practices/references/flaky-tests.md +0 -494
  29. package/dist/stably-plugin/skills/playwright-best-practices/references/global-setup.md +0 -434
  30. package/dist/stably-plugin/skills/playwright-best-practices/references/i18n.md +0 -508
  31. package/dist/stably-plugin/skills/playwright-best-practices/references/iframes.md +0 -403
  32. package/dist/stably-plugin/skills/playwright-best-practices/references/locators.md +0 -242
  33. package/dist/stably-plugin/skills/playwright-best-practices/references/mobile-testing.md +0 -409
  34. package/dist/stably-plugin/skills/playwright-best-practices/references/multi-context.md +0 -288
  35. package/dist/stably-plugin/skills/playwright-best-practices/references/multi-user.md +0 -393
  36. package/dist/stably-plugin/skills/playwright-best-practices/references/network-advanced.md +0 -452
  37. package/dist/stably-plugin/skills/playwright-best-practices/references/page-object-model.md +0 -315
  38. package/dist/stably-plugin/skills/playwright-best-practices/references/performance-testing.md +0 -476
  39. package/dist/stably-plugin/skills/playwright-best-practices/references/performance.md +0 -453
  40. package/dist/stably-plugin/skills/playwright-best-practices/references/projects-dependencies.md +0 -456
  41. package/dist/stably-plugin/skills/playwright-best-practices/references/security-testing.md +0 -430
  42. package/dist/stably-plugin/skills/playwright-best-practices/references/service-workers.md +0 -504
  43. package/dist/stably-plugin/skills/playwright-best-practices/references/test-coverage.md +0 -495
  44. package/dist/stably-plugin/skills/playwright-best-practices/references/test-data.md +0 -492
  45. package/dist/stably-plugin/skills/playwright-best-practices/references/test-organization.md +0 -361
  46. package/dist/stably-plugin/skills/playwright-best-practices/references/third-party.md +0 -464
  47. package/dist/stably-plugin/skills/playwright-best-practices/references/websockets.md +0 -403
@@ -0,0 +1,217 @@
1
+ ---
2
+ name: playwright-config-auth
3
+ description: Guide for Playwright config management including cache invalidation, auth project dependencies, and avoiding auth setup chains. Use when encountering config issues, auth/login setup, project dependencies configuration, cache problems, or unexpected auth behavior. Triggers on playwright.config, auth project, dependencies, storageState, config cache, cache-bust, auth setup chain, project selection.
4
+ ---
5
+
6
+ # Playwright Config & Auth Guide
7
+
8
+ This skill provides guidance for Playwright configuration management and authentication setup for the CLI environment.
9
+
10
+ ## Key Difference: No Catch-All Project
11
+
12
+ **The CLI does NOT have a `stably-internal-all-tests-project` catch-all project.** That project only exists in the web environment.
13
+
14
+ When you need to run tests without auth dependencies, you must add an isolated project to `playwright.config.ts` (see "Adding an Isolated Project" section below).
15
+
16
+ ## Troubleshooting: Stale Config Cache
17
+
18
+ If you edit `playwright.config.ts` and changes don't take effect, the cache may be stale:
19
+
20
+ ```bash
21
+ rm -rf /tmp/playwright-transform-cache-* 2>/dev/null || true
22
+ ```
23
+
24
+ This is rare in CLI - only try this if config changes are clearly not being picked up.
25
+
26
+ ## Avoiding Auth Setup Chains
27
+
28
+ Some repositories use multi-user authentication patterns with project dependencies. This can cause unexpected behavior when using setup tools.
29
+
30
+ ### The Problem
31
+
32
+ Projects with `dependencies: ['setup-xyz']` will run all dependency setup tests (auth flows) before your seed test - even if you don't need that auth state.
33
+
34
+ ### How to Recognize It
35
+
36
+ Look for:
37
+ - Multiple `setup-*` projects in `playwright.config.ts`
38
+ - `storageState` configurations
39
+ - `.auth/*.json` files
40
+
41
+ ### The Solution
42
+
43
+ Since the CLI has no catch-all project, you must add an isolated project to avoid auth chains.
44
+
45
+ 1. Use `tests/seed.spec.ts` for browser setup
46
+ 2. Add an isolated project to `playwright.config.ts` (see below)
47
+ 3. Use that project when running tests that don't need auth
48
+
49
+ ### Before Creating Test Files
50
+
51
+ Check if the target project's `testMatch` pattern will cover your new test file:
52
+
53
+ 1. Read `playwright.config.ts` and find the `isolated` project's `testMatch` pattern
54
+ 2. If your new file won't match (e.g., `testMatch: ['**/seed.spec.ts']` won't match `my-test.spec.ts`):
55
+ - Either update `testMatch` to include the new file (e.g., `['**/seed.spec.ts', '**/my-test.spec.ts']`)
56
+ - Or use a broader pattern (e.g., `tests/isolated/*.spec.ts` and place files there)
57
+ 3. After editing config: clear cache, restart MCP, run `test_list` to verify
58
+
59
+ ### Adding an Isolated Project (REQUIRED for No-Auth Tests)
60
+
61
+ Add an isolated project to `playwright.config.ts` with specific `testMatch` and NO dependencies:
62
+
63
+ ```typescript
64
+ {
65
+ name: 'isolated',
66
+ testMatch: '**/seed.spec.ts', // Or any pattern matching your seed file
67
+ use: {
68
+ ...devices['Desktop Chrome'],
69
+ // Optionally use existing auth state if available
70
+ storageState: '.auth/user.json',
71
+ },
72
+ // NO dependencies - this is key!
73
+ }
74
+ ```
75
+
76
+ This ensures only the isolated project matches your seed file, avoiding dependency chains.
77
+
78
+ Common patterns: `**/seed.spec.ts`, `**/setup.spec.ts`, or `tests/isolated/*.spec.ts`
79
+
80
+ ### After Adding or Editing the Project
81
+
82
+ 1. Clear Playwright cache: `rm -rf /tmp/playwright-transform-cache-* 2>/dev/null || true`
83
+ 2. Restart MCP servers to pick up the config change
84
+ 3. **Run `test_list` and verify your test appears under the correct project** before running `test_debug` or `test_run`
85
+ 4. If your test only appears under a project with auth dependencies (e.g., `all`), do NOT proceed - fix the project matching first
86
+ 5. **If test appears under multiple projects**, add `testIgnore` to the unintended projects to exclude your test file
87
+ 6. Use the new project: `test_run with projects: ['isolated']`
88
+
89
+ ### If Setup Takes Too Long or Runs Auth Unexpectedly
90
+
91
+ The seed file likely matched a user project with dependencies. Check `playwright.config.ts` for which project patterns match your seed file location, and add an isolated project.
92
+
93
+ ## Leveraging Auth Project Dependencies
94
+
95
+ When the repository uses authentication via project dependencies (a common pattern), follow these steps:
96
+
97
+ ### How to Recognize This Pattern
98
+
99
+ - `playwright.config.ts` has an `auth` project with `testMatch: /.*\.auth\.ts/`
100
+ - Other projects have `dependencies: ["auth"]` (e.g., `chromium`, `mobile-safari`)
101
+ - Auth tests create `storageState` files (e.g., `.auth/US.json`, `.auth/EU.json`)
102
+ - Test fixtures use `storageState` to load pre-authenticated sessions
103
+
104
+ ### The Problem
105
+
106
+ - The CLI has no catch-all project; the user's default project is used
107
+ - If you don't specify a project with auth dependencies, auth never runs
108
+ - Tests fail with "No auth file found" or missing storageState
109
+ - Even with right project, some auth setups may have skip conditions
110
+
111
+ ### The Solution
112
+
113
+ 1. **Specify a project with auth dependencies**: When calling `generator_setup_page` or `test_run`, explicitly specify a project that has `dependencies: ["auth"]` (e.g., `chromium`, `mobile-safari`)
114
+
115
+ 2. **Check for auth skip conditions**: If auth tests are being skipped, inspect auth test file (e.g., `*.auth.ts`) and related setup files for skip conditions. Look for environment variables or configuration that forces re-authentication.
116
+
117
+ 3. **Create tests using normal pattern**: With auth working via project dependencies, tests don't need manual login workarounds. They can use repository's standard auth pattern with `storageState`.
118
+
119
+ ### Example Workflow
120
+
121
+ 1. Read `playwright.config.ts` and identify projects with `dependencies: ["auth"]` (e.g., `chromium`, `mobile-safari`)
122
+ 2. Check auth test files for skip conditions or environment variables
123
+ 3. Create test file using repository's normal auth pattern (via storageState from fixtures)
124
+ 4. Call `generator_setup_page` with identified project (e.g., `project: "chromium"`)
125
+ 5. Auth project runs automatically as dependency -> creates auth files -> test runs authenticated
126
+
127
+ ### What NOT to Do
128
+
129
+ - Don't leave project unspecified and expect auth to run
130
+ - Don't create `seed.spec.ts` files with manual `login()` calls as workaround for auth issues
131
+ - Don't add `@noauth` tag unless user specifically wants tests that handle their own authentication independently
132
+
133
+ ## Project Selection for Auth (CRITICAL)
134
+
135
+ If config has auth project dependencies (e.g., `chromium` with `dependencies: ["auth"]`), you MUST specify that project when calling setup tools.
136
+
137
+ ```
138
+ generator_setup_page({ project: "chromium", seedFile: "tests/my-test.spec.ts", ... })
139
+ ```
140
+
141
+ **Do NOT leave the project param blank** - auth will not run without specifying a project that has auth dependencies.
142
+
143
+ ## stably.yaml Scheduled Runs
144
+
145
+ When creating or editing `stably.yaml` schedules, use this exact shape:
146
+
147
+ ```yaml
148
+ schedules:
149
+ schedule-name:
150
+ cron: "0 9 * * *"
151
+ # Optional: stablyTestArgs: "--project smoke"
152
+ # Optional: timezone: "America/Los_Angeles"
153
+ ```
154
+
155
+ ### Rules
156
+
157
+ - `schedules` MUST be an object/map keyed by schedule name
158
+ - Do NOT use array format like `schedules: [{ name: ..., cron: ... }]`
159
+ - Do NOT use `testMatch` inside `stably.yaml` schedules
160
+ - Use `stablyTestArgs` for filtering test selection
161
+
162
+ ## Test File Format Guidelines
163
+
164
+ - Stably supports all Playwright default test file extensions: `.spec.ts`, `.test.ts`, `.spec.js`, `.test.js`, `.spec.tsx`, `.test.tsx`, `.spec.jsx`, `.test.jsx`, and CommonJS/ESM variants
165
+ - For new tests, prefer `.spec.ts` or `.test.ts` (TypeScript) for best IDE support
166
+ - If user requests specific extension, proceed with their preference if Playwright-supported
167
+ - For consistency, check existing test files to match their convention
168
+ - Do NOT modify `testMatch` option in `playwright.config.ts` to use custom patterns (e.g., `testMatch: ["**/*.e2e.ts"]`)
169
+ - You CAN read and edit `playwright.config.ts` for other legitimate purposes (adjusting timeouts, adding projects, configuring reporters)
170
+
171
+ ## Test Execution Project Selection (CRITICAL)
172
+
173
+ This section covers how to select the right project when running tests with `test_run`.
174
+
175
+ ### Rule 1: Add an Isolated Project for Independent Tests
176
+
177
+ When running tests that DON'T need auth or other project dependencies (e.g., tests for public websites, tests with `test.use({ storageState: { cookies: [], origins: [] } })`):
178
+
179
+ 1. Add an isolated project to `playwright.config.ts` with NO dependencies (see "Adding an Isolated Project" above)
180
+ 2. Use that project:
181
+ ```
182
+ test_run with projects: ['isolated'] and locations: ['tests/my-test.spec.ts']
183
+ ```
184
+
185
+ **Why**: Playwright runs tests under ALL matching projects, not just one. If your test matches a project with `dependencies: ['setup-xyz']`, auth/setup flows will run unexpectedly.
186
+
187
+ ### Rule 2: Verify Project Config Before Specifying
188
+
189
+ Before specifying a project like `chromium`, `firefox`, etc., read `playwright.config.ts` and check that project for:
190
+
191
+ - **grep** - regex filter that restricts which test names can run
192
+ - **testMatch** - file pattern filter that restricts which test files can run
193
+ - **testIgnore** - file patterns that are excluded from running
194
+ - **dependencies** - other projects (like auth setup) that must run first
195
+
196
+ If the project has `grep` or `testMatch` filters that would exclude your test file or test name, do NOT use that project. Add an isolated project with no dependencies/filters instead.
197
+
198
+ ### Rule 3: Quick Decision Tree
199
+
200
+ ```
201
+ Does the test need auth/setup dependencies?
202
+ +-- NO (public website, no login needed)
203
+ | +-- Add isolated project to config, then use it
204
+ +-- YES (requires login, specific browser config, etc.)
205
+ +-- Check target project's grep/testMatch/testIgnore filters
206
+ +-- Test matches filters -> Use that project
207
+ +-- Test does NOT match filters -> Pick appropriate project
208
+ ```
209
+
210
+ ### Common Pitfalls
211
+
212
+ | Symptom | Cause | Fix |
213
+ |---------|-------|-----|
214
+ | Empty test output | Project filters exclude your test | Add isolated project with no filters |
215
+ | Auth runs unexpectedly | Test matches project with auth dependencies | Add isolated project with no dependencies |
216
+ | Test runs multiple times | Multiple projects match the test | Specify single project explicitly |
217
+ | "Project not found" | Tried using `stably-internal-all-tests-project` | This project doesn't exist in CLI; add isolated project |
@@ -0,0 +1,307 @@
1
+ ---
2
+ name: stably-sdk-reference
3
+ description: Complete reference for Stably SDK features including aiAssert, agent.act(), extract(), getLocatorsByAI(), and email inbox testing. Use when writing Playwright tests with AI-powered assertions, autonomous agent workflows, visual data extraction, AI-based element finding, or email verification flows. Triggers on aiAssert, toMatchScreenshotPrompt, agent.act, page.extract, getLocatorsByAI, @stablyai/email, Inbox.build, model selection.
4
+ ---
5
+
6
+ # Stably SDK Reference
7
+
8
+ This skill provides comprehensive guidance for using Stably's AI-powered testing features in Playwright tests.
9
+
10
+ ## Import Statement
11
+
12
+ Always use the Stably SDK import:
13
+
14
+ ```typescript
15
+ import { test, expect } from "@stablyai/playwright-test";
16
+ ```
17
+
18
+ ## AI Assertions (aiAssert)
19
+
20
+ Use `aiAssert` for intent-based visual verification of dynamic UIs:
21
+
22
+ ```typescript
23
+ // Page-level assertion
24
+ await expect(page).aiAssert(
25
+ "Shows revenue trend chart and spotlight card",
26
+ { timeout: 30_000 }
27
+ );
28
+
29
+ // Scoped to specific element (preferred for precision)
30
+ await expect(page.locator(".header"))
31
+ .aiAssert("Nav with avatar and bell icon");
32
+ ```
33
+
34
+ **Signature:** `expect(page|locator).aiAssert(prompt: string, options?: { timeout?: number, fullPage?: boolean, model?: AIModel })`
35
+
36
+ **Best Practices:**
37
+ - Use for **dynamic** UIs where deterministic assertions are insufficient
38
+ - Keep prompts specific with labels and units
39
+ - Scope with locators when possible (more precise, less noisy)
40
+ - **Consider `fullPage: true` carefully**: Only use when assertion requires content beyond the visible viewport. Viewport captures are faster and cheaper.
41
+
42
+ **Note:** `toMatchScreenshotPrompt` is deprecated. Use `aiAssert` instead.
43
+
44
+ ## AI Extraction (extract)
45
+
46
+ Extract data from visual content:
47
+
48
+ ```typescript
49
+ // Simple string extraction
50
+ const txt = await page.extract("List revenue, active users, and churn rate");
51
+
52
+ // Typed extraction with Zod schema
53
+ import { z } from "zod";
54
+ const Metrics = z.object({
55
+ revenue: z.string(),
56
+ activeUsers: z.number(),
57
+ churnRate: z.number()
58
+ });
59
+ const m = await page.extract(
60
+ "Return revenue (currency), active users, churn %",
61
+ { schema: Metrics }
62
+ );
63
+ ```
64
+
65
+ **Signatures:**
66
+ - `page.extract(prompt: string, options?: { model?: AIModel }): Promise<string>`
67
+ - `page.extract<T extends z.AnyZodObject>(prompt, { schema: T, model?: AIModel }): Promise<z.output<T>>`
68
+
69
+ ## AI Locator Finding (getLocatorsByAI)
70
+
71
+ Find elements using natural language based on accessibility properties:
72
+
73
+ ```typescript
74
+ // Find a single element
75
+ const { locator: loginBtn, count } = await page.getLocatorsByAI("the login button");
76
+ expect(count).toBe(1);
77
+ await loginBtn.click();
78
+
79
+ // Find multiple elements
80
+ const { locator: productCards, count: cardCount } = await page.getLocatorsByAI(
81
+ "all product cards in the grid"
82
+ );
83
+ await expect(productCards).toHaveCount(cardCount);
84
+ ```
85
+
86
+ **Signature:** `page.getLocatorsByAI(prompt: string, options?: { model?: AIModel }): Promise<{ locator: Locator, count: number, reason: string }>`
87
+
88
+ **Properties:**
89
+ - Returns a Playwright `Locator` usable for interactions and assertions
90
+ - `count` indicates how many elements were found (0 if none)
91
+ - `reason` contains the AI's explanation of what it found
92
+ - Requires Playwright v1.54.1 or higher
93
+
94
+ **Best Practices:**
95
+ - Describe elements by accessible properties (labels, roles, text) rather than visual attributes (colors, positioning)
96
+ - Best for finding elements when CSS selectors or test IDs are unreliable
97
+
98
+ ## AI Agent (agent.act)
99
+
100
+ Use the `agent` fixture for complex, autonomous workflows:
101
+
102
+ ```typescript
103
+ test("complex workflow", async ({ agent, page }) => {
104
+ await page.goto("/orders");
105
+ await agent.act("Find the first pending order and mark it as shipped", { page });
106
+ });
107
+
108
+ // Or create manually
109
+ const agent = context.newAgent();
110
+ await agent.act("Your task here", { page, maxCycles: 10 });
111
+ ```
112
+
113
+ **Signature:** `agent.act(prompt: string, options: { page: Page, maxCycles?: number, model?: string }): Promise<{ success: boolean }>`
114
+
115
+ **Default maxCycles:** 30
116
+ **Supported models:** `anthropic/claude-sonnet-4-6` (default), `google/gemini-2.5-computer-use-preview-10-2025`
117
+
118
+ ### Passing Variables to Prompts
119
+
120
+ Use template literals to pass variables:
121
+
122
+ ```typescript
123
+ const duration = 24 * 7 * 60;
124
+ await agent.act(`Enter the duration of ${duration} seconds`, { page });
125
+
126
+ const username = "john.doe@example.com";
127
+ await agent.act(`Login with username ${username}`, { page });
128
+ ```
129
+
130
+ ### Self-Contained Prompts (CRITICAL)
131
+
132
+ All prompts to Stably SDK AI methods must be self-contained with all necessary information:
133
+
134
+ 1. **No implicit references to outside context:**
135
+ - Bad: `agent.act("Verify the field you just filled in the form is 4", { page })`
136
+ - Good: `agent.act("Verify the 'timeout' field in the form has value 4", { page })`
137
+ - Bad: `agent.act("Pick something that's not in the previous step", { page })`
138
+ - Good: `const selectedItem = "Option A"; await agent.act(\`Pick an option other than ${selectedItem}\`, { page })`
139
+
140
+ 2. **Pass information between AI methods using explicit variables:**
141
+ ```typescript
142
+ const orderId = await page.extract("Get the order ID from the first row");
143
+ await agent.act(`Cancel order with ID ${orderId}`, { page });
144
+ ```
145
+
146
+ 3. **Include detailed instructions and domain knowledge:**
147
+ - Bad: `agent.act("Fill in the form", { page })`
148
+ - Good: `agent.act("Fill in the form with test data. On page 4 you might run into a popup asking for premium features - just click 'Skip' or 'Cancel' to ignore it", { page })`
149
+
150
+ ### Offload Work to Playwright
151
+
152
+ The less actions/cycles agent.act() needs, the better it performs. Offload work to Playwright code:
153
+
154
+ 1. **Repetition:** Use loops in code, not in prompts
155
+ - Bad: "Click the button 5 times"
156
+ - Good: "Click the button" (in a loop that runs 5 times)
157
+
158
+ 2. **Calculations:** Calculate in code, pass result to prompt
159
+ - Bad: "enter the duration of 24*7*60 seconds"
160
+ - Good: `const sum = 24*7*60; agent.act(\`enter the duration of ${sum} seconds\`, { page })`
161
+
162
+ 3. **Conditionals:** Use code for if/else when possible
163
+
164
+ ### agent.act() Best Practices
165
+
166
+ 1. **Split complex prompts into smaller tasks:**
167
+ ```typescript
168
+ // Bad - too many steps
169
+ await agent.act('Close popups, click menu, expand panel, find sliders', { page, maxCycles: 15 });
170
+
171
+ // Good - single responsibility
172
+ await agent.act('Close the tutorial popup if visible', { page, maxCycles: 5 });
173
+ await agent.act('Click the color menu and expand Basic Color panel', { page, maxCycles: 8 });
174
+ ```
175
+
176
+ 2. **Be specific in prompts** - Include visual hints:
177
+ ```typescript
178
+ // Bad
179
+ await agent.act('Adjust the slider', { page });
180
+
181
+ // Good
182
+ await agent.act('Move the "Brightness" slider (the one with the sun icon) to approximately 75%', { page });
183
+ ```
184
+
185
+ 3. **Use appropriate maxCycles:**
186
+ - Simple single action: 3-5 cycles
187
+ - Multi-step interaction: 8-10 cycles
188
+ - Complex workflow: 15-20 cycles
189
+ - Never rely on the default 30 cycles
190
+
191
+ ## Model Selection
192
+
193
+ `aiAssert`, `extract`, and `getLocatorsByAI` support an optional `model` parameter:
194
+
195
+ ```typescript
196
+ await expect(page).aiAssert("Shows the dashboard", { model: "google/gemini-3-flash-preview" });
197
+ const data = await page.extract("Get the price", { model: "openai/o4-mini" });
198
+ const { locator } = await page.getLocatorsByAI("the submit button", { model: "google/gemini-3-pro-preview" });
199
+ ```
200
+
201
+ **Available models:**
202
+ - `"openai/o4-mini"` - OpenAI's efficient reasoning model
203
+ - `"google/gemini-3-pro-preview"` - Google's most capable model
204
+ - `"google/gemini-3-flash-preview"` - Google's fast, efficient model (good for simple tasks)
205
+
206
+ **Tips:**
207
+ - Use `gemini-3-flash-preview` for fast, simple operations
208
+ - Use `gemini-3-pro-preview` or `o4-mini` for complex reasoning
209
+
210
+ ## Email Inbox Testing (@stablyai/email)
211
+
212
+ Use disposable email inboxes for testing email-dependent flows:
213
+
214
+ ```typescript
215
+ import { Inbox } from "@stablyai/email";
216
+
217
+ // Create a test-scoped inbox
218
+ const inbox = await Inbox.build({ suffix: `test-${Date.now()}` });
219
+ // inbox.address → "org+test-1706621234567@mail.stably.ai"
220
+
221
+ // Wait for an email
222
+ const email = await inbox.waitForEmail({
223
+ from: "noreply@example.com",
224
+ subject: "verification",
225
+ timeoutMs: 60_000,
226
+ });
227
+
228
+ // AI-powered extraction
229
+ const { data: otp } = await inbox.extractFromEmail({
230
+ id: email.id,
231
+ prompt: "Extract the 6-digit OTP code",
232
+ });
233
+
234
+ // Structured extraction with Zod
235
+ import { z } from "zod";
236
+ const { data } = await inbox.extractFromEmail({
237
+ id: email.id,
238
+ prompt: "Extract verification URL and expiration",
239
+ schema: z.object({ url: z.string().url(), expiresIn: z.string() }),
240
+ });
241
+ ```
242
+
243
+ ### Playwright Fixture Pattern
244
+
245
+ For test isolation and automatic cleanup:
246
+
247
+ ```typescript
248
+ import { test as base } from "@stablyai/playwright-test";
249
+ import { Inbox } from "@stablyai/email";
250
+
251
+ const test = base.extend<{ inbox: Inbox }>({
252
+ inbox: async ({}, use, testInfo) => {
253
+ const inbox = await Inbox.build({ suffix: `test-${testInfo.testId}` });
254
+ await use(inbox);
255
+ await inbox.deleteAllEmails();
256
+ },
257
+ });
258
+ ```
259
+
260
+ ### Key Options
261
+
262
+ **waitForEmail:** `from`, `subject`, `subjectMatch` (`'contains'` | `'exact'`), `timeoutMs` (default 120000), `pollIntervalMs` (default 3000)
263
+
264
+ **extractFromEmail:** `id` (required), `prompt` (required), `schema` (optional Zod). Returns `{ data, reason }`
265
+
266
+ **Best practices:**
267
+ - Always use unique suffixes for parallel test isolation
268
+ - Use the fixture pattern for automatic cleanup
269
+ - Prefer `waitForEmail` over polling with `listEmails`
270
+
271
+ ## When to Use SDK vs Playwright
272
+
273
+ **Use Playwright** when:
274
+ - Simple, concrete checks (element visible, text matches, URL correct)
275
+ - Faster and more reliable for deterministic scenarios
276
+
277
+ **Use Stably SDK** when:
278
+ 1. Test accuracy and stability are paramount
279
+ 2. Interactions are hard to express in Playwright or too brittle
280
+ 3. Canvas-related operations or drag/click requiring coordinates → use `agent.act()`
281
+ 4. Visual-heavy assertions → use `aiAssert`
282
+ 5. Email verification flows → use `@stablyai/email`
283
+
284
+ **IMPORTANT:** Do NOT use `toHaveScreenshot()` - this Playwright assertion is not supported. Use `aiAssert` for ALL visual assertions.
285
+
286
+ ## Minimal Template
287
+
288
+ ```typescript
289
+ import { test, expect } from "@stablyai/playwright-test";
290
+
291
+ test("AI-enhanced dashboard", async ({ page, agent }) => {
292
+ await page.goto("/dashboard");
293
+
294
+ // Use agent for complex workflows
295
+ await agent.act("Navigate to settings and enable notifications", { page });
296
+
297
+ // Use AI assertions for dynamic content
298
+ await expect(page).aiAssert(
299
+ "Dashboard shows revenue chart (>= 6 months) and account spotlight card"
300
+ );
301
+ });
302
+ ```
303
+
304
+ ## Troubleshooting
305
+
306
+ - **Slow assertions** → Scope visuals with locators; reduce viewport
307
+ - **Agent stops early** → Increase `maxCycles` or break task into smaller steps