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.
Files changed (63) hide show
  1. package/CHANGELOG.md +25 -3
  2. package/README.md +80 -160
  3. package/dist/lib/browser.d.ts +22 -0
  4. package/dist/lib/browser.d.ts.map +1 -1
  5. package/dist/lib/browser.js +14 -1
  6. package/dist/lib/browser.js.map +1 -1
  7. package/dist/lib/chrome.d.ts +15 -3
  8. package/dist/lib/chrome.d.ts.map +1 -1
  9. package/dist/lib/chrome.js +4 -2
  10. package/dist/lib/chrome.js.map +1 -1
  11. package/dist/lib/driver.d.ts.map +1 -1
  12. package/dist/lib/driver.js +2 -0
  13. package/dist/lib/driver.js.map +1 -1
  14. package/dist/lib/driverManager.d.ts +31 -0
  15. package/dist/lib/driverManager.d.ts.map +1 -1
  16. package/dist/lib/driverManager.js +165 -31
  17. package/dist/lib/driverManager.js.map +1 -1
  18. package/dist/lib/firefox.d.ts +4 -3
  19. package/dist/lib/firefox.d.ts.map +1 -1
  20. package/dist/lib/firefox.js.map +1 -1
  21. package/dist/lib/http.d.ts +1 -1
  22. package/dist/lib/http.d.ts.map +1 -1
  23. package/dist/lib/http.js +35 -7
  24. package/dist/lib/http.js.map +1 -1
  25. package/dist/lib/timing.d.ts +13 -0
  26. package/dist/lib/timing.d.ts.map +1 -1
  27. package/dist/lib/timing.js +13 -0
  28. package/dist/lib/timing.js.map +1 -1
  29. package/dist/lib/types.d.ts +2 -0
  30. package/dist/lib/types.d.ts.map +1 -1
  31. package/docs/agents.md +92 -0
  32. package/docs/api-reference.md +108 -46
  33. package/docs/browser-api.md +2 -1
  34. package/docs/browser-context.md +4 -7
  35. package/docs/browser-logs.md +158 -0
  36. package/docs/cli.md +26 -26
  37. package/docs/driver-configuration.md +103 -4
  38. package/docs/element-api.md +37 -6
  39. package/docs/emulation.md +6 -2
  40. package/docs/index.md +64 -0
  41. package/docs/keyboard-mouse.md +28 -10
  42. package/docs/mobile-emulation.md +5 -2
  43. package/docs/network.md +203 -0
  44. package/docs/public/craftdriver-mark.svg +15 -0
  45. package/docs/public/social-card.svg +27 -0
  46. package/docs/recipes/accessibility-gate.md +53 -0
  47. package/docs/recipes/console-error-gate.md +57 -0
  48. package/docs/recipes/file-upload-download.md +58 -0
  49. package/docs/recipes/login-once-reuse-session.md +73 -0
  50. package/docs/recipes/mobile-flow-with-network-and-logs.md +57 -0
  51. package/docs/recipes/mock-api-and-assert-network.md +60 -0
  52. package/docs/recipes/multi-user-contexts.md +58 -0
  53. package/docs/recipes/trace-failing-test.md +64 -0
  54. package/docs/recipes/virtual-clock-time-sensitive-ui.md +60 -0
  55. package/docs/recipes/vitest-browser-lifecycle.md +56 -0
  56. package/docs/recipes.md +33 -0
  57. package/docs/selectors.md +22 -1
  58. package/docs/session-management.md +18 -1
  59. package/docs/standards.md +40 -0
  60. package/docs/why-craftdriver.md +28 -0
  61. package/docs/zero-config-drivers.md +64 -0
  62. package/package.json +19 -5
  63. package/docs/bidi-features.md +0 -470
