webdriverio 8.22.1 → 8.23.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 (52) hide show
  1. package/README.md +2 -2
  2. package/build/commands/browser/$$.d.ts +2 -2
  3. package/build/commands/browser/$$.d.ts.map +1 -1
  4. package/build/commands/browser/custom$$.d.ts +2 -3
  5. package/build/commands/browser/custom$$.d.ts.map +1 -1
  6. package/build/commands/browser/custom$$.js +1 -1
  7. package/build/commands/browser/custom$.js +1 -1
  8. package/build/commands/browser/emulate.d.ts +59 -0
  9. package/build/commands/browser/emulate.d.ts.map +1 -0
  10. package/build/commands/browser/emulate.js +127 -0
  11. package/build/commands/browser/react$$.d.ts +2 -2
  12. package/build/commands/browser/react$$.d.ts.map +1 -1
  13. package/build/commands/browser/saveScreenshot.d.ts.map +1 -1
  14. package/build/commands/browser/saveScreenshot.js +2 -4
  15. package/build/commands/browser/throttle.d.ts +4 -1
  16. package/build/commands/browser/throttle.d.ts.map +1 -1
  17. package/build/commands/browser/throttle.js +7 -137
  18. package/build/commands/browser/throttleCPU.d.ts +25 -0
  19. package/build/commands/browser/throttleCPU.d.ts.map +1 -0
  20. package/build/commands/browser/throttleCPU.js +41 -0
  21. package/build/commands/browser/throttleNetwork.d.ts +3 -0
  22. package/build/commands/browser/throttleNetwork.d.ts.map +1 -0
  23. package/build/commands/browser/throttleNetwork.js +145 -0
  24. package/build/commands/browser/url.js +2 -2
  25. package/build/commands/browser.d.ts +3 -0
  26. package/build/commands/browser.d.ts.map +1 -1
  27. package/build/commands/browser.js +3 -0
  28. package/build/commands/element/click.d.ts.map +1 -1
  29. package/build/commands/element/click.js +40 -17
  30. package/build/commands/element/custom$$.d.ts +1 -2
  31. package/build/commands/element/custom$$.d.ts.map +1 -1
  32. package/build/commands/element/custom$.js +1 -1
  33. package/build/commands/element/getCSSProperty.d.ts +7 -5
  34. package/build/commands/element/getCSSProperty.d.ts.map +1 -1
  35. package/build/commands/element/getCSSProperty.js +55 -18
  36. package/build/commands/element/moveTo.d.ts.map +1 -1
  37. package/build/commands/element/moveTo.js +25 -14
  38. package/build/commands/element/react$$.d.ts +1 -1
  39. package/build/commands/element/react$$.d.ts.map +1 -1
  40. package/build/commands/element/shadow$$.d.ts +1 -2
  41. package/build/commands/element/shadow$$.d.ts.map +1 -1
  42. package/build/multiremote.d.ts +2 -2
  43. package/build/multiremote.d.ts.map +1 -1
  44. package/build/types.d.ts +38 -5
  45. package/build/types.d.ts.map +1 -1
  46. package/build/utils/findStrategy.d.ts.map +1 -1
  47. package/build/utils/findStrategy.js +12 -7
  48. package/build/utils/getElementObject.d.ts +2 -2
  49. package/build/utils/getElementObject.d.ts.map +1 -1
  50. package/build/utils/index.d.ts +2 -2
  51. package/build/utils/index.d.ts.map +1 -1
  52. package/package.json +7 -7
