@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,553 @@
|
|
|
1
|
+
# Running Custom Playwright Code
|
|
2
|
+
|
|
3
|
+
> **When to use**: When CLI commands aren't sufficient — geolocation, permissions, media emulation, waiting strategies, iframe interaction, file downloads, clipboard access, complex multi-step workflows, or any scenario requiring the full Playwright API.
|
|
4
|
+
> **Prerequisites**: [core-commands.md](core-commands.md) for basic CLI usage
|
|
5
|
+
|
|
6
|
+
## Quick Reference
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
# Syntax: run-code accepts an async function with page as argument
|
|
10
|
+
playwright-cli run-code "async page => {
|
|
11
|
+
// Full Playwright API available here
|
|
12
|
+
// page.context() for browser context operations
|
|
13
|
+
// Return a value to see it in output
|
|
14
|
+
return await page.title();
|
|
15
|
+
}"
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Geolocation
|
|
19
|
+
|
|
20
|
+
Override the browser's reported location — essential for testing location-based features like store locators, delivery zones, and weather apps.
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
# Grant permission and set location to New York
|
|
24
|
+
playwright-cli run-code "async page => {
|
|
25
|
+
await page.context().grantPermissions(['geolocation']);
|
|
26
|
+
await page.context().setGeolocation({ latitude: 40.7128, longitude: -74.0060 });
|
|
27
|
+
}"
|
|
28
|
+
|
|
29
|
+
# London
|
|
30
|
+
playwright-cli run-code "async page => {
|
|
31
|
+
await page.context().grantPermissions(['geolocation']);
|
|
32
|
+
await page.context().setGeolocation({ latitude: 51.5074, longitude: -0.1278 });
|
|
33
|
+
}"
|
|
34
|
+
|
|
35
|
+
# San Francisco
|
|
36
|
+
playwright-cli run-code "async page => {
|
|
37
|
+
await page.context().grantPermissions(['geolocation']);
|
|
38
|
+
await page.context().setGeolocation({ latitude: 37.7749, longitude: -122.4194 });
|
|
39
|
+
}"
|
|
40
|
+
|
|
41
|
+
# Tokyo
|
|
42
|
+
playwright-cli run-code "async page => {
|
|
43
|
+
await page.context().grantPermissions(['geolocation']);
|
|
44
|
+
await page.context().setGeolocation({ latitude: 35.6762, longitude: 139.6503 });
|
|
45
|
+
}"
|
|
46
|
+
|
|
47
|
+
# Update location mid-session (simulates user moving)
|
|
48
|
+
playwright-cli run-code "async page => {
|
|
49
|
+
await page.context().setGeolocation({ latitude: 34.0522, longitude: -118.2437 });
|
|
50
|
+
}"
|
|
51
|
+
|
|
52
|
+
# Clear geolocation override
|
|
53
|
+
playwright-cli run-code "async page => {
|
|
54
|
+
await page.context().clearPermissions();
|
|
55
|
+
}"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Permissions
|
|
59
|
+
|
|
60
|
+
Control browser permission grants — notifications, camera, microphone, clipboard, etc.
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
# Grant multiple permissions
|
|
64
|
+
playwright-cli run-code "async page => {
|
|
65
|
+
await page.context().grantPermissions([
|
|
66
|
+
'geolocation',
|
|
67
|
+
'notifications',
|
|
68
|
+
'camera',
|
|
69
|
+
'microphone'
|
|
70
|
+
]);
|
|
71
|
+
}"
|
|
72
|
+
|
|
73
|
+
# Grant permissions for a specific origin only
|
|
74
|
+
playwright-cli run-code "async page => {
|
|
75
|
+
await page.context().grantPermissions(['clipboard-read', 'clipboard-write'], {
|
|
76
|
+
origin: 'https://example.com'
|
|
77
|
+
});
|
|
78
|
+
}"
|
|
79
|
+
|
|
80
|
+
# Revoke all permissions
|
|
81
|
+
playwright-cli run-code "async page => {
|
|
82
|
+
await page.context().clearPermissions();
|
|
83
|
+
}"
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Available permissions: `geolocation`, `notifications`, `camera`, `microphone`, `clipboard-read`, `clipboard-write`, `payment-handler`, `midi`, `midi-sysex`, `ambient-light-sensor`, `accelerometer`, `gyroscope`, `magnetometer`, `accessibility-events`, `background-sync`
|
|
87
|
+
|
|
88
|
+
## Media Emulation
|
|
89
|
+
|
|
90
|
+
Test how your app behaves under different media conditions — dark mode, reduced motion, print layout.
|
|
91
|
+
|
|
92
|
+
### Color Scheme
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
# Dark mode
|
|
96
|
+
playwright-cli run-code "async page => {
|
|
97
|
+
await page.emulateMedia({ colorScheme: 'dark' });
|
|
98
|
+
}"
|
|
99
|
+
|
|
100
|
+
# Light mode
|
|
101
|
+
playwright-cli run-code "async page => {
|
|
102
|
+
await page.emulateMedia({ colorScheme: 'light' });
|
|
103
|
+
}"
|
|
104
|
+
|
|
105
|
+
# System preference (no override)
|
|
106
|
+
playwright-cli run-code "async page => {
|
|
107
|
+
await page.emulateMedia({ colorScheme: 'no-preference' });
|
|
108
|
+
}"
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Reduced Motion
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
# Simulate prefers-reduced-motion: reduce
|
|
115
|
+
playwright-cli run-code "async page => {
|
|
116
|
+
await page.emulateMedia({ reducedMotion: 'reduce' });
|
|
117
|
+
}"
|
|
118
|
+
|
|
119
|
+
# Reset to no preference
|
|
120
|
+
playwright-cli run-code "async page => {
|
|
121
|
+
await page.emulateMedia({ reducedMotion: 'no-preference' });
|
|
122
|
+
}"
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Forced Colors (High Contrast)
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
playwright-cli run-code "async page => {
|
|
129
|
+
await page.emulateMedia({ forcedColors: 'active' });
|
|
130
|
+
}"
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Print Media
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
# Emulate print stylesheet (useful before taking PDF)
|
|
137
|
+
playwright-cli run-code "async page => {
|
|
138
|
+
await page.emulateMedia({ media: 'print' });
|
|
139
|
+
}"
|
|
140
|
+
|
|
141
|
+
# Reset to screen
|
|
142
|
+
playwright-cli run-code "async page => {
|
|
143
|
+
await page.emulateMedia({ media: 'screen' });
|
|
144
|
+
}"
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### Combine Multiple Emulations
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
playwright-cli run-code "async page => {
|
|
151
|
+
await page.emulateMedia({
|
|
152
|
+
colorScheme: 'dark',
|
|
153
|
+
reducedMotion: 'reduce',
|
|
154
|
+
forcedColors: 'none'
|
|
155
|
+
});
|
|
156
|
+
}"
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Locale and Timezone
|
|
160
|
+
|
|
161
|
+
Override browser locale and timezone to test internationalization:
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
# Set locale (affects number formatting, date display, etc.)
|
|
165
|
+
playwright-cli run-code "async page => {
|
|
166
|
+
// Locale is set at context creation; for existing context, use evaluate
|
|
167
|
+
return await page.evaluate(() => navigator.language);
|
|
168
|
+
}"
|
|
169
|
+
|
|
170
|
+
# For new contexts, set locale and timezone at open time:
|
|
171
|
+
# playwright-cli open --config=locale-config.json
|
|
172
|
+
# where locale-config.json contains: { "locale": "de-DE", "timezoneId": "Europe/Berlin" }
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Wait Strategies
|
|
176
|
+
|
|
177
|
+
When the page needs time to load, render, or settle after an action.
|
|
178
|
+
|
|
179
|
+
### Wait for Load States
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
# Wait for all network requests to finish
|
|
183
|
+
playwright-cli run-code "async page => {
|
|
184
|
+
await page.waitForLoadState('networkidle');
|
|
185
|
+
}"
|
|
186
|
+
|
|
187
|
+
# Wait for DOM content loaded
|
|
188
|
+
playwright-cli run-code "async page => {
|
|
189
|
+
await page.waitForLoadState('domcontentloaded');
|
|
190
|
+
}"
|
|
191
|
+
|
|
192
|
+
# Wait for full load (including images, stylesheets)
|
|
193
|
+
playwright-cli run-code "async page => {
|
|
194
|
+
await page.waitForLoadState('load');
|
|
195
|
+
}"
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Wait for Elements
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
# Wait for a loading spinner to disappear
|
|
202
|
+
playwright-cli run-code "async page => {
|
|
203
|
+
await page.waitForSelector('.loading-spinner', { state: 'hidden' });
|
|
204
|
+
}"
|
|
205
|
+
|
|
206
|
+
# Wait for content to appear
|
|
207
|
+
playwright-cli run-code "async page => {
|
|
208
|
+
await page.waitForSelector('.search-results', { state: 'visible', timeout: 10000 });
|
|
209
|
+
}"
|
|
210
|
+
|
|
211
|
+
# Wait for element to be removed from DOM entirely
|
|
212
|
+
playwright-cli run-code "async page => {
|
|
213
|
+
await page.waitForSelector('.skeleton-loader', { state: 'detached' });
|
|
214
|
+
}"
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### Wait for URL Changes
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
playwright-cli run-code "async page => {
|
|
221
|
+
await page.waitForURL('**/dashboard');
|
|
222
|
+
}"
|
|
223
|
+
|
|
224
|
+
playwright-cli run-code "async page => {
|
|
225
|
+
await page.waitForURL(/.*\/order\/\d+/);
|
|
226
|
+
}"
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
### Wait for Custom Conditions
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
# Wait for a JavaScript variable to be set
|
|
233
|
+
playwright-cli run-code "async page => {
|
|
234
|
+
await page.waitForFunction(() => window.appReady === true);
|
|
235
|
+
}"
|
|
236
|
+
|
|
237
|
+
# Wait for specific number of elements
|
|
238
|
+
playwright-cli run-code "async page => {
|
|
239
|
+
await page.waitForFunction(() => document.querySelectorAll('.item').length >= 10);
|
|
240
|
+
}"
|
|
241
|
+
|
|
242
|
+
# Wait with polling
|
|
243
|
+
playwright-cli run-code "async page => {
|
|
244
|
+
await page.waitForFunction(
|
|
245
|
+
() => document.querySelector('.status')?.textContent === 'Complete',
|
|
246
|
+
{ polling: 500, timeout: 30000 }
|
|
247
|
+
);
|
|
248
|
+
}"
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### Wait for Network Requests
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
# Wait for a specific API call to complete
|
|
255
|
+
playwright-cli run-code "async page => {
|
|
256
|
+
const responsePromise = page.waitForResponse('**/api/users');
|
|
257
|
+
await page.click('button#load-users');
|
|
258
|
+
const response = await responsePromise;
|
|
259
|
+
return { status: response.status(), url: response.url() };
|
|
260
|
+
}"
|
|
261
|
+
|
|
262
|
+
# Wait for a request to be made
|
|
263
|
+
playwright-cli run-code "async page => {
|
|
264
|
+
const requestPromise = page.waitForRequest('**/api/submit');
|
|
265
|
+
await page.click('button#submit');
|
|
266
|
+
const request = await requestPromise;
|
|
267
|
+
return request.postDataJSON();
|
|
268
|
+
}"
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
## Frames and Iframes
|
|
272
|
+
|
|
273
|
+
Interact with content inside iframes:
|
|
274
|
+
|
|
275
|
+
```bash
|
|
276
|
+
# Click a button inside an iframe
|
|
277
|
+
playwright-cli run-code "async page => {
|
|
278
|
+
const frame = page.locator('iframe#my-iframe').contentFrame();
|
|
279
|
+
await frame.locator('button.submit').click();
|
|
280
|
+
}"
|
|
281
|
+
|
|
282
|
+
# Fill a form inside an iframe
|
|
283
|
+
playwright-cli run-code "async page => {
|
|
284
|
+
const frame = page.locator('iframe[name=\"checkout\"]').contentFrame();
|
|
285
|
+
await frame.locator('input[name=\"card-number\"]').fill('4111111111111111');
|
|
286
|
+
await frame.locator('input[name=\"expiry\"]').fill('12/25');
|
|
287
|
+
await frame.locator('input[name=\"cvc\"]').fill('123');
|
|
288
|
+
}"
|
|
289
|
+
|
|
290
|
+
# Get all frame URLs
|
|
291
|
+
playwright-cli run-code "async page => {
|
|
292
|
+
const frames = page.frames();
|
|
293
|
+
return frames.map(f => ({ name: f.name(), url: f.url() }));
|
|
294
|
+
}"
|
|
295
|
+
|
|
296
|
+
# Nested iframes
|
|
297
|
+
playwright-cli run-code "async page => {
|
|
298
|
+
const outerFrame = page.locator('iframe#outer').contentFrame();
|
|
299
|
+
const innerFrame = outerFrame.locator('iframe#inner').contentFrame();
|
|
300
|
+
await innerFrame.locator('button').click();
|
|
301
|
+
}"
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
## File Downloads
|
|
305
|
+
|
|
306
|
+
```bash
|
|
307
|
+
# Trigger download and save the file
|
|
308
|
+
playwright-cli run-code "async page => {
|
|
309
|
+
const [download] = await Promise.all([
|
|
310
|
+
page.waitForEvent('download'),
|
|
311
|
+
page.click('a.download-link')
|
|
312
|
+
]);
|
|
313
|
+
const filename = download.suggestedFilename();
|
|
314
|
+
await download.saveAs('./downloads/' + filename);
|
|
315
|
+
return 'Downloaded: ' + filename;
|
|
316
|
+
}"
|
|
317
|
+
|
|
318
|
+
# Download with custom path
|
|
319
|
+
playwright-cli run-code "async page => {
|
|
320
|
+
const [download] = await Promise.all([
|
|
321
|
+
page.waitForEvent('download'),
|
|
322
|
+
page.getByRole('button', { name: 'Export CSV' }).click()
|
|
323
|
+
]);
|
|
324
|
+
await download.saveAs('/tmp/export.csv');
|
|
325
|
+
return 'Saved to /tmp/export.csv';
|
|
326
|
+
}"
|
|
327
|
+
|
|
328
|
+
# Get download URL without saving
|
|
329
|
+
playwright-cli run-code "async page => {
|
|
330
|
+
const [download] = await Promise.all([
|
|
331
|
+
page.waitForEvent('download'),
|
|
332
|
+
page.click('#download-btn')
|
|
333
|
+
]);
|
|
334
|
+
return download.url();
|
|
335
|
+
}"
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
## Clipboard
|
|
339
|
+
|
|
340
|
+
```bash
|
|
341
|
+
# Read clipboard content
|
|
342
|
+
playwright-cli run-code "async page => {
|
|
343
|
+
await page.context().grantPermissions(['clipboard-read']);
|
|
344
|
+
return await page.evaluate(() => navigator.clipboard.readText());
|
|
345
|
+
}"
|
|
346
|
+
|
|
347
|
+
# Write to clipboard
|
|
348
|
+
playwright-cli run-code "async page => {
|
|
349
|
+
await page.evaluate(text => navigator.clipboard.writeText(text), 'Hello clipboard!');
|
|
350
|
+
}"
|
|
351
|
+
|
|
352
|
+
# Copy text from an element to clipboard
|
|
353
|
+
playwright-cli run-code "async page => {
|
|
354
|
+
const text = await page.locator('.api-key').textContent();
|
|
355
|
+
await page.evaluate(t => navigator.clipboard.writeText(t), text);
|
|
356
|
+
return 'Copied: ' + text;
|
|
357
|
+
}"
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
## Page Information
|
|
361
|
+
|
|
362
|
+
```bash
|
|
363
|
+
# Page title
|
|
364
|
+
playwright-cli run-code "async page => {
|
|
365
|
+
return await page.title();
|
|
366
|
+
}"
|
|
367
|
+
|
|
368
|
+
# Current URL
|
|
369
|
+
playwright-cli run-code "async page => {
|
|
370
|
+
return page.url();
|
|
371
|
+
}"
|
|
372
|
+
|
|
373
|
+
# Full page HTML content
|
|
374
|
+
playwright-cli run-code "async page => {
|
|
375
|
+
return await page.content();
|
|
376
|
+
}"
|
|
377
|
+
|
|
378
|
+
# Viewport size
|
|
379
|
+
playwright-cli run-code "async page => {
|
|
380
|
+
return page.viewportSize();
|
|
381
|
+
}"
|
|
382
|
+
|
|
383
|
+
# Browser information
|
|
384
|
+
playwright-cli run-code "async page => {
|
|
385
|
+
return await page.evaluate(() => ({
|
|
386
|
+
userAgent: navigator.userAgent,
|
|
387
|
+
language: navigator.language,
|
|
388
|
+
languages: navigator.languages,
|
|
389
|
+
cookiesEnabled: navigator.cookieEnabled,
|
|
390
|
+
onLine: navigator.onLine,
|
|
391
|
+
platform: navigator.platform,
|
|
392
|
+
screenSize: { width: screen.width, height: screen.height }
|
|
393
|
+
}));
|
|
394
|
+
}"
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
## JavaScript Execution
|
|
398
|
+
|
|
399
|
+
```bash
|
|
400
|
+
# Execute and return result
|
|
401
|
+
playwright-cli run-code "async page => {
|
|
402
|
+
return await page.evaluate(() => {
|
|
403
|
+
return {
|
|
404
|
+
title: document.title,
|
|
405
|
+
url: window.location.href,
|
|
406
|
+
elementCount: document.querySelectorAll('*').length,
|
|
407
|
+
scripts: document.querySelectorAll('script').length
|
|
408
|
+
};
|
|
409
|
+
});
|
|
410
|
+
}"
|
|
411
|
+
|
|
412
|
+
# Pass arguments to evaluate
|
|
413
|
+
playwright-cli run-code "async page => {
|
|
414
|
+
const selector = '.product-card';
|
|
415
|
+
const count = await page.evaluate(
|
|
416
|
+
sel => document.querySelectorAll(sel).length,
|
|
417
|
+
selector
|
|
418
|
+
);
|
|
419
|
+
return count + ' products found';
|
|
420
|
+
}"
|
|
421
|
+
|
|
422
|
+
# Modify the DOM
|
|
423
|
+
playwright-cli run-code "async page => {
|
|
424
|
+
await page.evaluate(() => {
|
|
425
|
+
document.querySelector('.banner')?.remove();
|
|
426
|
+
document.body.style.zoom = '80%';
|
|
427
|
+
});
|
|
428
|
+
}"
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
## Error Handling
|
|
432
|
+
|
|
433
|
+
```bash
|
|
434
|
+
# Try-catch for optional elements
|
|
435
|
+
playwright-cli run-code "async page => {
|
|
436
|
+
try {
|
|
437
|
+
await page.click('.cookie-consent-accept', { timeout: 2000 });
|
|
438
|
+
return 'Cookie banner dismissed';
|
|
439
|
+
} catch (e) {
|
|
440
|
+
return 'No cookie banner found';
|
|
441
|
+
}
|
|
442
|
+
}"
|
|
443
|
+
|
|
444
|
+
# Retry pattern
|
|
445
|
+
playwright-cli run-code "async page => {
|
|
446
|
+
for (let attempt = 1; attempt <= 3; attempt++) {
|
|
447
|
+
try {
|
|
448
|
+
await page.click('.flaky-button', { timeout: 3000 });
|
|
449
|
+
return 'Clicked on attempt ' + attempt;
|
|
450
|
+
} catch (e) {
|
|
451
|
+
if (attempt === 3) throw e;
|
|
452
|
+
await page.waitForTimeout(1000);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
}"
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
## Complex Workflows
|
|
459
|
+
|
|
460
|
+
### Login and Save Authentication State
|
|
461
|
+
|
|
462
|
+
```bash
|
|
463
|
+
playwright-cli run-code "async page => {
|
|
464
|
+
await page.goto('https://example.com/login');
|
|
465
|
+
await page.fill('input[name=email]', 'user@example.com');
|
|
466
|
+
await page.fill('input[name=password]', 'secret');
|
|
467
|
+
await page.click('button[type=submit]');
|
|
468
|
+
await page.waitForURL('**/dashboard');
|
|
469
|
+
await page.context().storageState({ path: 'auth.json' });
|
|
470
|
+
return 'Login successful, state saved to auth.json';
|
|
471
|
+
}"
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
### Scrape Data from Multiple Pages
|
|
475
|
+
|
|
476
|
+
```bash
|
|
477
|
+
playwright-cli run-code "async page => {
|
|
478
|
+
const results = [];
|
|
479
|
+
for (let i = 1; i <= 5; i++) {
|
|
480
|
+
await page.goto(\`https://example.com/products?page=\${i}\`);
|
|
481
|
+
await page.waitForSelector('.product-card');
|
|
482
|
+
const items = await page.locator('.product-card').evaluateAll(cards =>
|
|
483
|
+
cards.map(card => ({
|
|
484
|
+
name: card.querySelector('.title')?.textContent?.trim(),
|
|
485
|
+
price: card.querySelector('.price')?.textContent?.trim(),
|
|
486
|
+
rating: card.querySelector('.rating')?.getAttribute('data-value')
|
|
487
|
+
}))
|
|
488
|
+
);
|
|
489
|
+
results.push(...items);
|
|
490
|
+
}
|
|
491
|
+
return JSON.stringify(results, null, 2);
|
|
492
|
+
}"
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
### Fill Multi-Step Form (Wizard)
|
|
496
|
+
|
|
497
|
+
```bash
|
|
498
|
+
playwright-cli run-code "async page => {
|
|
499
|
+
// Step 1: Personal info
|
|
500
|
+
await page.fill('#firstName', 'Jane');
|
|
501
|
+
await page.fill('#lastName', 'Doe');
|
|
502
|
+
await page.fill('#email', 'jane@example.com');
|
|
503
|
+
await page.click('button:text(\"Next\")');
|
|
504
|
+
|
|
505
|
+
// Step 2: Address
|
|
506
|
+
await page.waitForSelector('#street');
|
|
507
|
+
await page.fill('#street', '123 Main St');
|
|
508
|
+
await page.fill('#city', 'Springfield');
|
|
509
|
+
await page.selectOption('#state', 'IL');
|
|
510
|
+
await page.fill('#zip', '62701');
|
|
511
|
+
await page.click('button:text(\"Next\")');
|
|
512
|
+
|
|
513
|
+
// Step 3: Confirm and submit
|
|
514
|
+
await page.waitForSelector('.review-summary');
|
|
515
|
+
await page.click('button:text(\"Submit\")');
|
|
516
|
+
await page.waitForURL('**/confirmation');
|
|
517
|
+
|
|
518
|
+
return 'Form submitted successfully';
|
|
519
|
+
}"
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
### Infinite Scroll Data Extraction
|
|
523
|
+
|
|
524
|
+
```bash
|
|
525
|
+
playwright-cli run-code "async page => {
|
|
526
|
+
await page.goto('https://example.com/feed');
|
|
527
|
+
const items = [];
|
|
528
|
+
|
|
529
|
+
while (items.length < 50) {
|
|
530
|
+
const newItems = await page.locator('.feed-item').evaluateAll(
|
|
531
|
+
els => els.map(el => el.textContent.trim())
|
|
532
|
+
);
|
|
533
|
+
items.push(...newItems.filter(item => !items.includes(item)));
|
|
534
|
+
|
|
535
|
+
await page.evaluate(() => window.scrollTo(0, document.body.scrollHeight));
|
|
536
|
+
await page.waitForTimeout(1000);
|
|
537
|
+
|
|
538
|
+
// Check if we've reached the end
|
|
539
|
+
const hasMore = await page.locator('.load-more').isVisible().catch(() => false);
|
|
540
|
+
if (!hasMore && newItems.length === items.length) break;
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
return items.slice(0, 50);
|
|
544
|
+
}"
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
## Tips
|
|
548
|
+
|
|
549
|
+
- **Return values**: Always `return` data from `run-code` to see it in the CLI output
|
|
550
|
+
- **`page.context()`**: Access browser context for permissions, cookies, storage, geolocation
|
|
551
|
+
- **Error messages**: Playwright errors include element snapshots and call logs — read them carefully
|
|
552
|
+
- **Combine with CLI**: Use `run-code` for setup (permissions, routes) then CLI commands for interaction
|
|
553
|
+
- **Async/await**: All Playwright operations are async — always `await` them
|