package/docs/agents.md ADDED
@@ -0,0 +1,92 @@
1
+ # AI Agent Guide
2
+
3
+ CraftDriver ships agent-facing tooling in the npm package. You can use the library directly, drive the browser from the shell, expose tools through MCP, or drop assistant rules into a project.
4
+
5
+ ## Which Surface Should I Use?
6
+
7
+ | Agent environment | Best surface | Why |
8
+ | -------------------------- | ------------------ | -------------------------------------------------------------------------------- |
9
+ | Shell-capable coding agent | CLI | Simple commands, persistent daemon, JSON output when piped. |
10
+ | MCP-aware host | MCP server | Typed tools, compact accessibility snapshots, artifact spilling for screenshots. |
11
+ | Code-writing assistant | `craftdriver init` | Project rules teach selector preference, auto-waiting, and error-code handling. |
12
+ | Custom orchestrator | Skill pack | Small always-on `SKILL.md` with deeper references loaded on demand. |
13
+
14
+ ## CLI
15
+
16
+ The CLI is good for agents that can run shell commands.
17
+
18
+ ```bash
19
+ npx craftdriver daemon start
20
+ npx craftdriver go http://127.0.0.1:8080/login.html
21
+ npx craftdriver snapshot
22
+ npx craftdriver fill 'label=Username' alice
23
+ npx craftdriver fill 'label=Password' hunter2
24
+ npx craftdriver click 'role=button[name=Sign in]'
25
+ npx craftdriver text '#result'
26
+ npx craftdriver daemon stop
27
+ ```
28
+
29
+ State survives between calls while the daemon is running, so an agent can explore, act, inspect, and refine.
30
+
31
+ Read the full [CLI reference](./cli.md).
32
+
33
+ ## MCP Server
34
+
35
+ MCP-aware hosts can use `craftdriver mcp`.
36
+
37
+ ```bash
38
+ claude mcp add craftdriver -- npx -y craftdriver mcp
39
+ ```
40
+
41
+ ```jsonc
42
+ {
43
+ "mcpServers": {
44
+ "craftdriver": {
45
+ "command": "npx",
46
+ "args": ["-y", "craftdriver", "mcp"],
47
+ },
48
+ },
49
+ }
50
+ ```
51
+
52
+ Mutating tools return compact accessibility snapshot diffs, so the agent can see what changed without a separate read. Large artifacts such as screenshots are written to disk instead of inlined into model context.
53
+
54
+ Read the full [MCP reference](./mcp.md).
55
+
56
+ ## Assistant Bootstrap Files
57
+
58
+ Use `craftdriver init` inside a project that uses CraftDriver:
59
+
60
+ ```bash
61
+ npx craftdriver init agents
62
+ npx craftdriver init copilot
63
+ npx craftdriver init claude
64
+ npx craftdriver init cursor
65
+ npx craftdriver init gemini
66
+ npx craftdriver init all
67
+ ```
68
+
69
+ The generated files tell assistants to:
70
+
71
+ - prefer semantic selectors before brittle CSS
72
+ - rely on auto-waiting instead of sleeps
73
+ - inspect stable `CraftdriverError.code` values
74
+ - use the CLI or MCP server for live browser work
75
+ - keep test code aligned with the public TypeScript API
76
+
77
+ ## Skill Pack
78
+
79
+ The npm tarball includes a tiered skill pack under `skills/craftdriver/`:
80
+
81
+ | File | Purpose |
82
+ | --------------- | -------------------------------------------------------------------------------------- |
83
+ | `SKILL.md` | Always-on rules and routing, kept small for model context. |
84
+ | `cheatsheet.md` | Fast command and API reference for tests. |
85
+ | `patterns.md` | Worked recipes such as login, uploads, network waits, a11y, tracing, and virtual time. |
86
+ | `cli.md` | Agent-facing CLI reference. |
87
+
88
+ Point compatible agents at:
89
+
90
+ ```text
91
+ node_modules/craftdriver/skills/craftdriver/SKILL.md
92
+ ```
@@ -1,71 +1,133 @@
1
1
  # API reference
2
2
 
3
- Every symbol re-exported from [`src/index.ts`](../src/index.ts). One row per export.
3
+ Every symbol re-exported from [`src/index.ts`](../src/index.ts), grouped by the feature area most users look for first.
4
4
  Generated by `scripts/gen-api-reference.mjs` — do not edit by hand.
5
5
 
6
6
  Run `npm run docs:api` to regenerate. CI fails when this file is out of date.
7
7
 