@@ -0,0 +1,145 @@
1
+ /**
2
+ * Throttle the network capabilities of the browser. This can help to
3
+ * emulate certain scenarios where a user loses their internet connection
4
+ * and your app needs to address that.
5
+ *
6
+ * There are many presets available with default configurations for ease of use.
7
+ * They are `offline`, `GPRS`, `Regular2G`, `Good2G`, `Regular3G`, `Good3G`,
8
+ * `Regular4G`, `DSL`, `WiFi`, `online`.
9
+ *
10
+ * You can see the values for these presets [in the source code](https://github.com/webdriverio/webdriverio/blob/6824e4eb118a8d20685f12f4bc42f13fd56f8a25/packages/webdriverio/src/commands/browser/throttleNetwork.js#L29).
11
+ *
12
+ * :::info
13
+ *
14
+ * Note that using the `throttleNetwork` command requires support for Chrome DevTools protocol and e.g.
15
+ * can not be used when running automated tests in the cloud. Find out more in the
16
+ * [Automation Protocols](/docs/automationProtocols) section.
17
+ *
18
+ * :::
19
+ *
20
+ * <example>
21
+ :throttleNetwork.js
22
+ it('should throttle the network', async () => {
23
+ // via static string preset
24
+ await browser.throttleNetwork('Regular3G')
25
+
26
+ // via custom values
27
+ await browser.throttleNetwork({
28
+ offline: false,
29
+ downloadThroughput: 200 * 1024 / 8,
30
+ uploadThroughput: 200 * 1024 / 8,
31
+ latency: 20
32
+ })
33
+ });
34
+ * </example>
35
+ *
36
+ * @alias browser.throttleNetwork
37
+ * @param {ThrottleOptions} params parameters for throttling
38
+ * @param {boolean} params.offline True to emulate internet disconnection.
39
+ * @param {number} params.latency Minimum latency from request sent to response headers received (ms).
40
+ * @param {number} params.downloadThroughput Maximal aggregated download throughput (bytes/sec). -1 disables download throttling.
41
+ * @param {number} params.uploadThroughput Maximal aggregated upload throughput (bytes/sec). -1 disables upload throttling.
42
+ * @type utility
43
+ *
44
+ */
45
+ import { getBrowserObject } from '../../utils/index.js';
46
+ const NETWORK_PRESETS = {
47
+ 'offline': {
48
+ offline: true,
49
+ downloadThroughput: 0,
50
+ uploadThroughput: 0,
51
+ latency: 1
52
+ },
53
+ 'GPRS': {
54
+ offline: false,
55
+ downloadThroughput: 50 * 1024 / 8,
56
+ uploadThroughput: 20 * 1024 / 8,
57
+ latency: 500
58
+ },
59
+ 'Regular2G': {
60
+ offline: false,
61
+ downloadThroughput: 250 * 1024 / 8,
62
+ uploadThroughput: 50 * 1024 / 8,
63
+ latency: 300
64
+ },
65
+ 'Good2G': {
66
+ offline: false,
67
+ downloadThroughput: 450 * 1024 / 8,
68
+ uploadThroughput: 150 * 1024 / 8,
69
+ latency: 150
70
+ },
71
+ 'Regular3G': {
72
+ offline: false,
73
+ downloadThroughput: 750 * 1024 / 8,
74
+ uploadThroughput: 250 * 1024 / 8,
75
+ latency: 100
76
+ },
77
+ 'Good3G': {
78
+ offline: false,
79
+ downloadThroughput: 1.5 * 1024 * 1024 / 8,
80
+ uploadThroughput: 750 * 1024 / 8,
81
+ latency: 40
82
+ },
83
+ 'Regular4G': {
84
+ offline: false,
85
+ downloadThroughput: 4 * 1024 * 1024 / 8,
86
+ uploadThroughput: 3 * 1024 * 1024 / 8,
87
+ latency: 20
88
+ },
89
+ 'DSL': {
90
+ offline: false,
91
+ downloadThroughput: 2 * 1024 * 1024 / 8,
92
+ uploadThroughput: 1 * 1024 * 1024 / 8,
93
+ latency: 5
94
+ },
95
+ 'WiFi': {
96
+ offline: false,
97
+ downloadThroughput: 30 * 1024 * 1024 / 8,
98
+ uploadThroughput: 15 * 1024 * 1024 / 8,
99
+ latency: 2
100
+ },
101
+ 'online': {
102
+ offline: false,
103
+ latency: 0,
104
+ downloadThroughput: -1,
105
+ uploadThroughput: -1
106
+ }
107
+ };
108
+ const NETWORK_PRESET_TYPES = Object.keys(NETWORK_PRESETS);
109
+ export async function throttleNetwork(params) {
110
+ if (
111
+ /**
112
+ * check string parameter
113
+ */
114
+ (typeof params !== 'string' || !NETWORK_PRESET_TYPES.includes(params)) &&
115
+ /**
116
+ * check object parameter
117
+ */
118
+ (typeof params !== 'object')) {
119
+ throw new Error(`Invalid parameter for "throttleNetwork". Expected it to be typeof object or one of the following values: ${NETWORK_PRESET_TYPES.join(', ')} but found "${params}"`);
120
+ }
121
+ /**
122
+ * use WebDriver extension if connected with cloud service
123
+ */
124
+ if (this.isSauce) {
125
+ const browser = getBrowserObject(this);
126
+ await browser.sauceThrottleNetwork(params);
127
+ return null;
128
+ }
129
+ const failedConnectionMessage = 'No Puppeteer connection could be established which is required to use this command';
130
+ // Connect to Chrome DevTools
131
+ await this.getPuppeteer();
132
+ if (!this.puppeteer) {
133
+ throw new Error(failedConnectionMessage);
134
+ }
135
+ const pages = await this.puppeteer.pages();
136
+ if (!pages.length) {
137
+ throw new Error(failedConnectionMessage);
138
+ }
139
+ const client = await pages[0].target().createCDPSession();
140
+ // Set throttling property
141
+ await client.send('Network.emulateNetworkConditions', typeof params === 'string'
142
+ ? NETWORK_PRESETS[params]
143
+ : params);
144
+ return null;
145
+ }
@@ -43,9 +43,9 @@ export async function url(path) {
43
43
  path = (new URL(path, this.options.baseUrl)).href;
44
44
  }
