@assertrx/dino 1.0.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.
- package/README.md +293 -0
- package/extensions/dino.ts +70 -0
- package/extensions/mabl-mcp.ts +306 -0
- package/extensions/playwright-mcp.ts +142 -0
- package/package.json +47 -0
- package/prompts/create-pr.md +110 -0
- package/prompts/generate-bdd-from-url.md +65 -0
- package/prompts/generate-pom-from-url-cli.md +48 -0
- package/prompts/generate-pom-from-url.md +45 -0
- package/prompts/generate-spec-from-feature.md +64 -0
- package/prompts/heal-playwright-failures.md +106 -0
- package/prompts/setup-playwright.md +81 -0
- package/scripts/start-dino.cmd +8 -0
- package/scripts/start-dino.mjs +226 -0
- package/scripts/start-dino.ps1 +9 -0
- package/scripts/start-dino.sh +10 -0
- package/skills/acli/SKILL.md +292 -0
- package/skills/bdd-gherkin/SKILL.md +552 -0
- package/skills/build-review-interface/SKILL.md +96 -0
- package/skills/error-analysis/SKILL.md +164 -0
- package/skills/eval-audit/SKILL.md +183 -0
- package/skills/evaluate-rag/SKILL.md +177 -0
- package/skills/generate-synthetic-data/SKILL.md +131 -0
- package/skills/mabl-mcp/SKILL.md +79 -0
- package/skills/playwright-cli/SKILL.md +246 -0
- package/skills/playwright-cli/advanced-workflows.md +679 -0
- package/skills/playwright-cli/core-commands.md +375 -0
- package/skills/playwright-cli/device-emulation.md +475 -0
- package/skills/playwright-cli/request-mocking.md +373 -0
- package/skills/playwright-cli/running-custom-code.md +553 -0
- package/skills/playwright-cli/screenshots-and-media.md +457 -0
- package/skills/playwright-cli/session-management.md +425 -0
- package/skills/playwright-cli/storage-and-auth.md +487 -0
- package/skills/playwright-cli/test-generation.md +336 -0
- package/skills/playwright-cli/tracing-and-debugging.md +501 -0
- package/skills/playwright-core/SKILL.md +101 -0
- package/skills/playwright-core/accessibility.md +1517 -0
- package/skills/playwright-core/angular.md +1086 -0
- package/skills/playwright-core/api-testing.md +1623 -0
- package/skills/playwright-core/assertions-and-waiting.md +703 -0
- package/skills/playwright-core/auth-flows.md +1081 -0
- package/skills/playwright-core/authentication.md +1409 -0
- package/skills/playwright-core/browser-apis.md +673 -0
- package/skills/playwright-core/browser-extensions.md +319 -0
- package/skills/playwright-core/canvas-and-webgl.md +494 -0
- package/skills/playwright-core/clock-and-time-mocking.md +427 -0
- package/skills/playwright-core/common-pitfalls.md +1318 -0
- package/skills/playwright-core/component-testing.md +1179 -0
- package/skills/playwright-core/configuration.md +731 -0
- package/skills/playwright-core/crud-testing.md +945 -0
- package/skills/playwright-core/debugging.md +827 -0
- package/skills/playwright-core/drag-and-drop.md +992 -0
- package/skills/playwright-core/electron-testing.md +622 -0
- package/skills/playwright-core/error-and-edge-cases.md +1181 -0
- package/skills/playwright-core/error-index.md +1903 -0
- package/skills/playwright-core/file-operations.md +749 -0
- package/skills/playwright-core/file-upload-download.md +1012 -0
- package/skills/playwright-core/fixtures-and-hooks.md +1072 -0
- package/skills/playwright-core/flaky-tests.md +883 -0
- package/skills/playwright-core/forms-and-validation.md +1056 -0
- package/skills/playwright-core/i18n-and-localization.md +622 -0
- package/skills/playwright-core/iframes-and-shadow-dom.md +488 -0
- package/skills/playwright-core/locator-strategy.md +588 -0
- package/skills/playwright-core/locators.md +743 -0
- package/skills/playwright-core/mobile-and-responsive.md +1669 -0
- package/skills/playwright-core/multi-context-and-popups.md +581 -0
- package/skills/playwright-core/multi-user-and-collaboration.md +477 -0
- package/skills/playwright-core/network-mocking.md +1395 -0
- package/skills/playwright-core/nextjs.md +1013 -0
- package/skills/playwright-core/performance-testing.md +608 -0
- package/skills/playwright-core/react.md +1082 -0
- package/skills/playwright-core/search-and-filter.md +1366 -0
- package/skills/playwright-core/security-testing.md +624 -0
- package/skills/playwright-core/service-workers-and-pwa.md +524 -0
- package/skills/playwright-core/test-architecture.md +569 -0
- package/skills/playwright-core/test-data-management.md +1209 -0
- package/skills/playwright-core/test-organization.md +947 -0
- package/skills/playwright-core/third-party-integrations.md +754 -0
- package/skills/playwright-core/trace-analysis.md +161 -0
- package/skills/playwright-core/visual-regression.md +1027 -0
- package/skills/playwright-core/vue.md +1162 -0
- package/skills/playwright-core/websockets-and-realtime.md +623 -0
- package/skills/playwright-core/when-to-mock.md +827 -0
- package/skills/playwright-pom/SKILL.md +94 -0
- package/skills/playwright-pom/page-object-model.md +921 -0
- package/skills/playwright-pom/pom-vs-fixtures-vs-helpers.md +937 -0
- package/skills/validate-evaluator/SKILL.md +215 -0
- package/skills/write-judge-prompt/SKILL.md +144 -0
- package/themes/dino.json +66 -0
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
# Test Generation
|
|
2
|
+
|
|
3
|
+
> **When to use**: Generating Playwright test code from interactive CLI sessions — recording user flows, building test scaffolds, converting manual testing into automated tests.
|
|
4
|
+
> **Prerequisites**: [core-commands.md](core-commands.md) for basic CLI usage
|
|
5
|
+
|
|
6
|
+
## Quick Reference
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
# Every CLI action outputs the equivalent Playwright code
|
|
10
|
+
playwright-cli open https://example.com/login
|
|
11
|
+
playwright-cli snapshot
|
|
12
|
+
playwright-cli fill e1 "user@example.com"
|
|
13
|
+
# Output: await page.getByRole('textbox', { name: 'Email' }).fill('user@example.com');
|
|
14
|
+
|
|
15
|
+
playwright-cli fill e2 "password123"
|
|
16
|
+
# Output: await page.getByRole('textbox', { name: 'Password' }).fill('password123');
|
|
17
|
+
|
|
18
|
+
playwright-cli click e3
|
|
19
|
+
# Output: await page.getByRole('button', { name: 'Sign In' }).click();
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## How It Works
|
|
23
|
+
|
|
24
|
+
Every action you perform with `playwright-cli` automatically generates the corresponding Playwright TypeScript code in the output. This code uses the same **role-based locators** that Playwright recommends for production tests.
|
|
25
|
+
|
|
26
|
+
The workflow:
|
|
27
|
+
|
|
28
|
+
1. **Open a page** → generates `await page.goto(url)`
|
|
29
|
+
2. **Take a snapshot** → see element refs and their accessible roles
|
|
30
|
+
3. **Interact** → each action generates one line of Playwright code
|
|
31
|
+
4. **Collect the code** → assemble generated lines into a complete test
|
|
32
|
+
|
|
33
|
+
## Recording a Flow
|
|
34
|
+
|
|
35
|
+
### Example: Login Flow
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
playwright-cli open https://example.com/login
|
|
39
|
+
# Ran Playwright code:
|
|
40
|
+
# await page.goto('https://example.com/login');
|
|
41
|
+
|
|
42
|
+
playwright-cli snapshot
|
|
43
|
+
# Output:
|
|
44
|
+
# e1 [textbox "Email"]
|
|
45
|
+
# e2 [textbox "Password"]
|
|
46
|
+
# e3 [button "Sign In"]
|
|
47
|
+
# e4 [link "Forgot password?"]
|
|
48
|
+
|
|
49
|
+
playwright-cli fill e1 "user@example.com"
|
|
50
|
+
# Ran Playwright code:
|
|
51
|
+
# await page.getByRole('textbox', { name: 'Email' }).fill('user@example.com');
|
|
52
|
+
|
|
53
|
+
playwright-cli fill e2 "password123"
|
|
54
|
+
# Ran Playwright code:
|
|
55
|
+
# await page.getByRole('textbox', { name: 'Password' }).fill('password123');
|
|
56
|
+
|
|
57
|
+
playwright-cli click e3
|
|
58
|
+
# Ran Playwright code:
|
|
59
|
+
# await page.getByRole('button', { name: 'Sign In' }).click();
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Assemble into a Test
|
|
63
|
+
|
|
64
|
+
Collect the generated code and wrap it in a Playwright test:
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
import { test, expect } from '@playwright/test';
|
|
68
|
+
|
|
69
|
+
test('user can log in', async ({ page }) => {
|
|
70
|
+
await page.goto('https://example.com/login');
|
|
71
|
+
await page.getByRole('textbox', { name: 'Email' }).fill('user@example.com');
|
|
72
|
+
await page.getByRole('textbox', { name: 'Password' }).fill('password123');
|
|
73
|
+
await page.getByRole('button', { name: 'Sign In' }).click();
|
|
74
|
+
|
|
75
|
+
// Add assertions (not generated — you add these)
|
|
76
|
+
await expect(page).toHaveURL(/.*dashboard/);
|
|
77
|
+
await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible();
|
|
78
|
+
});
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
```javascript
|
|
82
|
+
const { test, expect } = require('@playwright/test');
|
|
83
|
+
|
|
84
|
+
test('user can log in', async ({ page }) => {
|
|
85
|
+
await page.goto('https://example.com/login');
|
|
86
|
+
await page.getByRole('textbox', { name: 'Email' }).fill('user@example.com');
|
|
87
|
+
await page.getByRole('textbox', { name: 'Password' }).fill('password123');
|
|
88
|
+
await page.getByRole('button', { name: 'Sign In' }).click();
|
|
89
|
+
|
|
90
|
+
await expect(page).toHaveURL(/.*dashboard/);
|
|
91
|
+
await expect(page.getByRole('heading', { name: 'Dashboard' })).toBeVisible();
|
|
92
|
+
});
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Locator Strategies in Generated Code
|
|
96
|
+
|
|
97
|
+
The generated code uses Playwright's recommended locator hierarchy:
|
|
98
|
+
|
|
99
|
+
| Priority | Locator Type | Example | When used |
|
|
100
|
+
|----------|-------------|---------|-----------|
|
|
101
|
+
| 1 | Role-based | `getByRole('button', { name: 'Submit' })` | Elements with ARIA roles |
|
|
102
|
+
| 2 | Label-based | `getByLabel('Email')` | Form inputs with labels |
|
|
103
|
+
| 3 | Placeholder | `getByPlaceholder('Search...')` | Inputs with placeholder text |
|
|
104
|
+
| 4 | Text-based | `getByText('Welcome back')` | Static text content |
|
|
105
|
+
| 5 | Test ID | `getByTestId('submit-btn')` | Elements with `data-testid` |
|
|
106
|
+
|
|
107
|
+
These locators are **resilient to markup changes** — they mirror how users perceive the page rather than relying on CSS selectors or XPath.
|
|
108
|
+
|
|
109
|
+
## Recording Complex Flows
|
|
110
|
+
|
|
111
|
+
### E-Commerce Checkout
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
playwright-cli open https://shop.example.com
|
|
115
|
+
|
|
116
|
+
# Browse products
|
|
117
|
+
playwright-cli snapshot
|
|
118
|
+
playwright-cli click e5 # "Add to Cart" button
|
|
119
|
+
# await page.getByRole('button', { name: 'Add to Cart' }).click();
|
|
120
|
+
|
|
121
|
+
playwright-cli click e12 # Cart icon
|
|
122
|
+
# await page.getByRole('link', { name: 'Cart' }).click();
|
|
123
|
+
|
|
124
|
+
playwright-cli snapshot
|
|
125
|
+
playwright-cli click e3 # "Proceed to Checkout"
|
|
126
|
+
# await page.getByRole('button', { name: 'Proceed to Checkout' }).click();
|
|
127
|
+
|
|
128
|
+
# Shipping info
|
|
129
|
+
playwright-cli snapshot
|
|
130
|
+
playwright-cli fill e1 "Jane Doe"
|
|
131
|
+
# await page.getByRole('textbox', { name: 'Full Name' }).fill('Jane Doe');
|
|
132
|
+
playwright-cli fill e2 "123 Main St"
|
|
133
|
+
# await page.getByRole('textbox', { name: 'Address' }).fill('123 Main St');
|
|
134
|
+
playwright-cli fill e3 "Springfield"
|
|
135
|
+
# await page.getByRole('textbox', { name: 'City' }).fill('Springfield');
|
|
136
|
+
playwright-cli select e4 "IL"
|
|
137
|
+
# await page.getByRole('combobox', { name: 'State' }).selectOption('IL');
|
|
138
|
+
playwright-cli fill e5 "62701"
|
|
139
|
+
# await page.getByRole('textbox', { name: 'ZIP Code' }).fill('62701');
|
|
140
|
+
playwright-cli click e6 # "Continue to Payment"
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Multi-Step Wizard
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
playwright-cli open https://example.com/onboarding
|
|
147
|
+
|
|
148
|
+
# Step 1
|
|
149
|
+
playwright-cli snapshot
|
|
150
|
+
playwright-cli fill e1 "Acme Corp"
|
|
151
|
+
playwright-cli select e2 "technology"
|
|
152
|
+
playwright-cli click e3 # Next
|
|
153
|
+
|
|
154
|
+
# Step 2
|
|
155
|
+
playwright-cli snapshot
|
|
156
|
+
playwright-cli check e1 # Feature checkbox
|
|
157
|
+
playwright-cli check e3 # Another feature
|
|
158
|
+
playwright-cli click e5 # Next
|
|
159
|
+
|
|
160
|
+
# Step 3
|
|
161
|
+
playwright-cli snapshot
|
|
162
|
+
playwright-cli click e2 # "Complete Setup"
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Search with Dynamic Results
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
playwright-cli open https://example.com
|
|
169
|
+
playwright-cli snapshot
|
|
170
|
+
|
|
171
|
+
playwright-cli fill e1 "playwright testing"
|
|
172
|
+
# await page.getByRole('searchbox', { name: 'Search' }).fill('playwright testing');
|
|
173
|
+
|
|
174
|
+
playwright-cli press Enter
|
|
175
|
+
# await page.keyboard.press('Enter');
|
|
176
|
+
|
|
177
|
+
playwright-cli snapshot # See search results — new refs assigned
|
|
178
|
+
|
|
179
|
+
playwright-cli click e3 # First result
|
|
180
|
+
# await page.getByRole('link', { name: 'Getting Started with Playwright' }).click();
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## Adding Assertions
|
|
184
|
+
|
|
185
|
+
Generated code captures **actions** but not **assertions**. Always add assertions manually to create meaningful tests.
|
|
186
|
+
|
|
187
|
+
### Common Assertions to Add
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
// URL changed after navigation
|
|
191
|
+
await expect(page).toHaveURL(/.*dashboard/);
|
|
192
|
+
await expect(page).toHaveURL('https://example.com/success');
|
|
193
|
+
|
|
194
|
+
// Element is visible
|
|
195
|
+
await expect(page.getByRole('heading', { name: 'Welcome' })).toBeVisible();
|
|
196
|
+
await expect(page.getByText('Order confirmed')).toBeVisible();
|
|
197
|
+
|
|
198
|
+
// Element contains text
|
|
199
|
+
await expect(page.getByTestId('total')).toHaveText('$99.99');
|
|
200
|
+
await expect(page.getByRole('alert')).toContainText('saved');
|
|
201
|
+
|
|
202
|
+
// Element has specific attribute
|
|
203
|
+
await expect(page.getByRole('button', { name: 'Submit' })).toBeDisabled();
|
|
204
|
+
await expect(page.getByRole('checkbox')).toBeChecked();
|
|
205
|
+
|
|
206
|
+
// Element count
|
|
207
|
+
await expect(page.getByRole('listitem')).toHaveCount(5);
|
|
208
|
+
|
|
209
|
+
// Page title
|
|
210
|
+
await expect(page).toHaveTitle(/Dashboard/);
|
|
211
|
+
|
|
212
|
+
// Screenshot comparison
|
|
213
|
+
await expect(page).toHaveScreenshot('checkout.png');
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### Where to Place Assertions
|
|
217
|
+
|
|
218
|
+
```typescript
|
|
219
|
+
test('complete checkout flow', async ({ page }) => {
|
|
220
|
+
await page.goto('https://shop.example.com/products');
|
|
221
|
+
|
|
222
|
+
// Action: Add item to cart
|
|
223
|
+
await page.getByRole('button', { name: 'Add to Cart' }).click();
|
|
224
|
+
|
|
225
|
+
// Assertion: Cart badge updates
|
|
226
|
+
await expect(page.getByTestId('cart-count')).toHaveText('1');
|
|
227
|
+
|
|
228
|
+
// Action: Go to cart
|
|
229
|
+
await page.getByRole('link', { name: 'Cart' }).click();
|
|
230
|
+
|
|
231
|
+
// Assertion: Correct page
|
|
232
|
+
await expect(page).toHaveURL(/.*cart/);
|
|
233
|
+
await expect(page.getByRole('heading', { name: 'Your Cart' })).toBeVisible();
|
|
234
|
+
|
|
235
|
+
// Action: Proceed to checkout
|
|
236
|
+
await page.getByRole('button', { name: 'Checkout' }).click();
|
|
237
|
+
|
|
238
|
+
// Action: Fill shipping
|
|
239
|
+
await page.getByRole('textbox', { name: 'Full Name' }).fill('Jane Doe');
|
|
240
|
+
await page.getByRole('textbox', { name: 'Address' }).fill('123 Main St');
|
|
241
|
+
await page.getByRole('button', { name: 'Place Order' }).click();
|
|
242
|
+
|
|
243
|
+
// Assertion: Order confirmed
|
|
244
|
+
await expect(page.getByText('Order confirmed')).toBeVisible();
|
|
245
|
+
await expect(page.getByTestId('order-number')).toBeVisible();
|
|
246
|
+
});
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
## Best Practices
|
|
250
|
+
|
|
251
|
+
### 1. Explore Before Recording
|
|
252
|
+
|
|
253
|
+
Take a snapshot first to understand the page structure. Don't blindly click — know what elements are available:
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
playwright-cli open https://example.com
|
|
257
|
+
playwright-cli snapshot
|
|
258
|
+
# Review the elements, plan your flow, then start interacting
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### 2. Use Semantic Locators
|
|
262
|
+
|
|
263
|
+
The generated code already prefers role-based locators. If you see CSS selectors in generated output, consider filing an issue — role-based locators are more resilient:
|
|
264
|
+
|
|
265
|
+
```typescript
|
|
266
|
+
// Generated (good — semantic, resilient)
|
|
267
|
+
await page.getByRole('button', { name: 'Submit' }).click();
|
|
268
|
+
|
|
269
|
+
// Avoid writing manually (fragile — breaks if CSS changes)
|
|
270
|
+
await page.locator('#submit-btn').click();
|
|
271
|
+
await page.locator('.btn.btn-primary').click();
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### 3. Keep Tests Focused
|
|
275
|
+
|
|
276
|
+
One test = one user behavior. Don't record an entire session into a single test:
|
|
277
|
+
|
|
278
|
+
```typescript
|
|
279
|
+
// Good: Focused test
|
|
280
|
+
test('user can add item to cart', async ({ page }) => {
|
|
281
|
+
// Just the add-to-cart flow
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
test('user can complete checkout', async ({ page }) => {
|
|
285
|
+
// Just the checkout flow (use auth state to skip login)
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
// Bad: Monolith test
|
|
289
|
+
test('user journey', async ({ page }) => {
|
|
290
|
+
// Login + browse + add to cart + checkout + verify email...
|
|
291
|
+
});
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
### 4. Parameterize Test Data
|
|
295
|
+
|
|
296
|
+
Replace hardcoded values from the recording with variables or test data:
|
|
297
|
+
|
|
298
|
+
```typescript
|
|
299
|
+
// Instead of hardcoded values from recording
|
|
300
|
+
test('registration', async ({ page }) => {
|
|
301
|
+
const user = {
|
|
302
|
+
name: 'Jane Doe',
|
|
303
|
+
email: `test+${Date.now()}@example.com`,
|
|
304
|
+
password: 'SecurePass123!'
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
await page.goto('/register');
|
|
308
|
+
await page.getByRole('textbox', { name: 'Name' }).fill(user.name);
|
|
309
|
+
await page.getByRole('textbox', { name: 'Email' }).fill(user.email);
|
|
310
|
+
await page.getByRole('textbox', { name: 'Password' }).fill(user.password);
|
|
311
|
+
await page.getByRole('button', { name: 'Create Account' }).click();
|
|
312
|
+
|
|
313
|
+
await expect(page).toHaveURL(/.*welcome/);
|
|
314
|
+
});
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### 5. Add Wait Strategies for Flaky Steps
|
|
318
|
+
|
|
319
|
+
If a recorded action depends on async content loading, add explicit waits:
|
|
320
|
+
|
|
321
|
+
```typescript
|
|
322
|
+
// Before clicking a dynamically loaded element
|
|
323
|
+
await page.waitForSelector('.results-loaded');
|
|
324
|
+
await page.getByRole('link', { name: 'First Result' }).click();
|
|
325
|
+
|
|
326
|
+
// Or use Playwright's auto-waiting (preferred)
|
|
327
|
+
await expect(page.getByRole('link', { name: 'First Result' })).toBeVisible();
|
|
328
|
+
await page.getByRole('link', { name: 'First Result' }).click();
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
## Tips
|
|
332
|
+
|
|
333
|
+
- **Generated code is a starting point** — always review, add assertions, and parameterize before committing to your test suite
|
|
334
|
+
- **Re-snapshot after dynamic changes** — refs change when the DOM updates
|
|
335
|
+
- **Combine with `state-save`** — record a login flow once, save state, then start all other recordings from the authenticated state
|
|
336
|
+
- **Use `--filename` for snapshots** — save before/after snapshots for complex flows to help write assertions later
|