8
+ Start with [`Browser`](./browser-api.md), [`By`](./selectors.md) / [`Locator`](./selectors.md), and the feature guide that matches the job you are automating.
9
+
10
+ ## Browser And Pages
11
+
12
+ Launch browsers, move between pages and frames, handle dialogs, and wait for navigation.
13
+
8
14
  | Symbol | Kind | Summary | Docs |
9
15
  |---|---|---|---|
10
- | `A11y` | class | Ergonomic wrapper around axe-core. Obtain instances via the `.a11y` accessor on `Browser`, `ElementHandle`, or `Locator` — never construct directly. | [accessibility](accessibility.md) |
11
- | `A11yError` | class | Thrown by `A11y.check()` when violations are found. | [accessibility](accessibility.md) |
12
- | `A11yImpact` | type | Severity buckets reported by axe-core. | [accessibility](accessibility.md) |
13
- | `A11yOptions` | type | — | [accessibility](accessibility.md) |
14
- | `A11yResult` | type | — | [accessibility](accessibility.md) |
15
- | `A11yViolation` | type | — | [accessibility](accessibility.md) |
16
- | `A11yViolationNode` | type | — | [accessibility](accessibility.md) |
17
16
  | `Browser` | class | — | [browser-api](browser-api.md) |
17
+ | `LaunchOptions` | type | — | [browser-api](browser-api.md) |
18
+ | `LoadState` | type | When to consider a navigation complete. - `'load'` — page `load` event has fired (default) - `'domcontentloaded'` — `DOMContentLoaded` has fired (faster, no waiting for images/fonts) - `'networkidle'` — `load` + no in-flight requests for 500 ms - `'none'` — do not wait; return as soon as the navigation is initiated | [browser-api](browser-api.md) |
19
+ | `Page` | class | — | [browser-api](browser-api.md) |
20
+ | `Frame` | class | — | [browser-api](browser-api.md) |
21
+ | `Dialog` | type | Represents an open browser dialog (alert / confirm / prompt). Passed to handlers registered with `browser.onDialog()`. | [browser-api](browser-api.md) |
22
+ | `DialogType` | type | The type of a browser dialog. | [browser-api](browser-api.md) |
23
+ | `Download` | type | A file downloaded during a `waitForDownload()` call. | [browser-api](browser-api.md) |
24
+
25
+ ## Locators And Elements
26
+
27
+ Find page content with semantic locators and selector helpers.
28
+
29
+ | Symbol | Kind | Summary | Docs |
30
+ |---|---|---|---|
31
+ | `By` | class | — | [selectors](selectors.md) |
32
+ | `Locator` | class | — | [selectors](selectors.md) |
33
+
34
+ ## Input
35
+
36
+ Drive keyboard, mouse, and low-level key values.
37
+
38
+ | Symbol | Kind | Summary | Docs |
39
+ |---|---|---|---|
40
+ | `Key` | const | — | [keyboard-mouse](keyboard-mouse.md) |
41
+ | `Keyboard` | class | — | [keyboard-mouse](keyboard-mouse.md) |
42
+ | `Mouse` | class | — | [keyboard-mouse](keyboard-mouse.md) |
43
+
44
+ ## Contexts And Sessions
45
+
46
+ Isolate users, manage cookies, and save or restore browser state.
47
+
48
+ | Symbol | Kind | Summary | Docs |
49
+ |---|---|---|---|
18
50
  | `BrowserContext` | class | — | [browser-context](browser-context.md) |
19
51
  | `BrowserContextConfig` | type | Per-context options stored at creation time. | [browser-context](browser-context.md) |
20
52
  | `BrowserContextHooks` | type | Internal hooks the owning {@link Browser } passes to a new context. | [browser-context](browser-context.md) |
21
- | `By` | class | — | [selectors](selectors.md) |
22
- | `ChromeService` | class | — | [getting-started](getting-started.md) |
23
- | `ChromeServiceOptions` | type | — | [getting-started](getting-started.md) |
24
53
  | `ClearCookiesFilter` | type | Filter applied to {@link BrowserContext.clearCookies}. | [browser-context](browser-context.md) |