45
45
  if (this.isBidi) {
46
- const { contexts } = await this.browsingContextGetTree({});
46
+ const context = await this.getWindowHandle();
47
47
  const res = await this.browsingContextNavigate({
48
- context: contexts[0].context,
48
+ context,
49
49
  url: path
50
50
  });
51
51
  return res.url;
@@ -7,6 +7,7 @@ export * from './browser/custom$$.js';
7
7
  export * from './browser/custom$.js';
8
8
  export * from './browser/debug.js';
9
9
  export * from './browser/deleteCookies.js';
10
+ export * from './browser/emulate.js';
10
11
  export * from './browser/execute.js';
11
12
  export * from './browser/executeAsync.js';
12
13
  export * from './browser/getCookies.js';
@@ -30,6 +31,8 @@ export * from './browser/setTimeout.js';
30
31
  export * from './browser/setWindowSize.js';
31
32
  export * from './browser/switchWindow.js';
32
33
  export * from './browser/throttle.js';
34
+ export * from './browser/throttleCPU.js';
35
+ export * from './browser/throttleNetwork.js';
33
36
  export * from './browser/touchAction.js';
34
37
  export * from './browser/uploadFile.js';
35
38
  export * from './browser/url.js';
@@ -1 +1 @@
1
- {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../src/commands/browser.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAA;AAC/B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,qBAAqB,CAAA;AACnC,cAAc,sBAAsB,CAAA;AACpC,cAAc,mBAAmB,CAAA;AACjC,cAAc,uBAAuB,CAAA;AACrC,cAAc,sBAAsB,CAAA;AACpC,cAAc,oBAAoB,CAAA;AAClC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,sBAAsB,CAAA;AACpC,cAAc,2BAA2B,CAAA;AACzC,cAAc,yBAAyB,CAAA;AACvC,cAAc,2BAA2B,CAAA;AACzC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,mBAAmB,CAAA;AACjC,cAAc,mBAAmB,CAAA;AACjC,cAAc,2BAA2B,CAAA;AACzC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,wBAAwB,CAAA;AACtC,cAAc,oBAAoB,CAAA;AAClC,cAAc,sBAAsB,CAAA;AACpC,cAAc,qBAAqB,CAAA;AACnC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,sBAAsB,CAAA;AACpC,cAAc,kCAAkC,CAAA;AAChD,cAAc,6BAA6B,CAAA;AAC3C,cAAc,qBAAqB,CAAA;AACnC,cAAc,yBAAyB,CAAA;AACvC,cAAc,yBAAyB,CAAA;AACvC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,2BAA2B,CAAA;AACzC,cAAc,uBAAuB,CAAA;AACrC,cAAc,0BAA0B,CAAA;AACxC,cAAc,yBAAyB,CAAA;AACvC,cAAc,kBAAkB,CAAA;AAChC,cAAc,wBAAwB,CAAA"}
1
+ {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../src/commands/browser.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAA;AAC/B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,qBAAqB,CAAA;AACnC,cAAc,sBAAsB,CAAA;AACpC,cAAc,mBAAmB,CAAA;AACjC,cAAc,uBAAuB,CAAA;AACrC,cAAc,sBAAsB,CAAA;AACpC,cAAc,oBAAoB,CAAA;AAClC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,sBAAsB,CAAA;AACpC,cAAc,sBAAsB,CAAA;AACpC,cAAc,2BAA2B,CAAA;AACzC,cAAc,yBAAyB,CAAA;AACvC,cAAc,2BAA2B,CAAA;AACzC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,mBAAmB,CAAA;AACjC,cAAc,mBAAmB,CAAA;AACjC,cAAc,2BAA2B,CAAA;AACzC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,wBAAwB,CAAA;AACtC,cAAc,oBAAoB,CAAA;AAClC,cAAc,sBAAsB,CAAA;AACpC,cAAc,qBAAqB,CAAA;AACnC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,sBAAsB,CAAA;AACpC,cAAc,kCAAkC,CAAA;AAChD,cAAc,6BAA6B,CAAA;AAC3C,cAAc,qBAAqB,CAAA;AACnC,cAAc,yBAAyB,CAAA;AACvC,cAAc,yBAAyB,CAAA;AACvC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,2BAA2B,CAAA;AACzC,cAAc,uBAAuB,CAAA;AACrC,cAAc,0BAA0B,CAAA;AACxC,cAAc,8BAA8B,CAAA;AAC5C,cAAc,0BAA0B,CAAA;AACxC,cAAc,yBAAyB,CAAA;AACvC,cAAc,kBAAkB,CAAA;AAChC,cAAc,wBAAwB,CAAA"}
@@ -7,6 +7,7 @@ export * from './browser/custom$$.js';
7
7
  export * from './browser/custom$.js';
8
8
  export * from './browser/debug.js';
9
9
  export * from './browser/deleteCookies.js';
10
+ export * from './browser/emulate.js';
10
11
  export * from './browser/execute.js';
11
12
  export * from './browser/executeAsync.js';
12
13
  export * from './browser/getCookies.js';
@@ -30,6 +31,8 @@ export * from './browser/setTimeout.js';
30
31
  export * from './browser/setWindowSize.js';
31
32
  export * from './browser/switchWindow.js';
32
33
  export * from './browser/throttle.js';
34
+ export * from './browser/throttleCPU.js';
35
+ export * from './browser/throttleNetwork.js';
33
36
  export * from './browser/touchAction.js';
34
37
  export * from './browser/uploadFile.js';
35
38
  export * from './browser/url.js';
@@ -1 +1 @@
1
- {"version":3,"file":"click.d.ts","sourceRoot":"","sources":["../../../src/commands/element/click.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAGlD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8EG;AACH,wBAAsB,KAAK,CACvB,IAAI,EAAE,WAAW,CAAC,OAAO,EACzB,OAAO,CAAC,EAAE,YAAY,iBAyDzB"}
1
+ {"version":3,"file":"click.d.ts","sourceRoot":"","sources":["../../../src/commands/element/click.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAGlD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8EG;AACH,wBAAsB,KAAK,CACvB,IAAI,EAAE,WAAW,CAAC,OAAO,EACzB,OAAO,CAAC,EAAE,YAAY,iBA+EzB"}
@@ -86,11 +86,11 @@ export async function click(options) {
86
86
  throw new TypeError('Options must be an object');
87
87
  }
88
88
  let button = (options.button || 0);
89
- const { x: xoffset = 0, y: yoffset = 0, skipRelease = false } = options || {};
90
- if (typeof xoffset !== 'number'
91
- || typeof yoffset !== 'number'
92
- || !Number.isInteger(xoffset)
93
- || !Number.isInteger(yoffset)) {
89
+ const { x: xOffset = 0, y: yOffset = 0, skipRelease = false } = options || {};
90
+ if (typeof xOffset !== 'number'
91
+ || typeof yOffset !== 'number'
92
+ || !Number.isInteger(xOffset)
93
+ || !Number.isInteger(yOffset)) {
94
94
  throw new TypeError('Coordinates must be integers');
95
95
  }
96
96
  if (options.button === 'left') {
@@ -107,20 +107,43 @@ export async function click(options) {
107
107
  }
108
108
  if (this.isW3C) {
109
109
  const browser = getBrowserObject(this);
110
- await browser.action('pointer', {
111
- parameters: { pointerType: 'mouse' }
112
- })
113
- .move({
114
- origin: this,
115
- x: xoffset,
116
- y: yoffset
117
- })
118
- .down({ button })
119
- .up({ button })
120
- .perform(skipRelease);
110
+ if (xOffset || yOffset) {
111
+ const { width, height } = await browser.getElementRect(this.elementId);
112
+ if ((xOffset && xOffset < (-Math.floor(width / 2))) || (xOffset && xOffset > Math.floor(width / 2))) {
113
+ throw new Error('xOffset would cause a out of bounds error as it goes outside of element');
114
+ }
115
+ if ((yOffset && yOffset < (-Math.floor(height / 2))) || (yOffset && yOffset > Math.floor(height / 2))) {
116
+ throw new Error('yOffset would cause a out of bounds error as it goes outside of element');
117
+ }
118
+ }
119
+ const clickNested = async () => {
120
+ await browser.action('pointer', {
121
+ parameters: { pointerType: 'mouse' }
122
+ })
123
+ .move({
124
+ origin: this,
125
+ x: xOffset,
126
+ y: yOffset
127
+ })
128
+ .down({ button })
129
+ .up({ button })
130
+ .perform(skipRelease);
131
+ };
132
+ try {
133
+ await clickNested();
134
+ }
135
+ catch {
136
+ /**
137
+ * Workaround, because sometimes browser.action().move() flaky and isn't able to scroll pointer to into view
138
+ * Moreover the action with 'nearest' behavior by default where element is aligned at the bottom of its ancestor.
139
+ * and could be overlapped. Scroll to center should definitely work even if element was covered with sticky header/footer
140
+ */
141
+ await this.scrollIntoView({ block: 'center', inline: 'center' });
142
+ await clickNested();
143
+ }
121
144
  return;
122
145
  }
123
146
  const { width, height } = await this.getElementSize(this.elementId);
124
- await this.moveToElement(this.elementId, xoffset + (width / 2), yoffset + (height / 2));
147
+ await this.moveToElement(this.elementId, xOffset + (width / 2), yOffset + (height / 2));
125
148
  return this.positionClick(button);
126
149
  }
@@ -1,4 +1,3 @@
1
- import type { ElementArray } from '../../types.js';
2
1
  /**
3
2
  *
4
3
  * The `customs$$` allows you to use a custom strategy declared by using `browser.addLocatorStrategy`.
@@ -24,5 +23,5 @@ import type { ElementArray } from '../../types.js';
24
23
  * @param {*} strategyArguments
25
24
  * @return {ElementArray}
26
25
  */
27
- export declare function custom$$(this: WebdriverIO.Element, strategyName: string, ...strategyArguments: any[]): Promise<ElementArray>;
26
+ export declare function custom$$(this: WebdriverIO.Element, strategyName: string, ...strategyArguments: any[]): Promise<WebdriverIO.ElementArray>;
28
27
  //# sourceMappingURL=custom$$.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"custom$$.d.ts","sourceRoot":"","sources":["../../../src/commands/element/custom$$.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAA0B,MAAM,gBAAgB,CAAA;AAE1E;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAsB,QAAQ,CAC1B,IAAI,EAAE,WAAW,CAAC,OAAO,EACzB,YAAY,EAAE,MAAM,EACpB,GAAG,iBAAiB,EAAE,GAAG,EAAE,GAC5B,OAAO,CAAC,YAAY,CAAC,CAkCvB"}
1
+ {"version":3,"file":"custom$$.d.ts","sourceRoot":"","sources":["../../../src/commands/element/custom$$.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAsB,QAAQ,CAC1B,IAAI,EAAE,WAAW,CAAC,OAAO,EACzB,YAAY,EAAE,MAAM,EACpB,GAAG,iBAAiB,EAAE,GAAG,EAAE,GAC5B,OAAO,CAAC,WAAW,CAAC,YAAY,CAAC,CAkCnC"}
@@ -55,5 +55,5 @@ export async function custom$(strategyName, ...strategyArguments) {
55
55
  if (res && typeof res[ELEMENT_KEY] === 'string') {
56
56
  return await getElement.call(this, strategyRef, res);
57
57
  }
58
- throw Error('Your locator strategy script must return an element');
58
+ return await getElement.call(this, strategyRef, new Error('no such element'));
59
59
  }
@@ -1,3 +1,4 @@
1
+ type PseudoElement = '::before' | '::after';
1
2
  /**
2
3
  *
3
4
  * Get a css property from a DOM-element selected by given selector. The return value
@@ -46,7 +47,7 @@
46
47
  // }
47
48
  // }
48
49
 
49
- var width = await elem.getCSSProperty('width')
50
+ var width = await elem.getCSSProperty('width', '::before')
50
51
  console.log(width)
51
52
  // outputs the following:
52
53
  // {
@@ -61,11 +62,12 @@
61
62
  // }
62
63
  })
63
64
  * </example>
64
- *
65
65
  * @alias element.getCSSProperty
66
- * @param {string} cssProperty css property name
67
- * @return {CSSProperty} The specified css of the element
66
+ * @param {string} cssProperty css property name
67
+ * @param {PseudoElement} pseudoElement css pseudo element
68
+ * @return {CSSProperty} The specified css of the element
68
69
  *
69
70
  */
70
- export declare function getCSSProperty(this: WebdriverIO.Element, cssProperty: string): Promise<import("../../types.js").ParsedCSSValue>;
71
+ export declare function getCSSProperty(this: WebdriverIO.Element, cssProperty: string, pseudoElement?: PseudoElement): Promise<import("../../types.js").ParsedCSSValue>;
72
+ export {};
71
73
  //# sourceMappingURL=getCSSProperty.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"getCSSProperty.d.ts","sourceRoot":"","sources":["../../../src/commands/element/getCSSProperty.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoEG;AACH,wBAAsB,cAAc,CAChC,IAAI,EAAE,WAAW,CAAC,OAAO,EACzB,WAAW,EAAE,MAAM,oDAsCtB"}
1
+ {"version":3,"file":"getCSSProperty.d.ts","sourceRoot":"","sources":["../../../src/commands/element/getCSSProperty.ts"],"names":[],"mappings":"AAGA,KAAK,aAAa,GAAG,UAAU,GAAG,SAAS,CAAA;AAE3C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoEG;AACH,wBAAsB,cAAc,CAChC,IAAI,EAAE,WAAW,CAAC,OAAO,EACzB,WAAW,EAAE,MAAM,EACnB,aAAa,CAAC,EAAE,aAAa,oDAehC"}
@@ -1,5 +1,5 @@
1
1
  import cssShorthandProps from 'css-shorthand-properties';
2
- import { parseCSS } from '../../utils/index.js';
2
+ import { getBrowserObject, parseCSS } from '../../utils/index.js';
3
3
  /**
4
4
  *
5
5
  * Get a css property from a DOM-element selected by given selector. The return value
@@ -48,7 +48,7 @@ import { parseCSS } from '../../utils/index.js';
48
48
  // }
49
49
  // }
50
50
 
51
- var width = await elem.getCSSProperty('width')
51
+ var width = await elem.getCSSProperty('width', '::before')
52
52
  console.log(width)
53
53
  // outputs the following:
54
54
  // {
@@ -63,40 +63,77 @@ import { parseCSS } from '../../utils/index.js';
63
63
  // }
64
64
  })
65
65
  * </example>
66
- *
67
66
  * @alias element.getCSSProperty
68
- * @param {string} cssProperty css property name
69
- * @return {CSSProperty} The specified css of the element
67
+ * @param {string} cssProperty css property name
68
+ * @param {PseudoElement} pseudoElement css pseudo element
69
+ * @return {CSSProperty} The specified css of the element
70
70
  *
71
71
  */
72
- export async function getCSSProperty(cssProperty) {
72
+ export async function getCSSProperty(cssProperty, pseudoElement) {
73
+ const getCSSProperty = cssShorthandProps.isShorthand(cssProperty)
74
+ ? getShorthandPropertyCSSValue
75
+ : getPropertyCSSValue;
76
+ const cssValue = await getCSSProperty.call(this, {
77
+ cssProperty,
78
+ pseudoElement,
79
+ });
80
+ return parseCSS(cssValue, cssProperty);
81
+ }
82
+ async function getShorthandPropertyCSSValue(options) {
83
+ const { pseudoElement, cssProperty } = options;
84
+ const properties = getShorthandProperties(cssProperty);
85
+ if (pseudoElement) {
86
+ const cssValues = await Promise.all(properties.map((prop) => getPseudoElementCSSValue(this, {
87
+ pseudoElement,
88
+ cssProperty: prop,
89
+ })));
90
+ return mergeEqualSymmetricalValue(cssValues);
91
+ }
92
+ const cssValues = await Promise.all(properties.map((prop) => this.getElementCSSValue(this.elementId, prop)));
93
+ return mergeEqualSymmetricalValue(cssValues);
94
+ }
95
+ async function getPropertyCSSValue(options) {
96
+ const { pseudoElement, cssProperty } = options;
97
+ if (pseudoElement) {
98
+ return await getPseudoElementCSSValue(this, {
99
+ pseudoElement,
100
+ cssProperty
101
+ });
102
+ }
103
+ return await this.getElementCSSValue(this.elementId, cssProperty);
104
+ }
105
+ function getShorthandProperties(cssProperty) {
73
106
  /**
74
107
  * Getting the css value of a shorthand property results in different results
75
108
  * given that the behavior of `getComputedStyle` is not defined in this case.
76
109
  * Therefore if we don't deal with a shorthand property run `getElementCSSValue`
77
110
  * otherwise expand it and run the command for each longhand property.
78
111
  */
79
- if (!cssShorthandProps.isShorthand(cssProperty)) {
80
- const cssValue = await this.getElementCSSValue(this.elementId, cssProperty);
81
- return parseCSS(cssValue, cssProperty);
82
- }
83
- const properties = cssShorthandProps.expand(cssProperty);
84
- let cssValues = await Promise.all(properties.map((prop) => this.getElementCSSValue(this.elementId, prop)));
112
+ return cssShorthandProps.expand(cssProperty);
113
+ }
114
+ function mergeEqualSymmetricalValue(cssValues) {
85
115
  /**
86
116
  * merge equal symmetrical values
87
117
  * - e.g. `36px 10px 36px 10px` to `36px 10px`
88
118
  * - or `0px 0px 0px 0px` to `0px`
89
- */
90
- while ((cssValues.length % 2) === 0) {
119
+ */
120
+ let newCssValues = [...cssValues];
121
+ while ((newCssValues.length % 2) === 0) {
91
122
  const mergedValues = [
92
- cssValues.slice(0, cssValues.length / 2).join(' '),
93
- cssValues.slice(cssValues.length / 2).join(' ')
123
+ newCssValues.slice(0, newCssValues.length / 2).join(' '),
124
+ newCssValues.slice(newCssValues.length / 2).join(' ')
94
125
  ];
95
126
  const hasEqualProperties = mergedValues.every((v) => v === mergedValues[0]);
96
127
  if (!hasEqualProperties) {
97
128
  break;
98
129
  }
99
- cssValues = cssValues.slice(0, cssValues.length / 2);
130
+ newCssValues = newCssValues.slice(0, newCssValues.length / 2);
100
131
  }
101
- return parseCSS(cssValues.join(' '), cssProperty);
132
+ return newCssValues.join(' ');
133
+ }
134
+ async function getPseudoElementCSSValue(elem, options) {
135
+ const browser = getBrowserObject(elem);
136
+ const { cssProperty, pseudoElement } = options;
137
+ const cssValue = await browser.execute((elem, pseudoElement, cssProperty) => (window.getComputedStyle(elem, pseudoElement))[cssProperty], elem, pseudoElement, cssProperty);
138
+ return cssValue;
102
139
  }
@@ -1 +1 @@
1
- {"version":3,"file":"moveTo.d.ts","sourceRoot":"","sources":["../../../src/commands/element/moveTo.ts"],"names":[],"mappings":"AAIA,KAAK,aAAa,GAAG;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB,CAAA;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,MAAM,CACxB,IAAI,EAAE,WAAW,CAAC,OAAO,EACzB,EAAE,OAAO,EAAE,OAAO,EAAE,GAAE,aAAkB,iBAsB3C"}
1
+ {"version":3,"file":"moveTo.d.ts","sourceRoot":"","sources":["../../../src/commands/element/moveTo.ts"],"names":[],"mappings":"AAEA,KAAK,aAAa,GAAG;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB,CAAA;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,MAAM,CACxB,IAAI,EAAE,WAAW,CAAC,OAAO,EACzB,EAAE,OAAO,EAAE,OAAO,EAAE,GAAE,aAAkB,iBAkC3C"}
@@ -1,6 +1,4 @@
1
1
  import { getBrowserObject } from '../../utils/index.js';
2
- import { ELEMENT_KEY } from '../../constants.js';
3
- import isElementInViewportScript from '../../scripts/isElementInViewport.js';
4
2
  /**
5
3
  *
6
4
  * Move the mouse by an offset of the specified element. If no element is specified,
@@ -19,21 +17,34 @@ export async function moveTo({ xOffset, yOffset } = {}) {
19
17
  if (!this.isW3C) {
20
18
  return this.moveToElement(this.elementId, xOffset, yOffset);
21
19
  }
22
- const isIntoView = async () => {
23
- return await browser.execute(isElementInViewportScript, {
24
- [ELEMENT_KEY]: this.elementId,
25
- ELEMENT: this.elementId // jsonwp compatible
26
- });
27
- };
28
20
  /**
29
21
  * W3C way of handle the mouse move actions
30
22
  */
31
23
  const browser = getBrowserObject(this);
32
- await this.scrollIntoView({ block: 'nearest', inline: 'nearest', behavior: 'instant' });
33
- if (!(await isIntoView())) {
34
- await this.scrollIntoView({ block: 'center', inline: 'center', behavior: 'instant' });
24
+ if (xOffset || yOffset) {
25
+ const { width, height } = await browser.getElementRect(this.elementId);
26
+ if ((xOffset && xOffset < (-Math.floor(width / 2))) || (xOffset && xOffset > Math.floor(width / 2))) {
27
+ throw new Error('xOffset would cause a out of bounds error as it goes outside of element');
28
+ }
29
+ if ((yOffset && yOffset < (-Math.floor(height / 2))) || (yOffset && yOffset > Math.floor(height / 2))) {
30
+ throw new Error('yOffset would cause a out of bounds error as it goes outside of element');
31
+ }
32
+ }
33
+ const moveToNested = async () => {
34
+ await browser.action('pointer', { parameters: { pointerType: 'mouse' } })
35
+ .move({ origin: this, x: xOffset || 0, y: yOffset || 0 })
36
+ .perform();
37
+ };
38
+ try {
39
+ await moveToNested();
40
+ }
41
+ catch {
42
+ /**
43
+ * Workaround, because sometimes browser.action().move() flaky and isn't able to scroll pointer to into view
44
+ * Moreover the action with 'nearest' behavior by default where element is aligned at the bottom of its ancestor.
45
+ * and could be overlapped. Scroll to center should definitely work even if element was covered with sticky header/footer
46
+ */
47
+ await this.scrollIntoView({ block: 'center', inline: 'center' });
48
+ await moveToNested();
35
49
  }
36
- return browser.action('pointer', { parameters: { pointerType: 'mouse' } })
37
- .move({ origin: this, x: xOffset ? xOffset : 0, y: yOffset ? yOffset : 0 })
38
- .perform();
39
50
  }
@@ -32,5 +32,5 @@ import type { ReactSelectorOptions } from '../../types.js';
32
32
  * @return {ElementArray}
33
33
  *
34
34
  */
35
- export declare function react$$(this: WebdriverIO.Element, selector: string, { props, state }?: ReactSelectorOptions): Promise<import("../../types.js").ElementArray>;
35
+ export declare function react$$(this: WebdriverIO.Element, selector: string, { props, state }?: ReactSelectorOptions): Promise<WebdriverIO.ElementArray>;
36
36
  //# sourceMappingURL=react$$.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"react$$.d.ts","sourceRoot":"","sources":["../../../src/commands/element/react$$.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AAI1D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAsB,OAAO,CACzB,IAAI,EAAE,WAAW,CAAC,OAAO,EACzB,QAAQ,EAAE,MAAM,EAChB,EAAE,KAAU,EAAE,KAAU,EAAE,GAAE,oBAAyB,kDAgBxD"}
1
+ {"version":3,"file":"react$$.d.ts","sourceRoot":"","sources":["../../../src/commands/element/react$$.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AAI1D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAsB,OAAO,CACzB,IAAI,EAAE,WAAW,CAAC,OAAO,EACzB,QAAQ,EAAE,MAAM,EAChB,EAAE,KAAU,EAAE,KAAU,EAAE,GAAE,oBAAyB,qCAgBxD"}
@@ -1,4 +1,3 @@
1
- import type { ElementArray } from '../../types.js';
2
1
  /**
3
2
  *
4
3
  * Access elements inside a given element's shadowRoot. If you are working
@@ -19,5 +18,5 @@ import type { ElementArray } from '../../types.js';
19
18
  * @type utility
20
19
  *
21
20
  */
22
- export declare function shadow$$(this: WebdriverIO.Element, selector: string): Promise<ElementArray>;
21
+ export declare function shadow$$(this: WebdriverIO.Element, selector: string): Promise<WebdriverIO.ElementArray>;
23
22
  //# sourceMappingURL=shadow$$.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"shadow$$.d.ts","sourceRoot":"","sources":["../../../src/commands/element/shadow$$.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAY,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAI5D;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,QAAQ,CAC1B,IAAI,EAAE,WAAW,CAAC,OAAO,EACzB,QAAQ,EAAE,MAAM,yBAiBnB"}
1
+ {"version":3,"file":"shadow$$.d.ts","sourceRoot":"","sources":["../../../src/commands/element/shadow$$.ts"],"names":[],"mappings":"AAWA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,QAAQ,CAC1B,IAAI,EAAE,WAAW,CAAC,OAAO,EACzB,QAAQ,EAAE,MAAM,qCAiBnB"}
@@ -49,8 +49,8 @@ export declare class MultiRemoteDriver {
49
49
  isMultiremote: true;
50
50
  __propertiesObject__: Record<string, PropertyDescriptor>;
51
51
  constructor(instances: Record<string, WebdriverIO.Browser>, propertiesObject: Record<string, PropertyDescriptor>);
52
- on(this: WebdriverIO.MultiRemoteBrowser, eventName: string, emitter: EventEmitter): any;
53
- once(this: WebdriverIO.MultiRemoteBrowser, eventName: string, emitter: EventEmitter): any;
52
+ on(this: WebdriverIO.MultiRemoteBrowser, eventName: any, emitter: EventEmitter): any;
53
+ once(this: WebdriverIO.MultiRemoteBrowser, eventName: any, emitter: EventEmitter): any;
54
54
  emit(this: WebdriverIO.MultiRemoteBrowser, eventName: string, emitter: EventEmitter): boolean;
55
55
  eventNames(this: WebdriverIO.MultiRemoteBrowser): any;
56
56
  getMaxListeners(this: WebdriverIO.MultiRemoteBrowser): number;
@@ -1 +1 @@
1
- {"version":3,"file":"multiremote.d.ts","sourceRoot":"","sources":["../src/multiremote.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAIvD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAErD,KAAK,YAAY,GAAG,CAAC,IAAI,EAAE,GAAG,KAAK,IAAI,CAAA;AAEvC;;GAEG;AACH,MAAM,CAAC,OAAO,OAAO,WAAW;IAC5B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,CAAK;IACnD,YAAY,CAAC,EAAE,iBAAiB,CAAA;IAChC,SAAS,CAAC,EAAE,MAAM,CAAA;IAElB;;OAEG;IACG,WAAW,CAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG;IAKnD;;OAEG;IACH,QAAQ,CAAE,aAAa,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC,WAAW,CAAC;QAAC,WAAW,EAAE,CAAC,MAAM,CAAC,gBAAgB,GAAG,mBAAmB,CAAC,GAAG,aAAa,CAAC,EAAE,CAAA;KAAE;IAiC1I;;;;;;;;;;;;;;OAcG;IACH,MAAM,CAAC,cAAc,CACjB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,EAC9C,MAAM,EAAE,GAAG,EACX,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,EACpD,KAAK,EAAE,WAAW,GACnB,WAAW,CAAC,kBAAkB;IAwBjC;;OAEG;IACH,cAAc,CAAE,WAAW,EAAE,MAAM,CAAC,gBAAgB,GAAG,mBAAmB,CAAC,GAAG,aAAa,WAK5D,OAAO,MAAM,EAAE,YAAY,OAAO,GAAG,mBAAmB,CAAC,eAAe,MAAM;CAqChH;AAED;;GAEG;AAEH,qBAAa,iBAAiB;IAC1B,SAAS,EAAE,MAAM,EAAE,CAAA;IACnB,aAAa,OAAe;IAC5B,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAA;gBAGpD,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,EAC9C,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC;IAMxD,EAAE,CAAE,IAAI,EAAE,WAAW,CAAC,kBAAkB,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY;IAKlF,IAAI,CAAE,IAAI,EAAE,WAAW,CAAC,kBAAkB,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY;IAKpF,IAAI,CAAE,IAAI,EAAE,WAAW,CAAC,kBAAkB,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY;IAMpF,UAAU,CAAE,IAAI,EAAE,WAAW,CAAC,kBAAkB;IAMhD,eAAe,CAAE,IAAI,EAAE,WAAW,CAAC,kBAAkB;IAMrD,aAAa,CAAE,IAAI,EAAE,WAAW,CAAC,kBAAkB,EAAE,SAAS,EAAE,MAAM;IAMtE,SAAS,CAAE,IAAI,EAAE,WAAW,CAAC,kBAAkB,EAAE,SAAS,EAAE,MAAM;IASlE,cAAc,CAAE,IAAI,EAAE,WAAW,CAAC,kBAAkB,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY;IAK9F,kBAAkB,CAAE,IAAI,EAAE,WAAW,CAAC,kBAAkB,EAAE,SAAS,EAAE,MAAM;CAI9E"}
1
+ {"version":3,"file":"multiremote.d.ts","sourceRoot":"","sources":["../src/multiremote.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAIvD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAA;AAErD,KAAK,YAAY,GAAG,CAAC,IAAI,EAAE,GAAG,KAAK,IAAI,CAAA;AAEvC;;GAEG;AACH,MAAM,CAAC,OAAO,OAAO,WAAW;IAC5B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,CAAK;IACnD,YAAY,CAAC,EAAE,iBAAiB,CAAA;IAChC,SAAS,CAAC,EAAE,MAAM,CAAA;IAElB;;OAEG;IACG,WAAW,CAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG;IAKnD;;OAEG;IACH,QAAQ,CAAE,aAAa,EAAE;QAAE,OAAO,EAAE,OAAO,CAAC,WAAW,CAAC;QAAC,WAAW,EAAE,CAAC,MAAM,CAAC,gBAAgB,GAAG,mBAAmB,CAAC,GAAG,aAAa,CAAC,EAAE,CAAA;KAAE;IAiC1I;;;;;;;;;;;;;;OAcG;IACH,MAAM,CAAC,cAAc,CACjB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,EAC9C,MAAM,EAAE,GAAG,EACX,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,EACpD,KAAK,EAAE,WAAW,GACnB,WAAW,CAAC,kBAAkB;IAwBjC;;OAEG;IACH,cAAc,CAAE,WAAW,EAAE,MAAM,CAAC,gBAAgB,GAAG,mBAAmB,CAAC,GAAG,aAAa,WAK5D,OAAO,MAAM,EAAE,YAAY,OAAO,GAAG,mBAAmB,CAAC,eAAe,MAAM;CAqChH;AAED;;GAEG;AAEH,qBAAa,iBAAiB;IAC1B,SAAS,EAAE,MAAM,EAAE,CAAA;IACnB,aAAa,OAAe;IAC5B,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAA;gBAGpD,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,EAC9C,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC;IAMxD,EAAE,CAAE,IAAI,EAAE,WAAW,CAAC,kBAAkB,EAAE,SAAS,EAAE,GAAG,EAAE,OAAO,EAAE,YAAY;IAK/E,IAAI,CAAE,IAAI,EAAE,WAAW,CAAC,kBAAkB,EAAE,SAAS,EAAE,GAAG,EAAE,OAAO,EAAE,YAAY;IAKjF,IAAI,CAAE,IAAI,EAAE,WAAW,CAAC,kBAAkB,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY;IAMpF,UAAU,CAAE,IAAI,EAAE,WAAW,CAAC,kBAAkB;IAMhD,eAAe,CAAE,IAAI,EAAE,WAAW,CAAC,kBAAkB;IAMrD,aAAa,CAAE,IAAI,EAAE,WAAW,CAAC,kBAAkB,EAAE,SAAS,EAAE,MAAM;IAMtE,SAAS,CAAE,IAAI,EAAE,WAAW,CAAC,kBAAkB,EAAE,SAAS,EAAE,MAAM;IASlE,cAAc,CAAE,IAAI,EAAE,WAAW,CAAC,kBAAkB,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY;IAK9F,kBAAkB,CAAE,IAAI,EAAE,WAAW,CAAC,kBAAkB,EAAE,SAAS,EAAE,MAAM;CAI9E"}
package/build/types.d.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  /// <reference types="node" resolution-mode="require"/>
3
3
  import type { EventEmitter } from 'node:events';
4
4
  import type { Protocol } from 'devtools-protocol';
5
- import type { SessionFlags, AttachOptions as WebDriverAttachOptions, BidiHandler } from 'webdriver';
5
+ import type { SessionFlags, AttachOptions as WebDriverAttachOptions, BidiHandler, BidiEventHandler } from 'webdriver';
6
6
  import type { Options, Capabilities, FunctionProperties, ThenArg } from '@wdio/types';
7
7
  import type { ElementReference, ProtocolCommands } from '@wdio/protocols';
8
8
  import type { Browser as PuppeteerBrowser } from 'puppeteer-core/lib/esm/puppeteer/api/Browser.js';
@@ -112,7 +112,7 @@ export type MultiRemoteElementCommandsType = {
112
112
  export type MultiRemoteProtocolCommandsType = {
113
113
  [K in keyof ProtocolCommands]: (...args: Parameters<ProtocolCommands[K]>) => Promise<ThenArg<ReturnType<ProtocolCommands[K]>>[]>;
114
114
  };
115
- export interface ElementArray extends Array<WebdriverIO.Element> {
115
+ interface ElementArrayExport extends Array<WebdriverIO.Element> {
116
116
  selector: Selector;
117
117
  parent: WebdriverIO.Element | WebdriverIO.Browser | WebdriverIO.MultiRemoteBrowser;
118
118
  foundWith: string;
@@ -180,7 +180,7 @@ export interface BrowserBase extends InstanceBase, CustomInstanceCommands<Browse
180
180
  /**
181
181
  * @deprecated use `WebdriverIO.Browser` instead
182
182
  */
183
- export interface Browser extends BrowserBase, BidiHandler, BrowserCommandsType, ProtocolCommands {
183
+ export interface Browser extends Omit<BrowserBase, 'on' | 'once'>, BidiEventHandler, BidiEventHandler, BrowserCommandsType, ProtocolCommands {
184
184
  }
185
185
  /**
186
186
  * export a browser interface that can be used for typing plugins
@@ -416,12 +416,45 @@ export interface AttachOptions extends Omit<WebDriverAttachOptions, 'capabilitie
416
416
  }
417
417
  declare global {
418
418
  namespace WebdriverIO {
419
- interface Browser extends BrowserBase, BidiHandler, ProtocolCommands, BrowserCommandsType {
419
+ /**
420
+ * WebdriverIO browser object
421
+ * @see https://webdriver.io/docs/api/browser
422
+ */
423
+ interface Browser extends Omit<BrowserBase, 'on' | 'once'>, BidiEventHandler, BidiHandler, ProtocolCommands, BrowserCommandsType {
420
424
  }
421
- interface Element extends ElementBase, BidiHandler, ProtocolCommands, Omit<BrowserCommandsType, keyof ElementCommandsType>, ElementCommandsType {
425
+ /**
426
+ * WebdriverIO element object
427
+ * @see https://webdriver.io/docs/api/element
428
+ */
429
+ interface Element extends ElementBase, ProtocolCommands, ElementCommandsType {
422
430
  }
431
+ /**
432
+ * WebdriverIO element array
433
+ * When fetching elements via `$$`, `custom$$` or `shadow$$` commands an array of elements
434
+ * is returns. This array has extended prototype properties to provide information about
435
+ * the parent element, selector and properties of the fetched elements. This is useful to
436
+ * e.g. re-fetch the set in case no elements got returned.
437
+ */
438
+ interface ElementArray extends ElementArrayExport {
439
+ }
440
+ /**
441
+ * WebdriverIO multiremote browser object
442
+ * A multiremote browser instance is a property on the global WebdriverIO browser object that
443
+ * allows to control multiple browser instances at once. It can be represented as `Record<string, WebdriverIO.Browser>`
444
+ * where `string` is the capability name defined in the WebdriverIO options.
445
+ *
446
+ * @see https://webdriver.io/docs/multiremote/
447
+ */
423
448
  interface MultiRemoteBrowser extends MultiRemoteBrowserType {
424
449
  }
450
+ /**
451
+ * WebdriverIO multiremote browser object
452
+ * A multiremote browser instance is a property on the global WebdriverIO browser object that
453
+ * allows to control multiple browser instances at once. It can be represented as `Record<string, WebdriverIO.Element>`
454
+ * where `string` is the capability name defined in the WebdriverIO options.
455
+ *
456
+ * @see https://webdriver.io/docs/multiremote/
457
+ */
425
458
  interface MultiRemoteElement extends MultiRemoteElementType {
426
459
  }
427
460
  }