@serenity-js/webdriverio 3.0.0-rc.2 → 3.0.0-rc.3

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 (24) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/lib/screenplay/abilities/BrowseTheWebWithWebdriverIO.d.ts +6 -32
  3. package/lib/screenplay/abilities/BrowseTheWebWithWebdriverIO.js +9 -47
  4. package/lib/screenplay/abilities/BrowseTheWebWithWebdriverIO.js.map +1 -1
  5. package/lib/screenplay/models/WebdriverIONativeElementLocator.d.ts +27 -0
  6. package/lib/screenplay/models/WebdriverIONativeElementLocator.js +56 -0
  7. package/lib/screenplay/models/WebdriverIONativeElementLocator.js.map +1 -0
  8. package/lib/screenplay/models/WebdriverIONativeElementRoot.d.ts +1 -1
  9. package/lib/screenplay/models/WebdriverIOPageElement.d.ts +13 -4
  10. package/lib/screenplay/models/WebdriverIOPageElement.js +44 -5
  11. package/lib/screenplay/models/WebdriverIOPageElement.js.map +1 -1
  12. package/lib/screenplay/models/index.d.ts +1 -1
  13. package/lib/screenplay/models/index.js +1 -1
  14. package/lib/screenplay/models/index.js.map +1 -1
  15. package/package.json +5 -5
  16. package/src/screenplay/abilities/BrowseTheWebWithWebdriverIO.ts +13 -61
  17. package/src/screenplay/models/WebdriverIONativeElementLocator.ts +78 -0
  18. package/src/screenplay/models/WebdriverIONativeElementRoot.ts +1 -1
  19. package/src/screenplay/models/WebdriverIOPageElement.ts +62 -9
  20. package/src/screenplay/models/index.ts +1 -1
  21. package/lib/screenplay/models/WebdriverIOPageElements.d.ts +0 -15
  22. package/lib/screenplay/models/WebdriverIOPageElements.js +0 -65
  23. package/lib/screenplay/models/WebdriverIOPageElements.js.map +0 -1
  24. package/src/screenplay/models/WebdriverIOPageElements.ts +0 -91