54
+ | `ContextStorageStateOptions` | type | Options for {@link BrowserContext.storageState}. | [browser-context](browser-context.md) |
55
+ | `InitScriptHandle` | type | A handle returned by {@link BrowserContext.addInitScript}. | [browser-context](browser-context.md) |
56
+ | `RoutePattern` | type | Pattern accepted by {@link BrowserContext.route}. Same shape as the browser-level interceptor. | [browser-context](browser-context.md) |
57
+ | `Cookie` | type | — | [session-management](session-management.md) |
58
+ | `CookieInput` | type | — | [session-management](session-management.md) |
59
+ | `SessionState` | type | — | [session-management](session-management.md) |
60
+ | `SessionStateManager` | class | — | [session-management](session-management.md) |
61
+ | `StorageStateOptions` | type | — | [session-management](session-management.md) |
62
+
63
+ ## Network
64
+
65
+ Mock, intercept, observe, and assert browser network traffic.
66
+
67
+ | Symbol | Kind | Summary | Docs |
68
+ |---|---|---|---|
69
+ | `NetworkInterceptor` | class | — | [network](network.md) |
70
+ | `MockResponse` | type | — | [network](network.md) |
71
+ | `InterceptedRequest` | type | — | [network](network.md) |
72
+ | `InterceptedResponse` | type | — | [network](network.md) |
73
+
74
+ ## Logs And Tracing
75
+
76
+ Capture console output, JavaScript errors, and trace artifacts.
77
+
78
+ | Symbol | Kind | Summary | Docs |
79
+ |---|---|---|---|
80
+ | `LogMonitor` | class | — | [browser-logs](browser-logs.md) |
81
+ | `ConsoleMessage` | type | — | [browser-logs](browser-logs.md) |
82
+ | `JavaScriptError` | type | — | [browser-logs](browser-logs.md) |
83
+ | `LogMessage` | type | — | [browser-logs](browser-logs.md) |
84
+ | `TraceStartOptions` | type | — | [tracing](tracing.md) |
85
+ | `TraceScreenshotMode` | type | Screenshot mode for tracing. | [tracing](tracing.md) |
86
+ | `TraceEvent` | type | — | [tracing](tracing.md) |
87
+
88
+ ## Emulation And Time
89
+
90
+ Configure devices, emulation overrides, and deterministic browser time.
91
+
92
+ | Symbol | Kind | Summary | Docs |
93
+ |---|---|---|---|
94
+ | `devices` | const | Common mobile device presets | [browser-api](browser-api.md) |
95
+ | `DeviceMetrics` | type | Device metrics for custom mobile emulation | [browser-api](browser-api.md) |
96
+ | `DeviceName` | type | — | [browser-api](browser-api.md) |
97
+ | `MobileEmulation` | type | Mobile emulation configuration | [browser-api](browser-api.md) |
98
+ | `EmulateOptions` | type | Options for {@link Browser.emulate}. Every field is independent; only the keys you pass are applied, others stay at their previous value. Passing `null` for a field clears the override for that field. | [browser-api](browser-api.md) |
25
99
  | `Clock` | class | Controls the virtual clock inside the browser page. | [clock](clock.md) |
26
100
  | `ClockInstallOptions` | type | Options for {@link Clock.install}. | [clock](clock.md) |
27
101
  | `ClockTime` | type | Accepted forms for a point in time. | [clock](clock.md) |
28
- | `ConsoleMessage` | type | — | [bidi-features](bidi-features.md) |
29
- | `ContextStorageStateOptions` | type | Options for {@link BrowserContext.storageState}. | [browser-context](browser-context.md) |
30
- | `Cookie` | type | — | [bidi-features](bidi-features.md) |
31
- | `CookieInput` | type | | [bidi-features](bidi-features.md) |
102
+
103
+ ## Accessibility
104
+
105
+ Run axe-core accessibility checks and inspect violation details.
106
+
107
+ | Symbol | Kind | Summary | Docs |
108
+ |---|---|---|---|
109
+ | `A11y` | class | Ergonomic wrapper around axe-core. Obtain instances via the `.a11y` accessor on `Browser`, `ElementHandle`, or `Locator` — never construct directly. | [accessibility](accessibility.md) |
110
+ | `A11yError` | class | Thrown by `A11y.check()` when violations are found. | [accessibility](accessibility.md) |
111
+ | `A11yImpact` | type | Severity buckets reported by axe-core. | [accessibility](accessibility.md) |
112
+ | `A11yOptions` | type | — | [accessibility](accessibility.md) |
113
+ | `A11yResult` | type | — | [accessibility](accessibility.md) |
114
+ | `A11yViolation` | type | — | [accessibility](accessibility.md) |
115
+ | `A11yViolationNode` | type | — | [accessibility](accessibility.md) |
116
+
117
+ ## Errors And Driver Services
118
+
119
+ Handle stable CraftDriver errors or customize browser driver services.
120
+
121
+ | Symbol | Kind | Summary | Docs |
122
+ |---|---|---|---|
32
123
  | `CraftdriverError` | class | Base class for every error thrown from the public API. | [error-codes](error-codes.md) |
