craftdriver 1.0.3 → 1.1.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/CHANGELOG.md +25 -3
- package/README.md +80 -160
- package/dist/lib/browser.d.ts +22 -0
- package/dist/lib/browser.d.ts.map +1 -1
- package/dist/lib/browser.js +14 -1
- package/dist/lib/browser.js.map +1 -1
- package/dist/lib/chrome.d.ts +15 -3
- package/dist/lib/chrome.d.ts.map +1 -1
- package/dist/lib/chrome.js +4 -2
- package/dist/lib/chrome.js.map +1 -1
- package/dist/lib/driver.d.ts.map +1 -1
- package/dist/lib/driver.js +2 -0
- package/dist/lib/driver.js.map +1 -1
- package/dist/lib/driverManager.d.ts +31 -0
- package/dist/lib/driverManager.d.ts.map +1 -1
- package/dist/lib/driverManager.js +165 -31
- package/dist/lib/driverManager.js.map +1 -1
- package/dist/lib/firefox.d.ts +4 -3
- package/dist/lib/firefox.d.ts.map +1 -1
- package/dist/lib/firefox.js.map +1 -1
- package/dist/lib/http.d.ts +1 -1
- package/dist/lib/http.d.ts.map +1 -1
- package/dist/lib/http.js +35 -7
- package/dist/lib/http.js.map +1 -1
- package/dist/lib/timing.d.ts +13 -0
- package/dist/lib/timing.d.ts.map +1 -1
- package/dist/lib/timing.js +13 -0
- package/dist/lib/timing.js.map +1 -1
- package/dist/lib/types.d.ts +2 -0
- package/dist/lib/types.d.ts.map +1 -1
- package/docs/agents.md +92 -0
- package/docs/api-reference.md +108 -46
- package/docs/browser-api.md +2 -1
- package/docs/browser-context.md +4 -7
- package/docs/browser-logs.md +158 -0
- package/docs/cli.md +26 -26
- package/docs/driver-configuration.md +103 -4
- package/docs/element-api.md +37 -6
- package/docs/emulation.md +6 -2
- package/docs/index.md +64 -0
- package/docs/keyboard-mouse.md +28 -10
- package/docs/mobile-emulation.md +5 -2
- package/docs/network.md +203 -0
- package/docs/public/craftdriver-mark.svg +15 -0
- package/docs/public/social-card.svg +27 -0
- package/docs/recipes/accessibility-gate.md +53 -0
- package/docs/recipes/console-error-gate.md +57 -0
- package/docs/recipes/file-upload-download.md +58 -0
- package/docs/recipes/login-once-reuse-session.md +73 -0
- package/docs/recipes/mobile-flow-with-network-and-logs.md +57 -0
- package/docs/recipes/mock-api-and-assert-network.md +60 -0
- package/docs/recipes/multi-user-contexts.md +58 -0
- package/docs/recipes/trace-failing-test.md +64 -0
- package/docs/recipes/virtual-clock-time-sensitive-ui.md +60 -0
- package/docs/recipes/vitest-browser-lifecycle.md +56 -0
- package/docs/recipes.md +33 -0
- package/docs/selectors.md +22 -1
- package/docs/session-management.md +18 -1
- package/docs/standards.md +40 -0
- package/docs/why-craftdriver.md +28 -0
- package/docs/zero-config-drivers.md +64 -0
- package/package.json +19 -5
- package/docs/bidi-features.md +0 -470
package/docs/bidi-features.md
DELETED
|
@@ -1,470 +0,0 @@
|
|
|
1
|
-
# BiDi Features
|
|
2
|
-
|
|
3
|
-
CraftDriver is built on the WebDriver BiDi protocol, giving you network interception, browser log capture, and precise load-state detection out of the box.
|
|
4
|
-
|
|
5
|
-
> **Browser support in craftdriver:** Chrome, Chromium, and Firefox.
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## Feature matrix
|
|
10
|
-
|
|
11
|
-
Most of craftdriver works against both BiDi and Classic WebDriver. The
|
|
12
|
-
features below are **BiDi-only** — they require `enableBiDi: true`
|
|
13
|
-
(the default) and a browser that successfully negotiates a BiDi
|
|
14
|
-
WebSocket. Calling them after BiDi negotiation failed throws a clear
|
|
15
|
-
error; gate them with `browser.isBiDiEnabled()` if your code may run
|
|
16
|
-
in Classic mode.
|
|
17
|
-
|
|
18
|
-
| Capability | API | BiDi-only? |
|
|
19
|
-
|---|---|---|
|
|
20
|
-
| Network mocking / interception | [`browser.network.*`](#network-mocking) | yes |
|
|
21
|
-
| Console & error log capture | [`browser.logs.*`](#console--error-logs) | yes |
|
|
22
|
-
| `waitForLoadState('load' \| 'domcontentloaded' \| 'networkidle')` | `browser.waitForLoadState()` | no — event-driven over BiDi, polls `document.readyState` in Classic |
|
|
23
|
-
| `navigateTo(..., { waitUntil })` real load events | `browser.navigateTo()` | no — event-driven over BiDi, best-effort settle timer in Classic |
|
|
24
|
-
| `waitForRequest()` / `waitForResponse()` | `browser.waitForRequest()` / `waitForResponse()` | yes |
|
|
25
|
-
| Init scripts (run before any page script) | `browser.addInitScript()` | yes |
|
|
26
|
-
| Open new tab / popup | `browser.openPage()` | yes |
|
|
27
|
-
| Capture popup opened by an action | `browser.waitForPage()` | yes |
|
|
28
|
-
| Isolated user contexts (incognito profiles) | `browser.newContext()` / `browser.contexts()` | yes |
|
|
29
|
-
| Downloads | `browser.waitForDownload()` | yes |
|
|
30
|
-
| Tracing | `browser.startTrace()` / `browser.stopTrace()` | yes |
|
|
31
|
-
| Storage state (cookies + localStorage) | `browser.storage.*`, `saveState()`, `loadState()` | no — works in Classic too |
|
|
32
|
-
| Element actions, locators, assertions, frames, dialogs, screenshots, keyboard/mouse, mobile emulation | rest of the API | no — works in Classic too |
|
|
33
|
-
|
|
34
|
-
---
|
|
35
|
-
|
|
36
|
-
## Network Mocking
|
|
37
|
-
|
|
38
|
-
Intercept and mock network requests using `browser.network`.
|
|
39
|
-
|
|
40
|
-
### mock(pattern, response)
|
|
41
|
-
|
|
42
|
-
Return a mocked response for matching requests. Response can be an object or a function for dynamic mocking.
|
|
43
|
-
|
|
44
|
-
```typescript
|
|
45
|
-
// Static mock
|
|
46
|
-
await browser.network.mock('**/api/users', {
|
|
47
|
-
status: 200,
|
|
48
|
-
body: { users: [{ id: 1, name: 'Test User' }] },
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
// Dynamic mock - response based on request
|
|
52
|
-
await browser.network.mock('**/api/items/*', (request) => {
|
|
53
|
-
const id = request.url.split('/').pop();
|
|
54
|
-
return {
|
|
55
|
-
status: 200,
|
|
56
|
-
body: { id, name: `Item ${id}`, price: 9.99 },
|
|
57
|
-
};
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
// Navigate - API calls will return mocked data
|
|
61
|
-
await browser.navigateTo('https://example.com/dashboard');
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
### block(pattern)
|
|
65
|
-
|
|
66
|
-
Block all requests matching the pattern.
|
|
67
|
-
|
|
68
|
-
```typescript
|
|
69
|
-
// Block analytics and tracking
|
|
70
|
-
await browser.network.block('**/analytics/**');
|
|
71
|
-
await browser.network.block('**/tracking/**');
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
### setExtraHeaders(headers)
|
|
75
|
-
|
|
76
|
-
Add extra headers to all requests.
|
|
77
|
-
|
|
78
|
-
```typescript
|
|
79
|
-
await browser.network.setExtraHeaders({
|
|
80
|
-
'X-Test-Mode': 'true',
|
|
81
|
-
Authorization: 'Bearer test-token',
|
|
82
|
-
});
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
### setCacheBehavior(behavior)
|
|
86
|
-
|
|
87
|
-
Control browser caching behavior.
|
|
88
|
-
|
|
89
|
-
```typescript
|
|
90
|
-
// Bypass cache - always fetch fresh
|
|
91
|
-
await browser.network.setCacheBehavior('bypass');
|
|
92
|
-
|
|
93
|
-
// Use default caching
|
|
94
|
-
await browser.network.setCacheBehavior('default');
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
### intercept(pattern, handler)
|
|
98
|
-
|
|
99
|
-
Intercept requests and provide custom responses. The handler receives request details and can return a mock response.
|
|
100
|
-
|
|
101
|
-
```typescript
|
|
102
|
-
let capturedRequests: string[] = [];
|
|
103
|
-
|
|
104
|
-
const interceptId = await browser.network.intercept('**/api/**', async (request) => {
|
|
105
|
-
// Log request details
|
|
106
|
-
capturedRequests.push(`${request.method} ${request.url}`);
|
|
107
|
-
|
|
108
|
-
// Return a mock response
|
|
109
|
-
return {
|
|
110
|
-
status: 200,
|
|
111
|
-
body: { intercepted: true, originalUrl: request.url },
|
|
112
|
-
};
|
|
113
|
-
});
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
### removeIntercept(interceptId)
|
|
117
|
-
|
|
118
|
-
Remove a previously registered intercept using the ID returned from `intercept()` or `mock()`.
|
|
119
|
-
|
|
120
|
-
```typescript
|
|
121
|
-
const interceptId = await browser.network.mock('**/api/users', { status: 200, body: {} });
|
|
122
|
-
// ... later
|
|
123
|
-
await browser.network.removeIntercept(interceptId);
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
### Examples
|
|
127
|
-
|
|
128
|
-
#### Mock API Error
|
|
129
|
-
|
|
130
|
-
```typescript
|
|
131
|
-
await browser.network.mock('**/api/login', {
|
|
132
|
-
status: 401,
|
|
133
|
-
body: { error: 'Invalid credentials' },
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
await browser.find('#username').fill('baduser');
|
|
137
|
-
await browser.find('#password').fill('wrongpass');
|
|
138
|
-
await browser.find('#submit').click();
|
|
139
|
-
|
|
140
|
-
await browser.expect('#error').toHaveText('Invalid credentials');
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
#### Test Slow Network
|
|
144
|
-
|
|
145
|
-
```typescript
|
|
146
|
-
await browser.network.intercept('**/api/**', async (request) => {
|
|
147
|
-
// Simulate slow network
|
|
148
|
-
await new Promise((resolve) => setTimeout(resolve, 3000));
|
|
149
|
-
// Return mock response after delay
|
|
150
|
-
return { status: 200, body: { data: 'delayed response' } };
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
// Test loading state appears
|
|
154
|
-
await browser.find('#load-data').click();
|
|
155
|
-
await browser.expect('#loading-spinner').toBeVisible();
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
---
|
|
159
|
-
|
|
160
|
-
## Waiting for Network
|
|
161
|
-
|
|
162
|
-
`browser.waitForRequest` and `browser.waitForResponse` let you observe real network
|
|
163
|
-
traffic without intercepting it. Register them **before** the action that triggers
|
|
164
|
-
the request — the canonical pattern is `Promise.all`:
|
|
165
|
-
|
|
166
|
-
```typescript
|
|
167
|
-
const [response] = await Promise.all([
|
|
168
|
-
browser.waitForResponse('**/api/users'),
|
|
169
|
-
browser.click('#load-users'),
|
|
170
|
-
]);
|
|
171
|
-
expect(response.status).toBe(200);
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
Both accept a URL **glob** (same `**` syntax as `network.mock`) or a **predicate**:
|
|
175
|
-
|
|
176
|
-
```typescript
|
|
177
|
-
// Glob — matches by pathname
|
|
178
|
-
const [res] = await Promise.all([
|
|
179
|
-
browser.waitForResponse('**/api/users'),
|
|
180
|
-
browser.click('#load-users'),
|
|
181
|
-
]);
|
|
182
|
-
|
|
183
|
-
// Predicate — full control over matching
|
|
184
|
-
const [res2] = await Promise.all([
|
|
185
|
-
browser.waitForResponse(r => r.url.includes('/api/users') && r.status === 200),
|
|
186
|
-
browser.click('#load-users'),
|
|
187
|
-
]);
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
### waitForResponse(pattern, opts?)
|
|
191
|
-
|
|
192
|
-
Resolves with an `InterceptedResponse` once a matching completed response arrives.
|
|
193
|
-
|
|
194
|
-
| Property | Type | Description |
|
|
195
|
-
| ----------- | -------------------------- | ------------------------------------- |
|
|
196
|
-
| `url` | `string` | Full request URL |
|
|
197
|
-
| `status` | `number` | HTTP status code |
|
|
198
|
-
| `statusText`| `string` | E.g. `"OK"` |
|
|
199
|
-
| `headers` | `Record<string, string>` | Response headers |
|
|
200
|
-
| `mimeType` | `string` | E.g. `"application/json"` |
|
|
201
|
-
| `fromCache` | `boolean` | Whether served from browser cache |
|
|
202
|
-
| `request` | `{ id, url, method, headers }` | Matching request info |
|
|
203
|
-
|
|
204
|
-
### waitForRequest(pattern, opts?)
|
|
205
|
-
|
|
206
|
-
Resolves with an `InterceptedRequest` as soon as the browser sends the request
|
|
207
|
-
(before a response arrives). Useful for asserting that a request was made with
|
|
208
|
-
the right method/headers without waiting for the response.
|
|
209
|
-
|
|
210
|
-
| Property | Type | Description |
|
|
211
|
-
| --------- | ------------------------ | ---------------------- |
|
|
212
|
-
| `id` | `string` | BiDi request id |
|
|
213
|
-
| `url` | `string` | Full URL |
|
|
214
|
-
| `method` | `string` | `"GET"`, `"POST"`, … |
|
|
215
|
-
| `headers` | `Record<string, string>` | Request headers |
|
|
216
|
-
|
|
217
|
-
### Timeout
|
|
218
|
-
|
|
219
|
-
Both methods accept `{ timeout?: number }` (defaults to the browser navigation
|
|
220
|
-
timeout, 30 s). On timeout a clear error is thrown:
|
|
221
|
-
|
|
222
|
-
```
|
|
223
|
-
waitForResponse("**/api/users") timed out after 30000ms
|
|
224
|
-
```
|
|
225
|
-
|
|
226
|
-
---
|
|
227
|
-
|
|
228
|
-
## Console & Error Logs
|
|
229
|
-
|
|
230
|
-
Access browser console output and JavaScript errors via `browser.logs`.
|
|
231
|
-
|
|
232
|
-
> **Capture is lazy by default.** Craftdriver only subscribes to log events
|
|
233
|
-
> the first time you touch `browser.logs.onLog()` / `.onConsole()` /
|
|
234
|
-
> `.onError()` / `.on()` / `.waitForConsole()` / `.waitForError()` — messages
|
|
235
|
-
> emitted before that first touch are not captured, so a bare
|
|
236
|
-
> `browser.logs.getMessages()` right after `navigateTo()` can return `[]`.
|
|
237
|
-
> Either arm a listener before the action that logs, or launch with
|
|
238
|
-
> `Browser.launch({ captureLogs: true })` to start capture immediately.
|
|
239
|
-
|
|
240
|
-
### getMessages()
|
|
241
|
-
|
|
242
|
-
Get all console messages.
|
|
243
|
-
|
|
244
|
-
```typescript
|
|
245
|
-
const messages = browser.logs.getMessages();
|
|
246
|
-
|
|
247
|
-
for (const msg of messages) {
|
|
248
|
-
console.log(`[${msg.level}] ${msg.text}`);
|
|
249
|
-
}
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
Each message has:
|
|
253
|
-
|
|
254
|
-
- `type`: Always `'console'`
|
|
255
|
-
- `level`: `'debug'`, `'info'`, `'warn'`, or `'error'`
|
|
256
|
-
- `text`: The message content
|
|
257
|
-
- `method`: Console method used (`'log'`, `'warn'`, `'error'`, `'info'`, `'debug'`)
|
|
258
|
-
- `args`: Array of arguments passed to console
|
|
259
|
-
- `timestamp`: When the message was logged (Date object)
|
|
260
|
-
- `stackTrace`: Array of stack frames (optional)
|
|
261
|
-
|
|
262
|
-
### getLogsByLevel(level)
|
|
263
|
-
|
|
264
|
-
Get logs filtered by level.
|
|
265
|
-
|
|
266
|
-
```typescript
|
|
267
|
-
// Only warnings
|
|
268
|
-
const warnings = browser.logs.getLogsByLevel('warn');
|
|
269
|
-
|
|
270
|
-
// Only errors
|
|
271
|
-
const errors = browser.logs.getLogsByLevel('error');
|
|
272
|
-
```
|
|
273
|
-
|
|
274
|
-
### getErrors()
|
|
275
|
-
|
|
276
|
-
Get JavaScript errors that occurred on the page.
|
|
277
|
-
|
|
278
|
-
```typescript
|
|
279
|
-
const errors = browser.logs.getErrors();
|
|
280
|
-
|
|
281
|
-
for (const error of errors) {
|
|
282
|
-
console.log(`Error: ${error.text}`);
|
|
283
|
-
if (error.stackTrace) {
|
|
284
|
-
for (const frame of error.stackTrace) {
|
|
285
|
-
console.log(` at ${frame.functionName} (${frame.url}:${frame.lineNumber})`);
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
```
|
|
290
|
-
|
|
291
|
-
Each error has:
|
|
292
|
-
|
|
293
|
-
- `type`: Always `'javascript'`
|
|
294
|
-
- `level`: Always `'error'`
|
|
295
|
-
- `text`: The error message
|
|
296
|
-
- `timestamp`: When the error occurred (Date object)
|
|
297
|
-
- `stackTrace`: Array of stack frames (optional), each with:
|
|
298
|
-
- `functionName`: Name of the function
|
|
299
|
-
- `url`: Source file URL
|
|
300
|
-
- `lineNumber`: Line number
|
|
301
|
-
- `columnNumber`: Column number
|
|
302
|
-
|
|
303
|
-
### clearLogs()
|
|
304
|
-
|
|
305
|
-
Clear all collected logs (both console messages and errors).
|
|
306
|
-
|
|
307
|
-
```typescript
|
|
308
|
-
browser.logs.clearLogs();
|
|
309
|
-
```
|
|
310
|
-
|
|
311
|
-
### onError(handler)
|
|
312
|
-
|
|
313
|
-
Subscribe to JavaScript errors in real-time.
|
|
314
|
-
|
|
315
|
-
```typescript
|
|
316
|
-
const unsubscribe = browser.logs.onError((error) => {
|
|
317
|
-
console.log('JS Error detected:', error.text);
|
|
318
|
-
// Take screenshot, log to file, etc.
|
|
319
|
-
});
|
|
320
|
-
|
|
321
|
-
// Later: stop listening
|
|
322
|
-
unsubscribe();
|
|
323
|
-
```
|
|
324
|
-
|
|
325
|
-
### onConsole(handler)
|
|
326
|
-
|
|
327
|
-
Subscribe to console messages in real-time.
|
|
328
|
-
|
|
329
|
-
```typescript
|
|
330
|
-
const unsubscribe = browser.logs.onConsole((msg) => {
|
|
331
|
-
if (msg.level === 'error') {
|
|
332
|
-
console.log('Console error:', msg.text);
|
|
333
|
-
}
|
|
334
|
-
});
|
|
335
|
-
```
|
|
336
|
-
|
|
337
|
-
### Examples
|
|
338
|
-
|
|
339
|
-
#### Verify No Console Errors
|
|
340
|
-
|
|
341
|
-
```typescript
|
|
342
|
-
await browser.navigateTo('https://example.com');
|
|
343
|
-
|
|
344
|
-
// Interact with the page
|
|
345
|
-
await browser.find('#button').click();
|
|
346
|
-
await browser.pause(1000);
|
|
347
|
-
|
|
348
|
-
// Verify no errors occurred
|
|
349
|
-
const errors = browser.logs.getErrors();
|
|
350
|
-
expect(errors).toHaveLength(0);
|
|
351
|
-
```
|
|
352
|
-
|
|
353
|
-
#### Check for Expected Log
|
|
354
|
-
|
|
355
|
-
```typescript
|
|
356
|
-
await browser.find('#track-event').click();
|
|
357
|
-
|
|
358
|
-
const messages = browser.logs.getMessages();
|
|
359
|
-
const trackingLogs = messages.filter((m) => m.text.includes('Analytics event:'));
|
|
360
|
-
|
|
361
|
-
expect(trackingLogs.length).toBeGreaterThan(0);
|
|
362
|
-
```
|
|
363
|
-
|
|
364
|
-
#### Debug Test Failures
|
|
365
|
-
|
|
366
|
-
```typescript
|
|
367
|
-
test('form submission', async () => {
|
|
368
|
-
const browser = await Browser.launch({ browserName: 'chrome' });
|
|
369
|
-
|
|
370
|
-
try {
|
|
371
|
-
await browser.navigateTo('https://example.com/form');
|
|
372
|
-
await browser.find('#submit').click();
|
|
373
|
-
await browser.expect('#success').toBeVisible();
|
|
374
|
-
} catch (error) {
|
|
375
|
-
// On failure, log browser console output
|
|
376
|
-
console.log('Console messages:', browser.logs.getMessages());
|
|
377
|
-
console.log('JS errors:', browser.logs.getErrors());
|
|
378
|
-
throw error;
|
|
379
|
-
} finally {
|
|
380
|
-
await browser.quit();
|
|
381
|
-
}
|
|
382
|
-
});
|
|
383
|
-
```
|
|
384
|
-
|
|
385
|
-
---
|
|
386
|
-
|
|
387
|
-
## Session Storage
|
|
388
|
-
|
|
389
|
-
Manage cookies and browser storage via `browser.storage`.
|
|
390
|
-
|
|
391
|
-
### addCookie(cookie)
|
|
392
|
-
|
|
393
|
-
Add a cookie.
|
|
394
|
-
|
|
395
|
-
```typescript
|
|
396
|
-
await browser.storage.addCookie({
|
|
397
|
-
name: 'session_id',
|
|
398
|
-
value: 'abc123',
|
|
399
|
-
domain: 'example.com',
|
|
400
|
-
path: '/',
|
|
401
|
-
secure: true,
|
|
402
|
-
httpOnly: true,
|
|
403
|
-
sameSite: 'Lax',
|
|
404
|
-
expiry: new Date('2027-01-01'),
|
|
405
|
-
});
|
|
406
|
-
```
|
|
407
|
-
|
|
408
|
-
### getCookies(filter?)
|
|
409
|
-
|
|
410
|
-
Get cookies, optionally filtered.
|
|
411
|
-
|
|
412
|
-
```typescript
|
|
413
|
-
// All cookies
|
|
414
|
-
const cookies = await browser.storage.getCookies();
|
|
415
|
-
|
|
416
|
-
// Filter by domain
|
|
417
|
-
const sessionCookies = await browser.storage.getCookies({ domain: 'example.com' });
|
|
418
|
-
|
|
419
|
-
// Cookie value is a plain string
|
|
420
|
-
for (const cookie of cookies) {
|
|
421
|
-
console.log(`${cookie.name}=${cookie.value}`);
|
|
422
|
-
}
|
|
423
|
-
```
|
|
424
|
-
|
|
425
|
-
### clearCookies(filter?)
|
|
426
|
-
|
|
427
|
-
Clear cookies, optionally filtered.
|
|
428
|
-
|
|
429
|
-
```typescript
|
|
430
|
-
// Clear all cookies
|
|
431
|
-
await browser.storage.clearCookies();
|
|
432
|
-
|
|
433
|
-
// Clear specific domain
|
|
434
|
-
await browser.storage.clearCookies({ domain: 'example.com' });
|
|
435
|
-
```
|
|
436
|
-
|
|
437
|
-
### saveState(path, options?) / loadState(path)
|
|
438
|
-
|
|
439
|
-
Save and restore session state (cookies + localStorage) - Playwright-style persistence.
|
|
440
|
-
|
|
441
|
-
```typescript
|
|
442
|
-
// Save login session
|
|
443
|
-
await browser.navigateTo('https://example.com/login');
|
|
444
|
-
await browser.find('#username').fill('user');
|
|
445
|
-
await browser.find('#password').fill('pass');
|
|
446
|
-
await browser.find('#submit').click();
|
|
447
|
-
await browser.saveState('./auth.json');
|
|
448
|
-
|
|
449
|
-
// Later: restore session in new browser
|
|
450
|
-
const browser2 = await Browser.launch({
|
|
451
|
-
browserName: 'chrome',
|
|
452
|
-
storageState: './auth.json',
|
|
453
|
-
});
|
|
454
|
-
// Or manually:
|
|
455
|
-
await browser2.loadState('./auth.json');
|
|
456
|
-
```
|
|
457
|
-
|
|
458
|
-
### saveState options
|
|
459
|
-
|
|
460
|
-
```typescript
|
|
461
|
-
await browser.saveState('./state.json', {
|
|
462
|
-
includeCookies: true, // default: true
|
|
463
|
-
includeLocalStorage: true, // default: true
|
|
464
|
-
includeSessionStorage: false, // default: false
|
|
465
|
-
origins: ['https://example.com'], // specific origins only
|
|
466
|
-
});
|
|
467
|
-
```
|
|
468
|
-
|
|
469
|
-
---
|
|
470
|
-
|