craftdriver 1.0.3 → 1.0.4
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 +12 -3
- package/README.md +80 -160
- 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.map +1 -1
- package/dist/lib/driverManager.js +67 -24
- package/dist/lib/driverManager.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 +1 -1
- package/docs/browser-context.md +4 -7
- package/docs/browser-logs.md +158 -0
- package/docs/cli.md +26 -26
- 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 +52 -0
- package/package.json +19 -5
- package/docs/bidi-features.md +0 -470
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# Console Logs And JavaScript Errors
|
|
2
|
+
|
|
3
|
+
Use `browser.logs` to capture what the page writes to the console and what
|
|
4
|
+
JavaScript errors the browser reports. This is useful for failing tests on
|
|
5
|
+
unexpected client-side errors, debugging flaky flows, or asserting that an app
|
|
6
|
+
emitted a known log message.
|
|
7
|
+
|
|
8
|
+
> **Requires the default browser event connection.** Console and JavaScript
|
|
9
|
+
> error capture requires `enableBiDi: true` (the default) and a browser that
|
|
10
|
+
> supports WebDriver BiDi. If you launch with `enableBiDi: false`, these
|
|
11
|
+
> methods throw a clear `requires BiDi` error.
|
|
12
|
+
|
|
13
|
+
## Capture Timing
|
|
14
|
+
|
|
15
|
+
Capture is lazy by default. CraftDriver subscribes to log events the first time
|
|
16
|
+
you touch `browser.logs.onLog()`, `.onConsole()`, `.onError()`, `.on()`,
|
|
17
|
+
`.waitForConsole()`, or `.waitForError()`.
|
|
18
|
+
|
|
19
|
+
Messages emitted before that first touch are not captured, so this can return an
|
|
20
|
+
empty array:
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
await browser.navigateTo('https://example.com');
|
|
24
|
+
const messages = browser.logs.getMessages();
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Start capture before the action that logs:
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
const warning = browser.logs.waitForConsole((msg) => msg.level === 'warn');
|
|
31
|
+
|
|
32
|
+
await browser.getByRole('button', { name: 'Show warning' }).click();
|
|
33
|
+
expect((await warning).text).toContain('Heads up');
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Or start capture immediately at launch:
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
const browser = await Browser.launch({
|
|
40
|
+
browserName: 'chrome',
|
|
41
|
+
captureLogs: true,
|
|
42
|
+
});
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Read Collected Messages
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
const messages = browser.logs.getMessages();
|
|
49
|
+
|
|
50
|
+
for (const msg of messages) {
|
|
51
|
+
console.log(`[${msg.level}] ${msg.text}`);
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Each console message has:
|
|
56
|
+
|
|
57
|
+
| Property | Description |
|
|
58
|
+
| -------- | ----------- |
|
|
59
|
+
| `type` | Always `'console'` |
|
|
60
|
+
| `level` | `'debug'`, `'info'`, `'warn'`, or `'error'` |
|
|
61
|
+
| `text` | Message text |
|
|
62
|
+
| `method` | Console method, such as `'log'`, `'warn'`, or `'error'` |
|
|
63
|
+
| `args` | Arguments passed to `console.*` |
|
|
64
|
+
| `timestamp` | When the message was logged |
|
|
65
|
+
| `stackTrace` | Optional stack frames |
|
|
66
|
+
|
|
67
|
+
Filter by level:
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
const warnings = browser.logs.getLogsByLevel('warn');
|
|
71
|
+
const errors = browser.logs.getLogsByLevel('error');
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Read JavaScript Errors
|
|
75
|
+
|
|
76
|
+
```typescript
|
|
77
|
+
const errors = browser.logs.getErrors();
|
|
78
|
+
|
|
79
|
+
for (const error of errors) {
|
|
80
|
+
console.log(`Error: ${error.text}`);
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Each JavaScript error has:
|
|
85
|
+
|
|
86
|
+
| Property | Description |
|
|
87
|
+
| -------- | ----------- |
|
|
88
|
+
| `type` | Always `'javascript'` |
|
|
89
|
+
| `level` | Always `'error'` |
|
|
90
|
+
| `text` | Error message |
|
|
91
|
+
| `timestamp` | When the error occurred |
|
|
92
|
+
| `stackTrace` | Optional stack frames with function, URL, line, and column |
|
|
93
|
+
|
|
94
|
+
## Wait For A Log Or Error
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
const consoleMessage = browser.logs.waitForConsole((msg) => {
|
|
98
|
+
return msg.level === 'info' && msg.text.includes('Saved');
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
await browser.getByRole('button', { name: 'Save' }).click();
|
|
102
|
+
expect((await consoleMessage).text).toContain('Saved');
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
const pageError = browser.logs.waitForError((error) => {
|
|
107
|
+
return error.text.includes('Cannot read properties');
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
await browser.getByRole('button', { name: 'Trigger error' }).click();
|
|
111
|
+
expect((await pageError).text).toContain('Cannot read properties');
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Subscribe In Real Time
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
const unsubscribeConsole = browser.logs.onConsole((msg) => {
|
|
118
|
+
if (msg.level === 'error') {
|
|
119
|
+
console.log('Console error:', msg.text);
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
const unsubscribeErrors = browser.logs.onError((error) => {
|
|
124
|
+
console.log('JavaScript error:', error.text);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// Later:
|
|
128
|
+
unsubscribeConsole();
|
|
129
|
+
unsubscribeErrors();
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Fail On Unexpected Errors
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
await browser.navigateTo('https://example.com');
|
|
136
|
+
await browser.getByRole('button', { name: 'Run flow' }).click();
|
|
137
|
+
|
|
138
|
+
browser.logs.assertNoErrors();
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
You can also inspect errors yourself:
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
const errors = browser.logs.getErrors();
|
|
145
|
+
expect(errors).toHaveLength(0);
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Other Helpers
|
|
149
|
+
|
|
150
|
+
| Method | Description |
|
|
151
|
+
| ------ | ----------- |
|
|
152
|
+
| `onLog(handler)` | Subscribe to all log messages |
|
|
153
|
+
| `on(level, handler)` | Subscribe to one level: `debug`, `info`, `warn`, or `error` |
|
|
154
|
+
| `getLogs()` | Return all captured console and JavaScript error messages |
|
|
155
|
+
| `clearLogs()` | Clear all collected console messages and errors |
|
|
156
|
+
| `waitForConsole(predicate, timeout?)` | Wait for a matching console message |
|
|
157
|
+
| `waitForError(predicate?, timeout?)` | Wait for a JavaScript error |
|
|
158
|
+
| `assertNoErrors()` | Throw if any JavaScript errors were captured |
|
package/docs/cli.md
CHANGED
|
@@ -83,21 +83,21 @@ Run `craftdriver --help` for the full list.
|
|
|
83
83
|
|
|
84
84
|
CSS is the default. Switch kind with a `prefix=value` form:
|
|
85
85
|
|
|
86
|
-
| Prefix
|
|
87
|
-
|
|
|
88
|
-
| _none_, `css=`
|
|
89
|
-
| `xpath=`
|
|
90
|
-
| `role=`
|
|
91
|
-
| `text=`
|
|
92
|
-
| `text*=`
|
|
93
|
-
| `label=`
|
|
94
|
-
| `placeholder=`
|
|
95
|
-
| `alt=`
|
|
96
|
-
| `title=`
|
|
97
|
-
| `testid=`
|
|
98
|
-
| `id=`
|
|
99
|
-
| `name=`
|
|
100
|
-
| `ref=`
|
|
86
|
+
| Prefix | Maps to | Example |
|
|
87
|
+
| -------------- | --------------------------------------- | -------------------------------- |
|
|
88
|
+
| _none_, `css=` | `By.css` | `'.product-list li'` |
|
|
89
|
+
| `xpath=` | `By.xpath` | `'xpath=//button[1]'` |
|
|
90
|
+
| `role=` | `By.role` (+ `[name=...]` for the name) | `'role=button[name=Submit]'` |
|
|
91
|
+
| `text=` | `By.text` (exact) | `'text=Sign In'` |
|
|
92
|
+
| `text*=` | `By.partialText` | `'text*=Sign'` |
|
|
93
|
+
| `label=` | `By.labelText` | `'label=Email'` |
|
|
94
|
+
| `placeholder=` | `By.placeholder` | `'placeholder=name@example.com'` |
|
|
95
|
+
| `alt=` | `By.altText` | `'alt=Logo'` |
|
|
96
|
+
| `title=` | `By.title` | `'title=Help'` |
|
|
97
|
+
| `testid=` | `By.testId` | `'testid=login-btn'` |
|
|
98
|
+
| `id=` | `By.id` | `'id=submit'` |
|
|
99
|
+
| `name=` | `By.name` | `'name=email'` |
|
|
100
|
+
| `ref=` | snapshot ref (`craftdriver snapshot`) | `'ref=e5'` |
|
|
101
101
|
|
|
102
102
|
Anything else is treated as a CSS selector, so attribute selectors with
|
|
103
103
|
`=` inside (e.g. `'button[type=submit]'`) work as expected.
|
|
@@ -148,11 +148,11 @@ code: NO_MATCH
|
|
|
148
148
|
|
|
149
149
|
## Exit codes
|
|
150
150
|
|
|
151
|
-
| Code | Meaning
|
|
152
|
-
| ---- |
|
|
153
|
-
| `0` | success (or `exists` matched at least one element)
|
|
154
|
-
| `1` | assertion / timeout / `NO_MATCH` / `exists` matched zero elements
|
|
155
|
-
| `2` | usage error (missing argument, unknown command)
|
|
151
|
+
| Code | Meaning |
|
|
152
|
+
| ---- | ----------------------------------------------------------------- |
|
|
153
|
+
| `0` | success (or `exists` matched at least one element) |
|
|
154
|
+
| `1` | assertion / timeout / `NO_MATCH` / `exists` matched zero elements |
|
|
155
|
+
| `2` | usage error (missing argument, unknown command) |
|
|
156
156
|
|
|
157
157
|
## Fail-fast defaults
|
|
158
158
|
|
|
@@ -221,12 +221,12 @@ For agents that load skills explicitly (Claude Code's Skills system,
|
|
|
221
221
|
Copilot agent customization, custom orchestrators), the npm tarball
|
|
222
222
|
ships a tiered skill pack under `skills/craftdriver/`:
|
|
223
223
|
|
|
224
|
-
| File
|
|
225
|
-
|
|
|
226
|
-
| [`SKILL.md`](
|
|
227
|
-
| [`cheatsheet.md`](
|
|
228
|
-
| [`patterns.md`](
|
|
229
|
-
| [`cli.md`](
|
|
224
|
+
| File | Purpose |
|
|
225
|
+
| ----------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- |
|
|
226
|
+
| [`SKILL.md`](https://github.com/dtopuzov/craftdriver/blob/main/skills/craftdriver/SKILL.md) | Always-on, ≤ 500 tokens. Selector order, error-code-first, auto-wait. |
|
|
227
|
+
| [`cheatsheet.md`](https://github.com/dtopuzov/craftdriver/blob/main/skills/craftdriver/cheatsheet.md) | Command-by-command reference for writing tests. |
|
|
228
|
+
| [`patterns.md`](https://github.com/dtopuzov/craftdriver/blob/main/skills/craftdriver/patterns.md) | Worked recipes (login, upload, network-wait, a11y, tracing, clock). |
|
|
229
|
+
| [`cli.md`](https://github.com/dtopuzov/craftdriver/blob/main/skills/craftdriver/cli.md) | Agent-facing CLI reference. |
|
|
230
230
|
|
|
231
231
|
Point your agent at `node_modules/craftdriver/skills/craftdriver/SKILL.md`
|
|
232
232
|
or copy it into your project. The other files are referenced from
|
package/docs/element-api.md
CHANGED
|
@@ -9,8 +9,10 @@ The `ElementHandle` provides methods for interacting with individual DOM element
|
|
|
9
9
|
const element = browser.find('#my-element');
|
|
10
10
|
const button = browser.find(By.text('Submit'));
|
|
11
11
|
|
|
12
|
-
//
|
|
13
|
-
|
|
12
|
+
// Element-scoped operations
|
|
13
|
+
const input = browser.find('#input');
|
|
14
|
+
await input.fill('text');
|
|
15
|
+
await input.press('Enter');
|
|
14
16
|
```
|
|
15
17
|
|
|
16
18
|
> **Tip:** Use `browser.locator(selector)` instead of `find()` when you need
|
|
@@ -99,6 +101,14 @@ Get the current value of an input element.
|
|
|
99
101
|
const inputValue = await browser.find('#email').value();
|
|
100
102
|
```
|
|
101
103
|
|
|
104
|
+
### tagName()
|
|
105
|
+
|
|
106
|
+
Get the element tag name.
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
const tag = await browser.find('#submit').tagName(); // "button"
|
|
110
|
+
```
|
|
111
|
+
|
|
102
112
|
### getAttribute(name)
|
|
103
113
|
|
|
104
114
|
Get an attribute value from the element.
|
|
@@ -166,14 +176,35 @@ await browser.find('#message').expect().toHaveText('Success');
|
|
|
166
176
|
await browser.find('#input').expect().toHaveValue('test@example.com');
|
|
167
177
|
```
|
|
168
178
|
|
|
169
|
-
|
|
179
|
+
### setInputFiles(filePaths, options?)
|
|
180
|
+
|
|
181
|
+
Set files on an `<input type="file">`.
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
await browser.find('#avatar').setInputFiles('/absolute/path/avatar.png');
|
|
185
|
+
await browser.find('#photos').setInputFiles([
|
|
186
|
+
'/absolute/path/one.jpg',
|
|
187
|
+
'/absolute/path/two.jpg',
|
|
188
|
+
]);
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### evaluate(fn, ...args)
|
|
170
192
|
|
|
171
|
-
|
|
193
|
+
Run JavaScript with this element as the first argument.
|
|
172
194
|
|
|
173
195
|
```typescript
|
|
174
|
-
await browser.find('#
|
|
196
|
+
const tag = await browser.find('#submit').evaluate(el => el.tagName.toLowerCase());
|
|
197
|
+
const active = await browser
|
|
198
|
+
.find('#submit')
|
|
199
|
+
.evaluate((el, cls) => el.classList.contains(cls), 'active');
|
|
200
|
+
```
|
|
175
201
|
|
|
176
|
-
|
|
202
|
+
### a11y
|
|
203
|
+
|
|
204
|
+
Run an accessibility audit scoped to this element and its descendants.
|
|
205
|
+
|
|
206
|
+
```typescript
|
|
207
|
+
const result = await browser.find('#checkout').a11y.audit();
|
|
177
208
|
```
|
|
178
209
|
|
|
179
210
|
## Examples
|
package/docs/emulation.md
CHANGED
|
@@ -65,7 +65,9 @@ JavaScript-only patch.
|
|
|
65
65
|
await browser.emulate({ colorScheme: 'dark' });
|
|
66
66
|
await browser.navigateTo('https://app.example.com');
|
|
67
67
|
|
|
68
|
-
const bg = await browser.
|
|
68
|
+
const bg = await browser.evaluate(() =>
|
|
69
|
+
getComputedStyle(document.body).backgroundColor
|
|
70
|
+
);
|
|
69
71
|
expect(bg).toBe('rgb(17, 17, 17)');
|
|
70
72
|
```
|
|
71
73
|
|
|
@@ -108,7 +110,9 @@ Confirm animations are actually suppressed for users who request it.
|
|
|
108
110
|
await browser.emulate({ reducedMotion: 'reduce' });
|
|
109
111
|
await browser.navigateTo('https://app.example.com');
|
|
110
112
|
|
|
111
|
-
const anim = await browser.
|
|
113
|
+
const anim = await browser.evaluate(() =>
|
|
114
|
+
getComputedStyle(document.querySelector('.hero')!).animationName
|
|
115
|
+
);
|
|
112
116
|
expect(anim).toBe('none');
|
|
113
117
|
```
|
|
114
118
|
|
package/docs/index.md
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: home
|
|
3
|
+
title: CraftDriver
|
|
4
|
+
titleTemplate: false
|
|
5
|
+
hero:
|
|
6
|
+
name: CraftDriver
|
|
7
|
+
text: Crafted browser automation for Node.js.
|
|
8
|
+
tagline: Playwright-style ergonomics. WebDriver standards. AI friendly.
|
|
9
|
+
image:
|
|
10
|
+
src: /craftdriver-mark.svg
|
|
11
|
+
alt: CraftDriver
|
|
12
|
+
actions:
|
|
13
|
+
- theme: brand
|
|
14
|
+
text: Get Started
|
|
15
|
+
link: /getting-started
|
|
16
|
+
- theme: alt
|
|
17
|
+
text: API Reference
|
|
18
|
+
link: /api-reference
|
|
19
|
+
- theme: alt
|
|
20
|
+
text: AI Agent Guide
|
|
21
|
+
link: /agents
|
|
22
|
+
features:
|
|
23
|
+
- title: Control network traffic
|
|
24
|
+
details: Mock APIs, block noisy requests, intercept calls, and wait for real requests or responses.
|
|
25
|
+
- title: Reuse browser state
|
|
26
|
+
details: Save cookies and localStorage, launch already signed in, and isolate users with browser contexts.
|
|
27
|
+
- title: Test time and quality
|
|
28
|
+
details: Use virtual time, axe-core accessibility checks, traces, screenshots, console logs, and JS error capture.
|
|
29
|
+
- title: Agent-friendly
|
|
30
|
+
details: CLI, MCP server, and assistant rules are there when you want coding agents to drive the browser too.
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## One Install
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npm install craftdriver --save-dev
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
import { Browser } from 'craftdriver';
|
|
41
|
+
|
|
42
|
+
const browser = await Browser.launch({ browserName: 'chrome' });
|
|
43
|
+
|
|
44
|
+
await browser.navigateTo('https://example.com/login');
|
|
45
|
+
await browser.getByLabel('Username').fill('alice');
|
|
46
|
+
await browser.getByLabel('Password').fill('hunter2');
|
|
47
|
+
await browser.getByRole('button', { name: 'Sign in' }).click();
|
|
48
|
+
await browser.expect('#result').toHaveText('Welcome alice');
|
|
49
|
+
|
|
50
|
+
await browser.quit();
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Choose Your Path
|
|
54
|
+
|
|
55
|
+
| You want to... | Start |
|
|
56
|
+
| --------------------------------- | --------------------------------------- |
|
|
57
|
+
| Write browser automation | [Getting Started](./getting-started.md) |
|
|
58
|
+
| Give an AI coding agent a browser | [AI Agent Guide](./agents.md) |
|
|
59
|
+
|
|
60
|
+
## Good Stuff To Read Next
|
|
61
|
+
|
|
62
|
+
- [Zero-Config Drivers](./zero-config-drivers.md) explains driver resolution and caching.
|
|
63
|
+
- [WebDriver Standards](./standards.md) explains how Classic and BiDi work together.
|
|
64
|
+
- [Recipes](./recipes.md) collects KB-style patterns for common real-world workflows.
|
package/docs/keyboard-mouse.md
CHANGED
|
@@ -48,6 +48,15 @@ Release a held key.
|
|
|
48
48
|
await browser.keyboard.up('Shift');
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
+
### chord(...keys)
|
|
52
|
+
|
|
53
|
+
Press a key combination.
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
await browser.keyboard.chord('Control', 'a');
|
|
57
|
+
await browser.keyboard.chord('Shift', 'Tab');
|
|
58
|
+
```
|
|
59
|
+
|
|
51
60
|
### Key Combinations
|
|
52
61
|
|
|
53
62
|
Combine `down()` and `up()` for modifier key combinations:
|
|
@@ -129,23 +138,25 @@ await browser.mouse.move({ x: 150, y: 300 });
|
|
|
129
138
|
await browser.mouse.move('#target');
|
|
130
139
|
```
|
|
131
140
|
|
|
132
|
-
### down()
|
|
141
|
+
### down(button?)
|
|
133
142
|
|
|
134
143
|
Press the mouse button.
|
|
135
144
|
|
|
136
145
|
```typescript
|
|
137
146
|
await browser.mouse.down();
|
|
147
|
+
await browser.mouse.down('right');
|
|
138
148
|
```
|
|
139
149
|
|
|
140
|
-
### up()
|
|
150
|
+
### up(button?)
|
|
141
151
|
|
|
142
152
|
Release the mouse button.
|
|
143
153
|
|
|
144
154
|
```typescript
|
|
145
155
|
await browser.mouse.up();
|
|
156
|
+
await browser.mouse.up('right');
|
|
146
157
|
```
|
|
147
158
|
|
|
148
|
-
### wheel(deltaX, deltaY)
|
|
159
|
+
### wheel(deltaX, deltaY, target?)
|
|
149
160
|
|
|
150
161
|
Scroll the page.
|
|
151
162
|
|
|
@@ -158,6 +169,9 @@ await browser.mouse.wheel(0, -100);
|
|
|
158
169
|
|
|
159
170
|
// Scroll right
|
|
160
171
|
await browser.mouse.wheel(100, 0);
|
|
172
|
+
|
|
173
|
+
// Scroll while targeting an element
|
|
174
|
+
await browser.mouse.wheel(0, 300, '#scroll-panel');
|
|
161
175
|
```
|
|
162
176
|
|
|
163
177
|
### dragAndDrop(from, to)
|
|
@@ -194,14 +208,14 @@ await browser.mouse.dragAndDrop({ x: startX, y: startY }, { x: endX, y: endY });
|
|
|
194
208
|
|
|
195
209
|
```typescript
|
|
196
210
|
// Move to start position
|
|
197
|
-
await browser.mouse.move(100, 100);
|
|
211
|
+
await browser.mouse.move({ x: 100, y: 100 });
|
|
198
212
|
await browser.mouse.down();
|
|
199
213
|
|
|
200
214
|
// Draw a line
|
|
201
|
-
await browser.mouse.move(200, 100);
|
|
202
|
-
await browser.mouse.move(200, 200);
|
|
203
|
-
await browser.mouse.move(100, 200);
|
|
204
|
-
await browser.mouse.move(100, 100);
|
|
215
|
+
await browser.mouse.move({ x: 200, y: 100 });
|
|
216
|
+
await browser.mouse.move({ x: 200, y: 200 });
|
|
217
|
+
await browser.mouse.move({ x: 100, y: 200 });
|
|
218
|
+
await browser.mouse.move({ x: 100, y: 100 });
|
|
205
219
|
|
|
206
220
|
await browser.mouse.up();
|
|
207
221
|
```
|
|
@@ -227,10 +241,14 @@ For element-scoped key presses, use the `press()` method on ElementHandle:
|
|
|
227
241
|
|
|
228
242
|
```typescript
|
|
229
243
|
// Press Enter in a specific input
|
|
230
|
-
|
|
244
|
+
const search = browser.find('#search');
|
|
245
|
+
await search.fill('query');
|
|
246
|
+
await search.press('Enter');
|
|
231
247
|
|
|
232
248
|
// Tab out of a field
|
|
233
|
-
|
|
249
|
+
const username = browser.find('#username');
|
|
250
|
+
await username.fill('user');
|
|
251
|
+
await username.press('Tab');
|
|
234
252
|
```
|
|
235
253
|
|
|
236
254
|
This is often more convenient than using the global keyboard API.
|
package/docs/mobile-emulation.md
CHANGED
|
@@ -163,9 +163,9 @@ await browser.click('#mobile-menu-button');
|
|
|
163
163
|
await browser.expect('#mobile-menu').toBeVisible();
|
|
164
164
|
```
|
|
165
165
|
|
|
166
|
-
### Combine
|
|
166
|
+
### Combine With Network Mocking And Logs
|
|
167
167
|
|
|
168
|
-
Mobile emulation works alongside
|
|
168
|
+
Mobile emulation works alongside network mocking and browser log capture:
|
|
169
169
|
|
|
170
170
|
```typescript
|
|
171
171
|
const browser = await Browser.launch({
|
|
@@ -186,6 +186,9 @@ const errors = browser.logs.getErrors();
|
|
|
186
186
|
expect(errors).toHaveLength(0);
|
|
187
187
|
```
|
|
188
188
|
|
|
189
|
+
Learn more in [Network Mocking And Request Waiting](./network.md) and
|
|
190
|
+
[Console Logs And JavaScript Errors](./browser-logs.md).
|
|
191
|
+
|
|
189
192
|
## Limitations
|
|
190
193
|
|
|
191
194
|
- **Chrome/Chromium only**: Mobile emulation uses Chrome-specific capabilities
|