33
124
  | `CraftdriverErrorOptions` | type | — | [error-codes](error-codes.md) |
34
- | `DeviceMetrics` | type | Device metrics for custom mobile emulation | [browser-api](browser-api.md) |
35
- | `DeviceName` | type | — | [browser-api](browser-api.md) |
36
- | `devices` | const | Common mobile device presets | [browser-api](browser-api.md) |
37
- | `Dialog` | type | Represents an open browser dialog (alert / confirm / prompt). Passed to handlers registered with `browser.onDialog()`. | [browser-api](browser-api.md) |
38
- | `DialogType` | type | The type of a browser dialog. | [browser-api](browser-api.md) |
39
- | `Download` | type | A file downloaded during a `waitForDownload()` call. | [browser-api](browser-api.md) |
40
- | `EmulateOptions` | type | Options for {@link Browser.emulate}. Every field is independent; only the keys you pass are applied, others stay at their previous value. Passing `null` for a field clears the override for that field. | [browser-api](browser-api.md) |
41
125
  | `ErrorCode` | const | Stable, machine-readable error codes for the public craftdriver API. | [error-codes](error-codes.md) |
42
126
  | `ErrorCodeName` | type | — | [error-codes](error-codes.md) |
43
127
  | `ErrorCodeValue` | type | — | [error-codes](error-codes.md) |
128
+ | `ChromeService` | class | — | [getting-started](getting-started.md) |
129
+ | `ChromeServiceOptions` | type | — | [getting-started](getting-started.md) |
44
130
  | `FirefoxService` | class | — | [getting-started](getting-started.md) |
45
131
  | `FirefoxServiceOptions` | type | — | [getting-started](getting-started.md) |
46
- | `Frame` | class | — | [browser-api](browser-api.md) |
47
- | `InitScriptHandle` | type | A handle returned by {@link BrowserContext.addInitScript}. | [browser-context](browser-context.md) |
48
- | `InterceptedRequest` | type | — | [bidi-features](bidi-features.md) |
49
- | `InterceptedResponse` | type | — | [bidi-features](bidi-features.md) |
50
- | `JavaScriptError` | type | — | [bidi-features](bidi-features.md) |
51
- | `Key` | const | — | [keyboard-mouse](keyboard-mouse.md) |
52
- | `Keyboard` | class | — | [keyboard-mouse](keyboard-mouse.md) |
53
- | `LaunchOptions` | type | — | [browser-api](browser-api.md) |
54
- | `LoadState` | type | When to consider a navigation complete. - `'load'` — page `load` event has fired (default) - `'domcontentloaded'` — `DOMContentLoaded` has fired (faster, no waiting for images/fonts) - `'networkidle'` — `load` + no in-flight requests for 500 ms - `'none'` — do not wait; return as soon as the navigation is initiated | [browser-api](browser-api.md) |
55
- | `Locator` | class | — | [selectors](selectors.md) |
56
- | `LogMessage` | type | — | [bidi-features](bidi-features.md) |
57
- | `LogMonitor` | class | — | [bidi-features](bidi-features.md) |
58
- | `MobileEmulation` | type | Mobile emulation configuration | [browser-api](browser-api.md) |
59
- | `MockResponse` | type | — | [bidi-features](bidi-features.md) |
60
- | `Mouse` | class | — | [keyboard-mouse](keyboard-mouse.md) |
61
- | `NetworkInterceptor` | class | — | [bidi-features](bidi-features.md) |
62
- | `Page` | class | — | [browser-api](browser-api.md) |
63
- | `RoutePattern` | type | Pattern accepted by {@link BrowserContext.route}. Same shape as the browser-level interceptor. | [browser-context](browser-context.md) |
64
- | `SessionState` | type | — | [bidi-features](bidi-features.md) |
65
- | `SessionStateManager` | class | — | [bidi-features](bidi-features.md) |
66
- | `StorageStateOptions` | type | — | [bidi-features](bidi-features.md) |
67
- | `TraceEvent` | type | — | [tracing](tracing.md) |
68
- | `TraceScreenshotMode` | type | Screenshot mode for tracing. | [tracing](tracing.md) |
69
- | `TraceStartOptions` | type | — | [tracing](tracing.md) |
70
132
 
