craftdriver 1.4.0 → 1.6.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 +17 -3
- package/README.md +6 -2
- package/dist/cli/daemon.d.ts.map +1 -1
- package/dist/cli/daemon.js +4 -0
- package/dist/cli/daemon.js.map +1 -1
- package/dist/cli/mcp/server.d.ts.map +1 -1
- package/dist/cli/mcp/server.js +4 -0
- package/dist/cli/mcp/server.js.map +1 -1
- package/dist/cli/parseArgs.d.ts +2 -2
- package/dist/cli/parseArgs.d.ts.map +1 -1
- package/dist/cli/parseArgs.js +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/bidi/storage.d.ts +13 -0
- package/dist/lib/bidi/storage.d.ts.map +1 -1
- package/dist/lib/bidi/storage.js +81 -32
- package/dist/lib/bidi/storage.js.map +1 -1
- package/dist/lib/browser.d.ts +48 -3
- package/dist/lib/browser.d.ts.map +1 -1
- package/dist/lib/browser.js +212 -86
- package/dist/lib/browser.js.map +1 -1
- package/dist/lib/browserContext.d.ts +2 -2
- package/dist/lib/browserContext.d.ts.map +1 -1
- package/dist/lib/browserContext.js +1 -1
- package/dist/lib/builder.d.ts +16 -2
- package/dist/lib/builder.d.ts.map +1 -1
- package/dist/lib/builder.js +46 -2
- package/dist/lib/builder.js.map +1 -1
- package/dist/lib/capabilities.d.ts +20 -2
- package/dist/lib/capabilities.d.ts.map +1 -1
- package/dist/lib/capabilities.js +109 -48
- package/dist/lib/capabilities.js.map +1 -1
- package/dist/lib/driver.d.ts +33 -2
- package/dist/lib/driver.d.ts.map +1 -1
- package/dist/lib/driver.js +91 -2
- package/dist/lib/driver.js.map +1 -1
- package/dist/lib/driverManager.d.ts +28 -0
- package/dist/lib/driverManager.d.ts.map +1 -1
- package/dist/lib/driverManager.js +60 -0
- package/dist/lib/driverManager.js.map +1 -1
- package/dist/lib/elementHandle.d.ts.map +1 -1
- package/dist/lib/elementHandle.js +34 -0
- package/dist/lib/elementHandle.js.map +1 -1
- package/dist/lib/http.d.ts.map +1 -1
- package/dist/lib/http.js +31 -10
- package/dist/lib/http.js.map +1 -1
- package/dist/lib/launchTarget.d.ts +22 -3
- package/dist/lib/launchTarget.d.ts.map +1 -1
- package/dist/lib/launchTarget.js +159 -9
- package/dist/lib/launchTarget.js.map +1 -1
- package/dist/lib/remote.d.ts +55 -0
- package/dist/lib/remote.d.ts.map +1 -0
- package/dist/lib/remote.js +127 -0
- package/dist/lib/remote.js.map +1 -0
- package/dist/lib/safari.d.ts +90 -0
- package/dist/lib/safari.d.ts.map +1 -0
- package/dist/lib/safari.js +136 -0
- package/dist/lib/safari.js.map +1 -0
- package/dist/lib/tracing.d.ts +1 -1
- package/dist/lib/tracing.d.ts.map +1 -1
- package/dist/lib/tracing.js.map +1 -1
- package/dist/lib/types.d.ts +63 -0
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/vibiumTrace.d.ts +1 -1
- package/dist/lib/vibiumTrace.d.ts.map +1 -1
- package/dist/lib/webelement.d.ts.map +1 -1
- package/dist/lib/webelement.js +118 -2
- package/dist/lib/webelement.js.map +1 -1
- package/docs/api-reference.md +6 -2
- package/docs/browser-api.md +5 -4
- package/docs/driver-configuration.md +60 -0
- package/docs/getting-started.md +30 -10
- package/docs/index.md +2 -1
- package/docs/keyboard-mouse.md +7 -5
- package/docs/public/examples/displayed.html +86 -0
- package/docs/recipes/run-on-browserstack.md +265 -0
- package/docs/recipes.md +15 -1
- package/docs/remote-webdriver.md +308 -0
- package/docs/safari.md +118 -0
- package/docs/standards.md +18 -0
- package/docs/why-craftdriver.md +3 -1
- package/docs/zero-config-drivers.md +12 -0
- package/package.json +5 -1
- package/skills/craftdriver/SKILL.md +4 -1
- package/skills/craftdriver/cheatsheet.md +4 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webelement.d.ts","sourceRoot":"","sources":["../../src/lib/webelement.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAmB,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACrE,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAE7B,eAAO,MAAM,eAAe,wCAAwC,CAAC;AACrE,eAAO,MAAM,kBAAkB,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"webelement.d.ts","sourceRoot":"","sources":["../../src/lib/webelement.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAmB,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACrE,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAE7B,eAAO,MAAM,eAAe,wCAAwC,CAAC;AACrE,eAAO,MAAM,kBAAkB,YAAY,CAAC;AAuG5C,qBAAa,UAAU;IAEnB,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,SAAS;IACjB,OAAO,CAAC,SAAS;gBAFT,QAAQ,EAAE,iBAAiB,EAC3B,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM;IAG3B,KAAK,IAAI,MAAM;IAIT,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAStB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUrC,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC;IAUhC,MAAM;;;;IAIA,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IA0B/B,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC;IAUnC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAStB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAUlD,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAU3C,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;IAU7B,UAAU,IAAI,OAAO,CAAC,OAAO,CAAC;IAU9B,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC;IAU7B,OAAO,IAAI,OAAO,CAAC;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAU3E,YAAY,CAAC,OAAO,EAAE,EAAE,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;CAiBvD"}
|
package/dist/lib/webelement.js
CHANGED
|
@@ -1,6 +1,106 @@
|
|
|
1
1
|
import { HttpClient } from './http.js';
|
|
2
2
|
export const W3C_ELEMENT_KEY = 'element-6066-11e4-a52e-4f735466cecf';
|
|
3
3
|
export const LEGACY_ELEMENT_KEY = 'ELEMENT';
|
|
4
|
+
/**
|
|
5
|
+
* W3C-compatible "is element displayed" algorithm, executed via
|
|
6
|
+
* `POST /execute/sync`. Faithfully reproduces the behavior of Selenium's
|
|
7
|
+
* `bot.dom.isShown_` (the atom chromedriver and geckodriver's native
|
|
8
|
+
* `is displayed` commands are compiled from), so results match the browsers
|
|
9
|
+
* that currently answer via the legacy `/element/{id}/displayed` endpoint —
|
|
10
|
+
* while also working on Safari, whose command table omits that endpoint.
|
|
11
|
+
*
|
|
12
|
+
* Written in ES5-compatible style (plain `function`s, `var`, `for` loops) to
|
|
13
|
+
* match the other scripts sent to `/execute/sync` in this codebase and to run
|
|
14
|
+
* safely across every supported Classic remote end. Receives the element as
|
|
15
|
+
* `arguments[0]` and returns a boolean.
|
|
16
|
+
*
|
|
17
|
+
* Rules, each mirroring the corresponding `bot.dom` behavior:
|
|
18
|
+
* - `<input type="hidden">` and `<noscript>` are never shown.
|
|
19
|
+
* - `display:none` on the element OR any ancestor hides it. `display` is not
|
|
20
|
+
* inherited, so the ancestor chain must be walked explicitly.
|
|
21
|
+
* - `visibility:hidden`/`collapse` hides it. `visibility` IS inherited, and a
|
|
22
|
+
* descendant may override an ancestor back to `visible`, so we check only the
|
|
23
|
+
* element's OWN computed value (getComputedStyle already resolves
|
|
24
|
+
* inheritance) — this both matches `bot.dom` and is more correct than walking
|
|
25
|
+
* the chain for visibility.
|
|
26
|
+
* - No positive-area box hides it, unless a child has one (zero-size wrappers)
|
|
27
|
+
* or it is a `<br>` (a legitimately zero-width line break). Mirrors
|
|
28
|
+
* `bot.dom.positiveSize_`.
|
|
29
|
+
* - Being clipped out of view by an `overflow:hidden` ancestor hides it,
|
|
30
|
+
* matching `bot.dom.OverflowState.HIDDEN`. An element scrolled out of a
|
|
31
|
+
* `scroll`/`auto` ancestor is still considered shown (it can be scrolled
|
|
32
|
+
* into view — `bot.dom.OverflowState.SCROLL`), so it is not treated as
|
|
33
|
+
* hidden here.
|
|
34
|
+
*/
|
|
35
|
+
const IS_DISPLAYED_ATOM = `
|
|
36
|
+
var elem = arguments[0];
|
|
37
|
+
if (!elem || elem.nodeType !== 1) { return false; }
|
|
38
|
+
|
|
39
|
+
var win = elem.ownerDocument.defaultView || window;
|
|
40
|
+
function style(e, prop) {
|
|
41
|
+
var cs = win.getComputedStyle(e, null);
|
|
42
|
+
return cs ? cs.getPropertyValue(prop) : '';
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// <input type="hidden"> is never shown (bot.dom.isShown_).
|
|
46
|
+
var tag = elem.tagName ? elem.tagName.toUpperCase() : '';
|
|
47
|
+
if (tag === 'INPUT' && (elem.type || '').toLowerCase() === 'hidden') { return false; }
|
|
48
|
+
// <noscript> is not rendered.
|
|
49
|
+
if (tag === 'NOSCRIPT') { return false; }
|
|
50
|
+
|
|
51
|
+
// display:none on the element or any ancestor hides it. display is NOT
|
|
52
|
+
// inherited, so the whole chain must be checked (bot.dom.displayed_).
|
|
53
|
+
var node = elem;
|
|
54
|
+
while (node && node.nodeType === 1) {
|
|
55
|
+
if (style(node, 'display') === 'none') { return false; }
|
|
56
|
+
node = node.parentElement;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// visibility:hidden/collapse hides it. visibility IS inherited but overridable
|
|
60
|
+
// by descendants, so checking the element's own computed value is correct.
|
|
61
|
+
var vis = style(elem, 'visibility');
|
|
62
|
+
if (vis === 'hidden' || vis === 'collapse') { return false; }
|
|
63
|
+
|
|
64
|
+
// An element with no positive-area box is not shown, unless a child has one
|
|
65
|
+
// (zero-size wrapper) or it is a <br> (bot.dom.positiveSize_).
|
|
66
|
+
function positiveSize(e) {
|
|
67
|
+
var r = e.getBoundingClientRect();
|
|
68
|
+
if (r.width > 0 && r.height > 0) { return true; }
|
|
69
|
+
if (e.tagName && e.tagName.toUpperCase() === 'BR') { return true; }
|
|
70
|
+
var kids = e.childNodes;
|
|
71
|
+
for (var i = 0; i < kids.length; i++) {
|
|
72
|
+
var k = kids[i];
|
|
73
|
+
if (k.nodeType === 1 && positiveSize(k)) { return true; }
|
|
74
|
+
}
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
if (!positiveSize(elem)) { return false; }
|
|
78
|
+
|
|
79
|
+
// Clipped out of view by an overflow:hidden ancestor => hidden
|
|
80
|
+
// (bot.dom.OverflowState.HIDDEN). scroll/auto ancestors are treated as shown
|
|
81
|
+
// (OverflowState.SCROLL — scrollable into view). position:fixed escapes
|
|
82
|
+
// ancestor clipping, so skip the check for fixed elements.
|
|
83
|
+
if (style(elem, 'position') !== 'fixed') {
|
|
84
|
+
var rect = elem.getBoundingClientRect();
|
|
85
|
+
var parent = elem.parentElement;
|
|
86
|
+
while (parent) {
|
|
87
|
+
var ox = style(parent, 'overflow-x');
|
|
88
|
+
var oy = style(parent, 'overflow-y');
|
|
89
|
+
if (ox === 'hidden' || oy === 'hidden' || ox === 'clip' || oy === 'clip') {
|
|
90
|
+
var pr = parent.getBoundingClientRect();
|
|
91
|
+
var clippedX = (ox === 'hidden' || ox === 'clip') &&
|
|
92
|
+
(rect.right <= pr.left || rect.left >= pr.right);
|
|
93
|
+
var clippedY = (oy === 'hidden' || oy === 'clip') &&
|
|
94
|
+
(rect.bottom <= pr.top || rect.top >= pr.bottom);
|
|
95
|
+
if (clippedX || clippedY) { return false; }
|
|
96
|
+
}
|
|
97
|
+
if (style(parent, 'position') === 'fixed') { break; }
|
|
98
|
+
parent = parent.parentElement;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return true;
|
|
103
|
+
`;
|
|
4
104
|
export class WebElement {
|
|
5
105
|
endpoint;
|
|
6
106
|
sessionId;
|
|
@@ -43,10 +143,26 @@ export class WebElement {
|
|
|
43
143
|
return { [W3C_ELEMENT_KEY]: this.elementId, [LEGACY_ELEMENT_KEY]: this.elementId };
|
|
44
144
|
}
|
|
45
145
|
async isDisplayed() {
|
|
146
|
+
// The legacy `GET /element/{id}/displayed` endpoint is a pre-W3C JSON Wire
|
|
147
|
+
// Protocol command. chromedriver/geckodriver still accept it for backward
|
|
148
|
+
// compatibility, but it was never part of W3C WebDriver Classic and is
|
|
149
|
+
// absent from Apple's Safari 12+ command table. We therefore compute
|
|
150
|
+
// displayedness the same way every real driver does under the hood: by
|
|
151
|
+
// executing the well-known "displayedness atom" via the standard
|
|
152
|
+
// `POST /execute/sync` command, which every Classic remote end supports.
|
|
153
|
+
//
|
|
154
|
+
// The script below mirrors Selenium's `bot.dom.isShown_`
|
|
155
|
+
// (selenium/javascript/atoms/dom.js) — the exact algorithm chromedriver's
|
|
156
|
+
// and geckodriver's `is displayed` implementations are compiled from, and
|
|
157
|
+
// the same one wdio/Playwright rely on. Keeping it byte-for-byte faithful
|
|
158
|
+
// in behavior is what preserves existing Chrome/Chromium/Firefox results;
|
|
159
|
+
// this is a protocol change, not a semantics change. Each rule is annotated
|
|
160
|
+
// with the `bot.dom` behavior it reproduces so a reviewer can verify it.
|
|
46
161
|
const client = new HttpClient(this.endpoint);
|
|
47
162
|
const res = await client.send({
|
|
48
|
-
method: '
|
|
49
|
-
path: `/session/${this.sessionId}/
|
|
163
|
+
method: 'POST',
|
|
164
|
+
path: `/session/${this.sessionId}/execute/sync`,
|
|
165
|
+
body: { script: IS_DISPLAYED_ATOM, args: [this.toJSON()] },
|
|
50
166
|
});
|
|
51
167
|
const value = res?.value ?? res;
|
|
52
168
|
return Boolean(value);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webelement.js","sourceRoot":"","sources":["../../src/lib/webelement.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAIvC,MAAM,CAAC,MAAM,eAAe,GAAG,qCAAqC,CAAC;AACrE,MAAM,CAAC,MAAM,kBAAkB,GAAG,SAAS,CAAC;AAE5C,MAAM,OAAO,UAAU;IAEX;IACA;IACA;IAHV,YACU,QAA2B,EAC3B,SAAiB,EACjB,SAAiB;QAFjB,aAAQ,GAAR,QAAQ,CAAmB;QAC3B,cAAS,GAAT,SAAS,CAAQ;QACjB,cAAS,GAAT,SAAS,CAAQ;IACvB,CAAC;IAEL,KAAK;QACH,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAED,KAAK,CAAC,KAAK;QACT,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC7C,MAAM,MAAM,CAAC,IAAI,CAAC;YAChB,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,YAAY,IAAI,CAAC,SAAS,YAAY,IAAI,CAAC,SAAS,QAAQ;YAClE,IAAI,EAAE,EAAE;SACT,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,IAAY;QACzB,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC7C,MAAM,OAAO,GAAsC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC;QACnF,MAAM,MAAM,CAAC,IAAI,CAAC;YAChB,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,YAAY,IAAI,CAAC,SAAS,YAAY,IAAI,CAAC,SAAS,QAAQ;YAClE,IAAI,EAAE,OAAO;SACd,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,OAAO;QACX,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC7C,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CAAS;YACpC,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,YAAY,IAAI,CAAC,SAAS,YAAY,IAAI,CAAC,SAAS,OAAO;SAClE,CAAC,CAAC;QACH,MAAM,KAAK,GAAI,GAA+B,EAAE,KAAK,IAAK,GAAyB,CAAC;QACpF,OAAO,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;IAC7B,CAAC;IAED,MAAM;QACJ,OAAO,EAAE,CAAC,eAAe,CAAC,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,kBAAkB,CAAC,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC;IACrF,CAAC;IAED,KAAK,CAAC,WAAW;QACf,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC7C,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CAAU;YACrC,MAAM,EAAE,
|
|
1
|
+
{"version":3,"file":"webelement.js","sourceRoot":"","sources":["../../src/lib/webelement.ts"],"names":[],"mappings":"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"}
|
package/docs/api-reference.md
CHANGED
|
@@ -14,7 +14,7 @@ Launch browsers, move between pages and frames, handle dialogs, and wait for nav
|
|
|
14
14
|
| Symbol | Kind | Summary | Docs |
|
|
15
15
|
|---|---|---|---|
|
|
16
16
|
| `Browser` | class | — | [browser-api](browser-api.md) |
|
|
17
|
-
| `LaunchOptions` | type | Mutually-exclusive browser and
|
|
17
|
+
| `LaunchOptions` | type | Mutually-exclusive browser, Electron, and remote-WebDriver launch configurations. | [browser-api](browser-api.md) |
|
|
18
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
19
|
| `Page` | class | — | [browser-api](browser-api.md) |
|
|
20
20
|
| `Frame` | class | — | [browser-api](browser-api.md) |
|
|
@@ -153,6 +153,8 @@ Handle stable CraftDriver errors or customize browser driver services.
|
|
|
153
153
|
| `ChromeServiceOptions` | type | — | [getting-started](getting-started.md) |
|
|
154
154
|
| `FirefoxService` | class | — | [getting-started](getting-started.md) |
|
|
155
155
|
| `FirefoxServiceOptions` | type | — | [getting-started](getting-started.md) |
|
|
156
|
+
| `SafariService` | class | — | [getting-started](getting-started.md) |
|
|
157
|
+
| `SafariServiceOptions` | type | — | [getting-started](getting-started.md) |
|
|
156
158
|
|
|
157
159
|
## Other Exports
|
|
158
160
|
|
|
@@ -165,5 +167,7 @@ Exports that are public but not yet assigned to a feature group.
|
|
|
165
167
|
| `ElectronMockCall` | type | One recorded invocation of a mocked Electron main-process method. | — |
|
|
166
168
|
| `ElectronRemoteOptions` | type | Extra context ElectronRemote needs beyond the inspector endpoint. | [electron](electron.md) |
|
|
167
169
|
| `PageMatcher` | type | Selects a top-level page by `url` and/or `title` for {@link Browser.waitForPage}. A string matches as a substring; a `RegExp` is tested. When both fields are given, both must match. | [browser-api](browser-api.md) |
|
|
170
|
+
| `RemoteAuth` | type | — | — |
|
|
171
|
+
| `RemoteWebDriverOptions` | type | Options for connecting to any W3C-compatible remote WebDriver endpoint — a self-hosted Selenium Grid, BrowserStack, or another cloud provider. Provider-specific detail (BrowserStack's `bstack:options`, etc.) is forwarded through `capabilities` without schema conversion. | — |
|
|
168
172
|
|
|
169
|
-
Total exports: **
|
|
173
|
+
Total exports: **86**.
|
package/docs/browser-api.md
CHANGED
|
@@ -27,7 +27,7 @@ const browser = await Browser.launch({
|
|
|
27
27
|
|
|
28
28
|
| Option | Type | Default | Description |
|
|
29
29
|
|--------|------|---------|-------------|
|
|
30
|
-
| `browserName` | `'chrome' \| 'chromium' \| 'firefox'` | `'chrome'` |
|
|
30
|
+
| `browserName` | `'chrome' \| 'chromium' \| 'firefox' \| 'safari'`; any non-empty `string` remotely | `'chrome'` | Local browser to launch or provider-facing remote browser name |
|
|
31
31
|
| `enableBiDi` | `boolean` | browsers: `true`; Electron: `false` | Use WebDriver BiDi. Electron requires an explicit opt-in because negotiation resets its initial renderer to `about:blank`. |
|
|
32
32
|
| `storageState` | `string` | — | Path to a session-state JSON file to load on startup |
|
|
33
33
|
| `mobileEmulation` | `MobileEmulation \| DeviceName` | — | Mobile device emulation settings (Chrome/Chromium only) |
|
|
@@ -35,10 +35,11 @@ const browser = await Browser.launch({
|
|
|
35
35
|
| `browserPath` | `string` | — | Custom browser binary to launch (Chrome/Chromium/Firefox) — see [Driver Configuration → Browser Binary Configuration](./driver-configuration.md#browser-binary-configuration) |
|
|
36
36
|
| `electron` | `ElectronLaunchOptions` | — | Launch a packaged Electron application renderer instead of a browser. Mutually exclusive with browser-only options; see [Testing Electron Apps](./electron.md). |
|
|
37
37
|
| `electronService` | `ElectronService` | automatic | Customize the Electron-specific chromedriver service. Valid only with `electron`. |
|
|
38
|
+
| `remote` | `RemoteWebDriverOptions` | — | Connect to a remote W3C WebDriver endpoint instead of launching locally. It supports `browserName`, `enableBiDi`, and `storageState`, but not local service, binary, argument, emulation, or download-directory options. **Not supported by the CLI or MCP server.** See [Remote WebDriver](./remote-webdriver.md). |
|
|
38
39
|
|
|
39
|
-
The TypeScript surface is a discriminated union
|
|
40
|
-
|
|
41
|
-
JSON-driven callers.
|
|
40
|
+
The TypeScript surface is a discriminated union for local browser, Electron,
|
|
41
|
+
and remote targets. Target-specific conflicts are also validated at runtime
|
|
42
|
+
for JavaScript and JSON-driven callers.
|
|
42
43
|
|
|
43
44
|
## Navigation
|
|
44
45
|
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Driver Configuration
|
|
2
2
|
|
|
3
|
+
> This page is **local-only** — it covers resolving a local
|
|
4
|
+
> chromedriver/geckodriver/safaridriver binary. Connecting to a remote
|
|
5
|
+
> Selenium Grid or cloud provider instead of a local driver process is a
|
|
6
|
+
> different, simpler configuration surface — see
|
|
7
|
+
> [Remote WebDriver](./remote-webdriver.md).
|
|
8
|
+
|
|
3
9
|
Craftdriver resolves the WebDriver binary through a chain — first match wins:
|
|
4
10
|
|
|
5
11
|
| Step | Source |
|
|
@@ -279,3 +285,57 @@ const browser = await Browser.launch({
|
|
|
279
285
|
}),
|
|
280
286
|
});
|
|
281
287
|
```
|
|
288
|
+
|
|
289
|
+
## Safari (macOS): driver ships with the browser
|
|
290
|
+
|
|
291
|
+
Everything above (steps 1–9, the download chain, the TTL cache) resolves
|
|
292
|
+
**chromedriver**/**geckodriver** — binaries craftdriver may fetch and cache on
|
|
293
|
+
disk. `browserName: 'safari'` doesn't fit that model at all: Apple ships
|
|
294
|
+
`safaridriver` as part of macOS/Safari itself, so there is no download, no
|
|
295
|
+
version-matching problem, and no cache to warm. This page covers only driver
|
|
296
|
+
**resolution**; for setup (`safaridriver --enable`), capabilities, limitations,
|
|
297
|
+
and Safari Technology Preview, see the [**Safari guide**](./safari.md).
|
|
298
|
+
|
|
299
|
+
`SafariService` resolves the `safaridriver` binary through its own chain —
|
|
300
|
+
first match wins, and none of these steps ever triggers a network call:
|
|
301
|
+
|
|
302
|
+
| Step | Source |
|
|
303
|
+
|---|---|
|
|
304
|
+
| 1 | `binaryPath` passed to `new SafariService({ binaryPath })` |
|
|
305
|
+
| 2 | `CRAFTDRIVER_SAFARIDRIVER_PATH` env var |
|
|
306
|
+
| 3 | `CRAFTDRIVER_DRIVER_PATH` env var (generic fallback, shared with Chrome/Firefox) |
|
|
307
|
+
| 4 | `/usr/bin/safaridriver` (the fixed system location on macOS) |
|
|
308
|
+
| 5 | `safaridriver` on `PATH` |
|
|
309
|
+
| 6 | a clear, actionable error if nothing resolves — craftdriver never downloads a `safaridriver` |
|
|
310
|
+
|
|
311
|
+
To pin **Safari Technology Preview**, point `binaryPath` at its bundled driver
|
|
312
|
+
(`/Applications/Safari Technology Preview.app/Contents/MacOS/safaridriver`) —
|
|
313
|
+
see the [Safari guide](./safari.md#safari-technology-preview).
|
|
314
|
+
|
|
315
|
+
### Extra `safaridriver` arguments
|
|
316
|
+
|
|
317
|
+
`SafariService` accepts `args`, passed through verbatim after `--port <port>`.
|
|
318
|
+
The most useful one is `--diagnose`, which turns on `safaridriver`'s
|
|
319
|
+
diagnostic logging (written under `~/Library/Logs/com.apple.WebDriver/`) —
|
|
320
|
+
handy when a Safari session fails to start and the driver's own stdout/stderr
|
|
321
|
+
isn't enough to tell why:
|
|
322
|
+
|
|
323
|
+
```typescript
|
|
324
|
+
const browser = await Browser.launch({
|
|
325
|
+
browserName: 'safari',
|
|
326
|
+
safariService: new SafariService({ args: ['--diagnose'] }),
|
|
327
|
+
});
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### What's different from Chrome/Firefox here
|
|
331
|
+
|
|
332
|
+
- No `CRAFTDRIVER_CACHE_DIR`, `CRAFTDRIVER_DRIVER_TTL`, or `CRAFTDRIVER_OFFLINE`
|
|
333
|
+
behavior applies to Safari — there's nothing cached or downloaded to
|
|
334
|
+
configure.
|
|
335
|
+
- No browser-binary resolution chain (`browserPath` / `CRAFTDRIVER_CHROME_PATH`-
|
|
336
|
+
style) exists for Safari — you select which Safari build's driver to use via
|
|
337
|
+
`SafariService.binaryPath` directly, as shown above, not via a separate
|
|
338
|
+
browser-path option.
|
|
339
|
+
- `enableBiDi: true` is rejected before launch — Safari has no documented
|
|
340
|
+
WebDriver BiDi endpoint to negotiate. See
|
|
341
|
+
[WebDriver Standards → Safari is Classic-only](./standards.md#safari-is-classic-only).
|
package/docs/getting-started.md
CHANGED
|
@@ -75,29 +75,49 @@ returns the same `Page` the shortcuts would target.
|
|
|
75
75
|
|
|
76
76
|
## Launch Options
|
|
77
77
|
|
|
78
|
+
The simplest launch runs Chrome:
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
const browser = await Browser.launch(); // Chrome by default
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Pick a browser with `browserName`:
|
|
85
|
+
|
|
78
86
|
```typescript
|
|
79
|
-
// Chrome (default)
|
|
80
87
|
const browser = await Browser.launch({
|
|
81
|
-
browserName: '
|
|
88
|
+
browserName: 'firefox', // 'chrome' | 'chromium' | 'firefox' | 'safari'
|
|
82
89
|
storageState: './session.json', // optional: pre-load saved session state
|
|
83
90
|
});
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
To switch browsers from an environment variable in your own tests, read it
|
|
94
|
+
yourself and pass it to `browserName` — craftdriver doesn't read any browser
|
|
95
|
+
env var for you:
|
|
84
96
|
|
|
85
|
-
|
|
97
|
+
```typescript
|
|
86
98
|
const browser = await Browser.launch({
|
|
87
|
-
browserName: '
|
|
99
|
+
browserName: process.env.BROWSER_NAME ?? 'chrome',
|
|
88
100
|
});
|
|
89
101
|
```
|
|
90
102
|
|
|
91
|
-
###
|
|
103
|
+
### Safari
|
|
92
104
|
|
|
93
|
-
|
|
105
|
+
Safari runs on macOS with the same API, as a smaller Classic-only tier. Enable
|
|
106
|
+
automation once (`safaridriver --enable`) and launch:
|
|
94
107
|
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
108
|
+
```typescript
|
|
109
|
+
const browser = await Browser.launch({ browserName: 'safari' });
|
|
110
|
+
await browser.navigateTo('http://127.0.0.1:8080/login.html');
|
|
111
|
+
await browser.fill('#username', 'alice');
|
|
112
|
+
await browser.click('#submit');
|
|
113
|
+
await browser.quit();
|
|
99
114
|
```
|
|
100
115
|
|
|
116
|
+
Safari is macOS-only, headed, and serial (one session at a time), and doesn't
|
|
117
|
+
support BiDi-only features (network mocking, tracing, emulation, …). See the
|
|
118
|
+
[**Safari guide**](./safari.md) for the full picture — setup, what works, and
|
|
119
|
+
Safari Technology Preview.
|
|
120
|
+
|
|
101
121
|
### Custom WebDriver binary or port
|
|
102
122
|
|
|
103
123
|
`Browser.launch()` resolves the driver binary automatically. To pin a
|
package/docs/index.md
CHANGED
|
@@ -33,7 +33,7 @@ features:
|
|
|
33
33
|
details: CLI, MCP server, and assistant rules are there when you want coding agents to drive the browser too.
|
|
34
34
|
---
|
|
35
35
|
|
|
36
|
-
##
|
|
36
|
+
## Quick Start
|
|
37
37
|
|
|
38
38
|
```bash
|
|
39
39
|
npm install craftdriver --save-dev
|
|
@@ -60,6 +60,7 @@ await browser.quit();
|
|
|
60
60
|
| Write browser automation | [Getting Started](./getting-started.md) |
|
|
61
61
|
| Solve a common testing workflow | [Recipes](./recipes.md) |
|
|
62
62
|
| Give an AI coding agent a browser | [AI Agent Guide](./agents.md) |
|
|
63
|
+
| Run on a Grid or cloud provider | [Remote WebDriver](./remote-webdriver.md) |
|
|
63
64
|
|
|
64
65
|
## Good Stuff To Read Next
|
|
65
66
|
|
package/docs/keyboard-mouse.md
CHANGED
|
@@ -255,10 +255,11 @@ This is often more convenient than using the global keyboard API.
|
|
|
255
255
|
|
|
256
256
|
---
|
|
257
257
|
|
|
258
|
-
## Touch gestures
|
|
258
|
+
## Touch gestures
|
|
259
259
|
|
|
260
|
-
When running with `mobileEmulation`,
|
|
261
|
-
|
|
260
|
+
When running Chrome/Chromium with `mobileEmulation`, or a remote real-device
|
|
261
|
+
session whose provider supports W3C touch-pointer actions, two convenience
|
|
262
|
+
gestures are exposed under `browser.gesture`:
|
|
262
263
|
|
|
263
264
|
```typescript
|
|
264
265
|
// Swipe from one point to another (px coordinates).
|
|
@@ -277,5 +278,6 @@ await browser.gesture.pinch({
|
|
|
277
278
|
});
|
|
278
279
|
```
|
|
279
280
|
|
|
280
|
-
These
|
|
281
|
-
|
|
281
|
+
These use W3C Pointer Actions and do not require BiDi. Remote support depends
|
|
282
|
+
on the selected device, browser, and provider. Local desktop Safari rejects
|
|
283
|
+
touch gestures because it has no documented touch-pointer automation surface.
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="utf-8" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
7
|
+
<title>Craftdriver Displayedness</title>
|
|
8
|
+
<style>
|
|
9
|
+
body {
|
|
10
|
+
font-family: system-ui, Arial, sans-serif;
|
|
11
|
+
margin: 1rem;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/* An ancestor hidden via display:none. Its descendant #hidden-by-ancestor
|
|
15
|
+
has no style of its own but must count as not displayed. */
|
|
16
|
+
#display-none-ancestor {
|
|
17
|
+
display: none;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/* Own visibility:hidden. */
|
|
21
|
+
#visibility-hidden {
|
|
22
|
+
visibility: hidden;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/* Zero-sized content: no rendered box, overflow clipped. */
|
|
26
|
+
#zero-size {
|
|
27
|
+
width: 0;
|
|
28
|
+
height: 0;
|
|
29
|
+
overflow: hidden;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/* A scrollable-but-CLIPPING (overflow:hidden) container. The child at the
|
|
33
|
+
bottom is scrolled out of the container's viewport, so it is clipped and
|
|
34
|
+
not displayed (bot.dom OverflowState.HIDDEN). */
|
|
35
|
+
#clip-container {
|
|
36
|
+
width: 120px;
|
|
37
|
+
height: 80px;
|
|
38
|
+
overflow: hidden;
|
|
39
|
+
border: 1px solid #ccc;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
#clip-spacer {
|
|
43
|
+
height: 400px;
|
|
44
|
+
}
|
|
45
|
+
</style>
|
|
46
|
+
</head>
|
|
47
|
+
|
|
48
|
+
<body>
|
|
49
|
+
<div class="container">
|
|
50
|
+
<!-- Plainly visible baseline. -->
|
|
51
|
+
<div id="visible-el">I am visible</div>
|
|
52
|
+
|
|
53
|
+
<!-- Hidden by a display:none ancestor. -->
|
|
54
|
+
<div id="display-none-ancestor">
|
|
55
|
+
<div id="hidden-by-ancestor">Hidden because my ancestor is display:none</div>
|
|
56
|
+
</div>
|
|
57
|
+
|
|
58
|
+
<!-- Own display:none. -->
|
|
59
|
+
<div id="display-none-self" style="display: none">Hidden by my own display:none</div>
|
|
60
|
+
|
|
61
|
+
<!-- Own visibility:hidden. -->
|
|
62
|
+
<div id="visibility-hidden">Hidden by my own visibility:hidden</div>
|
|
63
|
+
|
|
64
|
+
<!-- Visibility hidden ancestor with a visible descendant override:
|
|
65
|
+
the child sets visibility:visible and MUST count as displayed. -->
|
|
66
|
+
<div style="visibility: hidden">
|
|
67
|
+
<div id="visibility-visible-override" style="visibility: visible">
|
|
68
|
+
Visible again despite hidden ancestor
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
|
|
72
|
+
<!-- Zero-sized content. -->
|
|
73
|
+
<div id="zero-size">unrenderable</div>
|
|
74
|
+
|
|
75
|
+
<!-- A <br> is legitimately zero-width but should count as displayed. -->
|
|
76
|
+
<br id="line-break" />
|
|
77
|
+
|
|
78
|
+
<!-- Element scrolled out of an overflow:hidden container's viewport. -->
|
|
79
|
+
<div id="clip-container">
|
|
80
|
+
<div id="clip-spacer"></div>
|
|
81
|
+
<div id="scrolled-out-of-clip">I am below the clipped fold</div>
|
|
82
|
+
</div>
|
|
83
|
+
</div>
|
|
84
|
+
</body>
|
|
85
|
+
|
|
86
|
+
</html>
|