webdriverio 8.33.0 → 8.34.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.
@@ -12,7 +12,7 @@ import type { Selector } from '../../types.js';
12
12
  * to walk down the DOM tree, e.g.:
13
13
  *
14
14
  * ```js
15
- * const imageSrc = await $$('div')[1].nextElement().$$('img')[2].getAttribute('src)
15
+ * const imageSrc = await $$('div')[1].nextElement().$$('img')[2].getAttribute('src')
16
16
  * ```
17
17
  *
18
18
  * It is also possible to use async iterators to loop over the result of the query, e.g.:
@@ -12,7 +12,7 @@ import { getElements } from '../../utils/getElementObject.js';
12
12
  * to walk down the DOM tree, e.g.:
13
13
  *
14
14
  * ```js
15
- * const imageSrc = await $$('div')[1].nextElement().$$('img')[2].getAttribute('src)
15
+ * const imageSrc = await $$('div')[1].nextElement().$$('img')[2].getAttribute('src')
16
16
  * ```
17
17
  *
18
18
  * It is also possible to use async iterators to loop over the result of the query, e.g.:
@@ -21,7 +21,7 @@ import type { Selector } from '../../types.js';
21
21
  * to walk down the DOM tree, e.g.:
22
22
  *
23
23
  * ```js
24
- * const imageSrc = await $$('div')[1].nextElement().$$('img')[2].getAttribute('src)
24
+ * const imageSrc = await $$('div')[1].nextElement().$$('img')[2].getAttribute('src')
25
25
  * ```
26
26
  *
27
27
  * :::info
@@ -23,7 +23,7 @@ import { getElement } from '../../utils/getElementObject.js';
23
23
  * to walk down the DOM tree, e.g.:
24
24
  *
25
25
  * ```js
26
- * const imageSrc = await $$('div')[1].nextElement().$$('img')[2].getAttribute('src)
26
+ * const imageSrc = await $$('div')[1].nextElement().$$('img')[2].getAttribute('src')
27
27
  * ```
28
28
  *
29
29
  * :::info
@@ -19,7 +19,7 @@
19
19
  * to walk down the DOM tree, e.g.:
20
20
  *
21
21
  * ```js
22
- * const imageSrc = await $$('div')[1].nextElement().$$('img')[2].getAttribute('src)
22
+ * const imageSrc = await $$('div')[1].nextElement().$$('img')[2].getAttribute('src')
23
23
  * ```
24
24
  *
25
25
  * :::info
@@ -19,7 +19,7 @@
19
19
  * to walk down the DOM tree, e.g.:
20
20
  *
21
21
  * ```js
22
- * const imageSrc = await $$('div')[1].nextElement().$$('img')[2].getAttribute('src)
22
+ * const imageSrc = await $$('div')[1].nextElement().$$('img')[2].getAttribute('src')
23
23
  * ```
24
24
  *
25
25
  * :::info