71
133
  Total exports: **60**.
@@ -29,10 +29,11 @@ const browser = await Browser.launch({
29
29
  |--------|------|---------|-------------|
30
30
  | `browserName` | `'chrome' \| 'chromium' \| 'firefox'` | `'chrome'` | Browser to launch |
31
31
  | `enableBiDi` | `boolean` | `true` | Use WebDriver BiDi. Set `false` only when running against a browser that does not support it — every BiDi-only feature then throws a `requires BiDi` error if called. |
32
- | `captureLogs` | `boolean` | `false` | Start console/error log capture immediately at launch instead of lazily on first `browser.logs`/`onConsole`/`onError`/`waitForConsole` touch. See [BiDi Features Console & Error Logs](./bidi-features.md#console--error-logs). |
32
+ | `captureLogs` | `boolean` | `false` | Start console/error log capture immediately at launch instead of lazily on first `browser.logs`/`onConsole`/`onError`/`waitForConsole` touch. See [Console Logs And JavaScript Errors](./browser-logs.md). |
33
33
  | `storageState` | `string` | — | Path to a session-state JSON file to load on startup |
34
34
  | `mobileEmulation` | `MobileEmulation \| DeviceName` | — | Mobile device emulation settings (Chrome/Chromium only) |
35
35
  | `downloadsDir` | `string` | temp dir | Directory where downloaded files are saved |
36
+ | `browserPath` | `string` | — | Custom browser binary to launch (Chrome/Chromium/Firefox) — see [Driver Configuration → Browser Binary Configuration](./driver-configuration.md#browser-binary-configuration) |
36
37
 
37
38
  ## Navigation
38
39
 
@@ -262,19 +262,16 @@ this context.
262
262
  the listener reference than the unsubscribe function.
263
263
 
264
264
  ```typescript
265
- // Real-world: capture every console error across every tab a test opens,
266
- // including popups. No more "why did my test pass with a 500 in a popup".
267
- const errors: string[] = [];
265
+ const opened: string[] = [];
268
266
  ctx.on('page', (page) => {
269
- page.on('console', (msg) => {
270
- if (msg.type() === 'error') errors.push(`${page.url()}: ${msg.text()}`);
271
- });
267
+ void page.url().then((url) => opened.push(url));
272
268
  });
273
269
 
274
270
  const main = await ctx.newPage({ url: '/checkout' });
275
271
  const receipt = await ctx.waitForPage(() => main.find('#print').click());
276
272
  await receipt.waitForLoadState('load');
277
- expect(errors).toEqual([]);
273
+
274
+ expect(opened.some((url) => url.endsWith('/checkout'))).toBe(true);
278
275
  ```
279
276
 
280
277
  ### `BrowserContext.addInitScript(script): Promise<InitScriptHandle>`
@@ -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 | 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'` |
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 | Purpose |
225
- | ------------------------------------------------------------- | ------------------------------------------------------------------------ |
226
- | [`SKILL.md`](../skills/craftdriver/SKILL.md) | Always-on, ≤ 500 tokens. Selector order, error-code-first, auto-wait. |
227
- | [`cheatsheet.md`](../skills/craftdriver/cheatsheet.md) | Command-by-command reference for writing tests. |
228
- | [`patterns.md`](../skills/craftdriver/patterns.md) | Worked recipes (login, upload, network-wait, a11y, tracing, clock). |
229
- | [`cli.md`](../skills/craftdriver/cli.md) | Agent-facing CLI reference. |
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