@badisi/wdio-harness 1.0.5 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -20
- package/{cjs/WebdriverIOHarnessEnvironment.d.ts → WebdriverIOHarnessEnvironment.d.ts} +7 -5
- package/{esm/WebdriverIOHarnessEnvironment.js → WebdriverIOHarnessEnvironment.js} +18 -8
- package/{cjs/WebdriverIOTestElement.d.ts → WebdriverIOTestElement.d.ts} +16 -5
- package/{esm/WebdriverIOTestElement.js → WebdriverIOTestElement.js} +74 -61
- package/{esm/index.d.ts → index.d.ts} +16 -15
- package/{esm/index.js → index.js} +23 -17
- package/package.json +11 -9
- package/cjs/WebdriverIOHarnessEnvironment.js +0 -63
- package/cjs/WebdriverIOTestElement.js +0 -279
- package/cjs/index.d.ts +0 -30
- package/cjs/index.js +0 -56
- package/cjs/package.json +0 -3
- package/esm/WebdriverIOHarnessEnvironment.d.ts +0 -32
- package/esm/WebdriverIOTestElement.d.ts +0 -81
- package/esm/package.json +0 -3
package/README.md
CHANGED
|
@@ -1,13 +1,31 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
1
|
+
<h1 align="center">
|
|
2
|
+
@badisi/wdio-harness
|
|
3
|
+
</h1>
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<i>🔬 <a href="https://webdriver.io" alt="wdio">WebdriverIO</a> support for Angular component test harnesses.</i><br/>
|
|
7
|
+
</p>
|
|
8
|
+
|
|
9
|
+
<p align="center">
|
|
10
|
+
<a href="https://www.npmjs.com/package/@badisi/wdio-harness">
|
|
11
|
+
<img src="https://img.shields.io/npm/v/@badisi/wdio-harness.svg?color=blue&logo=npm" alt="npm version" />
|
|
12
|
+
</a>
|
|
13
|
+
<a href="https://npmcharts.com/compare/@badisi/wdio-harness?minimal=true">
|
|
14
|
+
<img src="https://img.shields.io/npm/dw/@badisi/wdio-harness.svg?color=7986CB&logo=npm" alt="npm donwloads" />
|
|
15
|
+
</a>
|
|
16
|
+
<a href="https://github.com/badisi/wdio-harness/blob/main/LICENSE">
|
|
17
|
+
<img src="https://img.shields.io/npm/l/@badisi/wdio-harness.svg?color=ff69b4" alt="license" />
|
|
18
|
+
</a>
|
|
19
|
+
</p>
|
|
20
|
+
|
|
21
|
+
<p align="center">
|
|
22
|
+
<a href="https://github.com/Badisi/wdio-harness/actions/workflows/ci_tests.yml">
|
|
23
|
+
<img src="https://github.com/Badisi/wdio-harness/actions/workflows/ci_tests.yml/badge.svg" alt="build status" />
|
|
24
|
+
</a>
|
|
25
|
+
<a href="https://github.com/badisi/wdio-harness/blob/main/CONTRIBUTING.md#-submitting-a-pull-request-pr">
|
|
26
|
+
<img src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg" alt="PRs welcome" />
|
|
27
|
+
</a>
|
|
28
|
+
</p>
|
|
11
29
|
|
|
12
30
|
<hr/>
|
|
13
31
|
|
|
@@ -17,6 +35,7 @@
|
|
|
17
35
|
|
|
18
36
|
[More info](https://material.angular.io/cdk/test-harnesses/overview)
|
|
19
37
|
|
|
38
|
+
<hr/>
|
|
20
39
|
|
|
21
40
|
## Installation
|
|
22
41
|
|
|
@@ -33,8 +52,10 @@ yarn add @badisi/wdio-harness --dev
|
|
|
33
52
|
|
|
34
53
|
__Methods__
|
|
35
54
|
|
|
36
|
-
- `createHarnessEnvironment(
|
|
37
|
-
- `getHarness(
|
|
55
|
+
- `createHarnessEnvironment(rootElement)` - gets a HarnessLoader instance from a given element (defaults to body)
|
|
56
|
+
- `getHarness(harnessType, element)` - searches for an harness instance from a given ComponentHarness class and element
|
|
57
|
+
- `getHarness(harnessType)` - searches for an harness instance from a given ComponentHarness class
|
|
58
|
+
- `getHarness(query)` - searches for an harness instance from a given HarnessPredicate
|
|
38
59
|
- `getAllHarnesses(query)` - acts like getHarness, but returns an array of harness instances
|
|
39
60
|
- `waitForAngular()` - waits for Angular to finish bootstrapping
|
|
40
61
|
|
|
@@ -47,12 +68,11 @@ __Example__
|
|
|
47
68
|
|
|
48
69
|
/** ESM / Typescript */
|
|
49
70
|
import { MatDatepickerInputHarness } from '@angular/material/datepicker/testing';
|
|
50
|
-
import { getHarness
|
|
71
|
+
import { getHarness } from '@badisi/wdio-harness';
|
|
51
72
|
|
|
52
73
|
describe('Angular Material Harness', () => {
|
|
53
74
|
beforeEach(async () => {
|
|
54
75
|
await browser.url('http://localhost:4200');
|
|
55
|
-
await waitForAngular();
|
|
56
76
|
});
|
|
57
77
|
|
|
58
78
|
it('MatDatePicker', async () => {
|
|
@@ -93,13 +113,7 @@ Please read and follow the [Code of Conduct][codeofconduct] and help me keep thi
|
|
|
93
113
|
|
|
94
114
|
|
|
95
115
|
|
|
96
|
-
[npm]: https://www.npmjs.com/package/@badisi/wdio-harness
|
|
97
|
-
[npm-dl]: https://npmcharts.com/compare/@badisi/wdio-harness?minimal=true
|
|
98
|
-
[ci-tests]: https://github.com/badisi/wdio-harness/actions?query=workflow:CI%20tests
|
|
99
|
-
[pullrequest]: https://github.com/badisi/wdio-harness/blob/main/CONTRIBUTING.md#-submitting-a-pull-request-pr
|
|
100
|
-
[license]: https://github.com/badisi/wdio-harness/blob/main/LICENSE
|
|
101
116
|
[developer]: https://github.com/badisi/wdio-harness/blob/main/DEVELOPER.md
|
|
102
117
|
[contributing]: https://github.com/badisi/wdio-harness/blob/main/CONTRIBUTING.md
|
|
103
118
|
[codeofconduct]: https://github.com/badisi/wdio-harness/blob/main/CODE_OF_CONDUCT.md
|
|
104
|
-
[wdio]: https://webdriver.io/
|
|
105
119
|
[examples]: https://github.com/badisi/wdio-harness/blob/main/projects/tests-e2e/harness.e2e.ts
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
/// <reference types="
|
|
2
|
-
import {
|
|
1
|
+
/// <reference types="@wdio/globals/types" />
|
|
2
|
+
import { ComponentHarness, ComponentHarnessConstructor, HarnessEnvironment, TestElement } from '@angular/cdk/testing';
|
|
3
3
|
/**
|
|
4
4
|
* A `HarnessEnvironment` implementation for WebdriverIO.
|
|
5
5
|
*/
|
|
@@ -13,7 +13,7 @@ export declare class WebdriverIOHarnessEnvironment extends HarnessEnvironment<We
|
|
|
13
13
|
documentRoot: WebdriverIO.Element;
|
|
14
14
|
});
|
|
15
15
|
/** Creates a `HarnessLoader` rooted at the document root. */
|
|
16
|
-
static loader(documentRoot: WebdriverIO.Element): Promise<
|
|
16
|
+
static loader(documentRoot: WebdriverIO.Element): Promise<WebdriverIOHarnessEnvironment>;
|
|
17
17
|
/**
|
|
18
18
|
* Flushes change detection and async tasks captured in the Angular zone.
|
|
19
19
|
* In most cases it should not be necessary to call this manually. However, there may be some edge
|
|
@@ -21,12 +21,14 @@ export declare class WebdriverIOHarnessEnvironment extends HarnessEnvironment<We
|
|
|
21
21
|
*/
|
|
22
22
|
forceStabilize(): Promise<void>;
|
|
23
23
|
waitForTasksOutsideAngular(): Promise<void>;
|
|
24
|
+
/** Creates a `ComponentHarness` for the given harness type with the given raw host element. */
|
|
25
|
+
createComponentHarness<T extends ComponentHarness>(harnessType: ComponentHarnessConstructor<T>, element: WebdriverIO.Element): T;
|
|
26
|
+
/** Gets a list of all elements matching the given selector under this environment's root element. */
|
|
27
|
+
protected getAllRawElements(selector: string): Promise<WebdriverIO.ElementArray>;
|
|
24
28
|
/** Gets the root element for the document. */
|
|
25
29
|
protected getDocumentRoot(): WebdriverIO.Element;
|
|
26
30
|
/** Creates a `TestElement` from a raw element. */
|
|
27
31
|
protected createTestElement(element: WebdriverIO.Element): TestElement;
|
|
28
32
|
/** Creates a `HarnessLoader` rooted at the given raw element. */
|
|
29
33
|
protected createEnvironment(element: WebdriverIO.Element): HarnessEnvironment<WebdriverIO.Element>;
|
|
30
|
-
/** Gets a list of all elements matching the given selector under this environment's root element. */
|
|
31
|
-
protected getAllRawElements(selector: string): Promise<WebdriverIO.ElementArray>;
|
|
32
34
|
}
|
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import { HarnessEnvironment } from '@angular/cdk/testing';
|
|
2
2
|
import logger from '@wdio/logger';
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
3
|
+
import { WebdriverIOTestElement } from './WebdriverIOTestElement.js';
|
|
4
|
+
import colors from '@colors/colors/safe.js';
|
|
5
|
+
const { magenta, green } = colors;
|
|
5
6
|
/** Registers the environment logger. */
|
|
6
7
|
const log = logger('wdio-harness');
|
|
7
8
|
/**
|
|
8
9
|
* A `HarnessEnvironment` implementation for WebdriverIO.
|
|
9
10
|
*/
|
|
10
11
|
export class WebdriverIOHarnessEnvironment extends HarnessEnvironment {
|
|
12
|
+
/**
|
|
13
|
+
* Keep a reference to the `document` element because `rawRootElement`
|
|
14
|
+
* will be the root element of the harness's environment.
|
|
15
|
+
*/
|
|
16
|
+
documentRoot;
|
|
11
17
|
constructor(rawRootElement, options) {
|
|
12
18
|
super(rawRootElement);
|
|
13
19
|
this.documentRoot = options.documentRoot;
|
|
@@ -27,9 +33,18 @@ export class WebdriverIOHarnessEnvironment extends HarnessEnvironment {
|
|
|
27
33
|
window.requestAnimationFrame(done);
|
|
28
34
|
`, []);*/
|
|
29
35
|
}
|
|
30
|
-
waitForTasksOutsideAngular() {
|
|
36
|
+
async waitForTasksOutsideAngular() {
|
|
31
37
|
throw new Error('Method not implemented.');
|
|
32
38
|
}
|
|
39
|
+
/** Creates a `ComponentHarness` for the given harness type with the given raw host element. */
|
|
40
|
+
createComponentHarness(harnessType, element) {
|
|
41
|
+
return super.createComponentHarness(harnessType, element);
|
|
42
|
+
}
|
|
43
|
+
/** Gets a list of all elements matching the given selector under this environment's root element. */
|
|
44
|
+
async getAllRawElements(selector) {
|
|
45
|
+
log.info(`${magenta('GET_ALL_RAW_ELEMENTS')} ${green(selector.toString())}`);
|
|
46
|
+
return await this.rawRootElement.$$(selector);
|
|
47
|
+
}
|
|
33
48
|
/** Gets the root element for the document. */
|
|
34
49
|
getDocumentRoot() {
|
|
35
50
|
return this.documentRoot;
|
|
@@ -44,9 +59,4 @@ export class WebdriverIOHarnessEnvironment extends HarnessEnvironment {
|
|
|
44
59
|
documentRoot: this.documentRoot
|
|
45
60
|
});
|
|
46
61
|
}
|
|
47
|
-
/** Gets a list of all elements matching the given selector under this environment's root element. */
|
|
48
|
-
async getAllRawElements(selector) {
|
|
49
|
-
log.info(`${magenta('GET_ALL_RAW_ELEMENTS')} ${green(selector.toString())}`);
|
|
50
|
-
return await this.rawRootElement.$$(selector);
|
|
51
|
-
}
|
|
52
62
|
}
|
|
@@ -1,11 +1,22 @@
|
|
|
1
|
-
/// <reference types="
|
|
1
|
+
/// <reference types="@wdio/globals/types" />
|
|
2
2
|
import { ElementDimensions, EventData, ModifierKeys, TestElement, TestKey, TextOptions } from '@angular/cdk/testing';
|
|
3
|
+
/** Module augmentation to expose the host element as a public api */
|
|
4
|
+
declare module '@angular/cdk/testing' {
|
|
5
|
+
interface ComponentHarness {
|
|
6
|
+
element(): WebdriverIO.Element;
|
|
7
|
+
}
|
|
8
|
+
interface TestElement {
|
|
9
|
+
element(): WebdriverIO.Element;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
3
12
|
/**
|
|
4
13
|
* A `TestElement` implementation for WebdriverIO.
|
|
5
14
|
*/
|
|
6
15
|
export declare class WebdriverIOTestElement implements TestElement {
|
|
7
|
-
readonly
|
|
8
|
-
constructor(
|
|
16
|
+
readonly hostElement: WebdriverIO.Element;
|
|
17
|
+
constructor(hostElement: WebdriverIO.Element);
|
|
18
|
+
/** Return the host element. */
|
|
19
|
+
element(): WebdriverIO.Element;
|
|
9
20
|
/** Blur the element. */
|
|
10
21
|
blur(): Promise<void>;
|
|
11
22
|
/** Clear the element's input (for input and textarea elements only). */
|
|
@@ -70,12 +81,12 @@ export declare class WebdriverIOTestElement implements TestElement {
|
|
|
70
81
|
selectOptions(...optionIndexes: number[]): Promise<void>;
|
|
71
82
|
/** Dispatches an event with a particular name. */
|
|
72
83
|
dispatchEvent(name: string, data?: Record<string, EventData>): Promise<void>;
|
|
73
|
-
/** Dispatches all the events that are part of a click event sequence. */
|
|
74
|
-
private dispatchClickEventSequence;
|
|
75
84
|
/** Performs a key-down action. */
|
|
76
85
|
keyDown(value: string): Promise<void>;
|
|
77
86
|
/** Performs a key-up action. */
|
|
78
87
|
keyUp(value: string): Promise<void>;
|
|
88
|
+
/** Dispatches all the events that are part of a click event sequence. */
|
|
89
|
+
private dispatchClickEventSequence;
|
|
79
90
|
/** Writes info to the console outputs. */
|
|
80
91
|
private logAction;
|
|
81
92
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { TestKey } from '@angular/cdk/testing';
|
|
1
|
+
import { TestKey, ComponentHarness } from '@angular/cdk/testing';
|
|
2
|
+
import { browser } from '@wdio/globals';
|
|
2
3
|
import logger from '@wdio/logger';
|
|
3
|
-
import
|
|
4
|
+
import colors from '@colors/colors/safe.js';
|
|
5
|
+
const { magenta, green } = colors;
|
|
4
6
|
var Button;
|
|
5
7
|
(function (Button) {
|
|
6
8
|
Button["LEFT"] = "left";
|
|
@@ -42,6 +44,9 @@ const keyMap = {
|
|
|
42
44
|
[TestKey.F12]: 'F12',
|
|
43
45
|
[TestKey.META]: 'Meta'
|
|
44
46
|
};
|
|
47
|
+
ComponentHarness.prototype.element = function () {
|
|
48
|
+
return this.locatorFactory.rootElement.element();
|
|
49
|
+
};
|
|
45
50
|
/** Converts a `ModifierKeys` object to a list of WebdriverIO `Key`s. */
|
|
46
51
|
const toWebdriverIOModifierKeys = (modifiers) => {
|
|
47
52
|
const result = [];
|
|
@@ -63,52 +68,57 @@ const toWebdriverIOModifierKeys = (modifiers) => {
|
|
|
63
68
|
* A `TestElement` implementation for WebdriverIO.
|
|
64
69
|
*/
|
|
65
70
|
export class WebdriverIOTestElement {
|
|
66
|
-
|
|
67
|
-
|
|
71
|
+
hostElement;
|
|
72
|
+
constructor(hostElement) {
|
|
73
|
+
this.hostElement = hostElement;
|
|
74
|
+
}
|
|
75
|
+
/** Return the host element. */
|
|
76
|
+
element() {
|
|
77
|
+
return this.hostElement;
|
|
68
78
|
}
|
|
69
79
|
/** Blur the element. */
|
|
70
|
-
blur() {
|
|
80
|
+
async blur() {
|
|
71
81
|
this.logAction('BLUR');
|
|
72
|
-
return browser.executeScript('arguments[0].blur()', [this.
|
|
82
|
+
return browser.executeScript('arguments[0].blur()', [this.hostElement]);
|
|
73
83
|
}
|
|
74
84
|
/** Clear the element's input (for input and textarea elements only). */
|
|
75
|
-
clear() {
|
|
85
|
+
async clear() {
|
|
76
86
|
this.logAction('CLEAR');
|
|
77
|
-
return this.
|
|
87
|
+
return this.hostElement.clearValue();
|
|
78
88
|
}
|
|
79
|
-
click(...args) {
|
|
89
|
+
async click(...args) {
|
|
80
90
|
this.logAction('CLICK');
|
|
81
91
|
return this.dispatchClickEventSequence(args, Button.LEFT);
|
|
82
92
|
}
|
|
83
|
-
rightClick(...args) {
|
|
93
|
+
async rightClick(...args) {
|
|
84
94
|
this.logAction('RIGHT_CLICK');
|
|
85
95
|
return this.dispatchClickEventSequence(args, Button.RIGHT);
|
|
86
96
|
}
|
|
87
97
|
/** Focus the element. */
|
|
88
|
-
focus() {
|
|
98
|
+
async focus() {
|
|
89
99
|
this.logAction('FOCUS');
|
|
90
|
-
return browser.executeScript('arguments[0].focus()', [this.
|
|
100
|
+
return browser.executeScript('arguments[0].focus()', [this.hostElement]);
|
|
91
101
|
}
|
|
92
102
|
/** Get the computed value of the given CSS property for the element. */
|
|
93
103
|
async getCssValue(property) {
|
|
94
104
|
this.logAction('GET_CSS_VALUE');
|
|
95
|
-
return (await this.
|
|
105
|
+
return (await this.hostElement.getCSSProperty(property)).value ?? '';
|
|
96
106
|
}
|
|
97
107
|
/** Hovers the mouse over the element. */
|
|
98
|
-
hover() {
|
|
108
|
+
async hover() {
|
|
99
109
|
this.logAction('HOVER');
|
|
100
|
-
return this.
|
|
110
|
+
return this.hostElement.moveTo();
|
|
101
111
|
}
|
|
102
112
|
/** Moves the mouse away from the element. */
|
|
103
|
-
mouseAway() {
|
|
113
|
+
async mouseAway() {
|
|
104
114
|
this.logAction('MOUSE_AWAY');
|
|
105
|
-
return this.
|
|
115
|
+
return this.hostElement.moveTo({ xOffset: -1, yOffset: -1 });
|
|
106
116
|
}
|
|
107
|
-
sendKeys(...modifiersAndKeys) {
|
|
117
|
+
async sendKeys(...modifiersAndKeys) {
|
|
108
118
|
let modifiers;
|
|
109
119
|
let rest;
|
|
110
120
|
const first = modifiersAndKeys[0];
|
|
111
|
-
if (typeof first !== 'string' && typeof first !== 'number') {
|
|
121
|
+
if (first !== undefined && typeof first !== 'string' && typeof first !== 'number') {
|
|
112
122
|
modifiers = first;
|
|
113
123
|
rest = modifiersAndKeys.slice(1);
|
|
114
124
|
}
|
|
@@ -128,10 +138,13 @@ export class WebdriverIOTestElement {
|
|
|
128
138
|
return arr.concat(k);
|
|
129
139
|
}, []);
|
|
130
140
|
this.logAction('SEND_KEYS', `[${keys.join(', ')}]`);
|
|
131
|
-
|
|
141
|
+
if (keys.length !== 0) {
|
|
142
|
+
await this.focus();
|
|
143
|
+
return browser.keys(keys);
|
|
144
|
+
}
|
|
132
145
|
}
|
|
133
146
|
/** Gets the text from the element. */
|
|
134
|
-
text(options) {
|
|
147
|
+
async text(options) {
|
|
135
148
|
this.logAction('TEXT', `{ exclude: ${options?.exclude} }`);
|
|
136
149
|
if (options?.exclude) {
|
|
137
150
|
return browser.executeScript(`
|
|
@@ -140,16 +153,16 @@ export class WebdriverIOTestElement {
|
|
|
140
153
|
for (let i = 0; i < exclusions.length; i++) {
|
|
141
154
|
exclusions[i].remove();
|
|
142
155
|
}
|
|
143
|
-
return (clone.textContent
|
|
144
|
-
`, [this.
|
|
156
|
+
return (clone.textContent ?? '').trim();
|
|
157
|
+
`, [this.hostElement, options.exclude]);
|
|
145
158
|
}
|
|
146
159
|
// We don't go through WebdriverIO's `getText`, because it excludes text from hidden elements.
|
|
147
|
-
return browser.executeScript(`return (arguments[0].textContent
|
|
160
|
+
return browser.executeScript(`return (arguments[0].textContent ?? '').trim()`, [this.hostElement]);
|
|
148
161
|
}
|
|
149
162
|
/** Gets the value for the given attribute from the element. */
|
|
150
|
-
getAttribute(name) {
|
|
163
|
+
async getAttribute(name) {
|
|
151
164
|
this.logAction('GET_ATTRIBUTE', name);
|
|
152
|
-
return this.
|
|
165
|
+
return this.hostElement.getAttribute(name);
|
|
153
166
|
}
|
|
154
167
|
/** Checks whether the element has the given class. */
|
|
155
168
|
async hasClass(name) {
|
|
@@ -160,36 +173,36 @@ export class WebdriverIOTestElement {
|
|
|
160
173
|
/** Gets the dimensions of the element. */
|
|
161
174
|
async getDimensions() {
|
|
162
175
|
this.logAction('GET_DIMENSIONS');
|
|
163
|
-
const { width, height } = await this.
|
|
164
|
-
const { x: left, y: top } = await this.
|
|
176
|
+
const { width, height } = await this.hostElement.getSize();
|
|
177
|
+
const { x: left, y: top } = await this.hostElement.getLocation();
|
|
165
178
|
return { width, height, left, top };
|
|
166
179
|
}
|
|
167
180
|
/** Gets the value of a property of an element. */
|
|
168
|
-
getProperty(name) {
|
|
181
|
+
async getProperty(name) {
|
|
169
182
|
this.logAction('GET_PROPERTY', name);
|
|
170
|
-
return this.
|
|
183
|
+
return this.hostElement.getProperty(name);
|
|
171
184
|
}
|
|
172
185
|
/** Checks whether this element matches the given selector. */
|
|
173
|
-
matchesSelector(selector) {
|
|
186
|
+
async matchesSelector(selector) {
|
|
174
187
|
this.logAction('MATCHES_SELECTOR', selector);
|
|
175
188
|
return browser.executeScript(`
|
|
176
|
-
return (Element.prototype.matches
|
|
177
|
-
`, [this.
|
|
189
|
+
return (Element.prototype.matches ?? Element.prototype.msMatchesSelector).call(arguments[0], arguments[1])
|
|
190
|
+
`, [this.hostElement, selector]);
|
|
178
191
|
}
|
|
179
192
|
/** Checks whether the element is focused. */
|
|
180
|
-
isFocused() {
|
|
193
|
+
async isFocused() {
|
|
181
194
|
this.logAction('IS_FOCUSED');
|
|
182
|
-
return this.
|
|
195
|
+
return this.hostElement.isFocused();
|
|
183
196
|
}
|
|
184
197
|
/** Sets the value of a property of an input. */
|
|
185
|
-
setInputValue(value) {
|
|
198
|
+
async setInputValue(value) {
|
|
186
199
|
this.logAction('SET_INPUT_VALUE', value);
|
|
187
|
-
return this.
|
|
200
|
+
return this.hostElement.setValue(value);
|
|
188
201
|
}
|
|
189
202
|
/** Selects the options at the specified indexes inside of a native `select` element. */
|
|
190
203
|
async selectOptions(...optionIndexes) {
|
|
191
204
|
this.logAction('SELECT_OPTIONS', `[${optionIndexes.join(', ')}]`);
|
|
192
|
-
const options = await this.
|
|
205
|
+
const options = await this.hostElement.$$('option');
|
|
193
206
|
const indexes = new Set(optionIndexes); // Convert to a set to remove duplicates.
|
|
194
207
|
if (options.length && indexes.size) {
|
|
195
208
|
// Reset the value so all the selected states are cleared. We can
|
|
@@ -207,7 +220,7 @@ export class WebdriverIOTestElement {
|
|
|
207
220
|
}
|
|
208
221
|
}
|
|
209
222
|
/** Dispatches an event with a particular name. */
|
|
210
|
-
dispatchEvent(name, data) {
|
|
223
|
+
async dispatchEvent(name, data) {
|
|
211
224
|
this.logAction('DISPATCH_EVENT', name);
|
|
212
225
|
return browser.executeScript(`
|
|
213
226
|
const event = document.createEvent('Event');
|
|
@@ -216,7 +229,25 @@ export class WebdriverIOTestElement {
|
|
|
216
229
|
Object.assign(event, arguments[2]);
|
|
217
230
|
}
|
|
218
231
|
arguments[1]['dispatchEvent'](event);
|
|
219
|
-
`, [name, this.
|
|
232
|
+
`, [name, this.hostElement, data]);
|
|
233
|
+
}
|
|
234
|
+
/** Performs a key-down action. */
|
|
235
|
+
async keyDown(value) {
|
|
236
|
+
this.logAction('KEY_DOWN:', value);
|
|
237
|
+
return browser.performActions([{
|
|
238
|
+
id: 'keyboard',
|
|
239
|
+
type: 'key',
|
|
240
|
+
actions: [{ type: 'keyDown', value }],
|
|
241
|
+
}]);
|
|
242
|
+
}
|
|
243
|
+
/** Performs a key-up action. */
|
|
244
|
+
async keyUp(value) {
|
|
245
|
+
this.logAction('KEY_UP:', value);
|
|
246
|
+
return browser.performActions([{
|
|
247
|
+
id: 'keyboard',
|
|
248
|
+
type: 'key',
|
|
249
|
+
actions: [{ type: 'keyUp', value }],
|
|
250
|
+
}]);
|
|
220
251
|
}
|
|
221
252
|
// --- HELPER(s) ---
|
|
222
253
|
/** Dispatches all the events that are part of a click event sequence. */
|
|
@@ -230,35 +261,17 @@ export class WebdriverIOTestElement {
|
|
|
230
261
|
// This is the default behavior we want, so we use an empty array of offsetArgs if
|
|
231
262
|
// no args remain after popping the modifiers from the args passed to this function.
|
|
232
263
|
const offsetArgs = (args.length === 2 ? { xOffset: Number(args[0]), yOffset: Number(args[1]) } : undefined);
|
|
233
|
-
await this.
|
|
264
|
+
await this.hostElement.moveTo(offsetArgs);
|
|
234
265
|
for (const modifierKey of modifierKeys) {
|
|
235
266
|
this.keyDown(modifierKey);
|
|
236
267
|
}
|
|
237
|
-
await this.
|
|
268
|
+
await this.hostElement.click({ button });
|
|
238
269
|
for (const modifierKey of modifierKeys) {
|
|
239
270
|
this.keyUp(modifierKey);
|
|
240
271
|
}
|
|
241
272
|
}
|
|
242
|
-
/** Performs a key-down action. */
|
|
243
|
-
keyDown(value) {
|
|
244
|
-
this.logAction('KEY_DOWN:', value);
|
|
245
|
-
return browser.performActions([{
|
|
246
|
-
id: 'keyboard',
|
|
247
|
-
type: 'key',
|
|
248
|
-
actions: [{ type: 'keyDown', value }],
|
|
249
|
-
}]);
|
|
250
|
-
}
|
|
251
|
-
/** Performs a key-up action. */
|
|
252
|
-
keyUp(value) {
|
|
253
|
-
this.logAction('KEY_UP:', value);
|
|
254
|
-
return browser.performActions([{
|
|
255
|
-
id: 'keyboard',
|
|
256
|
-
type: 'key',
|
|
257
|
-
actions: [{ type: 'keyUp', value }],
|
|
258
|
-
}]);
|
|
259
|
-
}
|
|
260
273
|
/** Writes info to the console outputs. */
|
|
261
274
|
logAction(action, args) {
|
|
262
|
-
log.info(`${magenta(action)} ${green(this.
|
|
275
|
+
log.info(`${magenta(action)} ${green(this.hostElement.selector.toString())} ${args ? args : ''}`);
|
|
263
276
|
}
|
|
264
277
|
}
|
|
@@ -1,27 +1,28 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
1
|
+
import { ComponentHarness, HarnessQuery } from '@angular/cdk/testing';
|
|
2
|
+
import { WebdriverIOHarnessEnvironment } from './WebdriverIOHarnessEnvironment.js';
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Searches for all instances of the component corresponding to the given harness type under the
|
|
5
|
+
* `HarnessLoader`'s root element, and returns a list of `ComponentHarness` for each instance.
|
|
6
|
+
* @param query A query for a harness to create
|
|
7
|
+
* @return A list of instances of the given harness type
|
|
6
8
|
*/
|
|
7
|
-
export declare const
|
|
9
|
+
export declare const getAllHarnesses: <T extends ComponentHarness>(query: HarnessQuery<T>) => Promise<T[]>;
|
|
8
10
|
/**
|
|
9
|
-
* Searches for an instance of the component corresponding to the given harness type
|
|
10
|
-
* `HarnessLoader`'s root element, and returns a `ComponentHarness` for that instance. If
|
|
11
|
-
* matching components are found, a harness for the first one is returned. If no matching
|
|
11
|
+
* Searches for an instance of the component corresponding to the given harness type or host element
|
|
12
|
+
* under the `HarnessLoader`'s root element, and returns a `ComponentHarness` for that instance. If
|
|
13
|
+
* multiple matching components are found, a harness for the first one is returned. If no matching
|
|
12
14
|
* component is found, an error is thrown.
|
|
13
15
|
* @param query A query for a harness to create
|
|
16
|
+
* @param element A raw host element for a harness to create
|
|
14
17
|
* @return An instance of the given harness type
|
|
15
|
-
* @throws If a matching component instance can't be found
|
|
18
|
+
* @throws If a matching component instance can't be found
|
|
16
19
|
*/
|
|
17
|
-
export declare const getHarness: <T extends ComponentHarness>(query: HarnessQuery<T
|
|
20
|
+
export declare const getHarness: <T extends ComponentHarness>(query: HarnessQuery<T>, element?: WebdriverIO.Element) => Promise<T>;
|
|
18
21
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
* @param query A query for a harness to create
|
|
22
|
-
* @return A list instances of the given harness type.
|
|
22
|
+
* Returns a base harness environment instance.
|
|
23
|
+
* @return An HarnessLoader instance for the current HTML document, rooted at the document's root element
|
|
23
24
|
*/
|
|
24
|
-
export declare const
|
|
25
|
+
export declare const createHarnessEnvironment: (rootElement?: WebdriverIO.Element) => Promise<WebdriverIOHarnessEnvironment>;
|
|
25
26
|
/**
|
|
26
27
|
* Returns a promise that resolves when the application is "stable".
|
|
27
28
|
* The promise might be rejected due to timeouts, or async tasks in the client
|
|
@@ -1,31 +1,37 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { browser, $ } from '@wdio/globals';
|
|
2
|
+
import { WebdriverIOHarnessEnvironment } from './WebdriverIOHarnessEnvironment.js';
|
|
2
3
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
4
|
+
* Searches for all instances of the component corresponding to the given harness type under the
|
|
5
|
+
* `HarnessLoader`'s root element, and returns a list of `ComponentHarness` for each instance.
|
|
6
|
+
* @param query A query for a harness to create
|
|
7
|
+
* @return A list of instances of the given harness type
|
|
5
8
|
*/
|
|
6
|
-
export const
|
|
7
|
-
return
|
|
9
|
+
export const getAllHarnesses = async (query) => {
|
|
10
|
+
return (await createHarnessEnvironment()).getAllHarnesses(query);
|
|
8
11
|
};
|
|
9
12
|
/**
|
|
10
|
-
* Searches for an instance of the component corresponding to the given harness type
|
|
11
|
-
* `HarnessLoader`'s root element, and returns a `ComponentHarness` for that instance. If
|
|
12
|
-
* matching components are found, a harness for the first one is returned. If no matching
|
|
13
|
+
* Searches for an instance of the component corresponding to the given harness type or host element
|
|
14
|
+
* under the `HarnessLoader`'s root element, and returns a `ComponentHarness` for that instance. If
|
|
15
|
+
* multiple matching components are found, a harness for the first one is returned. If no matching
|
|
13
16
|
* component is found, an error is thrown.
|
|
14
17
|
* @param query A query for a harness to create
|
|
18
|
+
* @param element A raw host element for a harness to create
|
|
15
19
|
* @return An instance of the given harness type
|
|
16
|
-
* @throws If a matching component instance can't be found
|
|
20
|
+
* @throws If a matching component instance can't be found
|
|
17
21
|
*/
|
|
18
|
-
export const getHarness = async (query) => {
|
|
19
|
-
|
|
22
|
+
export const getHarness = async (query, element) => {
|
|
23
|
+
const env = await createHarnessEnvironment(element);
|
|
24
|
+
if (element) {
|
|
25
|
+
return env.createComponentHarness(query, element);
|
|
26
|
+
}
|
|
27
|
+
return env.getHarness(query);
|
|
20
28
|
};
|
|
21
29
|
/**
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
* @param query A query for a harness to create
|
|
25
|
-
* @return A list instances of the given harness type.
|
|
30
|
+
* Returns a base harness environment instance.
|
|
31
|
+
* @return An HarnessLoader instance for the current HTML document, rooted at the document's root element
|
|
26
32
|
*/
|
|
27
|
-
export const
|
|
28
|
-
return (await
|
|
33
|
+
export const createHarnessEnvironment = async (rootElement) => {
|
|
34
|
+
return WebdriverIOHarnessEnvironment.loader(rootElement || await $('body'));
|
|
29
35
|
};
|
|
30
36
|
/**
|
|
31
37
|
* Returns a promise that resolves when the application is "stable".
|
package/package.json
CHANGED
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@badisi/wdio-harness",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "WebdriverIO support for Angular component test harnesses.",
|
|
5
5
|
"homepage": "https://github.com/badisi/wdio-harness",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "Badisi"
|
|
9
9
|
},
|
|
10
|
-
"
|
|
11
|
-
"module": "
|
|
12
|
-
"types": "
|
|
10
|
+
"type": "module",
|
|
11
|
+
"module": "index.js",
|
|
12
|
+
"types": "index.d.ts",
|
|
13
13
|
"exports": {
|
|
14
14
|
".": {
|
|
15
|
-
"
|
|
16
|
-
"import": "./esm/index.js"
|
|
15
|
+
"import": "./index.js"
|
|
17
16
|
}
|
|
18
17
|
},
|
|
19
18
|
"repository": {
|
|
@@ -33,10 +32,13 @@
|
|
|
33
32
|
"webdriver",
|
|
34
33
|
"webdriverio"
|
|
35
34
|
],
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": "^16.13 || >=18"
|
|
37
|
+
},
|
|
36
38
|
"peerDependencies": {
|
|
37
|
-
"@angular/cdk": ">=
|
|
38
|
-
"@wdio/logger": ">=
|
|
39
|
-
"webdriverio": ">=
|
|
39
|
+
"@angular/cdk": ">= 13 < 16",
|
|
40
|
+
"@wdio/logger": ">= 8 < 9",
|
|
41
|
+
"webdriverio": ">= 8 < 9"
|
|
40
42
|
},
|
|
41
43
|
"dependencies": {
|
|
42
44
|
"@colors/colors": "^1.5.0"
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.WebdriverIOHarnessEnvironment = void 0;
|
|
4
|
-
const tslib_1 = require("tslib");
|
|
5
|
-
const testing_1 = require("@angular/cdk/testing");
|
|
6
|
-
const logger_1 = tslib_1.__importDefault(require("@wdio/logger"));
|
|
7
|
-
const safe_1 = require("@colors/colors/safe");
|
|
8
|
-
const WebdriverIOTestElement_1 = require("./WebdriverIOTestElement");
|
|
9
|
-
/** Registers the environment logger. */
|
|
10
|
-
const log = logger_1.default('wdio-harness');
|
|
11
|
-
/**
|
|
12
|
-
* A `HarnessEnvironment` implementation for WebdriverIO.
|
|
13
|
-
*/
|
|
14
|
-
class WebdriverIOHarnessEnvironment extends testing_1.HarnessEnvironment {
|
|
15
|
-
constructor(rawRootElement, options) {
|
|
16
|
-
super(rawRootElement);
|
|
17
|
-
this.documentRoot = options.documentRoot;
|
|
18
|
-
}
|
|
19
|
-
/** Creates a `HarnessLoader` rooted at the document root. */
|
|
20
|
-
static loader(documentRoot) {
|
|
21
|
-
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
22
|
-
return new WebdriverIOHarnessEnvironment(documentRoot, { documentRoot });
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Flushes change detection and async tasks captured in the Angular zone.
|
|
27
|
-
* In most cases it should not be necessary to call this manually. However, there may be some edge
|
|
28
|
-
* cases where it is needed to fully flush animation events.
|
|
29
|
-
*/
|
|
30
|
-
forceStabilize() {
|
|
31
|
-
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
32
|
-
/* await browser.executeAsyncScript(`
|
|
33
|
-
const done = arguments[0];
|
|
34
|
-
window.requestAnimationFrame(done);
|
|
35
|
-
`, []);*/
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
waitForTasksOutsideAngular() {
|
|
39
|
-
throw new Error('Method not implemented.');
|
|
40
|
-
}
|
|
41
|
-
/** Gets the root element for the document. */
|
|
42
|
-
getDocumentRoot() {
|
|
43
|
-
return this.documentRoot;
|
|
44
|
-
}
|
|
45
|
-
/** Creates a `TestElement` from a raw element. */
|
|
46
|
-
createTestElement(element) {
|
|
47
|
-
return new WebdriverIOTestElement_1.WebdriverIOTestElement(element);
|
|
48
|
-
}
|
|
49
|
-
/** Creates a `HarnessLoader` rooted at the given raw element. */
|
|
50
|
-
createEnvironment(element) {
|
|
51
|
-
return new WebdriverIOHarnessEnvironment(element, {
|
|
52
|
-
documentRoot: this.documentRoot
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
/** Gets a list of all elements matching the given selector under this environment's root element. */
|
|
56
|
-
getAllRawElements(selector) {
|
|
57
|
-
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
58
|
-
log.info(`${safe_1.magenta('GET_ALL_RAW_ELEMENTS')} ${safe_1.green(selector.toString())}`);
|
|
59
|
-
return yield this.rawRootElement.$$(selector);
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
exports.WebdriverIOHarnessEnvironment = WebdriverIOHarnessEnvironment;
|
|
@@ -1,279 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.WebdriverIOTestElement = void 0;
|
|
4
|
-
const tslib_1 = require("tslib");
|
|
5
|
-
const testing_1 = require("@angular/cdk/testing");
|
|
6
|
-
const logger_1 = tslib_1.__importDefault(require("@wdio/logger"));
|
|
7
|
-
const safe_1 = require("@colors/colors/safe");
|
|
8
|
-
var Button;
|
|
9
|
-
(function (Button) {
|
|
10
|
-
Button["LEFT"] = "left";
|
|
11
|
-
Button["MIDDLE"] = "middle";
|
|
12
|
-
Button["RIGHT"] = "right";
|
|
13
|
-
})(Button || (Button = {}));
|
|
14
|
-
/** Registers the element logger. */
|
|
15
|
-
const log = logger_1.default('wdio-harness');
|
|
16
|
-
/** Maps the `TestKey` constants to WebdriverIO's `Key` constants. */
|
|
17
|
-
const keyMap = {
|
|
18
|
-
[testing_1.TestKey.BACKSPACE]: 'Backspace',
|
|
19
|
-
[testing_1.TestKey.TAB]: 'Tab',
|
|
20
|
-
[testing_1.TestKey.ENTER]: 'Enter',
|
|
21
|
-
[testing_1.TestKey.SHIFT]: 'Shift',
|
|
22
|
-
[testing_1.TestKey.CONTROL]: 'Control',
|
|
23
|
-
[testing_1.TestKey.ALT]: 'Alt',
|
|
24
|
-
[testing_1.TestKey.ESCAPE]: 'Escape',
|
|
25
|
-
[testing_1.TestKey.PAGE_UP]: 'PageUp',
|
|
26
|
-
[testing_1.TestKey.PAGE_DOWN]: 'PageDown',
|
|
27
|
-
[testing_1.TestKey.END]: 'End',
|
|
28
|
-
[testing_1.TestKey.HOME]: 'Home',
|
|
29
|
-
[testing_1.TestKey.LEFT_ARROW]: 'ArrowLeft',
|
|
30
|
-
[testing_1.TestKey.UP_ARROW]: 'ArrowUp',
|
|
31
|
-
[testing_1.TestKey.RIGHT_ARROW]: 'ArrowRight',
|
|
32
|
-
[testing_1.TestKey.DOWN_ARROW]: 'ArrowDown',
|
|
33
|
-
[testing_1.TestKey.INSERT]: 'Insert',
|
|
34
|
-
[testing_1.TestKey.DELETE]: 'Delete',
|
|
35
|
-
[testing_1.TestKey.F1]: 'F1',
|
|
36
|
-
[testing_1.TestKey.F2]: 'F2',
|
|
37
|
-
[testing_1.TestKey.F3]: 'F3',
|
|
38
|
-
[testing_1.TestKey.F4]: 'F4',
|
|
39
|
-
[testing_1.TestKey.F5]: 'F5',
|
|
40
|
-
[testing_1.TestKey.F6]: 'F6',
|
|
41
|
-
[testing_1.TestKey.F7]: 'F7',
|
|
42
|
-
[testing_1.TestKey.F8]: 'F8',
|
|
43
|
-
[testing_1.TestKey.F9]: 'F9',
|
|
44
|
-
[testing_1.TestKey.F10]: 'F10',
|
|
45
|
-
[testing_1.TestKey.F11]: 'F11',
|
|
46
|
-
[testing_1.TestKey.F12]: 'F12',
|
|
47
|
-
[testing_1.TestKey.META]: 'Meta'
|
|
48
|
-
};
|
|
49
|
-
/** Converts a `ModifierKeys` object to a list of WebdriverIO `Key`s. */
|
|
50
|
-
const toWebdriverIOModifierKeys = (modifiers) => {
|
|
51
|
-
const result = [];
|
|
52
|
-
if (modifiers.control) {
|
|
53
|
-
result.push(keyMap[testing_1.TestKey.CONTROL]);
|
|
54
|
-
}
|
|
55
|
-
if (modifiers.alt) {
|
|
56
|
-
result.push(keyMap[testing_1.TestKey.ALT]);
|
|
57
|
-
}
|
|
58
|
-
if (modifiers.shift) {
|
|
59
|
-
result.push(keyMap[testing_1.TestKey.SHIFT]);
|
|
60
|
-
}
|
|
61
|
-
if (modifiers.meta) {
|
|
62
|
-
result.push(keyMap[testing_1.TestKey.META]);
|
|
63
|
-
}
|
|
64
|
-
return result;
|
|
65
|
-
};
|
|
66
|
-
/**
|
|
67
|
-
* A `TestElement` implementation for WebdriverIO.
|
|
68
|
-
*/
|
|
69
|
-
class WebdriverIOTestElement {
|
|
70
|
-
constructor(element) {
|
|
71
|
-
this.element = element;
|
|
72
|
-
}
|
|
73
|
-
/** Blur the element. */
|
|
74
|
-
blur() {
|
|
75
|
-
this.logAction('BLUR');
|
|
76
|
-
return browser.executeScript('arguments[0].blur()', [this.element]);
|
|
77
|
-
}
|
|
78
|
-
/** Clear the element's input (for input and textarea elements only). */
|
|
79
|
-
clear() {
|
|
80
|
-
this.logAction('CLEAR');
|
|
81
|
-
return this.element.clearValue();
|
|
82
|
-
}
|
|
83
|
-
click(...args) {
|
|
84
|
-
this.logAction('CLICK');
|
|
85
|
-
return this.dispatchClickEventSequence(args, Button.LEFT);
|
|
86
|
-
}
|
|
87
|
-
rightClick(...args) {
|
|
88
|
-
this.logAction('RIGHT_CLICK');
|
|
89
|
-
return this.dispatchClickEventSequence(args, Button.RIGHT);
|
|
90
|
-
}
|
|
91
|
-
/** Focus the element. */
|
|
92
|
-
focus() {
|
|
93
|
-
this.logAction('FOCUS');
|
|
94
|
-
return browser.executeScript('arguments[0].focus()', [this.element]);
|
|
95
|
-
}
|
|
96
|
-
/** Get the computed value of the given CSS property for the element. */
|
|
97
|
-
getCssValue(property) {
|
|
98
|
-
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
99
|
-
this.logAction('GET_CSS_VALUE');
|
|
100
|
-
return (yield this.element.getCSSProperty(property)).value || '';
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
/** Hovers the mouse over the element. */
|
|
104
|
-
hover() {
|
|
105
|
-
this.logAction('HOVER');
|
|
106
|
-
return this.element.moveTo();
|
|
107
|
-
}
|
|
108
|
-
/** Moves the mouse away from the element. */
|
|
109
|
-
mouseAway() {
|
|
110
|
-
this.logAction('MOUSE_AWAY');
|
|
111
|
-
return this.element.moveTo({ xOffset: -1, yOffset: -1 });
|
|
112
|
-
}
|
|
113
|
-
sendKeys(...modifiersAndKeys) {
|
|
114
|
-
let modifiers;
|
|
115
|
-
let rest;
|
|
116
|
-
const first = modifiersAndKeys[0];
|
|
117
|
-
if (typeof first !== 'string' && typeof first !== 'number') {
|
|
118
|
-
modifiers = first;
|
|
119
|
-
rest = modifiersAndKeys.slice(1);
|
|
120
|
-
}
|
|
121
|
-
else {
|
|
122
|
-
modifiers = {};
|
|
123
|
-
rest = modifiersAndKeys;
|
|
124
|
-
}
|
|
125
|
-
const KeyNULL = String.fromCharCode(57344);
|
|
126
|
-
const modifierKeys = toWebdriverIOModifierKeys(modifiers);
|
|
127
|
-
const keys = rest
|
|
128
|
-
.map(k => (typeof k === 'string' ? k.split('') : [keyMap[k]]))
|
|
129
|
-
.reduce((arr, k) => arr.concat(k), [])
|
|
130
|
-
.reduce((arr, k) => {
|
|
131
|
-
if (modifierKeys.length > 0) {
|
|
132
|
-
return arr.concat(...modifierKeys, k, KeyNULL);
|
|
133
|
-
}
|
|
134
|
-
return arr.concat(k);
|
|
135
|
-
}, []);
|
|
136
|
-
this.logAction('SEND_KEYS', `[${keys.join(', ')}]`);
|
|
137
|
-
return this.element.setValue(keys);
|
|
138
|
-
}
|
|
139
|
-
/** Gets the text from the element. */
|
|
140
|
-
text(options) {
|
|
141
|
-
this.logAction('TEXT', `{ exclude: ${options === null || options === void 0 ? void 0 : options.exclude} }`);
|
|
142
|
-
if (options === null || options === void 0 ? void 0 : options.exclude) {
|
|
143
|
-
return browser.executeScript(`
|
|
144
|
-
const clone = arguments[0].cloneNode(true) as Element;
|
|
145
|
-
const exclusions = clone.querySelectorAll(arguments[1]);
|
|
146
|
-
for (let i = 0; i < exclusions.length; i++) {
|
|
147
|
-
exclusions[i].remove();
|
|
148
|
-
}
|
|
149
|
-
return (clone.textContent || '').trim();
|
|
150
|
-
`, [this.element, options.exclude]);
|
|
151
|
-
}
|
|
152
|
-
// We don't go through WebdriverIO's `getText`, because it excludes text from hidden elements.
|
|
153
|
-
return browser.executeScript(`return (arguments[0].textContent || '').trim()`, [this.element]);
|
|
154
|
-
}
|
|
155
|
-
/** Gets the value for the given attribute from the element. */
|
|
156
|
-
getAttribute(name) {
|
|
157
|
-
this.logAction('GET_ATTRIBUTE', name);
|
|
158
|
-
return this.element.getAttribute(name);
|
|
159
|
-
}
|
|
160
|
-
/** Checks whether the element has the given class. */
|
|
161
|
-
hasClass(name) {
|
|
162
|
-
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
163
|
-
this.logAction('HAS_CLASS', name);
|
|
164
|
-
const classes = (yield this.getAttribute('class')) || '';
|
|
165
|
-
return new Set(classes.split(/\s+/).filter(c => c)).has(name);
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
|
-
/** Gets the dimensions of the element. */
|
|
169
|
-
getDimensions() {
|
|
170
|
-
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
171
|
-
this.logAction('GET_DIMENSIONS');
|
|
172
|
-
const { width, height } = yield this.element.getSize();
|
|
173
|
-
const { x: left, y: top } = yield this.element.getLocation();
|
|
174
|
-
return { width, height, left, top };
|
|
175
|
-
});
|
|
176
|
-
}
|
|
177
|
-
/** Gets the value of a property of an element. */
|
|
178
|
-
getProperty(name) {
|
|
179
|
-
this.logAction('GET_PROPERTY', name);
|
|
180
|
-
return this.element.getProperty(name);
|
|
181
|
-
}
|
|
182
|
-
/** Checks whether this element matches the given selector. */
|
|
183
|
-
matchesSelector(selector) {
|
|
184
|
-
this.logAction('MATCHES_SELECTOR', selector);
|
|
185
|
-
return browser.executeScript(`
|
|
186
|
-
return (Element.prototype.matches || Element.prototype.msMatchesSelector).call(arguments[0], arguments[1])
|
|
187
|
-
`, [this.element, selector]);
|
|
188
|
-
}
|
|
189
|
-
/** Checks whether the element is focused. */
|
|
190
|
-
isFocused() {
|
|
191
|
-
this.logAction('IS_FOCUSED');
|
|
192
|
-
return this.element.isFocused();
|
|
193
|
-
}
|
|
194
|
-
/** Sets the value of a property of an input. */
|
|
195
|
-
setInputValue(value) {
|
|
196
|
-
this.logAction('SET_INPUT_VALUE', value);
|
|
197
|
-
return this.element.setValue(value);
|
|
198
|
-
}
|
|
199
|
-
/** Selects the options at the specified indexes inside of a native `select` element. */
|
|
200
|
-
selectOptions(...optionIndexes) {
|
|
201
|
-
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
202
|
-
this.logAction('SELECT_OPTIONS', `[${optionIndexes.join(', ')}]`);
|
|
203
|
-
const options = yield this.element.$$('option');
|
|
204
|
-
const indexes = new Set(optionIndexes); // Convert to a set to remove duplicates.
|
|
205
|
-
if (options.length && indexes.size) {
|
|
206
|
-
// Reset the value so all the selected states are cleared. We can
|
|
207
|
-
// reuse the input-specific method since the logic is the same.
|
|
208
|
-
yield this.setInputValue('');
|
|
209
|
-
for (let i = 0; i < options.length; i++) {
|
|
210
|
-
if (indexes.has(i)) {
|
|
211
|
-
// We have to hold the control key while clicking on options so that multiple can be
|
|
212
|
-
// selected in multi-selection mode. The key doesn't do anything for single selection.
|
|
213
|
-
yield this.keyDown(keyMap[testing_1.TestKey.CONTROL]);
|
|
214
|
-
yield options[i].click();
|
|
215
|
-
yield this.keyUp(keyMap[testing_1.TestKey.CONTROL]);
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
});
|
|
220
|
-
}
|
|
221
|
-
/** Dispatches an event with a particular name. */
|
|
222
|
-
dispatchEvent(name, data) {
|
|
223
|
-
this.logAction('DISPATCH_EVENT', name);
|
|
224
|
-
return browser.executeScript(`
|
|
225
|
-
const event = document.createEvent('Event');
|
|
226
|
-
event.initEvent(arguments[0]);
|
|
227
|
-
if (arguments[2]) {
|
|
228
|
-
Object.assign(event, arguments[2]);
|
|
229
|
-
}
|
|
230
|
-
arguments[1]['dispatchEvent'](event);
|
|
231
|
-
`, [name, this.element, data]);
|
|
232
|
-
}
|
|
233
|
-
// --- HELPER(s) ---
|
|
234
|
-
/** Dispatches all the events that are part of a click event sequence. */
|
|
235
|
-
dispatchClickEventSequence(args, button) {
|
|
236
|
-
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
237
|
-
let modifiers = {};
|
|
238
|
-
if (args.length && typeof args[args.length - 1] === 'object') {
|
|
239
|
-
modifiers = args.pop();
|
|
240
|
-
}
|
|
241
|
-
const modifierKeys = toWebdriverIOModifierKeys(modifiers);
|
|
242
|
-
// Omitting the offset argument to mouseMove results in clicking the center.
|
|
243
|
-
// This is the default behavior we want, so we use an empty array of offsetArgs if
|
|
244
|
-
// no args remain after popping the modifiers from the args passed to this function.
|
|
245
|
-
const offsetArgs = (args.length === 2 ? { xOffset: Number(args[0]), yOffset: Number(args[1]) } : undefined);
|
|
246
|
-
yield this.element.moveTo(offsetArgs);
|
|
247
|
-
for (const modifierKey of modifierKeys) {
|
|
248
|
-
this.keyDown(modifierKey);
|
|
249
|
-
}
|
|
250
|
-
yield this.element.click({ button });
|
|
251
|
-
for (const modifierKey of modifierKeys) {
|
|
252
|
-
this.keyUp(modifierKey);
|
|
253
|
-
}
|
|
254
|
-
});
|
|
255
|
-
}
|
|
256
|
-
/** Performs a key-down action. */
|
|
257
|
-
keyDown(value) {
|
|
258
|
-
this.logAction('KEY_DOWN:', value);
|
|
259
|
-
return browser.performActions([{
|
|
260
|
-
id: 'keyboard',
|
|
261
|
-
type: 'key',
|
|
262
|
-
actions: [{ type: 'keyDown', value }],
|
|
263
|
-
}]);
|
|
264
|
-
}
|
|
265
|
-
/** Performs a key-up action. */
|
|
266
|
-
keyUp(value) {
|
|
267
|
-
this.logAction('KEY_UP:', value);
|
|
268
|
-
return browser.performActions([{
|
|
269
|
-
id: 'keyboard',
|
|
270
|
-
type: 'key',
|
|
271
|
-
actions: [{ type: 'keyUp', value }],
|
|
272
|
-
}]);
|
|
273
|
-
}
|
|
274
|
-
/** Writes info to the console outputs. */
|
|
275
|
-
logAction(action, args) {
|
|
276
|
-
log.info(`${safe_1.magenta(action)} ${safe_1.green(this.element.selector.toString())} ${args ? args : ''}`);
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
exports.WebdriverIOTestElement = WebdriverIOTestElement;
|
package/cjs/index.d.ts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
/// <reference types="webdriverio/async" />
|
|
2
|
-
import { ComponentHarness, HarnessLoader, HarnessQuery } from '@angular/cdk/testing/';
|
|
3
|
-
/**
|
|
4
|
-
* Returns a base harness environment instance.
|
|
5
|
-
* @return An HarnessLoader instance for the current HTML document, rooted at the document's root element
|
|
6
|
-
*/
|
|
7
|
-
export declare const createHarnessEnvironment: (documentRoot?: WebdriverIO.Element | undefined) => Promise<HarnessLoader>;
|
|
8
|
-
/**
|
|
9
|
-
* Searches for an instance of the component corresponding to the given harness type under the
|
|
10
|
-
* `HarnessLoader`'s root element, and returns a `ComponentHarness` for that instance. If multiple
|
|
11
|
-
* matching components are found, a harness for the first one is returned. If no matching
|
|
12
|
-
* component is found, an error is thrown.
|
|
13
|
-
* @param query A query for a harness to create
|
|
14
|
-
* @return An instance of the given harness type
|
|
15
|
-
* @throws If a matching component instance can't be found.
|
|
16
|
-
*/
|
|
17
|
-
export declare const getHarness: <T extends ComponentHarness>(query: HarnessQuery<T>) => Promise<T>;
|
|
18
|
-
/**
|
|
19
|
-
* Searches for all instances of the component corresponding to the given harness type under the
|
|
20
|
-
* `HarnessLoader`'s root element, and returns a list `ComponentHarness` for each instance.
|
|
21
|
-
* @param query A query for a harness to create
|
|
22
|
-
* @return A list instances of the given harness type.
|
|
23
|
-
*/
|
|
24
|
-
export declare const getAllHarnesses: <T extends ComponentHarness>(query: HarnessQuery<T>) => Promise<T[]>;
|
|
25
|
-
/**
|
|
26
|
-
* Returns a promise that resolves when the application is "stable".
|
|
27
|
-
* The promise might be rejected due to timeouts, or async tasks in the client
|
|
28
|
-
* app that never finish (timers, etc).
|
|
29
|
-
*/
|
|
30
|
-
export declare const waitForAngular: () => Promise<void>;
|
package/cjs/index.js
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.waitForAngular = exports.getAllHarnesses = exports.getHarness = exports.createHarnessEnvironment = void 0;
|
|
4
|
-
const tslib_1 = require("tslib");
|
|
5
|
-
const WebdriverIOHarnessEnvironment_1 = require("./WebdriverIOHarnessEnvironment");
|
|
6
|
-
/**
|
|
7
|
-
* Returns a base harness environment instance.
|
|
8
|
-
* @return An HarnessLoader instance for the current HTML document, rooted at the document's root element
|
|
9
|
-
*/
|
|
10
|
-
const createHarnessEnvironment = (documentRoot) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
|
|
11
|
-
return WebdriverIOHarnessEnvironment_1.WebdriverIOHarnessEnvironment.loader(documentRoot || (yield $('body')));
|
|
12
|
-
});
|
|
13
|
-
exports.createHarnessEnvironment = createHarnessEnvironment;
|
|
14
|
-
/**
|
|
15
|
-
* Searches for an instance of the component corresponding to the given harness type under the
|
|
16
|
-
* `HarnessLoader`'s root element, and returns a `ComponentHarness` for that instance. If multiple
|
|
17
|
-
* matching components are found, a harness for the first one is returned. If no matching
|
|
18
|
-
* component is found, an error is thrown.
|
|
19
|
-
* @param query A query for a harness to create
|
|
20
|
-
* @return An instance of the given harness type
|
|
21
|
-
* @throws If a matching component instance can't be found.
|
|
22
|
-
*/
|
|
23
|
-
const getHarness = (query) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
|
|
24
|
-
return (yield exports.createHarnessEnvironment()).getHarness(query);
|
|
25
|
-
});
|
|
26
|
-
exports.getHarness = getHarness;
|
|
27
|
-
/**
|
|
28
|
-
* Searches for all instances of the component corresponding to the given harness type under the
|
|
29
|
-
* `HarnessLoader`'s root element, and returns a list `ComponentHarness` for each instance.
|
|
30
|
-
* @param query A query for a harness to create
|
|
31
|
-
* @return A list instances of the given harness type.
|
|
32
|
-
*/
|
|
33
|
-
const getAllHarnesses = (query) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
|
|
34
|
-
return (yield exports.createHarnessEnvironment()).getAllHarnesses(query);
|
|
35
|
-
});
|
|
36
|
-
exports.getAllHarnesses = getAllHarnesses;
|
|
37
|
-
/**
|
|
38
|
-
* Returns a promise that resolves when the application is "stable".
|
|
39
|
-
* The promise might be rejected due to timeouts, or async tasks in the client
|
|
40
|
-
* app that never finish (timers, etc).
|
|
41
|
-
*/
|
|
42
|
-
const waitForAngular = () => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
|
|
43
|
-
yield browser.waitUntil(() => browser.executeScript(`
|
|
44
|
-
return Array.isArray(window.frameworkStabilizers)
|
|
45
|
-
`, []));
|
|
46
|
-
yield browser.executeAsyncScript(`
|
|
47
|
-
const done = arguments[0];
|
|
48
|
-
const promises = window.frameworkStabilizers.map(stabilizer => {
|
|
49
|
-
// Stabilizer will invoke the resolve function with a
|
|
50
|
-
// boolean to indicate whether any work is done.
|
|
51
|
-
return new Promise(resolve => stabilizer(resolve));
|
|
52
|
-
});
|
|
53
|
-
Promise.all(promises).then(done);
|
|
54
|
-
`, []);
|
|
55
|
-
});
|
|
56
|
-
exports.waitForAngular = waitForAngular;
|
package/cjs/package.json
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
/// <reference types="webdriverio/async" />
|
|
2
|
-
import { HarnessEnvironment, HarnessLoader, TestElement } from '@angular/cdk/testing';
|
|
3
|
-
/**
|
|
4
|
-
* A `HarnessEnvironment` implementation for WebdriverIO.
|
|
5
|
-
*/
|
|
6
|
-
export declare class WebdriverIOHarnessEnvironment extends HarnessEnvironment<WebdriverIO.Element> {
|
|
7
|
-
/**
|
|
8
|
-
* Keep a reference to the `document` element because `rawRootElement`
|
|
9
|
-
* will be the root element of the harness's environment.
|
|
10
|
-
*/
|
|
11
|
-
private documentRoot;
|
|
12
|
-
protected constructor(rawRootElement: WebdriverIO.Element, options: {
|
|
13
|
-
documentRoot: WebdriverIO.Element;
|
|
14
|
-
});
|
|
15
|
-
/** Creates a `HarnessLoader` rooted at the document root. */
|
|
16
|
-
static loader(documentRoot: WebdriverIO.Element): Promise<HarnessLoader>;
|
|
17
|
-
/**
|
|
18
|
-
* Flushes change detection and async tasks captured in the Angular zone.
|
|
19
|
-
* In most cases it should not be necessary to call this manually. However, there may be some edge
|
|
20
|
-
* cases where it is needed to fully flush animation events.
|
|
21
|
-
*/
|
|
22
|
-
forceStabilize(): Promise<void>;
|
|
23
|
-
waitForTasksOutsideAngular(): Promise<void>;
|
|
24
|
-
/** Gets the root element for the document. */
|
|
25
|
-
protected getDocumentRoot(): WebdriverIO.Element;
|
|
26
|
-
/** Creates a `TestElement` from a raw element. */
|
|
27
|
-
protected createTestElement(element: WebdriverIO.Element): TestElement;
|
|
28
|
-
/** Creates a `HarnessLoader` rooted at the given raw element. */
|
|
29
|
-
protected createEnvironment(element: WebdriverIO.Element): HarnessEnvironment<WebdriverIO.Element>;
|
|
30
|
-
/** Gets a list of all elements matching the given selector under this environment's root element. */
|
|
31
|
-
protected getAllRawElements(selector: string): Promise<WebdriverIO.ElementArray>;
|
|
32
|
-
}
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
/// <reference types="webdriverio/async" />
|
|
2
|
-
import { ElementDimensions, EventData, ModifierKeys, TestElement, TestKey, TextOptions } from '@angular/cdk/testing';
|
|
3
|
-
/**
|
|
4
|
-
* A `TestElement` implementation for WebdriverIO.
|
|
5
|
-
*/
|
|
6
|
-
export declare class WebdriverIOTestElement implements TestElement {
|
|
7
|
-
readonly element: WebdriverIO.Element;
|
|
8
|
-
constructor(element: WebdriverIO.Element);
|
|
9
|
-
/** Blur the element. */
|
|
10
|
-
blur(): Promise<void>;
|
|
11
|
-
/** Clear the element's input (for input and textarea elements only). */
|
|
12
|
-
clear(): Promise<void>;
|
|
13
|
-
/**
|
|
14
|
-
* Click the element at the default location for the current environment. If you need to guarantee
|
|
15
|
-
* the element is clicked at a specific location, consider using `click('center')` or
|
|
16
|
-
* `click(x, y)` instead.
|
|
17
|
-
*/
|
|
18
|
-
click(modifiers?: ModifierKeys): Promise<void>;
|
|
19
|
-
/** Click the element at the element's center. */
|
|
20
|
-
click(location: 'center', modifiers?: ModifierKeys): Promise<void>;
|
|
21
|
-
/**
|
|
22
|
-
* Click the element at the specified coordinates relative to the top-left of the element.
|
|
23
|
-
* @param relativeX Coordinate within the element, along the X-axis at which to click.
|
|
24
|
-
* @param relativeY Coordinate within the element, along the Y-axis at which to click.
|
|
25
|
-
* @param modifiers Modifier keys held while clicking
|
|
26
|
-
*/
|
|
27
|
-
click(relativeX: number, relativeY: number, modifiers?: ModifierKeys): Promise<void>;
|
|
28
|
-
/**
|
|
29
|
-
* Right clicks on the element at the specified coordinates relative to the top-left of it.
|
|
30
|
-
* @param relativeX Coordinate within the element, along the X-axis at which to click.
|
|
31
|
-
* @param relativeY Coordinate within the element, along the Y-axis at which to click.
|
|
32
|
-
* @param modifiers Modifier keys held while clicking
|
|
33
|
-
*/
|
|
34
|
-
rightClick(relativeX: number, relativeY: number, modifiers?: ModifierKeys): Promise<void>;
|
|
35
|
-
/** Focus the element. */
|
|
36
|
-
focus(): Promise<void>;
|
|
37
|
-
/** Get the computed value of the given CSS property for the element. */
|
|
38
|
-
getCssValue(property: string): Promise<string>;
|
|
39
|
-
/** Hovers the mouse over the element. */
|
|
40
|
-
hover(): Promise<void>;
|
|
41
|
-
/** Moves the mouse away from the element. */
|
|
42
|
-
mouseAway(): Promise<void>;
|
|
43
|
-
/**
|
|
44
|
-
* Sends the given string to the input as a series of key presses. Also fires input events
|
|
45
|
-
* and attempts to add the string to the Element's value.
|
|
46
|
-
*/
|
|
47
|
-
sendKeys(...keys: (string | TestKey)[]): Promise<void>;
|
|
48
|
-
/**
|
|
49
|
-
* Sends the given string to the input as a series of key presses. Also fires input events
|
|
50
|
-
* and attempts to add the string to the Element's value.
|
|
51
|
-
*/
|
|
52
|
-
sendKeys(modifiers: ModifierKeys, ...keys: (string | TestKey)[]): Promise<void>;
|
|
53
|
-
/** Gets the text from the element. */
|
|
54
|
-
text(options?: TextOptions): Promise<string>;
|
|
55
|
-
/** Gets the value for the given attribute from the element. */
|
|
56
|
-
getAttribute(name: string): Promise<string | null>;
|
|
57
|
-
/** Checks whether the element has the given class. */
|
|
58
|
-
hasClass(name: string): Promise<boolean>;
|
|
59
|
-
/** Gets the dimensions of the element. */
|
|
60
|
-
getDimensions(): Promise<ElementDimensions>;
|
|
61
|
-
/** Gets the value of a property of an element. */
|
|
62
|
-
getProperty(name: string): Promise<any>;
|
|
63
|
-
/** Checks whether this element matches the given selector. */
|
|
64
|
-
matchesSelector(selector: string): Promise<boolean>;
|
|
65
|
-
/** Checks whether the element is focused. */
|
|
66
|
-
isFocused(): Promise<boolean>;
|
|
67
|
-
/** Sets the value of a property of an input. */
|
|
68
|
-
setInputValue(value: string): Promise<void>;
|
|
69
|
-
/** Selects the options at the specified indexes inside of a native `select` element. */
|
|
70
|
-
selectOptions(...optionIndexes: number[]): Promise<void>;
|
|
71
|
-
/** Dispatches an event with a particular name. */
|
|
72
|
-
dispatchEvent(name: string, data?: Record<string, EventData>): Promise<void>;
|
|
73
|
-
/** Dispatches all the events that are part of a click event sequence. */
|
|
74
|
-
private dispatchClickEventSequence;
|
|
75
|
-
/** Performs a key-down action. */
|
|
76
|
-
keyDown(value: string): Promise<void>;
|
|
77
|
-
/** Performs a key-up action. */
|
|
78
|
-
keyUp(value: string): Promise<void>;
|
|
79
|
-
/** Writes info to the console outputs. */
|
|
80
|
-
private logAction;
|
|
81
|
-
}
|
package/esm/package.json
DELETED