package/CHANGELOG.md CHANGED
@@ -3,6 +3,25 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [3.0.0-rc.3](https://github.com/serenity-js/serenity-js/compare/v3.0.0-rc.2...v3.0.0-rc.3) (2021-12-29)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+ * **core:** refactored Mappable so that it's easier to implement filters ([176e0cd](https://github.com/serenity-js/serenity-js/commit/176e0cd0303d63271477b2b7a8e7b0572dda99a0)), closes [#1074](https://github.com/serenity-js/serenity-js/issues/1074)
12
+ * **deps:** updated tiny-types to 1.17.0 ([3187051](https://github.com/serenity-js/serenity-js/commit/3187051594158b4b450c82e851e417fd2ed21652))
13
+ * **web:** refactored Selector and NativeElementLocator classes to simplify the implementation ([f0c8f11](https://github.com/serenity-js/serenity-js/commit/f0c8f113433958877d36f13d0bc7f355ea68d280))
14
+
15
+
16
+ ### Features
17
+
18
+ * **web:** isVisible checks if the element is in viewport and not hidden behind other elements ([429040f](https://github.com/serenity-js/serenity-js/commit/429040fb32b04cd4bc7524100635203fd8128eb6))
19
+ * **web:** re-introduced PageElements.where DSL and universal By selectors ([39fe0a1](https://github.com/serenity-js/serenity-js/commit/39fe0a10edf7f652e93911159e4a4689c36d6876)), closes [#1081](https://github.com/serenity-js/serenity-js/issues/1081)
20
+
21
+
22
+
23
+
24
+
6
25
  # [3.0.0-rc.2](https://github.com/serenity-js/serenity-js/compare/v3.0.0-rc.1...v3.0.0-rc.2) (2021-12-09)
7
26
 
8
27
  **Note:** Version bump only for package @serenity-js/webdriverio
@@ -1,7 +1,7 @@
1
1
  import { Duration, UsesAbilities } from '@serenity-js/core';
2
- import { BrowserCapabilities, BrowseTheWeb, Cookie, CookieData, Key, ModalDialog, Page, PageElement } from '@serenity-js/web';
2
+ import { BrowserCapabilities, BrowseTheWeb, Cookie, CookieData, Key, ModalDialog, NativeElementLocator, Page, PageElement, Selector } from '@serenity-js/web';
3
3
  import type * as wdio from 'webdriverio';
4
- import { WebdriverIOPageElement, WebdriverIOPageElements } from '../models';
4
+ import { WebdriverIOPageElement } from '../models';
5
5
  /**
6
6
  * @desc
7
7
  * An {@link @serenity-js/core/lib/screenplay~Ability} that enables the {@link @serenity-js/core/lib/screenplay/actor~Actor}
@@ -35,7 +35,7 @@ import { WebdriverIOPageElement, WebdriverIOPageElements } from '../models';
35
35
  * @implements {@serenity-js/core/lib/screenplay~Ability}
36
36
  * @see {@link @serenity-js/core/lib/screenplay/actor~Actor}
37
37
  */
38
- export declare class BrowseTheWebWithWebdriverIO extends BrowseTheWeb {
38
+ export declare class BrowseTheWebWithWebdriverIO extends BrowseTheWeb<wdio.Element<'async'>> {
39
39
  readonly browser: wdio.Browser<'async'>;
40
40
  /**
41
41
  * @param {@wdio/types~Browser} browserInstance
@@ -64,35 +64,9 @@ export declare class BrowseTheWebWithWebdriverIO extends BrowseTheWeb {
64
64
  cookie(name: string): Promise<Cookie>;
65
65
  setCookie(cookieData: CookieData): Promise<void>;
66
66
  deleteAllCookies(): Promise<void>;
67
- findByCss(selector: string): WebdriverIOPageElement;
68
- /**
69
- * @desc
70
- * Retrieves a {@link @serenity-js/web/lib/screenplay/models~PageElement} which text includes `text`
71
- * and which can be located using the CSS `selector`.
72
- *
73
- * Under the hood, this command uses https://webdriver.io/docs/selectors#element-with-certain-text
74
- *
75
- * This means that only some selectors are supported. For example:
76
- * - 'h1'
77
- * - 'h1.some-class'
78
- * - '#someId'
79
- * - 'h1[attribute-name="attribute-selector"]
80
- *
81
- * Notably, complex CSS selectors such as 'header h1' or 'header > h1' **WON'T WORK**.
82
- *
83
- * @param {string} selector
84
- * @param {string} text
85
- * @returns {@serenity-js/web/lib/screenplay/models~PageElement}
86
- */
87
- findByCssContainingText(selector: string, text: RegExp | string): WebdriverIOPageElement;
88
- findById(selector: string): WebdriverIOPageElement;
89
- findByTagName(selector: string): WebdriverIOPageElement;
90
- findByXPath(selector: string): WebdriverIOPageElement;
91
- findAllByCss(selector: string): WebdriverIOPageElements;
92
- findAllByTagName(selector: string): WebdriverIOPageElements;
93
- findAllByXPath(selector: string): WebdriverIOPageElements;
94
- private find;
95
- private findAll;
67
+ locate<T>(selector: Selector<T>, locator?: NativeElementLocator<wdio.Element<'async'>>): WebdriverIOPageElement;
68
+ locateAll<T>(selector: Selector<T>, locator?: NativeElementLocator<wdio.Element<'async'>>): Promise<WebdriverIOPageElement[]>;
69
+ nativeElementLocator(): NativeElementLocator<wdio.Element<'async'>>;
96
70
  /**
97
71
  * @desc
98
72
  * Navigate to a given destination, specified as an absolute URL
@@ -45,7 +45,7 @@ class BrowseTheWebWithWebdriverIO extends web_1.BrowseTheWeb {
45
45
  super();
46
46
  this.browser = browser;
47
47
  if (!this.browser.$ || !this.browser.$$) {
48
- throw new core_1.LogicError(`WebdriverIO browser object is not initalised yet, so can't be assigned to an actor. Are you trying to instantiate an actor outside of a test or a test hook?`);
48
+ throw new core_1.LogicError(`WebdriverIO browser object is not initialised yet, so can't be assigned to an actor. Are you trying to instantiate an actor outside of a test or a test hook?`);
49
49
  }
50
50
  }
51
51
  /**
@@ -90,54 +90,16 @@ class BrowseTheWebWithWebdriverIO extends web_1.BrowseTheWeb {
90
90
  deleteAllCookies() {
91
91
  return this.browser.deleteCookies();
92
92
  }
93
- findByCss(selector) {
94
- return this.find(root => root.$(selector));
93
+ locate(selector, locator) {
94
+ return new models_1.WebdriverIOPageElement(selector, locator !== null && locator !== void 0 ? locator : this.nativeElementLocator());
95
95
  }
96
- /**
97
- * @desc
98
- * Retrieves a {@link @serenity-js/web/lib/screenplay/models~PageElement} which text includes `text`
99
- * and which can be located using the CSS `selector`.
100
- *
101
- * Under the hood, this command uses https://webdriver.io/docs/selectors#element-with-certain-text
102
- *
103
- * This means that only some selectors are supported. For example:
104
- * - 'h1'
105
- * - 'h1.some-class'
106
- * - '#someId'
107
- * - 'h1[attribute-name="attribute-selector"]
108
- *
109
- * Notably, complex CSS selectors such as 'header h1' or 'header > h1' **WON'T WORK**.
110
- *
111
- * @param {string} selector
112
- * @param {string} text
113
- * @returns {@serenity-js/web/lib/screenplay/models~PageElement}
114
- */
115
- findByCssContainingText(selector, text) {
116
- return this.find(root => root.$(`${selector}*=${text}`));
117
- }
118
- findById(selector) {
119
- return this.find(root => root.$(`#${selector}`));
120
- }
121
- findByTagName(selector) {
122
- return this.find(root => root.$(`<${selector} />`));
123
- }
124
- findByXPath(selector) {
125
- return this.find(root => root.$(selector));
126
- }
127
- findAllByCss(selector) {
128
- return this.findAll(root => root.$$(selector));
129
- }
130
- findAllByTagName(selector) {
131
- return this.findAll(root => root.$$(`<${selector} />`));
132
- }
133
- findAllByXPath(selector) {
134
- return this.findAll(root => root.$$(selector));
135
- }
136
- find(locator) {
137
- return new models_1.WebdriverIOPageElement(() => this.browser, locator);
96
+ async locateAll(selector, locator) {
97
+ const l = locator !== null && locator !== void 0 ? locator : this.nativeElementLocator();
98
+ const elements = await l.locateAll(selector);
99
+ return elements.map(element => new models_1.WebdriverIOPageElement(selector, new web_1.PassThroughNativeElementLocator(locator, element)));
138
100
  }
139
- findAll(locator) {
140
- return new models_1.WebdriverIOPageElements(() => this.browser, locator);
101
+ nativeElementLocator() {
102
+ return new models_1.WebdriverIONativeElementLocator(() => this.browser);
141
103
  }
142
104
  /**
143
105
  * @desc
@@ -1 +1 @@
1
- {"version":3,"file":"BrowseTheWebWithWebdriverIO.js","sourceRoot":"","sources":["../../../src/screenplay/abilities/BrowseTheWebWithWebdriverIO.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"BrowseTheWebWithWebdriverIO.js","sourceRoot":"","sources":["../../../src/screenplay/abilities/BrowseTheWebWithWebdriverIO.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import { NativeElementLocator, Selector } from '@serenity-js/web';
2
+ import * as wdio from 'webdriverio';
3
+ import { WebdriverIONativeElementRoot } from './WebdriverIONativeElementRoot';
4
+ export declare class WebdriverIONativeElementLocator implements NativeElementLocator<wdio.Element<'async'>> {
5
+ private readonly resolver;
6
+ constructor(resolver: () => Promise<WebdriverIONativeElementRoot> | WebdriverIONativeElementRoot);
7
+ /**
8
+ * @desc
9
+ * Retrieves a {@link @serenity-js/web/lib/screenplay/models~PageElement} which text includes `text`
10
+ * and which can be located using the CSS `selector`.
11
+ *
12
+ * Under the hood, this command uses https://webdriver.io/docs/selectors#element-with-certain-text
13
+ *
14
+ * This means that only some selectors are supported. For example:
15
+ * - 'h1'
16
+ * - 'h1.some-class'
17
+ * - '#someId'
18
+ * - 'h1[attribute-name="attribute-selector"]
19
+ *
20
+ * Notably, complex CSS selectors such as 'header h1' or 'header > h1' **WON'T WORK**.
21
+ *
22
+ * @param {Selector<T>} selector
23
+ * @returns {Promise<wdio.Element<'async'>>}
24
+ */
25
+ locate<T>(selector: Selector<T>): Promise<wdio.Element<'async'>>;
26
+ locateAll<T>(selector: Selector<T>): Promise<Array<wdio.Element<'async'>>>;
27
+ }
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WebdriverIONativeElementLocator = void 0;
4
+ const core_1 = require("@serenity-js/core");
5
+ const web_1 = require("@serenity-js/web");
6
+ const tiny_types_1 = require("tiny-types");
7
+ const f = (0, core_1.format)({ markQuestions: false });
8
+ class WebdriverIONativeElementLocator {
9
+ constructor(resolver) {
10
+ this.resolver = resolver;
11
+ }
12
+ /**
13
+ * @desc
14
+ * Retrieves a {@link @serenity-js/web/lib/screenplay/models~PageElement} which text includes `text`
15
+ * and which can be located using the CSS `selector`.
16
+ *
17
+ * Under the hood, this command uses https://webdriver.io/docs/selectors#element-with-certain-text
18
+ *
19
+ * This means that only some selectors are supported. For example:
20
+ * - 'h1'
21
+ * - 'h1.some-class'
22
+ * - '#someId'
23
+ * - 'h1[attribute-name="attribute-selector"]
24
+ *
25
+ * Notably, complex CSS selectors such as 'header h1' or 'header > h1' **WON'T WORK**.
26
+ *
27
+ * @param {Selector<T>} selector
28
+ * @returns {Promise<wdio.Element<'async'>>}
29
+ */
30
+ async locate(selector) {
31
+ const resolver = await this.resolver();
32
+ const byLocator = (0, tiny_types_1.match)(selector)
33
+ .when(web_1.ByCss, (s) => s.value)
34
+ .when(web_1.ByCssContainingText, (s) => `${s.value}*=${s.text}`)
35
+ .when(web_1.ById, (s) => `#${s.value}`)
36
+ .when(web_1.ByTagName, (s) => `<${s.value} />`)
37
+ .when(web_1.ByXPath, (s) => s.value)
38
+ .else(() => {
39
+ throw new core_1.LogicError(f `Selector ${selector} not supported`);
40
+ });
41
+ return resolver.$(byLocator);
42
+ }
43
+ async locateAll(selector) {
44
+ const resolver = await this.resolver();
45
+ const byLocator = (0, tiny_types_1.match)(selector)
46
+ .when(web_1.ByCss, (s) => s.value)
47
+ .when(web_1.ByTagName, (s) => `<${s.value} />`)
48
+ .when(web_1.ByXPath, (s) => s.value)
49
+ .else(() => {
50
+ throw new core_1.LogicError(f `Selector ${selector} not supported`);
51
+ });
52
+ return resolver.$$(byLocator);
53
+ }
54
+ }
55
+ exports.WebdriverIONativeElementLocator = WebdriverIONativeElementLocator;
56
+ //# sourceMappingURL=WebdriverIONativeElementLocator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebdriverIONativeElementLocator.js","sourceRoot":"","sources":["../../../src/screenplay/models/WebdriverIONativeElementLocator.ts"],"names":[],"mappings":";;;AAAA,4CAAuD;AACvD,0CAAwH;AACxH,2CAAmC;AAKnC,MAAM,CAAC,GAAG,IAAA,aAAM,EAAC,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC,CAAC;AAE3C,MAAa,+BAA+B;IACxC,YAA6B,QAAoF;QAApF,aAAQ,GAAR,QAAQ,CAA4E;IACjH,CAAC;IAED;;;;;;;;;;;;;;;;;OAiBG;IACH,KAAK,CAAC,MAAM,CAAI,QAAqB;QACjC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;QAEvC,MAAM,SAAS,GAAG,IAAA,kBAAK,EAA4B,QAAQ,CAAC;aACvD,IAAI,CAAC,WAAK,EAAE,CAAC,CAAQ,EAAE,EAAE,CACtB,CAAC,CAAC,KAAK,CACV;aACA,IAAI,CAAC,yBAAmB,EAAE,CAAC,CAAsB,EAAE,EAAE,CAClD,GAAI,CAAC,CAAC,KAAM,KAAM,CAAC,CAAC,IAAK,EAAE,CAC9B;aACA,IAAI,CAAC,UAAI,EAAE,CAAC,CAAO,EAAE,EAAE,CACpB,IAAK,CAAC,CAAC,KAAM,EAAE,CAClB;aACA,IAAI,CAAC,eAAS,EAAE,CAAC,CAAY,EAAE,EAAE,CAC9B,IAAK,CAAC,CAAC,KAAM,KAAK,CACrB;aACA,IAAI,CAAC,aAAO,EAAE,CAAC,CAAU,EAAE,EAAE,CAC1B,CAAC,CAAC,KAAK,CACV;aACA,IAAI,CAAC,GAAG,EAAE;YACP,MAAM,IAAI,iBAAU,CAAC,CAAC,CAAA,YAAa,QAAS,gBAAgB,CAAC,CAAC;QAClE,CAAC,CAAC,CAAC;QAEP,OAAO,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IACjC,CAAC;IAED,KAAK,CAAC,SAAS,CAAI,QAAqB;QACpC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;QAEvC,MAAM,SAAS,GAAG,IAAA,kBAAK,EAA4B,QAAQ,CAAC;aACvD,IAAI,CAAC,WAAK,EAAE,CAAC,CAAQ,EAAE,EAAE,CACtB,CAAC,CAAC,KAAK,CACV;aACA,IAAI,CAAC,eAAS,EAAE,CAAC,CAAY,EAAE,EAAE,CAC9B,IAAK,CAAC,CAAC,KAAM,KAAK,CACrB;aACA,IAAI,CAAC,aAAO,EAAE,CAAC,CAAU,EAAE,EAAE,CAC1B,CAAC,CAAC,KAAK,CACV;aACA,IAAI,CAAC,GAAG,EAAE;YACP,MAAM,IAAI,iBAAU,CAAC,CAAC,CAAA,YAAa,QAAS,gBAAgB,CAAC,CAAC;QAClE,CAAC,CAAC,CAAC;QAEP,OAAO,QAAQ,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC;IAClC,CAAC;CACJ;AAnED,0EAmEC"}
@@ -1,2 +1,2 @@
1
1
  import * as wdio from 'webdriverio';
2
- export declare type WebdriverIONativeElementRoot = Pick<wdio.Browser<'async'>, '$' | '$$' | 'react$' | 'react$$'>;
2
+ export declare type WebdriverIONativeElementRoot = Pick<wdio.Browser<'async'>, '$' | '$$'>;
@@ -1,8 +1,7 @@
1
1
  import { PageElement } from '@serenity-js/web';
2
2
  import * as wdio from 'webdriverio';
3
- import { WebdriverIONativeElementRoot } from './WebdriverIONativeElementRoot';
4
- export declare class WebdriverIOPageElement extends PageElement<WebdriverIONativeElementRoot, wdio.Element<'async'>> {
5
- of(parent: WebdriverIOPageElement): PageElement<WebdriverIONativeElementRoot, wdio.Element<'async'>>;
3
+ export declare class WebdriverIOPageElement extends PageElement<wdio.Element<'async'>> {
4
+ of(parent: WebdriverIOPageElement): WebdriverIOPageElement;
6
5
  clearValue(): Promise<void>;
7
6
  click(): Promise<void>;
8
7
  doubleClick(): Promise<void>;
@@ -15,8 +14,18 @@ export declare class WebdriverIOPageElement extends PageElement<WebdriverIONativ
15
14
  value(): Promise<string>;
16
15
  isActive(): Promise<boolean>;
17
16
  isClickable(): Promise<boolean>;
18
- isDisplayed(): Promise<boolean>;
19
17
  isEnabled(): Promise<boolean>;
20
18
  isPresent(): Promise<boolean>;
21
19
  isSelected(): Promise<boolean>;
20
+ /**
21
+ * @desc
22
+ * Checks if the PageElement:
23
+ * - is displayed,
24
+ * - is visible within the browser viewport,
25
+ * - has not its center covered by other elements
26
+ *
27
+ * @see https://webdriver.io/docs/api/element/isDisplayedInViewport/
28
+ */
29
+ isVisible(): Promise<boolean>;
30
+ private browserFor;
22
31
  }
@@ -2,9 +2,10 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.WebdriverIOPageElement = void 0;
4
4
  const web_1 = require("@serenity-js/web");
5
+ const WebdriverIONativeElementLocator_1 = require("./WebdriverIONativeElementLocator");
5
6
  class WebdriverIOPageElement extends web_1.PageElement {
6
7
  of(parent) {
7
- return new WebdriverIOPageElement(() => parent.nativeElement(), this.locator);
8
+ return new WebdriverIOPageElement(this.selector, new WebdriverIONativeElementLocator_1.WebdriverIONativeElementLocator(() => parent.nativeElement()));
8
9
  }
9
10
  async clearValue() {
10
11
  const element = await this.nativeElement();
@@ -54,10 +55,6 @@ class WebdriverIOPageElement extends web_1.PageElement {
54
55
  const element = await this.nativeElement();
55
56
  return element.isClickable();
56
57
  }
57
- async isDisplayed() {
58
- const element = await this.nativeElement();
59
- return element.isDisplayed();
60
- }
61
58
  async isEnabled() {
62
59
  const element = await this.nativeElement();
63
60
  return element.isEnabled();
@@ -70,6 +67,48 @@ class WebdriverIOPageElement extends web_1.PageElement {
70
67
  const element = await this.nativeElement();
71
68
  return element.isSelected();
72
69
  }
70
+ /**
71
+ * @desc
72
+ * Checks if the PageElement:
73
+ * - is displayed,
74
+ * - is visible within the browser viewport,
75
+ * - has not its center covered by other elements
76
+ *
77
+ * @see https://webdriver.io/docs/api/element/isDisplayedInViewport/
78
+ */
79
+ async isVisible() {
80
+ const element = await this.nativeElement();
81
+ if (!await element.isDisplayed()) {
82
+ return false;
83
+ }
84
+ if (!await element.isDisplayedInViewport()) {
85
+ return false;
86
+ }
87
+ const browser = await this.browserFor(element);
88
+ /* eslint-disable no-var */
89
+ // get element at cx/cy and see if the element we found is our element, and therefore it's visible.
90
+ return browser.execute(
91
+ /* istanbul ignore next */
92
+ function isVisible(element) {
93
+ if (!element.getBoundingClientRect) {
94
+ return false;
95
+ }
96
+ var box = element.getBoundingClientRect(), cx = box.left + box.width / 2, cy = box.top + box.height / 2, e = document.elementFromPoint(cx, cy);
97
+ for (; e; e = e.parentElement) {
98
+ if (e === element)
99
+ return true;
100
+ }
101
+ return false;
102
+ }, element);
103
+ /* eslint-enable no-var */
104
+ }
105
+ // based on https://github.com/webdriverio/webdriverio/blob/dec6da76b0e218af935dbf39735ae3491d5edd8c/packages/webdriverio/src/utils/index.ts#L98
106
+ async browserFor(nativeElement) {
107
+ const element = nativeElement;
108
+ return element.parent
109
+ ? this.browserFor(element.parent)
110
+ : nativeElement;
111
+ }
73
112
  }
74
113
  exports.WebdriverIOPageElement = WebdriverIOPageElement;
75
114
  //# sourceMappingURL=WebdriverIOPageElement.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"WebdriverIOPageElement.js","sourceRoot":"","sources":["../../../src/screenplay/models/WebdriverIOPageElement.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"WebdriverIOPageElement.js","sourceRoot":"","sources":["../../../src/screenplay/models/WebdriverIOPageElement.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  export * from './WebdriverIOCookie';
2
2
  export * from './WebdriverIOModalDialog';
3
+ export * from './WebdriverIONativeElementLocator';
3
4
  export * from './WebdriverIONativeElementRoot';
4
5
  export * from './WebdriverIOPage';
5
6
  export * from './WebdriverIOPageElement';
6
- export * from './WebdriverIOPageElements';
@@ -12,8 +12,8 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
13
13
  __exportStar(require("./WebdriverIOCookie"), exports);
14
14
  __exportStar(require("./WebdriverIOModalDialog"), exports);
15
+ __exportStar(require("./WebdriverIONativeElementLocator"), exports);
15
16
  __exportStar(require("./WebdriverIONativeElementRoot"), exports);
16
17
  __exportStar(require("./WebdriverIOPage"), exports);
17
18
  __exportStar(require("./WebdriverIOPageElement"), exports);
18
- __exportStar(require("./WebdriverIOPageElements"), exports);
19
19
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/screenplay/models/index.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,sDAAoC;AACpC,2DAAyC;AACzC,iEAA+C;AAC/C,oDAAkC;AAClC,2DAAyC;AACzC,4DAA0C"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/screenplay/models/index.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,sDAAoC;AACpC,2DAAyC;AACzC,oEAAkD;AAClD,iEAA+C;AAC/C,oDAAkC;AAClC,2DAAyC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@serenity-js/webdriverio",
3
- "version": "3.0.0-rc.2",
3
+ "version": "3.0.0-rc.3",
4
4
  "description": "Serenity/JS reporter and Screenplay Pattern library for WebdriverIO",
5
5
  "author": {
6
6
  "name": "Jan Molak",
@@ -49,13 +49,13 @@
49
49
  "npm": "^6 || ^7 || ^8"
50
50
  },
51
51
  "dependencies": {
52
- "@serenity-js/core": "3.0.0-rc.1",
53
- "@serenity-js/web": "3.0.0-rc.2",
52
+ "@serenity-js/core": "3.0.0-rc.3",
53
+ "@serenity-js/web": "3.0.0-rc.3",
54
54
  "@wdio/reporter": "^7.16.3",
55
55
  "@wdio/types": "^7.16.3",
56
56
  "deepmerge": "^4.2.2",
57
57
  "is-plain-object": "^5.0.0",
58
- "tiny-types": "^1.16.1"
58
+ "tiny-types": "^1.17.0"
59
59
  },
60
60
  "peerDependencies": {
61
61
  "@serenity-js/cucumber": "^3.0.0-rc",
@@ -112,5 +112,5 @@
112
112
  "cache": true,
113
113
  "all": false
114
114
  },
115
- "gitHead": "944ff400a3766e75980aea5d3b401d8acca7c6d8"
115
+ "gitHead": "69da7444e581c457e29e87edcd910ec06a069338"
116
116
  }
@@ -1,8 +1,8 @@
1
1
  import { Duration, LogicError, UsesAbilities } from '@serenity-js/core';
2
- import { BrowserCapabilities, BrowseTheWeb, Cookie, CookieData, Key, ModalDialog, Page, PageElement } from '@serenity-js/web';
2
+ import { BrowserCapabilities, BrowseTheWeb, Cookie, CookieData, Key, ModalDialog, NativeElementLocator, Page, PageElement, PassThroughNativeElementLocator, Selector } from '@serenity-js/web';
3
3
  import type * as wdio from 'webdriverio';
4
4
 
5
- import { WebdriverIOCookie, WebdriverIOModalDialog, WebdriverIONativeElementRoot, WebdriverIOPage, WebdriverIOPageElement, WebdriverIOPageElements } from '../models';
5
+ import { WebdriverIOCookie, WebdriverIOModalDialog, WebdriverIONativeElementLocator, WebdriverIOPage, WebdriverIOPageElement } from '../models';
6
6
 
7
7
  /**
8
8
  * @desc
@@ -37,7 +37,7 @@ import { WebdriverIOCookie, WebdriverIOModalDialog, WebdriverIONativeElementRoot
37
37
  * @implements {@serenity-js/core/lib/screenplay~Ability}
38
38
  * @see {@link @serenity-js/core/lib/screenplay/actor~Actor}
39
39
  */
40
- export class BrowseTheWebWithWebdriverIO extends BrowseTheWeb {
40
+ export class BrowseTheWebWithWebdriverIO extends BrowseTheWeb<wdio.Element<'async'>> {
41
41
 
42
42
  /**
43
43
  * @param {@wdio/types~Browser} browserInstance
@@ -72,7 +72,7 @@ export class BrowseTheWebWithWebdriverIO extends BrowseTheWeb {
72
72
  super();
73
73
 
74
74
  if (! this.browser.$ || ! this.browser.$$) {
75
- throw new LogicError(`WebdriverIO browser object is not initalised yet, so can't be assigned to an actor. Are you trying to instantiate an actor outside of a test or a test hook?`)
75
+ throw new LogicError(`WebdriverIO browser object is not initialised yet, so can't be assigned to an actor. Are you trying to instantiate an actor outside of a test or a test hook?`)
76
76
  }
77
77
  }
78
78
 
@@ -103,69 +103,21 @@ export class BrowseTheWebWithWebdriverIO extends BrowseTheWeb {
103
103
  return this.browser.deleteCookies() as Promise<void>;
104
104
  }
105
105
 
106
- findByCss(selector: string): WebdriverIOPageElement {
107
- return this.find(root => root.$(selector));
106
+ locate<T>(selector: Selector<T>, locator?: NativeElementLocator<wdio.Element<'async'>>): WebdriverIOPageElement {
107
+ return new WebdriverIOPageElement(selector, locator ?? this.nativeElementLocator());
108
108
  }
109
109
 
110
- /**
111
- * @desc
112
- * Retrieves a {@link @serenity-js/web/lib/screenplay/models~PageElement} which text includes `text`
113
- * and which can be located using the CSS `selector`.
114
- *
115
- * Under the hood, this command uses https://webdriver.io/docs/selectors#element-with-certain-text
116
- *
117
- * This means that only some selectors are supported. For example:
118
- * - 'h1'
119
- * - 'h1.some-class'
120
- * - '#someId'
121
- * - 'h1[attribute-name="attribute-selector"]
122
- *
123
- * Notably, complex CSS selectors such as 'header h1' or 'header > h1' **WON'T WORK**.
124
- *
125
- * @param {string} selector
126
- * @param {string} text
127
- * @returns {@serenity-js/web/lib/screenplay/models~PageElement}
128
- */
129
- findByCssContainingText(selector: string, text: RegExp | string): WebdriverIOPageElement {
130
- return this.find(root => root.$(`${ selector }*=${ text }`));
131
- }
110
+ async locateAll<T>(selector: Selector<T>, locator?: NativeElementLocator<wdio.Element<'async'>>): Promise<WebdriverIOPageElement[]> {
111
+ const l = locator ?? this.nativeElementLocator();
112
+ const elements = await l.locateAll(selector);
132
113
 
133
- findById(selector: string): WebdriverIOPageElement {
134
- return this.find(root => root.$(`#${selector}`));
135
- }
136
-
137
- findByTagName(selector: string): WebdriverIOPageElement {
138
- return this.find(root => root.$(`<${ selector } />`));
139
- }
140
-
141
- findByXPath(selector: string): WebdriverIOPageElement {
142
- return this.find(root => root.$(selector));
143
- }
144
-
145
- findAllByCss(selector: string): WebdriverIOPageElements {
146
- return this.findAll(root => root.$$(selector));
147
- }
148
-
149
- findAllByTagName(selector: string): WebdriverIOPageElements {
150
- return this.findAll(root => root.$$(`<${ selector } />`));
151
- }
152
-
153
- findAllByXPath(selector: string): WebdriverIOPageElements {
154
- return this.findAll(root => root.$$(selector));
155
- }
156
-
157
- private find(locator: (root: WebdriverIONativeElementRoot) => wdio.ChainablePromiseElement<Promise<wdio.Element<'async'>>> | Promise<wdio.Element<'async'>>): WebdriverIOPageElement {
158
- return new WebdriverIOPageElement(
159
- () => this.browser,
160
- locator as unknown as (root: WebdriverIONativeElementRoot) => Promise<wdio.Element<'async'>>, // We don't need the ChainablePromiseElement
114
+ return elements.map(element =>
115
+ new WebdriverIOPageElement(selector, new PassThroughNativeElementLocator<wdio.Element<'async'>>(locator, element)),
161
116
  );
162
117
  }
163
118
 
164
- private findAll(locator: (root: WebdriverIONativeElementRoot) => wdio.ChainablePromiseArray<wdio.ElementArray> | Promise<wdio.ElementArray>): WebdriverIOPageElements {
165
- return new WebdriverIOPageElements(
166
- () => this.browser,
167
- locator as unknown as (root: WebdriverIONativeElementRoot) => Promise<wdio.ElementArray>, // We don't need the ChainablePromiseArray
168
- );
119
+ nativeElementLocator(): NativeElementLocator<wdio.Element<'async'>> {
120
+ return new WebdriverIONativeElementLocator(() => this.browser);
169
121
  }
170
122
 
171
123
  /**
@@ -0,0 +1,78 @@
1
+ import { format, LogicError } from '@serenity-js/core';
2
+ import { ByCss, ByCssContainingText, ById, ByTagName, ByXPath, NativeElementLocator, Selector } from '@serenity-js/web';
3
+ import { match } from 'tiny-types';
4
+ import * as wdio from 'webdriverio';
5
+
6
+ import { WebdriverIONativeElementRoot } from './WebdriverIONativeElementRoot';
7
+
8
+ const f = format({ markQuestions: false });
9
+
10
+ export class WebdriverIONativeElementLocator implements NativeElementLocator<wdio.Element<'async'>> {
11
+ constructor(private readonly resolver: () => Promise<WebdriverIONativeElementRoot> | WebdriverIONativeElementRoot) {
12
+ }
13
+
14
+ /**
15
+ * @desc
16
+ * Retrieves a {@link @serenity-js/web/lib/screenplay/models~PageElement} which text includes `text`
17
+ * and which can be located using the CSS `selector`.
18
+ *
19
+ * Under the hood, this command uses https://webdriver.io/docs/selectors#element-with-certain-text
20
+ *
21
+ * This means that only some selectors are supported. For example:
22
+ * - 'h1'
23
+ * - 'h1.some-class'
24
+ * - '#someId'
25
+ * - 'h1[attribute-name="attribute-selector"]
26
+ *
27
+ * Notably, complex CSS selectors such as 'header h1' or 'header > h1' **WON'T WORK**.
28
+ *
29
+ * @param {Selector<T>} selector
30
+ * @returns {Promise<wdio.Element<'async'>>}
31
+ */
32
+ async locate<T>(selector: Selector<T>): Promise<wdio.Element<'async'>> {
33
+ const resolver = await this.resolver();
34
+
35
+ const byLocator = match<Selector<unknown>, string>(selector)
36
+ .when(ByCss, (s: ByCss) =>
37
+ s.value,
38
+ )
39
+ .when(ByCssContainingText, (s: ByCssContainingText) =>
40
+ `${ s.value }*=${ s.text }`,
41
+ )
42
+ .when(ById, (s: ById) =>
43
+ `#${ s.value }`,
44
+ )
45
+ .when(ByTagName, (s: ByTagName) =>
46
+ `<${ s.value } />`,
47
+ )
48
+ .when(ByXPath, (s: ByXPath) =>
49
+ s.value,
50
+ )
51
+ .else(() => {
52
+ throw new LogicError(f`Selector ${ selector } not supported`);
53
+ });
54
+
55
+ return resolver.$(byLocator);
56
+ }
57
+
58
+ async locateAll<T>(selector: Selector<T>): Promise<Array<wdio.Element<'async'>>> {
59
+ const resolver = await this.resolver();
60
+
61
+ const byLocator = match<Selector<unknown>, string>(selector)
62
+ .when(ByCss, (s: ByCss) =>
63
+ s.value,
64
+ )
65
+ .when(ByTagName, (s: ByTagName) =>
66
+ `<${ s.value } />`,
67
+ )
68
+ .when(ByXPath, (s: ByXPath) =>
69
+ s.value,
70
+ )
71
+ .else(() => {
72
+ throw new LogicError(f`Selector ${ selector } not supported`);
73
+ });
74
+
75
+ return resolver.$$(byLocator);
76
+ }
77
+ }
78
+
@@ -1,3 +1,3 @@
1
1
  import * as wdio from 'webdriverio';
2
2
 
3
- export type WebdriverIONativeElementRoot = Pick<wdio.Browser<'async'>, '$' | '$$' | 'react$' | 'react$$'>;
3
+ export type WebdriverIONativeElementRoot = Pick<wdio.Browser<'async'>, '$' | '$$'>;
@@ -1,13 +1,13 @@
1
1
  import { PageElement } from '@serenity-js/web';
2
2
  import * as wdio from 'webdriverio';
3
3
 
4
- import { WebdriverIONativeElementRoot } from './WebdriverIONativeElementRoot';
4
+ import { WebdriverIONativeElementLocator } from './WebdriverIONativeElementLocator';
5
5
 
6
6
  export class WebdriverIOPageElement
7
- extends PageElement<WebdriverIONativeElementRoot, wdio.Element<'async'>>
7
+ extends PageElement<wdio.Element<'async'>>
8
8
  {
9
- of(parent: WebdriverIOPageElement): PageElement<WebdriverIONativeElementRoot, wdio.Element<'async'>> {
10
- return new WebdriverIOPageElement(() => parent.nativeElement(), this.locator);
9
+ of(parent: WebdriverIOPageElement): WebdriverIOPageElement {
10
+ return new WebdriverIOPageElement(this.selector, new WebdriverIONativeElementLocator(() => parent.nativeElement()));
11
11
  }
12
12
 
13
13
  async clearValue(): Promise<void> {
@@ -70,11 +70,6 @@ export class WebdriverIOPageElement
70
70
  return element.isClickable();
71
71
  }
72
72
 
73
- async isDisplayed(): Promise<boolean> {
74
- const element = await this.nativeElement();
75
- return element.isDisplayed();
76
- }
77
-
78
73
  async isEnabled(): Promise<boolean> {
79
74
  const element = await this.nativeElement();
80
75
  return element.isEnabled();
@@ -89,4 +84,62 @@ export class WebdriverIOPageElement
89
84
  const element = await this.nativeElement();
90
85
  return element.isSelected();
91
86
  }
87
+
88
+ /**
89
+ * @desc
90
+ * Checks if the PageElement:
91
+ * - is displayed,
92
+ * - is visible within the browser viewport,
93
+ * - has not its center covered by other elements
94
+ *
95
+ * @see https://webdriver.io/docs/api/element/isDisplayedInViewport/
96
+ */
97
+ async isVisible(): Promise<boolean> { // isVisible?
98
+ const element = await this.nativeElement();
99
+
100
+ if (! await element.isDisplayed()) {
101
+ return false;
102
+ }
103
+
104
+ if (! await element.isDisplayedInViewport()) {
105
+ return false;
106
+ }
107
+
108
+ const browser = await this.browserFor(element);
109
+
110
+ /* eslint-disable no-var */
111
+
112
+ // get element at cx/cy and see if the element we found is our element, and therefore it's visible.
113
+ return browser.execute(
114
+ /* istanbul ignore next */
115
+ function isVisible(element: any) {
116
+ if (! element.getBoundingClientRect) {
117
+ return false;
118
+ }
119
+
120
+ var
121
+ box = element.getBoundingClientRect(),
122
+ cx = box.left + box.width / 2,
123
+ cy = box.top + box.height / 2,
124
+ e = document.elementFromPoint(cx, cy);
125
+
126
+ for (; e; e = e.parentElement) {
127
+ if (e === element)
128
+ return true;
129
+ }
130
+ return false;
131
+ },
132
+ element,
133
+ );
134
+
135
+ /* eslint-enable no-var */
136
+ }
137
+
138
+ // based on https://github.com/webdriverio/webdriverio/blob/dec6da76b0e218af935dbf39735ae3491d5edd8c/packages/webdriverio/src/utils/index.ts#L98
139
+ private async browserFor(nativeElement: wdio.Element<'async'> | wdio.Browser<'async'>): Promise<wdio.Browser<'async'>> {
140
+ const element = nativeElement as wdio.Element<'async'>;
141
+ return element.parent
142
+ ? this.browserFor(element.parent)
143
+ : nativeElement
144
+ }
92
145
  }
@@ -1,6 +1,6 @@
1
1
  export * from './WebdriverIOCookie';
2
2
  export * from './WebdriverIOModalDialog';
3
+ export * from './WebdriverIONativeElementLocator';
3
4
  export * from './WebdriverIONativeElementRoot';
4
5
  export * from './WebdriverIOPage';
5
6
  export * from './WebdriverIOPageElement';
6
- export * from './WebdriverIOPageElements';
@@ -1,15 +0,0 @@
1
- import { PageElement, PageElements } from '@serenity-js/web';
2
- import * as wdio from 'webdriverio';
3
- import { WebdriverIONativeElementRoot } from './WebdriverIONativeElementRoot';
4
- import { WebdriverIOPageElement } from './WebdriverIOPageElement';
5
- export declare class WebdriverIOPageElements extends PageElements<WebdriverIONativeElementRoot, wdio.ElementArray, wdio.Element<'async'>> {
6
- of(parent: PageElement<WebdriverIONativeElementRoot, wdio.Element<'async'>>): WebdriverIOPageElements;
7
- count(): Promise<number>;
8
- first(): Promise<WebdriverIOPageElement>;
9
- last(): Promise<WebdriverIOPageElement>;
10
- get(index: number): Promise<WebdriverIOPageElement>;
11
- private elementAt;
12
- map<O>(fn: (element: PageElement, index?: number, elements?: PageElements) => Promise<O> | O): Promise<O[]>;
13
- filter(fn: (element: PageElement, index?: number) => Promise<boolean> | boolean): WebdriverIOPageElements;
14
- forEach(fn: (element: PageElement, index?: number, elements?: PageElements) => Promise<void> | void): Promise<void>;
15
- }
@@ -1,65 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.WebdriverIOPageElements = void 0;
4
- const core_1 = require("@serenity-js/core");
5
- const web_1 = require("@serenity-js/web");
6
- const WebdriverIOPageElement_1 = require("./WebdriverIOPageElement");
7
- class WebdriverIOPageElements extends web_1.PageElements {
8
- of(parent) {
9
- return new WebdriverIOPageElements(() => parent.nativeElement(), this.locator);
10
- }
11
- async count() {
12
- const elements = await this.nativeElementList();
13
- return elements.length;
14
- }
15
- first() {
16
- return this.elementAt(0);
17
- }
18
- async last() {
19
- const elements = await this.nativeElementList();
20
- const index = elements.length - 1;
21
- return this.elementAt(index);
22
- }
23
- get(index) {
24
- return this.elementAt(index);
25
- }
26
- async elementAt(index) {
27
- const elements = await this.nativeElementList();
28
- if (!elements[index]) {
29
- throw new core_1.LogicError(`There's no item at index ${index}`);
30
- }
31
- return new WebdriverIOPageElement_1.WebdriverIOPageElement(this.context, () => elements[index]);
32
- }
33
- async map(fn) {
34
- const elements = await this.nativeElementList();
35
- return Promise.all(elements.map((element, index) => fn(new WebdriverIOPageElement_1.WebdriverIOPageElement(this.context, () => element), index, this)));
36
- }
37
- filter(fn) {
38
- return new WebdriverIOPageElements(this.context, async (context) => {
39
- const elements = await this.locator(context);
40
- const matching = await Promise.all(elements.map(async (nativeElement, index) => {
41
- const element = new WebdriverIOPageElement_1.WebdriverIOPageElement(this.context, () => nativeElement);
42
- const matches = await fn(element, index);
43
- return matches
44
- ? nativeElement
45
- : undefined;
46
- }));
47
- const results = matching.filter((element) => {
48
- return element !== undefined;
49
- });
50
- results.selector = elements.selector;
51
- results.parent = elements.parent;
52
- results.foundWith = elements.foundWith;
53
- results.props = elements.props;
54
- return results;
55
- });
56
- }
57
- async forEach(fn) {
58
- const elements = await this.nativeElementList();
59
- return elements.reduce((previous, element, index) => {
60
- return previous.then(() => fn(new WebdriverIOPageElement_1.WebdriverIOPageElement(this.context, () => element), index, this));
61
- }, Promise.resolve());
62
- }
63
- }
64
- exports.WebdriverIOPageElements = WebdriverIOPageElements;
65
- //# sourceMappingURL=WebdriverIOPageElements.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"WebdriverIOPageElements.js","sourceRoot":"","sources":["../../../src/screenplay/models/WebdriverIOPageElements.ts"],"names":[],"mappings":"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"}
@@ -1,91 +0,0 @@
1
- import { LogicError } from '@serenity-js/core';
2
- import { PageElement, PageElements } from '@serenity-js/web';
3
- import * as wdio from 'webdriverio';
4
-
5
- import { WebdriverIONativeElementRoot } from './WebdriverIONativeElementRoot';
6
- import { WebdriverIOPageElement } from './WebdriverIOPageElement';
7
-
8
- export class WebdriverIOPageElements
9
- extends PageElements<WebdriverIONativeElementRoot, wdio.ElementArray, wdio.Element<'async'>>
10
- {
11
- of(parent: PageElement<WebdriverIONativeElementRoot, wdio.Element<'async'>>): WebdriverIOPageElements {
12
- return new WebdriverIOPageElements(() => parent.nativeElement(), this.locator);
13
- }
14
-
15
- async count(): Promise<number> {
16
- const elements = await this.nativeElementList();
17
- return elements.length;
18
- }
19
-
20
- first(): Promise<WebdriverIOPageElement> {
21
- return this.elementAt(0);
22
- }
23
-
24
- async last(): Promise<WebdriverIOPageElement> {
25
- const elements = await this.nativeElementList();
26
- const index = elements.length - 1;
27
-
28
- return this.elementAt(index);
29
- }
30
-
31
- get(index: number): Promise<WebdriverIOPageElement> {
32
- return this.elementAt(index);
33
- }
34
-
35
- private async elementAt(index: number): Promise<WebdriverIOPageElement> {
36
- const elements = await this.nativeElementList();
37
-
38
- if (! elements[index]) {
39
- throw new LogicError(`There's no item at index ${ index }`);
40
- }
41
-
42
- return new WebdriverIOPageElement(this.context, () => elements[index])
43
- }
44
-
45
- async map<O>(fn: (element: PageElement, index?: number, elements?: PageElements) => Promise<O> | O): Promise<O[]> {
46
- const elements = await this.nativeElementList();
47
-
48
- return Promise.all(
49
- elements.map((element, index) =>
50
- fn(new WebdriverIOPageElement(this.context, () => element), index, this)
51
- )
52
- );
53
- }
54
-
55
- filter(fn: (element: PageElement, index?: number) => Promise<boolean> | boolean): WebdriverIOPageElements {
56
-
57
- return new WebdriverIOPageElements(this.context, async context => {
58
- const elements = await this.locator(context);
59
-
60
- const matching = await Promise.all(
61
- elements.map(async (nativeElement: wdio.Element<'async'>, index: number) => {
62
- const element = new WebdriverIOPageElement(this.context, () => nativeElement);
63
- const matches = await fn(element, index);
64
-
65
- return matches
66
- ? nativeElement
67
- : undefined;
68
- })
69
- );
70
-
71
- const results = matching.filter((element: wdio.Element<'async'> | undefined) => {
72
- return element !== undefined;
73
- }) as wdio.ElementArray;
74
-
75
- results.selector = elements.selector;
76
- results.parent = elements.parent;
77
- results.foundWith = elements.foundWith;
78
- results.props = elements.props;
79
-
80
- return results;
81
- });
82
- }
83
-
84
- async forEach(fn: (element: PageElement, index?: number, elements?: PageElements) => Promise<void> | void): Promise<void> {
85
- const elements = await this.nativeElementList();
86
-
87
- return elements.reduce((previous: Promise<void>, element: wdio.Element<'async'>, index: number) => {
88
- return previous.then(() => fn(new WebdriverIOPageElement(this.context, () => element), index, this));
89
- }, Promise.resolve());
90
- }
91
- }