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.
Files changed (87) hide show
  1. package/CHANGELOG.md +17 -3
  2. package/README.md +6 -2
  3. package/dist/cli/daemon.d.ts.map +1 -1
  4. package/dist/cli/daemon.js +4 -0
  5. package/dist/cli/daemon.js.map +1 -1
  6. package/dist/cli/mcp/server.d.ts.map +1 -1
  7. package/dist/cli/mcp/server.js +4 -0
  8. package/dist/cli/mcp/server.js.map +1 -1
  9. package/dist/cli/parseArgs.d.ts +2 -2
  10. package/dist/cli/parseArgs.d.ts.map +1 -1
  11. package/dist/cli/parseArgs.js +1 -1
  12. package/dist/index.d.ts +2 -0
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +1 -0
  15. package/dist/index.js.map +1 -1
  16. package/dist/lib/bidi/storage.d.ts +13 -0
  17. package/dist/lib/bidi/storage.d.ts.map +1 -1
  18. package/dist/lib/bidi/storage.js +81 -32
  19. package/dist/lib/bidi/storage.js.map +1 -1
  20. package/dist/lib/browser.d.ts +48 -3
  21. package/dist/lib/browser.d.ts.map +1 -1
  22. package/dist/lib/browser.js +212 -86
  23. package/dist/lib/browser.js.map +1 -1
  24. package/dist/lib/browserContext.d.ts +2 -2
  25. package/dist/lib/browserContext.d.ts.map +1 -1
  26. package/dist/lib/browserContext.js +1 -1
  27. package/dist/lib/builder.d.ts +16 -2
  28. package/dist/lib/builder.d.ts.map +1 -1
  29. package/dist/lib/builder.js +46 -2
  30. package/dist/lib/builder.js.map +1 -1
  31. package/dist/lib/capabilities.d.ts +20 -2
  32. package/dist/lib/capabilities.d.ts.map +1 -1
  33. package/dist/lib/capabilities.js +109 -48
  34. package/dist/lib/capabilities.js.map +1 -1
  35. package/dist/lib/driver.d.ts +33 -2
  36. package/dist/lib/driver.d.ts.map +1 -1
  37. package/dist/lib/driver.js +91 -2
  38. package/dist/lib/driver.js.map +1 -1
  39. package/dist/lib/driverManager.d.ts +28 -0
  40. package/dist/lib/driverManager.d.ts.map +1 -1
  41. package/dist/lib/driverManager.js +60 -0
  42. package/dist/lib/driverManager.js.map +1 -1
  43. package/dist/lib/elementHandle.d.ts.map +1 -1
  44. package/dist/lib/elementHandle.js +34 -0
  45. package/dist/lib/elementHandle.js.map +1 -1
  46. package/dist/lib/http.d.ts.map +1 -1
  47. package/dist/lib/http.js +31 -10
  48. package/dist/lib/http.js.map +1 -1
  49. package/dist/lib/launchTarget.d.ts +22 -3
  50. package/dist/lib/launchTarget.d.ts.map +1 -1
  51. package/dist/lib/launchTarget.js +159 -9
  52. package/dist/lib/launchTarget.js.map +1 -1
  53. package/dist/lib/remote.d.ts +55 -0
  54. package/dist/lib/remote.d.ts.map +1 -0
  55. package/dist/lib/remote.js +127 -0
  56. package/dist/lib/remote.js.map +1 -0
  57. package/dist/lib/safari.d.ts +90 -0
  58. package/dist/lib/safari.d.ts.map +1 -0
  59. package/dist/lib/safari.js +136 -0
  60. package/dist/lib/safari.js.map +1 -0
  61. package/dist/lib/tracing.d.ts +1 -1
  62. package/dist/lib/tracing.d.ts.map +1 -1
  63. package/dist/lib/tracing.js.map +1 -1
  64. package/dist/lib/types.d.ts +63 -0
  65. package/dist/lib/types.d.ts.map +1 -1
  66. package/dist/lib/vibiumTrace.d.ts +1 -1
  67. package/dist/lib/vibiumTrace.d.ts.map +1 -1
  68. package/dist/lib/webelement.d.ts.map +1 -1
  69. package/dist/lib/webelement.js +118 -2
  70. package/dist/lib/webelement.js.map +1 -1
  71. package/docs/api-reference.md +6 -2
  72. package/docs/browser-api.md +5 -4
  73. package/docs/driver-configuration.md +60 -0
  74. package/docs/getting-started.md +30 -10
  75. package/docs/index.md +2 -1
  76. package/docs/keyboard-mouse.md +7 -5
  77. package/docs/public/examples/displayed.html +86 -0
  78. package/docs/recipes/run-on-browserstack.md +265 -0
  79. package/docs/recipes.md +15 -1
  80. package/docs/remote-webdriver.md +308 -0
  81. package/docs/safari.md +118 -0
  82. package/docs/standards.md +18 -0
  83. package/docs/why-craftdriver.md +3 -1
  84. package/docs/zero-config-drivers.md +12 -0
  85. package/package.json +5 -1
  86. package/skills/craftdriver/SKILL.md +4 -1
  87. 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;AAE5C,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;IAU/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"}
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"}
@@ -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: 'GET',
49
- path: `/session/${this.sessionId}/element/${this.elementId}/displayed`,
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,KAAK;YACb,IAAI,EAAE,YAAY,IAAI,CAAC,SAAS,YAAY,IAAI,CAAC,SAAS,YAAY;SACvE,CAAC,CAAC;QACH,MAAM,KAAK,GAAI,GAAgC,EAAE,KAAK,IAAK,GAA0B,CAAC;QACtF,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC;IACxB,CAAC;IAED,KAAK,CAAC,gBAAgB;QACpB,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,aAAa;SACxE,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,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,YAAY,CAAC,IAAY;QAC7B,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC7C,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CAAgB;YAC3C,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,YAAY,IAAI,CAAC,SAAS,YAAY,IAAI,CAAC,SAAS,cAAc,IAAI,EAAE;SAC/E,CAAC,CAAC;QACH,MAAM,KAAK,GAAI,GAAsC,EAAE,KAAK,IAAK,GAAgC,CAAC;QAClG,OAAO,KAAK,CAAC;IACf,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,IAAY;QAC5B,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC7C,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CAAU;YACrC,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,YAAY,IAAI,CAAC,SAAS,YAAY,IAAI,CAAC,SAAS,aAAa,IAAI,EAAE;SAC9E,CAAC,CAAC;QACH,MAAM,KAAK,GAAI,GAAgC,EAAE,KAAK,IAAI,GAAG,CAAC;QAC9D,OAAO,KAAK,CAAC;IACf,CAAC;IAED,KAAK,CAAC,SAAS;QACb,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC7C,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CAAU;YACrC,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,YAAY,IAAI,CAAC,SAAS,YAAY,IAAI,CAAC,SAAS,UAAU;SACrE,CAAC,CAAC;QACH,MAAM,KAAK,GAAI,GAAgC,EAAE,KAAK,IAAK,GAA0B,CAAC;QACtF,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC;IACxB,CAAC;IAED,KAAK,CAAC,UAAU;QACd,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC7C,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CAAU;YACrC,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,YAAY,IAAI,CAAC,SAAS,YAAY,IAAI,CAAC,SAAS,WAAW;SACtE,CAAC,CAAC;QACH,MAAM,KAAK,GAAI,GAAgC,EAAE,KAAK,IAAK,GAA0B,CAAC;QACtF,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC;IACxB,CAAC;IAED,KAAK,CAAC,UAAU;QACd,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,WAAW,EAAE,CAAC;IAC3C,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,CAA0D;YACrF,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,YAAY,IAAI,CAAC,SAAS,YAAY,IAAI,CAAC,SAAS,OAAO;SAClE,CAAC,CAAC;QACH,MAAM,KAAK,GAAI,GAAgF,EAAE,KAAK,IAAI,GAAG,CAAC;QAC9G,OAAO,KAAgE,CAAC;IAC1E,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,OAAW;QAC5B,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC7C,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CAAgC;YAC3D,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,YAAY,IAAI,CAAC,SAAS,YAAY,IAAI,CAAC,SAAS,WAAW;YACrE,IAAI,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE;SACrD,CAAC,CAAC;QACH,MAAM,GAAG,GAAG,CAAE,GAAsD,EAAE,KAAK;YACxE,GAAgD,CAAkC,CAAC;QACtF,OAAO,CAAC,GAAG,IAAI,EAAE,CAAC;aACf,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YACT,MAAM,IAAI,GAAI,CAAS,EAAE,CAAC,eAAe,CAAC,IAAK,CAAS,EAAE,CAAC,kBAAkB,CAAC,CAAC;YAC/E,IAAI,CAAC,IAAI;gBAAE,OAAO,SAAS,CAAC;YAC5B,OAAO,IAAI,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;QAC7D,CAAC,CAAC;aACD,MAAM,CAAC,OAAO,CAAiB,CAAC;IACrC,CAAC;CACF"}
1
+ {"version":3,"file":"webelement.js","sourceRoot":"","sources":["../../src/lib/webelement.ts"],"names":[],"mappings":"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"}
@@ -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 Electron renderer launch configurations. | [browser-api](browser-api.md) |
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: **82**.
173
+ Total exports: **86**.
@@ -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'` | Browser to launch |
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: browser options and Electron
40
- options cannot be mixed. The same validation runs at runtime for JavaScript and
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).
@@ -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: 'chrome', // 'chrome' | 'chromium' | 'firefox'
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
- // Firefox
97
+ ```typescript
86
98
  const browser = await Browser.launch({
87
- browserName: 'firefox',
99
+ browserName: process.env.BROWSER_NAME ?? 'chrome',
88
100
  });
89
101
  ```
90
102
 
91
- ### Running tests on Firefox
103
+ ### Safari
92
104
 
93
- Set `BROWSER_NAME=firefox` before running your test command:
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
- ```bash
96
- BROWSER_NAME=firefox npx vitest run
97
- # or use the built-in script if your package.json has it:
98
- npm run test:firefox
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
- ## One Install
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
 
@@ -255,10 +255,11 @@ This is often more convenient than using the global keyboard API.
255
255
 
256
256
  ---
257
257
 
258
- ## Touch gestures (mobile emulation)
258
+ ## Touch gestures
259
259
 
260
- When running with `mobileEmulation`, two convenience gestures are
261
- exposed under `browser.gesture`:
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 wrap the W3C Pointer Actions API with two simulated touch
281
- pointers. They work whether or not BiDi is enabled.
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>