@@ -1,12 +1,13 @@
1
1
  /**
2
2
  *
3
- * Return true if the selected DOM-element:
4
- *
5
- * - exists
6
- * - is visible
7
- * - is within viewport (if not try scroll to it)
8
- * - its center is not overlapped with another element
9
- * - is not disabled
3
+ * An element is considered to be clickable when the following conditions are met:
4
+ *
5
+ * - the element exists
6
+ * - the element is displayed
7
+ * - the element is not disabled
8
+ * - the element is within the viewport
9
+ * - the element can be scrolled into the viewport
10
+ * - the element's center is not overlapped with another element
10
11
  *
11
12
  * otherwise return false.
12
13
  *
@@ -1 +1 @@
1
- {"version":3,"file":"isClickable.d.ts","sourceRoot":"","sources":["../../../src/commands/element/isClickable.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AACH,wBAAsB,WAAW,CAAE,IAAI,EAAE,WAAW,CAAC,OAAO,oBAkB3D"}
1
+ {"version":3,"file":"isClickable.d.ts","sourceRoot":"","sources":["../../../src/commands/element/isClickable.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,wBAAsB,WAAW,CAAE,IAAI,EAAE,WAAW,CAAC,OAAO,oBAkB3D"}
@@ -3,13 +3,14 @@ import { getBrowserObject } from '../../utils/index.js';
3
3
  import isElementClickableScript from '../../scripts/isElementClickable.js';
4
4
  /**
5
5
  *
6
- * Return true if the selected DOM-element:
7
- *
8
- * - exists
9
- * - is visible
10
- * - is within viewport (if not try scroll to it)
11
- * - its center is not overlapped with another element
12
- * - is not disabled
6
+ * An element is considered to be clickable when the following conditions are met:
7
+ *
8
+ * - the element exists
9
+ * - the element is displayed
10
+ * - the element is not disabled
11
+ * - the element is within the viewport
12
+ * - the element can be scrolled into the viewport
13
+ * - the element's center is not overlapped with another element
13
14
  *
14
15
  * otherwise return false.
15
16
  *
@@ -1 +1 @@
1
- {"version":3,"file":"isElementClickable.d.ts","sourceRoot":"","sources":["../../src/scripts/isElementClickable.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,CAAC,OAAO,UAAU,kBAAkB,CAAE,IAAI,EAAE,WAAW,WA4I5D"}
1
+ {"version":3,"file":"isElementClickable.d.ts","sourceRoot":"","sources":["../../src/scripts/isElementClickable.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,CAAC,OAAO,UAAU,kBAAkB,CAAE,IAAI,EAAE,WAAW,WAiJ5D"}
@@ -23,14 +23,12 @@ export default function isElementClickable(elem) {
23
23
  // applicable if element's text is multiline.
24
24
  function getOverlappingRects(elem, context) {
25
25
  context = context || document;
26
- const elems = [];
27
26
  const rects = elem.getClientRects();
28
27
  // webdriver clicks on center of the first element's rect (line of text), it might change in future
29
28
  const rect = rects[0];
30
29
  const x = rect.left + (rect.width / 2);
31
30
  const y = rect.top + (rect.height / 2);
32
- elems.push(context.elementFromPoint(x, y));
33
- return elems;
31
+ return [context.elementFromPoint(x, y)];
34
32
  }
35
33
  // get overlapping elements
36
34
  function getOverlappingElements(elem, context) {
@@ -98,21 +96,28 @@ export default function isElementClickable(elem) {
98
96
  const horInView = (rect.left <= windowWidth) && ((rect.left + rect.width) > 0);
99
97
  return (vertInView && horInView);
100
98
  }
101
- function isClickable(elem) {
102
- return (isElementInViewport(elem) && elem.disabled !== true &&
103
- isOverlappingElementMatch(getOverlappingElements(elem), elem));
99
+ function isEnabled(elem) {
100
+ return elem.disabled !== true;
104
101
  }
105
- // scroll to the element if it's not clickable
106
- if (!isClickable(elem)) {
107
- // works well in dialogs, but the element may be still overlapped by some sticky header/footer
108
- elem.scrollIntoView(scrollIntoViewFullSupport ? { block: 'nearest', inline: 'nearest' } : false);
109
- // if element is still not clickable take another scroll attempt
110
- if (!isClickable(elem)) {
111
- // scroll to element, try put it in the screen center.
112
- // Should definitely work even if element was covered with sticky header/footer
113
- elem.scrollIntoView(scrollIntoViewFullSupport ? { block: 'center', inline: 'center' } : true);
114
- return isClickable(elem);
102
+ function hasOverlaps(elem) {
103
+ return !isOverlappingElementMatch(getOverlappingElements(elem), elem);
104
+ }
105
+ function isFullyDisplayedInViewport(elem) {
106
+ return isElementInViewport(elem) && !hasOverlaps(elem);
107
+ }
108
+ // scroll the element to the center of the viewport when
109
+ // it is not fully displayed in the viewport or is overlapped by another element
110
+ // to check if it still overlapped/not in the viewport
111
+ // afterwards we scroll back to the original position
112
+ let _isFullyDisplayedInViewport = isFullyDisplayedInViewport(elem);
113
+ if (!_isFullyDisplayedInViewport) {
114
+ const { x: originalX, y: originalY } = elem.getBoundingClientRect();
115
+ elem.scrollIntoView(scrollIntoViewFullSupport ? { block: 'center', inline: 'center' } : false);
116
+ _isFullyDisplayedInViewport = isFullyDisplayedInViewport(elem);
117
+ const { x, y } = elem.getBoundingClientRect();
118
+ if (x !== originalX || y !== originalY) {
119
+ elem.scroll(scrollX, scrollY);
115
120
  }
116
121
  }
117
- return true;
122
+ return _isFullyDisplayedInViewport && isEnabled(elem);
118
123
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "webdriverio",
3
3
  "description": "Next-gen browser and mobile automation test framework for Node.js",
4
- "version": "8.33.0",
4
+ "version": "8.34.0",
5
5
  "homepage": "https://webdriver.io",
6
6
  "author": "Christian Bromann <mail@bromann.dev>",
7
7
  "license": "MIT",
@@ -69,12 +69,12 @@
69
69
  },
70
70
  "dependencies": {
71
71
  "@types/node": "^20.1.0",
72
- "@wdio/config": "8.33.0",
72
+ "@wdio/config": "8.34.0",
73
73
  "@wdio/logger": "8.28.0",
74
74
  "@wdio/protocols": "8.32.0",
75
75
  "@wdio/repl": "8.24.12",
76
76
  "@wdio/types": "8.32.4",
77
- "@wdio/utils": "8.33.0",
77
+ "@wdio/utils": "8.33.1",
78
78
  "archiver": "^7.0.0",
79
79
  "aria-query": "^5.0.0",
80
80
  "css-shorthand-properties": "^1.1.1",
@@ -91,7 +91,7 @@
91
91
  "resq": "^1.9.1",
92
92
  "rgb2hex": "0.2.5",
93
93
  "serialize-error": "^11.0.1",
94
- "webdriver": "8.33.0"
94
+ "webdriver": "8.34.0"
95
95
  },
96
96
  "peerDependencies": {
97
97
  "devtools": "^8.14.0"
@@ -101,5 +101,5 @@
101
101
  "optional": true
102
102
  }
103
103
  },
104
- "gitHead": "b00f5062e9ca87d6b2d01b1e9fa66ab15d8636b4"
104
+ "gitHead": "72856f9e3e4c6ae0750a1d3f17b137724a30e4e5"
105
105
  }