playwriter 0.0.30 → 0.0.33
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/dist/debugger-api.md +457 -0
- package/dist/debugger-examples-types.d.ts +7 -1
- package/dist/debugger-examples-types.d.ts.map +1 -1
- package/dist/editor-api.md +364 -0
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +25 -49
- package/dist/mcp.js.map +1 -1
- package/dist/styles-api.md +117 -0
- package/dist/styles-examples.d.ts +8 -0
- package/dist/styles-examples.d.ts.map +1 -0
- package/dist/styles-examples.js +64 -0
- package/dist/styles-examples.js.map +1 -0
- package/package.json +2 -2
- package/src/debugger-examples-types.ts +4 -1
- package/src/mcp.ts +25 -49
- package/src/prompt.md +4 -73
- package/src/styles-examples.ts +77 -0
- package/dist/debugger-examples.ts +0 -66
- package/dist/prompt.md +0 -328
- package/dist/resource.md +0 -436
package/dist/resource.md
DELETED
|
@@ -1,436 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
You can also find `getByRole` to get elements on the page.
|
|
4
|
-
|
|
5
|
-
```javascript
|
|
6
|
-
// Then use the information from the snapshot to click elements
|
|
7
|
-
// For example, if snapshot shows: { "role": "button", "name": "Sign In" }
|
|
8
|
-
await page.getByRole('button', { name: 'Sign In' }).click()
|
|
9
|
-
|
|
10
|
-
// For a link with { "role": "link", "name": "About" }
|
|
11
|
-
await page.getByRole('link', { name: 'About' }).click()
|
|
12
|
-
|
|
13
|
-
// For a textbox with { "role": "textbox", "name": "Email" }
|
|
14
|
-
await page.getByRole('textbox', { name: 'Email' }).fill('user@example.com')
|
|
15
|
-
|
|
16
|
-
// For a heading with { "role": "heading", "name": "Welcome to Example.com" }
|
|
17
|
-
const headingText = await page
|
|
18
|
-
.getByRole('heading', { name: 'Welcome to Example.com' })
|
|
19
|
-
.textContent()
|
|
20
|
-
console.log('Heading text:', headingText)
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
### Complete Example: Find and Click Elements
|
|
24
|
-
|
|
25
|
-
```javascript
|
|
26
|
-
await page.getByRole('button', { name: 'Submit Form' }).click()
|
|
27
|
-
console.log('Clicked submit button')
|
|
28
|
-
|
|
29
|
-
await page.waitForLoadState('networkidle')
|
|
30
|
-
console.log('Form submitted successfully')
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
## Core Concepts
|
|
34
|
-
|
|
35
|
-
### Page and Context
|
|
36
|
-
|
|
37
|
-
In Playwright, automation happens through a `page` object (representing a browser tab) and `context` (representing a browser session with cookies, storage, etc.).
|
|
38
|
-
|
|
39
|
-
```javascript
|
|
40
|
-
// Assuming you have page and context already available
|
|
41
|
-
const page = await context.newPage()
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
### Element Selection
|
|
45
|
-
|
|
46
|
-
Playwright uses locators to find elements. The examples below show various selection methods:
|
|
47
|
-
|
|
48
|
-
```javascript
|
|
49
|
-
// By role (recommended)
|
|
50
|
-
await page.getByRole('button', { name: 'Submit' })
|
|
51
|
-
|
|
52
|
-
// By text
|
|
53
|
-
await page.getByText('Welcome')
|
|
54
|
-
|
|
55
|
-
// By placeholder
|
|
56
|
-
await page.getByPlaceholder('Enter email')
|
|
57
|
-
|
|
58
|
-
// By label
|
|
59
|
-
await page.getByLabel('Username')
|
|
60
|
-
|
|
61
|
-
// By test id
|
|
62
|
-
await page.getByTestId('submit-button')
|
|
63
|
-
|
|
64
|
-
// By CSS selector
|
|
65
|
-
await page.locator('.my-class')
|
|
66
|
-
|
|
67
|
-
// By XPath
|
|
68
|
-
await page.locator('//div[@class="content"]')
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
## Navigation
|
|
72
|
-
|
|
73
|
-
### Navigate to URL
|
|
74
|
-
|
|
75
|
-
```javascript
|
|
76
|
-
await page.goto('https://example.com')
|
|
77
|
-
// Wait for network idle (no requests for 500ms)
|
|
78
|
-
await page.goto('https://example.com', { waitUntil: 'networkidle' })
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
### Navigate Back/Forward
|
|
82
|
-
|
|
83
|
-
```javascript
|
|
84
|
-
// Go back to previous page
|
|
85
|
-
await page.goBack()
|
|
86
|
-
|
|
87
|
-
// Go forward to next page
|
|
88
|
-
await page.goForward()
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
## Screenshots
|
|
92
|
-
|
|
93
|
-
### Take Screenshot
|
|
94
|
-
|
|
95
|
-
```javascript
|
|
96
|
-
// Screenshot of viewport
|
|
97
|
-
await page.screenshot({ path: 'screenshot.png' })
|
|
98
|
-
|
|
99
|
-
// Full page screenshot
|
|
100
|
-
await page.screenshot({ path: 'fullpage.png', fullPage: true })
|
|
101
|
-
|
|
102
|
-
// Screenshot of specific element
|
|
103
|
-
const element = await page.getByRole('button', { name: 'Submit' })
|
|
104
|
-
await element.screenshot({ path: 'button.png' })
|
|
105
|
-
|
|
106
|
-
// Screenshot with custom dimensions
|
|
107
|
-
await page.setViewportSize({ width: 1280, height: 720 })
|
|
108
|
-
await page.screenshot({ path: 'custom-size.png' })
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
## Mouse Interactions
|
|
112
|
-
|
|
113
|
-
### Click Elements
|
|
114
|
-
|
|
115
|
-
```javascript
|
|
116
|
-
// Click by role
|
|
117
|
-
await page.getByRole('button', { name: 'Submit' }).click()
|
|
118
|
-
|
|
119
|
-
// Click at coordinates
|
|
120
|
-
await page.mouse.click(100, 200)
|
|
121
|
-
|
|
122
|
-
// Double click
|
|
123
|
-
await page.getByText('Double click me').dblclick()
|
|
124
|
-
|
|
125
|
-
// Right click
|
|
126
|
-
await page.getByText('Right click me').click({ button: 'right' })
|
|
127
|
-
|
|
128
|
-
// Click with modifiers
|
|
129
|
-
await page.getByText('Ctrl click me').click({ modifiers: ['Control'] })
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
### Hover
|
|
133
|
-
|
|
134
|
-
```javascript
|
|
135
|
-
// Hover over element
|
|
136
|
-
await page.getByText('Hover me').hover()
|
|
137
|
-
|
|
138
|
-
// Hover at coordinates
|
|
139
|
-
await page.mouse.move(100, 200)
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
## Keyboard Input
|
|
143
|
-
|
|
144
|
-
### Type Text
|
|
145
|
-
|
|
146
|
-
```javascript
|
|
147
|
-
// Type into input field
|
|
148
|
-
await page.getByLabel('Email').fill('user@example.com')
|
|
149
|
-
|
|
150
|
-
// Type character by character (simulates real typing)
|
|
151
|
-
await page.getByLabel('Email').type('user@example.com', { delay: 100 })
|
|
152
|
-
|
|
153
|
-
// Clear and type
|
|
154
|
-
await page.getByLabel('Email').clear()
|
|
155
|
-
await page.getByLabel('Email').fill('new@example.com')
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
### Press Keys
|
|
159
|
-
|
|
160
|
-
```javascript
|
|
161
|
-
// Press single key
|
|
162
|
-
await page.keyboard.press('Enter')
|
|
163
|
-
|
|
164
|
-
// Press key combination
|
|
165
|
-
await page.keyboard.press('Control+A')
|
|
166
|
-
|
|
167
|
-
// Press sequence of keys
|
|
168
|
-
await page.keyboard.press('Tab')
|
|
169
|
-
await page.keyboard.press('Tab')
|
|
170
|
-
await page.keyboard.press('Space')
|
|
171
|
-
|
|
172
|
-
// Common key shortcuts
|
|
173
|
-
await page.keyboard.press('Control+C') // Copy
|
|
174
|
-
await page.keyboard.press('Control+V') // Paste
|
|
175
|
-
await page.keyboard.press('Control+Z') // Undo
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
## Form Interactions
|
|
179
|
-
|
|
180
|
-
### Select Dropdown Options
|
|
181
|
-
|
|
182
|
-
```javascript
|
|
183
|
-
// Select by value
|
|
184
|
-
await page.selectOption('select#country', 'us')
|
|
185
|
-
|
|
186
|
-
// Select by label
|
|
187
|
-
await page.selectOption('select#country', { label: 'United States' })
|
|
188
|
-
|
|
189
|
-
// Select multiple options
|
|
190
|
-
await page.selectOption('select#colors', ['red', 'blue', 'green'])
|
|
191
|
-
|
|
192
|
-
// Get selected option
|
|
193
|
-
const selectedValue = await page.$eval('select#country', (el) => el.value)
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
### Checkboxes and Radio Buttons
|
|
197
|
-
|
|
198
|
-
```javascript
|
|
199
|
-
// Check checkbox
|
|
200
|
-
await page.getByLabel('I agree').check()
|
|
201
|
-
|
|
202
|
-
// Uncheck checkbox
|
|
203
|
-
await page.getByLabel('Subscribe').uncheck()
|
|
204
|
-
|
|
205
|
-
// Check if checked
|
|
206
|
-
const isChecked = await page.getByLabel('I agree').isChecked()
|
|
207
|
-
|
|
208
|
-
// Select radio button
|
|
209
|
-
await page.getByLabel('Option A').check()
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
## JavaScript Evaluation
|
|
213
|
-
|
|
214
|
-
### Execute JavaScript in Page Context
|
|
215
|
-
|
|
216
|
-
```javascript
|
|
217
|
-
// Evaluate simple expression
|
|
218
|
-
const result = await page.evaluate(() => 2 + 2)
|
|
219
|
-
|
|
220
|
-
// Access page variables
|
|
221
|
-
const pageTitle = await page.evaluate(() => document.title)
|
|
222
|
-
|
|
223
|
-
// Modify page
|
|
224
|
-
await page.evaluate(() => {
|
|
225
|
-
document.body.style.backgroundColor = 'red'
|
|
226
|
-
})
|
|
227
|
-
|
|
228
|
-
// Pass arguments to page context
|
|
229
|
-
const sum = await page.evaluate(([a, b]) => a + b, [5, 3])
|
|
230
|
-
|
|
231
|
-
// Work with elements
|
|
232
|
-
const elementText = await page.evaluate(
|
|
233
|
-
(el) => el.textContent,
|
|
234
|
-
await page.getByRole('heading'),
|
|
235
|
-
)
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
### Execute JavaScript on Element
|
|
239
|
-
|
|
240
|
-
```javascript
|
|
241
|
-
// Get element property
|
|
242
|
-
const href = await page.getByRole('link').evaluate((el) => el.href)
|
|
243
|
-
|
|
244
|
-
// Modify element
|
|
245
|
-
await page.getByRole('button').evaluate((el) => {
|
|
246
|
-
el.style.backgroundColor = 'green'
|
|
247
|
-
el.disabled = true
|
|
248
|
-
})
|
|
249
|
-
|
|
250
|
-
// Scroll element into view
|
|
251
|
-
await page.getByText('Section').evaluate((el) => el.scrollIntoView())
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
## File Handling
|
|
255
|
-
|
|
256
|
-
### File Upload
|
|
257
|
-
|
|
258
|
-
```javascript
|
|
259
|
-
// Upload single file
|
|
260
|
-
await page.getByLabel('Upload file').setInputFiles('/path/to/file.pdf')
|
|
261
|
-
|
|
262
|
-
// Upload multiple files
|
|
263
|
-
await page
|
|
264
|
-
.getByLabel('Upload files')
|
|
265
|
-
.setInputFiles(['/path/to/file1.pdf', '/path/to/file2.pdf'])
|
|
266
|
-
|
|
267
|
-
// Clear file input
|
|
268
|
-
await page.getByLabel('Upload file').setInputFiles([])
|
|
269
|
-
|
|
270
|
-
// For file inputs, use setInputFiles directly on the input element
|
|
271
|
-
// Find the file input element (often hidden)
|
|
272
|
-
await page.locator('input[type="file"]').setInputFiles('/path/to/file.pdf')
|
|
273
|
-
```
|
|
274
|
-
|
|
275
|
-
## Network Monitoring
|
|
276
|
-
|
|
277
|
-
### Check Network Activity
|
|
278
|
-
|
|
279
|
-
```javascript
|
|
280
|
-
// Wait for a specific request to complete and get its response
|
|
281
|
-
const response = await page.waitForResponse(
|
|
282
|
-
(response) =>
|
|
283
|
-
response.url().includes('/api/user') && response.status() === 200,
|
|
284
|
-
)
|
|
285
|
-
|
|
286
|
-
// Get response data
|
|
287
|
-
const responseBody = await response.json()
|
|
288
|
-
console.log('API response:', responseBody)
|
|
289
|
-
|
|
290
|
-
// Wait for specific request
|
|
291
|
-
const request = await page.waitForRequest('**/api/data')
|
|
292
|
-
console.log('Request URL:', request.url())
|
|
293
|
-
console.log('Request method:', request.method())
|
|
294
|
-
|
|
295
|
-
// Get all resources loaded by the page
|
|
296
|
-
const resources = await page.evaluate(() =>
|
|
297
|
-
performance.getEntriesByType('resource').map((r) => ({
|
|
298
|
-
name: r.name,
|
|
299
|
-
duration: r.duration,
|
|
300
|
-
size: r.transferSize,
|
|
301
|
-
})),
|
|
302
|
-
)
|
|
303
|
-
console.log('Page resources:', resources)
|
|
304
|
-
```
|
|
305
|
-
|
|
306
|
-
## Console Messages
|
|
307
|
-
|
|
308
|
-
### Capture Console Output
|
|
309
|
-
|
|
310
|
-
```javascript
|
|
311
|
-
// Console messages are automatically captured by the MCP implementation
|
|
312
|
-
// Use the console_logs tool to retrieve them
|
|
313
|
-
|
|
314
|
-
// To trigger console messages from the page:
|
|
315
|
-
await page.evaluate(() => {
|
|
316
|
-
console.log('This message will be captured')
|
|
317
|
-
console.error('This error will be captured')
|
|
318
|
-
console.warn('This warning will be captured')
|
|
319
|
-
})
|
|
320
|
-
|
|
321
|
-
// Then use the console_logs MCP tool to retrieve all captured messages
|
|
322
|
-
// The tool provides filtering by type and pagination
|
|
323
|
-
```
|
|
324
|
-
|
|
325
|
-
## Waiting
|
|
326
|
-
|
|
327
|
-
### Wait for Conditions
|
|
328
|
-
|
|
329
|
-
```javascript
|
|
330
|
-
// Wait for element to appear
|
|
331
|
-
await page.waitForSelector('.success-message')
|
|
332
|
-
|
|
333
|
-
// Wait for element to disappear
|
|
334
|
-
await page.waitForSelector('.loading', { state: 'hidden' })
|
|
335
|
-
|
|
336
|
-
await page.waitForURL(/github\.com.*\/pull/)
|
|
337
|
-
await page.waitForURL(/\/new-org/)
|
|
338
|
-
|
|
339
|
-
// Wait for text to appear
|
|
340
|
-
await page.waitForFunction(
|
|
341
|
-
(text) => document.body.textContent.includes(text),
|
|
342
|
-
'Success!',
|
|
343
|
-
)
|
|
344
|
-
|
|
345
|
-
// Wait for navigation
|
|
346
|
-
await page.waitForURL('**/success')
|
|
347
|
-
|
|
348
|
-
// Wait for page load
|
|
349
|
-
await page.waitForLoadState('networkidle')
|
|
350
|
-
|
|
351
|
-
// Wait for specific condition
|
|
352
|
-
await page.waitForFunction(
|
|
353
|
-
(text) => document.querySelector('.status')?.textContent === text,
|
|
354
|
-
'Ready',
|
|
355
|
-
)
|
|
356
|
-
```
|
|
357
|
-
|
|
358
|
-
### Wait for Text to Appear or Disappear
|
|
359
|
-
|
|
360
|
-
```javascript
|
|
361
|
-
// Wait for specific text to appear on the page
|
|
362
|
-
await page.getByText('Loading complete').first().waitFor({ state: 'visible' })
|
|
363
|
-
console.log('Loading complete text is now visible')
|
|
364
|
-
|
|
365
|
-
// Wait for text to disappear from the page
|
|
366
|
-
await page.getByText('Loading...').first().waitFor({ state: 'hidden' })
|
|
367
|
-
console.log('Loading text has disappeared')
|
|
368
|
-
|
|
369
|
-
// Wait for multiple conditions sequentially
|
|
370
|
-
// First wait for loading to disappear, then wait for success message
|
|
371
|
-
await page.getByText('Processing...').first().waitFor({ state: 'hidden' })
|
|
372
|
-
await page.getByText('Success!').first().waitFor({ state: 'visible' })
|
|
373
|
-
console.log('Processing finished and success message appeared')
|
|
374
|
-
|
|
375
|
-
// Example: Wait for error message to disappear before proceeding
|
|
376
|
-
await page
|
|
377
|
-
.getByText('Error: Please try again')
|
|
378
|
-
.first()
|
|
379
|
-
.waitFor({ state: 'hidden' })
|
|
380
|
-
await page.getByRole('button', { name: 'Submit' }).click()
|
|
381
|
-
|
|
382
|
-
// Example: Wait for confirmation text after form submission
|
|
383
|
-
await page.getByRole('button', { name: 'Save' }).click()
|
|
384
|
-
await page
|
|
385
|
-
.getByText('Your changes have been saved')
|
|
386
|
-
.first()
|
|
387
|
-
.waitFor({ state: 'visible' })
|
|
388
|
-
console.log('Save confirmed')
|
|
389
|
-
|
|
390
|
-
// Example: Wait for dynamic content to load
|
|
391
|
-
await page.getByRole('button', { name: 'Load More' }).click()
|
|
392
|
-
await page
|
|
393
|
-
.getByText('Loading more items...')
|
|
394
|
-
.first()
|
|
395
|
-
.waitFor({ state: 'visible' })
|
|
396
|
-
await page
|
|
397
|
-
.getByText('Loading more items...')
|
|
398
|
-
.first()
|
|
399
|
-
.waitFor({ state: 'hidden' })
|
|
400
|
-
console.log('Additional items loaded')
|
|
401
|
-
```
|
|
402
|
-
|
|
403
|
-
### Work with Frames
|
|
404
|
-
|
|
405
|
-
```javascript
|
|
406
|
-
// Get frame by name
|
|
407
|
-
const frame = page.frame('frameName')
|
|
408
|
-
|
|
409
|
-
// Get frame by URL
|
|
410
|
-
const frame = page.frame({ url: /frame\.html/ })
|
|
411
|
-
|
|
412
|
-
// Interact with frame content
|
|
413
|
-
await frame.getByText('In Frame').click()
|
|
414
|
-
|
|
415
|
-
// Get all frames
|
|
416
|
-
const frames = page.frames()
|
|
417
|
-
```
|
|
418
|
-
|
|
419
|
-
## Best Practices
|
|
420
|
-
|
|
421
|
-
### Reliable Selectors
|
|
422
|
-
|
|
423
|
-
```javascript
|
|
424
|
-
// Prefer user-facing attributes
|
|
425
|
-
await page.getByRole('button', { name: 'Submit' })
|
|
426
|
-
await page.getByLabel('Email')
|
|
427
|
-
await page.getByPlaceholder('Search...')
|
|
428
|
-
await page.getByText('Welcome')
|
|
429
|
-
|
|
430
|
-
// Use test IDs for complex cases
|
|
431
|
-
await page.getByTestId('complex-component')
|
|
432
|
-
|
|
433
|
-
// Avoid brittle selectors
|
|
434
|
-
// Bad: await page.locator('.btn-3842');
|
|
435
|
-
// Good: await page.getByRole('button', { name: 'Submit' });
|
|
436
|
-
```
|