@serenity-js/webdriverio 2.32.7 → 3.0.0-rc.10
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/CHANGELOG.md +340 -0
- package/lib/adapter/WebdriverIOFrameworkAdapter.js +1 -1
- package/lib/adapter/WebdriverIOFrameworkAdapter.js.map +1 -1
- package/lib/adapter/WebdriverIONotifier.d.ts +35 -1
- package/lib/adapter/WebdriverIONotifier.js +174 -13
- package/lib/adapter/WebdriverIONotifier.js.map +1 -1
- package/lib/index.d.ts +0 -3
- package/lib/index.js +0 -3
- package/lib/index.js.map +1 -1
- package/lib/screenplay/abilities/{BrowseTheWeb.d.ts → BrowseTheWebWithWebdriverIO.d.ts} +44 -27
- package/lib/screenplay/abilities/{BrowseTheWeb.js → BrowseTheWebWithWebdriverIO.js} +112 -32
- package/lib/screenplay/abilities/BrowseTheWebWithWebdriverIO.js.map +1 -0
- package/lib/screenplay/abilities/index.d.ts +1 -1
- package/lib/screenplay/abilities/index.js +1 -1
- package/lib/screenplay/abilities/index.js.map +1 -1
- package/lib/screenplay/index.d.ts +1 -2
- package/lib/screenplay/index.js +1 -2
- package/lib/screenplay/index.js.map +1 -1
- package/lib/screenplay/models/WebdriverIOCookie.d.ts +8 -0
- package/lib/screenplay/models/WebdriverIOCookie.js +39 -0
- package/lib/screenplay/models/WebdriverIOCookie.js.map +1 -0
- package/lib/screenplay/models/WebdriverIOModalDialog.d.ts +11 -0
- package/lib/screenplay/models/WebdriverIOModalDialog.js +40 -0
- package/lib/screenplay/models/WebdriverIOModalDialog.js.map +1 -0
- package/lib/screenplay/models/WebdriverIOPage.d.ts +24 -0
- package/lib/screenplay/models/WebdriverIOPage.js +98 -0
- package/lib/screenplay/models/WebdriverIOPage.js.map +1 -0
- package/lib/screenplay/models/WebdriverIOPageElement.d.ts +31 -0
- package/lib/screenplay/models/WebdriverIOPageElement.js +185 -0
- package/lib/screenplay/models/WebdriverIOPageElement.js.map +1 -0
- package/lib/screenplay/models/index.d.ts +4 -0
- package/lib/{stage → screenplay/models}/index.js +4 -1
- package/lib/screenplay/models/index.js.map +1 -0
- package/lib/screenplay/models/locators/WebdriverIOLocator.d.ts +9 -0
- package/lib/screenplay/models/locators/WebdriverIOLocator.js +22 -0
- package/lib/screenplay/models/locators/WebdriverIOLocator.js.map +1 -0
- package/lib/screenplay/models/locators/WebdriverIONativeElementRoot.d.ts +2 -0
- package/lib/screenplay/{interactions/EnterBuilder.js → models/locators/WebdriverIONativeElementRoot.js} +1 -1
- package/lib/screenplay/models/locators/WebdriverIONativeElementRoot.js.map +1 -0
- package/lib/screenplay/models/locators/index.d.ts +2 -0
- package/lib/{stage/crew/photographer → screenplay/models/locators}/index.js +2 -2
- package/lib/screenplay/models/locators/index.js.map +1 -0
- package/package.json +15 -25
- package/src/adapter/WebdriverIOFrameworkAdapter.ts +2 -0
- package/src/adapter/WebdriverIONotifier.ts +225 -23
- package/src/index.ts +0 -3
- package/src/screenplay/abilities/{BrowseTheWeb.ts → BrowseTheWebWithWebdriverIO.ts} +133 -35
- package/src/screenplay/abilities/index.ts +1 -1
- package/src/screenplay/index.ts +1 -2
- package/src/screenplay/models/WebdriverIOCookie.ts +44 -0
- package/src/screenplay/models/WebdriverIOModalDialog.ts +45 -0
- package/src/screenplay/models/WebdriverIOPage.ts +120 -0
- package/src/screenplay/models/WebdriverIOPageElement.ts +227 -0
- package/src/screenplay/models/index.ts +4 -0
- package/src/screenplay/models/locators/WebdriverIOLocator.ts +43 -0
- package/src/screenplay/models/locators/WebdriverIONativeElementRoot.ts +3 -0
- package/src/screenplay/models/locators/index.ts +2 -0
- package/lib/expectations/ElementExpectation.d.ts +0 -11
- package/lib/expectations/ElementExpectation.js +0 -27
- package/lib/expectations/ElementExpectation.js.map +0 -1
- package/lib/expectations/index.d.ts +0 -6
- package/lib/expectations/index.js +0 -19
- package/lib/expectations/index.js.map +0 -1
- package/lib/expectations/isActive.d.ts +0 -15
- package/lib/expectations/isActive.js +0 -21
- package/lib/expectations/isActive.js.map +0 -1
- package/lib/expectations/isClickable.d.ts +0 -20
- package/lib/expectations/isClickable.js +0 -26
- package/lib/expectations/isClickable.js.map +0 -1
- package/lib/expectations/isEnabled.d.ts +0 -14
- package/lib/expectations/isEnabled.js +0 -20
- package/lib/expectations/isEnabled.js.map +0 -1
- package/lib/expectations/isPresent.d.ts +0 -15
- package/lib/expectations/isPresent.js +0 -21
- package/lib/expectations/isPresent.js.map +0 -1
- package/lib/expectations/isSelected.d.ts +0 -14
- package/lib/expectations/isSelected.js +0 -20
- package/lib/expectations/isSelected.js.map +0 -1
- package/lib/expectations/isVisible.d.ts +0 -14
- package/lib/expectations/isVisible.js +0 -20
- package/lib/expectations/isVisible.js.map +0 -1
- package/lib/input/Key.d.ts +0 -73
- package/lib/input/Key.js +0 -84
- package/lib/input/Key.js.map +0 -1
- package/lib/input/index.d.ts +0 -1
- package/lib/input/index.js +0 -14
- package/lib/input/index.js.map +0 -1
- package/lib/screenplay/abilities/BrowseTheWeb.js.map +0 -1
- package/lib/screenplay/interactions/Clear.d.ts +0 -79
- package/lib/screenplay/interactions/Clear.js +0 -97
- package/lib/screenplay/interactions/Clear.js.map +0 -1
- package/lib/screenplay/interactions/Click.d.ts +0 -73
- package/lib/screenplay/interactions/Click.js +0 -84
- package/lib/screenplay/interactions/Click.js.map +0 -1
- package/lib/screenplay/interactions/DoubleClick.d.ts +0 -90
- package/lib/screenplay/interactions/DoubleClick.js +0 -101
- package/lib/screenplay/interactions/DoubleClick.js.map +0 -1
- package/lib/screenplay/interactions/Enter.d.ts +0 -73
- package/lib/screenplay/interactions/Enter.js +0 -87
- package/lib/screenplay/interactions/Enter.js.map +0 -1
- package/lib/screenplay/interactions/EnterBuilder.d.ts +0 -25
- package/lib/screenplay/interactions/EnterBuilder.js.map +0 -1
- package/lib/screenplay/interactions/ExecuteScript.d.ts +0 -206
- package/lib/screenplay/interactions/ExecuteScript.js +0 -311
- package/lib/screenplay/interactions/ExecuteScript.js.map +0 -1
- package/lib/screenplay/interactions/Hover.d.ts +0 -78
- package/lib/screenplay/interactions/Hover.js +0 -89
- package/lib/screenplay/interactions/Hover.js.map +0 -1
- package/lib/screenplay/interactions/Navigate.d.ts +0 -141
- package/lib/screenplay/interactions/Navigate.js +0 -197
- package/lib/screenplay/interactions/Navigate.js.map +0 -1
- package/lib/screenplay/interactions/Press.d.ts +0 -84
- package/lib/screenplay/interactions/Press.js +0 -152
- package/lib/screenplay/interactions/Press.js.map +0 -1
- package/lib/screenplay/interactions/PressBuilder.d.ts +0 -26
- package/lib/screenplay/interactions/PressBuilder.js +0 -3
- package/lib/screenplay/interactions/PressBuilder.js.map +0 -1
- package/lib/screenplay/interactions/RightClick.d.ts +0 -89
- package/lib/screenplay/interactions/RightClick.js +0 -100
- package/lib/screenplay/interactions/RightClick.js.map +0 -1
- package/lib/screenplay/interactions/Scroll.d.ts +0 -75
- package/lib/screenplay/interactions/Scroll.js +0 -86
- package/lib/screenplay/interactions/Scroll.js.map +0 -1
- package/lib/screenplay/interactions/Wait.d.ts +0 -143
- package/lib/screenplay/interactions/Wait.js +0 -247
- package/lib/screenplay/interactions/Wait.js.map +0 -1
- package/lib/screenplay/interactions/WaitBuilder.d.ts +0 -32
- package/lib/screenplay/interactions/WaitBuilder.js +0 -3
- package/lib/screenplay/interactions/WaitBuilder.js.map +0 -1
- package/lib/screenplay/interactions/WebElementInteraction.d.ts +0 -37
- package/lib/screenplay/interactions/WebElementInteraction.js +0 -52
- package/lib/screenplay/interactions/WebElementInteraction.js.map +0 -1
- package/lib/screenplay/interactions/index.d.ts +0 -13
- package/lib/screenplay/interactions/index.js +0 -26
- package/lib/screenplay/interactions/index.js.map +0 -1
- package/lib/screenplay/questions/Attribute.d.ts +0 -82
- package/lib/screenplay/questions/Attribute.js +0 -102
- package/lib/screenplay/questions/Attribute.js.map +0 -1
- package/lib/screenplay/questions/CSSClasses.d.ts +0 -92
- package/lib/screenplay/questions/CSSClasses.js +0 -112
- package/lib/screenplay/questions/CSSClasses.js.map +0 -1
- package/lib/screenplay/questions/LastScriptExecution.d.ts +0 -14
- package/lib/screenplay/questions/LastScriptExecution.js +0 -22
- package/lib/screenplay/questions/LastScriptExecution.js.map +0 -1
- package/lib/screenplay/questions/NestedTargetBuilder.d.ts +0 -27
- package/lib/screenplay/questions/NestedTargetBuilder.js +0 -3
- package/lib/screenplay/questions/NestedTargetBuilder.js.map +0 -1
- package/lib/screenplay/questions/TargetBuilder.d.ts +0 -25
- package/lib/screenplay/questions/TargetBuilder.js +0 -3
- package/lib/screenplay/questions/TargetBuilder.js.map +0 -1
- package/lib/screenplay/questions/Text.d.ts +0 -95
- package/lib/screenplay/questions/Text.js +0 -130
- package/lib/screenplay/questions/Text.js.map +0 -1
- package/lib/screenplay/questions/Value.d.ts +0 -63
- package/lib/screenplay/questions/Value.js +0 -78
- package/lib/screenplay/questions/Value.js.map +0 -1
- package/lib/screenplay/questions/Website.d.ts +0 -21
- package/lib/screenplay/questions/Website.js +0 -31
- package/lib/screenplay/questions/Website.js.map +0 -1
- package/lib/screenplay/questions/index.d.ts +0 -10
- package/lib/screenplay/questions/index.js +0 -23
- package/lib/screenplay/questions/index.js.map +0 -1
- package/lib/screenplay/questions/lists.d.ts +0 -86
- package/lib/screenplay/questions/lists.js +0 -137
- package/lib/screenplay/questions/lists.js.map +0 -1
- package/lib/screenplay/questions/locators.d.ts +0 -196
- package/lib/screenplay/questions/locators.js +0 -219
- package/lib/screenplay/questions/locators.js.map +0 -1
- package/lib/screenplay/questions/targets.d.ts +0 -254
- package/lib/screenplay/questions/targets.js +0 -334
- package/lib/screenplay/questions/targets.js.map +0 -1
- package/lib/stage/crew/index.d.ts +0 -1
- package/lib/stage/crew/index.js +0 -14
- package/lib/stage/crew/index.js.map +0 -1
- package/lib/stage/crew/photographer/Photographer.d.ts +0 -83
- package/lib/stage/crew/photographer/Photographer.js +0 -102
- package/lib/stage/crew/photographer/Photographer.js.map +0 -1
- package/lib/stage/crew/photographer/index.d.ts +0 -2
- package/lib/stage/crew/photographer/index.js.map +0 -1
- package/lib/stage/crew/photographer/strategies/PhotoTakingStrategy.d.ts +0 -28
- package/lib/stage/crew/photographer/strategies/PhotoTakingStrategy.js +0 -65
- package/lib/stage/crew/photographer/strategies/PhotoTakingStrategy.js.map +0 -1
- package/lib/stage/crew/photographer/strategies/TakePhotosBeforeAndAfterInteractions.d.ts +0 -18
- package/lib/stage/crew/photographer/strategies/TakePhotosBeforeAndAfterInteractions.js +0 -30
- package/lib/stage/crew/photographer/strategies/TakePhotosBeforeAndAfterInteractions.js.map +0 -1
- package/lib/stage/crew/photographer/strategies/TakePhotosOfFailures.d.ts +0 -17
- package/lib/stage/crew/photographer/strategies/TakePhotosOfFailures.js +0 -28
- package/lib/stage/crew/photographer/strategies/TakePhotosOfFailures.js.map +0 -1
- package/lib/stage/crew/photographer/strategies/TakePhotosOfInteractions.d.ts +0 -19
- package/lib/stage/crew/photographer/strategies/TakePhotosOfInteractions.js +0 -28
- package/lib/stage/crew/photographer/strategies/TakePhotosOfInteractions.js.map +0 -1
- package/lib/stage/crew/photographer/strategies/index.d.ts +0 -4
- package/lib/stage/crew/photographer/strategies/index.js +0 -17
- package/lib/stage/crew/photographer/strategies/index.js.map +0 -1
- package/lib/stage/index.d.ts +0 -1
- package/lib/stage/index.js.map +0 -1
- package/src/expectations/ElementExpectation.ts +0 -31
- package/src/expectations/index.ts +0 -6
- package/src/expectations/isActive.ts +0 -21
- package/src/expectations/isClickable.ts +0 -26
- package/src/expectations/isEnabled.ts +0 -19
- package/src/expectations/isPresent.ts +0 -20
- package/src/expectations/isSelected.ts +0 -19
- package/src/expectations/isVisible.ts +0 -19
- package/src/input/Key.ts +0 -83
- package/src/input/index.ts +0 -1
- package/src/screenplay/interactions/Clear.ts +0 -102
- package/src/screenplay/interactions/Click.ts +0 -85
- package/src/screenplay/interactions/DoubleClick.ts +0 -102
- package/src/screenplay/interactions/Enter.ts +0 -93
- package/src/screenplay/interactions/EnterBuilder.ts +0 -27
- package/src/screenplay/interactions/ExecuteScript.ts +0 -344
- package/src/screenplay/interactions/Hover.ts +0 -90
- package/src/screenplay/interactions/Navigate.ts +0 -208
- package/src/screenplay/interactions/Press.ts +0 -172
- package/src/screenplay/interactions/PressBuilder.ts +0 -28
- package/src/screenplay/interactions/RightClick.ts +0 -100
- package/src/screenplay/interactions/Scroll.ts +0 -87
- package/src/screenplay/interactions/Wait.ts +0 -267
- package/src/screenplay/interactions/WaitBuilder.ts +0 -34
- package/src/screenplay/interactions/WebElementInteraction.ts +0 -56
- package/src/screenplay/interactions/index.ts +0 -13
- package/src/screenplay/questions/Attribute.ts +0 -112
- package/src/screenplay/questions/CSSClasses.ts +0 -116
- package/src/screenplay/questions/LastScriptExecution.ts +0 -21
- package/src/screenplay/questions/NestedTargetBuilder.ts +0 -30
- package/src/screenplay/questions/TargetBuilder.ts +0 -27
- package/src/screenplay/questions/Text.ts +0 -140
- package/src/screenplay/questions/Value.ts +0 -82
- package/src/screenplay/questions/Website.ts +0 -34
- package/src/screenplay/questions/index.ts +0 -10
- package/src/screenplay/questions/lists.ts +0 -161
- package/src/screenplay/questions/locators.ts +0 -254
- package/src/screenplay/questions/targets.ts +0 -401
- package/src/stage/crew/index.ts +0 -1
- package/src/stage/crew/photographer/Photographer.ts +0 -108
- package/src/stage/crew/photographer/index.ts +0 -2
- package/src/stage/crew/photographer/strategies/PhotoTakingStrategy.ts +0 -103
- package/src/stage/crew/photographer/strategies/TakePhotosBeforeAndAfterInteractions.ts +0 -28
- package/src/stage/crew/photographer/strategies/TakePhotosOfFailures.ts +0 -26
- package/src/stage/crew/photographer/strategies/TakePhotosOfInteractions.ts +0 -26
- package/src/stage/crew/photographer/strategies/index.ts +0 -4
- package/src/stage/index.ts +0 -1
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { LogicError, Stage, StageCrewMember } from '@serenity-js/core';
|
|
2
|
-
import { DomainEvent, SceneFinished, SceneStarts, TestSuiteFinished, TestSuiteStarts } from '@serenity-js/core/lib/events';
|
|
2
|
+
import { AsyncOperationAttempted, AsyncOperationCompleted, DomainEvent, SceneFinished, SceneStarts, TestRunFinishes, TestSuiteFinished, TestSuiteStarts } from '@serenity-js/core/lib/events';
|
|
3
3
|
import {
|
|
4
4
|
CorrelationId,
|
|
5
|
+
Description,
|
|
5
6
|
ExecutionCompromised,
|
|
6
7
|
ExecutionFailedWithAssertionError,
|
|
7
8
|
ExecutionFailedWithError,
|
|
@@ -12,20 +13,35 @@ import {
|
|
|
12
13
|
ProblemIndication,
|
|
13
14
|
TestSuiteDetails,
|
|
14
15
|
} from '@serenity-js/core/lib/model';
|
|
15
|
-
import { Suite } from '@wdio/reporter/build/stats/suite';
|
|
16
|
-
import { Test } from '@wdio/reporter/build/stats/test';
|
|
16
|
+
import { Suite as suiteStats } from '@wdio/reporter/build/stats/suite';
|
|
17
|
+
import { Test as testStats } from '@wdio/reporter/build/stats/test';
|
|
18
|
+
import { RemoteCapability } from '@wdio/types/build/Capabilities';
|
|
19
|
+
import * as frameworks from '@wdio/types/build/Frameworks';
|
|
17
20
|
import type { EventEmitter } from 'events';
|
|
18
21
|
import { match } from 'tiny-types';
|
|
19
22
|
|
|
23
|
+
import { WebdriverIOConfig } from './WebdriverIOConfig';
|
|
24
|
+
|
|
20
25
|
/**
|
|
21
26
|
* @package
|
|
22
27
|
*/
|
|
23
28
|
export class WebdriverIONotifier implements StageCrewMember {
|
|
24
29
|
|
|
30
|
+
/**
|
|
31
|
+
* We don't have access to the "context" object produced by Mocha,
|
|
32
|
+
* and can't assume that other test runners have a similar concept.
|
|
33
|
+
* Since, at the time of writing, none of the WebdriverIO rely on this parameter
|
|
34
|
+
* using a dummy seems to be sufficient.
|
|
35
|
+
* @private
|
|
36
|
+
*/
|
|
37
|
+
private static dummmyContext = {};
|
|
38
|
+
|
|
25
39
|
private readonly events = new EventLog();
|
|
26
40
|
private readonly suites: TestSuiteDetails[] = [];
|
|
27
41
|
|
|
28
42
|
constructor(
|
|
43
|
+
private readonly config: WebdriverIOConfig,
|
|
44
|
+
private readonly capabilities: RemoteCapability,
|
|
29
45
|
private readonly reporter: EventEmitter,
|
|
30
46
|
private readonly successThreshold: Outcome | { Code: number },
|
|
31
47
|
private readonly cid: string,
|
|
@@ -46,28 +62,42 @@ export class WebdriverIONotifier implements StageCrewMember {
|
|
|
46
62
|
.when(TestSuiteFinished, WebdriverIONotifier.prototype.onTestSuiteFinished.bind(this))
|
|
47
63
|
.when(SceneStarts, WebdriverIONotifier.prototype.onSceneStarts.bind(this))
|
|
48
64
|
.when(SceneFinished, WebdriverIONotifier.prototype.onSceneFinished.bind(this))
|
|
65
|
+
.when(TestRunFinishes, WebdriverIONotifier.prototype.onTestRunFinishes.bind(this))
|
|
49
66
|
.else(() => void 0);
|
|
50
67
|
}
|
|
51
68
|
|
|
69
|
+
private onTestRunFinishes(): Promise<any> {
|
|
70
|
+
return this.invokeHooks('after', this.config.after, [this.failures, this.capabilities, this.specs]);
|
|
71
|
+
}
|
|
72
|
+
|
|
52
73
|
failureCount(): number {
|
|
53
74
|
return this.failures;
|
|
54
75
|
}
|
|
55
76
|
|
|
56
|
-
private onTestSuiteStarts(started: TestSuiteStarts) {
|
|
77
|
+
private onTestSuiteStarts(started: TestSuiteStarts): Promise<any> {
|
|
57
78
|
this.events.record(started.details.correlationId, started);
|
|
58
|
-
|
|
79
|
+
|
|
80
|
+
const suite = this.suiteStartEventFrom(started);
|
|
81
|
+
|
|
82
|
+
this.reporter.emit('suite:start', suite);
|
|
59
83
|
|
|
60
84
|
this.suites.push(started.details);
|
|
85
|
+
|
|
86
|
+
return this.invokeHooks('beforeSuite', this.config.beforeSuite, [suite as any]); // todo: correct types
|
|
61
87
|
}
|
|
62
88
|
|
|
63
|
-
private onTestSuiteFinished(finished: TestSuiteFinished) {
|
|
89
|
+
private onTestSuiteFinished(finished: TestSuiteFinished): Promise<any> {
|
|
64
90
|
this.suites.pop();
|
|
65
91
|
|
|
66
92
|
const started = this.events.getByCorrelationId<TestSuiteStarts>(finished.details.correlationId);
|
|
67
|
-
|
|
93
|
+
const suite = this.suiteEndEventFrom(started, finished);
|
|
94
|
+
|
|
95
|
+
this.reporter.emit('suite:end', suite);
|
|
96
|
+
|
|
97
|
+
return this.invokeHooks('afterSuite', this.config.afterSuite, [suite as any]); // todo: correct types
|
|
68
98
|
}
|
|
69
99
|
|
|
70
|
-
private suiteStartEventFrom(started: TestSuiteStarts): Suite {
|
|
100
|
+
private suiteStartEventFrom(started: TestSuiteStarts): suiteStats & frameworks.Suite {
|
|
71
101
|
return {
|
|
72
102
|
type: 'suite:start',
|
|
73
103
|
uid: started.details.correlationId.value,
|
|
@@ -85,7 +115,7 @@ export class WebdriverIONotifier implements StageCrewMember {
|
|
|
85
115
|
return this.suites.map(suite => suite.name.value).concat(name).join(' ');
|
|
86
116
|
}
|
|
87
117
|
|
|
88
|
-
private suiteEndEventFrom(started: TestSuiteStarts, finished: TestSuiteFinished): Suite {
|
|
118
|
+
private suiteEndEventFrom(started: TestSuiteStarts, finished: TestSuiteFinished): suiteStats & frameworks.Suite {
|
|
89
119
|
return {
|
|
90
120
|
...this.suiteStartEventFrom(started),
|
|
91
121
|
type: 'suite:end',
|
|
@@ -99,6 +129,8 @@ export class WebdriverIONotifier implements StageCrewMember {
|
|
|
99
129
|
this.events.record(started.sceneId, started);
|
|
100
130
|
|
|
101
131
|
this.reporter.emit(test.type, test);
|
|
132
|
+
|
|
133
|
+
return this.invokeHooks('beforeTest', this.config.beforeTest, [ this.testFrom(started), WebdriverIONotifier.dummmyContext ]);
|
|
102
134
|
}
|
|
103
135
|
|
|
104
136
|
private onSceneFinished(finished: SceneFinished) {
|
|
@@ -108,37 +140,59 @@ export class WebdriverIONotifier implements StageCrewMember {
|
|
|
108
140
|
}
|
|
109
141
|
|
|
110
142
|
const started = this.events.getByCorrelationId<SceneStarts>(finished.sceneId);
|
|
143
|
+
let testEnd: testStats;
|
|
111
144
|
|
|
112
145
|
if (this.willBeRetried(finished.outcome)) {
|
|
113
|
-
|
|
146
|
+
testEnd = this.testEndEventFrom(started, finished);
|
|
114
147
|
|
|
115
148
|
const type = 'test:retry';
|
|
116
149
|
|
|
117
150
|
this.reporter.emit(type, {
|
|
118
|
-
...
|
|
151
|
+
...testEnd,
|
|
119
152
|
type,
|
|
120
153
|
error: this.errorFrom(finished.outcome),
|
|
121
154
|
});
|
|
122
155
|
|
|
123
156
|
} else {
|
|
124
157
|
|
|
125
|
-
const
|
|
126
|
-
this.reporter.emit(
|
|
158
|
+
const testResultEvent = this.testResultEventFrom(started, finished);
|
|
159
|
+
this.reporter.emit(testResultEvent.type, testResultEvent);
|
|
127
160
|
|
|
128
|
-
|
|
161
|
+
testEnd = this.testEndEventFrom(started, finished);
|
|
129
162
|
this.reporter.emit(testEnd.type, testEnd);
|
|
130
163
|
}
|
|
164
|
+
|
|
165
|
+
return this.invokeHooks('afterTest', this.config.afterTest, [ this.testFrom(started), WebdriverIONotifier.dummmyContext, this.testResultFrom(started, finished) ]);
|
|
131
166
|
}
|
|
132
167
|
|
|
133
168
|
private willBeRetried(outcome: Outcome): outcome is ExecutionIgnored {
|
|
134
169
|
return outcome instanceof ExecutionIgnored;
|
|
135
170
|
}
|
|
136
171
|
|
|
137
|
-
private
|
|
138
|
-
|
|
172
|
+
private testShortTitleFrom(started: SceneStarts): string {
|
|
173
|
+
return started.details.name.value
|
|
139
174
|
.replace(new RegExp(`^.*?(${ this.parentSuiteName() })`), '')
|
|
140
175
|
.trim();
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
private testFrom(started: SceneStarts): frameworks.Test {
|
|
179
|
+
const
|
|
180
|
+
title = this.testShortTitleFrom(started);
|
|
141
181
|
|
|
182
|
+
return {
|
|
183
|
+
ctx: WebdriverIONotifier.dummmyContext,
|
|
184
|
+
file: started.details.location.path.value,
|
|
185
|
+
fullName: this.suiteNamesConcatenatedWith(title),
|
|
186
|
+
fullTitle: this.suiteNamesConcatenatedWith(title),
|
|
187
|
+
parent: this.parentSuiteName(),
|
|
188
|
+
pending: false,
|
|
189
|
+
title,
|
|
190
|
+
type: 'test' // I _think_ it's either 'test' or 'hook' - https://github.com/mochajs/mocha/blob/0ea732c1169c678ef116c3eb452cc94758fff150/lib/test.js#L31
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
private testStartEventFrom(started: SceneStarts): testStats {
|
|
195
|
+
const title = this.testShortTitleFrom(started);
|
|
142
196
|
return {
|
|
143
197
|
type: 'test:start',
|
|
144
198
|
title,
|
|
@@ -156,7 +210,95 @@ export class WebdriverIONotifier implements StageCrewMember {
|
|
|
156
210
|
return this.suites[this.suites.length - 1]?.name.value || '';
|
|
157
211
|
}
|
|
158
212
|
|
|
159
|
-
|
|
213
|
+
/**
|
|
214
|
+
* test status is 'passed' | 'pending' | 'skipped' | 'failed' | 'broken' | 'canceled'
|
|
215
|
+
* Since this is not documented, we're mimicking other WebdriverIO reporters, for example:
|
|
216
|
+
* https://github.com/webdriverio/webdriverio/blob/7415f3126e15a733b51721492e4995ceafae6046/packages/wdio-allure-reporter/src/constants.ts#L3-L9
|
|
217
|
+
*
|
|
218
|
+
* @param started
|
|
219
|
+
* @param finished
|
|
220
|
+
* @private
|
|
221
|
+
*/
|
|
222
|
+
private testResultFrom(started: SceneStarts, finished: SceneFinished): frameworks.TestResult {
|
|
223
|
+
const duration = finished.timestamp.diff(started.timestamp).inMilliseconds();
|
|
224
|
+
const defaultRetries = { attempts: 0, limit: 0 };
|
|
225
|
+
|
|
226
|
+
const passedOrFailed = (outcome: Outcome): boolean =>
|
|
227
|
+
this.whenSuccessful<boolean>(outcome, true, false);
|
|
228
|
+
|
|
229
|
+
return match<Outcome, frameworks.TestResult>(finished.outcome)
|
|
230
|
+
.when(ExecutionCompromised, (outcome: ExecutionCompromised) => {
|
|
231
|
+
const error = this.errorFrom(outcome);
|
|
232
|
+
return {
|
|
233
|
+
duration,
|
|
234
|
+
error,
|
|
235
|
+
exception: error.message,
|
|
236
|
+
passed: passedOrFailed(outcome),
|
|
237
|
+
status: 'broken',
|
|
238
|
+
retries: defaultRetries
|
|
239
|
+
}
|
|
240
|
+
})
|
|
241
|
+
.when(ExecutionFailedWithError, (outcome: ExecutionFailedWithError) => {
|
|
242
|
+
const error = this.errorFrom(outcome);
|
|
243
|
+
return {
|
|
244
|
+
duration,
|
|
245
|
+
error,
|
|
246
|
+
exception: error.message,
|
|
247
|
+
passed: passedOrFailed(outcome),
|
|
248
|
+
status: 'broken',
|
|
249
|
+
retries: defaultRetries
|
|
250
|
+
}
|
|
251
|
+
})
|
|
252
|
+
.when(ExecutionFailedWithAssertionError, (outcome: ExecutionFailedWithAssertionError) => {
|
|
253
|
+
const error = this.errorFrom(outcome);
|
|
254
|
+
return {
|
|
255
|
+
duration,
|
|
256
|
+
error,
|
|
257
|
+
exception: error.message,
|
|
258
|
+
passed: passedOrFailed(outcome),
|
|
259
|
+
status: 'failed',
|
|
260
|
+
retries: defaultRetries
|
|
261
|
+
}
|
|
262
|
+
})
|
|
263
|
+
.when(ImplementationPending, (outcome: ImplementationPending) => {
|
|
264
|
+
const error = this.errorFrom(outcome);
|
|
265
|
+
return {
|
|
266
|
+
duration,
|
|
267
|
+
error,
|
|
268
|
+
exception: error.message,
|
|
269
|
+
passed: passedOrFailed(outcome),
|
|
270
|
+
status: 'pending',
|
|
271
|
+
retries: defaultRetries
|
|
272
|
+
}
|
|
273
|
+
})
|
|
274
|
+
.when(ExecutionIgnored, (outcome: ExecutionIgnored) => {
|
|
275
|
+
const error = this.errorFrom(outcome);
|
|
276
|
+
return {
|
|
277
|
+
duration,
|
|
278
|
+
error,
|
|
279
|
+
exception: error.message,
|
|
280
|
+
passed: passedOrFailed(outcome),
|
|
281
|
+
status: 'canceled', // fixme: mark as canceled for now for the lack of a better alternative;
|
|
282
|
+
retries: defaultRetries // consider capturing info about retries from Mocha and putting it on the ExecutionIgnored event so we can pass it on
|
|
283
|
+
}
|
|
284
|
+
})
|
|
285
|
+
.when(ExecutionSkipped, (outcome: ExecutionSkipped) => ({
|
|
286
|
+
duration,
|
|
287
|
+
exception: '',
|
|
288
|
+
passed: passedOrFailed(outcome),
|
|
289
|
+
status: 'skipped',
|
|
290
|
+
retries: defaultRetries
|
|
291
|
+
}))
|
|
292
|
+
.else(() => ({
|
|
293
|
+
duration,
|
|
294
|
+
exception: '',
|
|
295
|
+
passed: true,
|
|
296
|
+
status: 'passed',
|
|
297
|
+
retries: defaultRetries
|
|
298
|
+
}));
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
private testEndEventFrom(started: SceneStarts, finished: SceneFinished): testStats {
|
|
160
302
|
const duration = finished.timestamp.diff(started.timestamp).inMilliseconds();
|
|
161
303
|
return {
|
|
162
304
|
...this.testStartEventFrom(started),
|
|
@@ -165,15 +307,19 @@ export class WebdriverIONotifier implements StageCrewMember {
|
|
|
165
307
|
};
|
|
166
308
|
}
|
|
167
309
|
|
|
168
|
-
private
|
|
310
|
+
private whenSuccessful<O>(outcome: Outcome, resultWhenSuccessful: O, resultWhenNotSuccessful: O): O {
|
|
311
|
+
return ! outcome.isWorseThan(this.successThreshold) && (outcome instanceof ProblemIndication)
|
|
312
|
+
? resultWhenSuccessful
|
|
313
|
+
: resultWhenNotSuccessful
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
private testResultEventFrom(started: SceneStarts, finished: SceneFinished): testStats {
|
|
169
317
|
const test = this.testEndEventFrom(started, finished)
|
|
170
318
|
|
|
171
|
-
const unlessSuccessful = (outcome: Outcome, type:
|
|
172
|
-
|
|
173
|
-
? 'test:pass'
|
|
174
|
-
: type;
|
|
319
|
+
const unlessSuccessful = (outcome: Outcome, type: testStats['type']) =>
|
|
320
|
+
this.whenSuccessful<testStats['type']>(outcome, 'test:pass', type);
|
|
175
321
|
|
|
176
|
-
return match<Outcome,
|
|
322
|
+
return match<Outcome, testStats>(finished.outcome)
|
|
177
323
|
.when(ExecutionCompromised, (outcome: ExecutionCompromised) => ({
|
|
178
324
|
...test,
|
|
179
325
|
type: unlessSuccessful(outcome, 'test:fail'),
|
|
@@ -231,6 +377,62 @@ export class WebdriverIONotifier implements StageCrewMember {
|
|
|
231
377
|
actual: error.actual
|
|
232
378
|
}
|
|
233
379
|
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* @see https://github.com/webdriverio/webdriverio/blob/main/packages/wdio-utils/src/shim.ts
|
|
383
|
+
* @param hookName
|
|
384
|
+
* @param hookFunctions
|
|
385
|
+
* @param args
|
|
386
|
+
* @private
|
|
387
|
+
*/
|
|
388
|
+
private invokeHooks<Result, InnerArguments extends any[]>(
|
|
389
|
+
hookName: string,
|
|
390
|
+
hookFunctions: ((...parameters: InnerArguments) => Promise<Result> | Result) | Array<((...parameters: InnerArguments) => Result)>,
|
|
391
|
+
args: InnerArguments
|
|
392
|
+
): Promise<Array<Result | Error>> {
|
|
393
|
+
|
|
394
|
+
const hooks = ! Array.isArray(hookFunctions)
|
|
395
|
+
? [ hookFunctions ]
|
|
396
|
+
: hookFunctions;
|
|
397
|
+
|
|
398
|
+
const asyncOperationId = CorrelationId.create();
|
|
399
|
+
|
|
400
|
+
this.stage.announce(new AsyncOperationAttempted(
|
|
401
|
+
new Description(`[WebdriverIONotifier#invokeHooks] Invoking ${ hookName } hook`),
|
|
402
|
+
asyncOperationId,
|
|
403
|
+
));
|
|
404
|
+
|
|
405
|
+
return Promise.all(hooks.map((hook) => new Promise<Result | Error>((resolve) => {
|
|
406
|
+
let result
|
|
407
|
+
|
|
408
|
+
try {
|
|
409
|
+
result = hook(...args);
|
|
410
|
+
} catch (error) {
|
|
411
|
+
return resolve(error);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* if a promise is returned make sure we don't have a catch handler
|
|
416
|
+
* so in case of a rejection it won't cause the hook to fail
|
|
417
|
+
*/
|
|
418
|
+
if (result && typeof result.then === 'function') {
|
|
419
|
+
return result.then(resolve, (error: Error) => {
|
|
420
|
+
resolve(error);
|
|
421
|
+
})
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
resolve(result);
|
|
425
|
+
}))).
|
|
426
|
+
then(results => {
|
|
427
|
+
|
|
428
|
+
this.stage.announce(new AsyncOperationCompleted(
|
|
429
|
+
new Description(`[WebdriverIONotifier#invokeHooks] Invoking ${ hookName } hook completed`),
|
|
430
|
+
asyncOperationId,
|
|
431
|
+
));
|
|
432
|
+
|
|
433
|
+
return results;
|
|
434
|
+
});
|
|
435
|
+
}
|
|
234
436
|
}
|
|
235
437
|
|
|
236
438
|
class EventLog {
|
package/src/index.ts
CHANGED
|
@@ -12,7 +12,4 @@ const adapterFactory = new WebdriverIOFrameworkAdapterFactory(
|
|
|
12
12
|
export default adapterFactory;
|
|
13
13
|
|
|
14
14
|
export { WebdriverIOConfig } from './adapter';
|
|
15
|
-
export * from './expectations';
|
|
16
|
-
export * from './input';
|
|
17
15
|
export * from './screenplay';
|
|
18
|
-
export * from './stage';
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
1
|
+
import { Duration, LogicError } from '@serenity-js/core';
|
|
2
|
+
import { BrowserCapabilities, BrowseTheWeb, ByCss, ByCssContainingText, ById, ByTagName, ByXPath, Cookie, CookieData, Key, ModalDialog, Page, PageElement } from '@serenity-js/web';
|
|
3
|
+
import type * as wdio from 'webdriverio';
|
|
3
4
|
|
|
4
|
-
import {
|
|
5
|
+
import { WebdriverIOCookie, WebdriverIOModalDialog, WebdriverIOPage, WebdriverIOPageElement } from '../models';
|
|
6
|
+
import { WebdriverIOLocator, WebdriverIONativeElementRoot } from '../models/locators';
|
|
5
7
|
|
|
6
8
|
/**
|
|
7
9
|
* @desc
|
|
@@ -12,8 +14,6 @@ import { Key } from '../../input';
|
|
|
12
14
|
* This means that its interface can change without affecting the major version of Serenity/JS itself.
|
|
13
15
|
* In particular, please don't rely on the `browser` field to remain `public` in future releases.
|
|
14
16
|
*
|
|
15
|
-
* @experimental
|
|
16
|
-
*
|
|
17
17
|
* @example <caption>Using the WebdriverIO browser</caption>
|
|
18
18
|
* import { Actor } from '@serenity-js/core';
|
|
19
19
|
* import { BrowseTheWeb, by, Navigate, Target } from '@serenity-js/webdriverio'
|
|
@@ -38,7 +38,15 @@ import { Key } from '../../input';
|
|
|
38
38
|
* @implements {@serenity-js/core/lib/screenplay~Ability}
|
|
39
39
|
* @see {@link @serenity-js/core/lib/screenplay/actor~Actor}
|
|
40
40
|
*/
|
|
41
|
-
export class BrowseTheWeb
|
|
41
|
+
export class BrowseTheWebWithWebdriverIO extends BrowseTheWeb<wdio.Element<'async'>, WebdriverIONativeElementRoot> {
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* @param {@wdio/types~Browser} browserInstance
|
|
45
|
+
* @returns {BrowseTheWebWithWebdriverIO}
|
|
46
|
+
*/
|
|
47
|
+
static using(browserInstance: wdio.Browser<'async'>): BrowseTheWebWithWebdriverIO {
|
|
48
|
+
return new BrowseTheWebWithWebdriverIO(browserInstance);
|
|
49
|
+
}
|
|
42
50
|
|
|
43
51
|
/**
|
|
44
52
|
* @private
|
|
@@ -46,42 +54,114 @@ export class BrowseTheWeb implements Ability {
|
|
|
46
54
|
private lastScriptExecutionSummary: LastScriptExecutionSummary;
|
|
47
55
|
|
|
48
56
|
/**
|
|
49
|
-
* @param {@wdio/types~Browser}
|
|
50
|
-
* @returns {BrowseTheWeb}
|
|
57
|
+
* @param {@wdio/types~Browser} browser
|
|
51
58
|
*/
|
|
52
|
-
|
|
53
|
-
|
|
59
|
+
constructor(protected readonly browser: wdio.Browser<'async'>) {
|
|
60
|
+
super(new Map()
|
|
61
|
+
.set(ByCss, (selector: ByCss) => WebdriverIOLocator.createRootLocator(this.browser, selector, selector.value))
|
|
62
|
+
.set(ByCssContainingText, (selector: ByCssContainingText) => WebdriverIOLocator.createRootLocator(this.browser, selector, `${ selector.value }*=${ selector.text }`))
|
|
63
|
+
.set(ById, (selector: ById) => WebdriverIOLocator.createRootLocator(this.browser, selector, `#${ selector.value }`))
|
|
64
|
+
.set(ByTagName, (selector: ByTagName) => WebdriverIOLocator.createRootLocator(this.browser, selector, `<${ selector.value } />`))
|
|
65
|
+
.set(ByXPath, (selector: ByXPath) => WebdriverIOLocator.createRootLocator(this.browser, selector, selector.value))
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
if (! this.browser.$ || ! this.browser.$$) {
|
|
69
|
+
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?`)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
browserCapabilities(): Promise<BrowserCapabilities> {
|
|
74
|
+
return Promise.resolve(this.browser.capabilities as BrowserCapabilities);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async cookie(name: string): Promise<Cookie> {
|
|
78
|
+
return new WebdriverIOCookie(this.browser, name);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async setCookie(cookieData: CookieData): Promise<void> {
|
|
82
|
+
return this.browser.setCookies({
|
|
83
|
+
name: cookieData.name,
|
|
84
|
+
value: cookieData.value,
|
|
85
|
+
path: cookieData.path,
|
|
86
|
+
domain: cookieData.domain,
|
|
87
|
+
secure: cookieData.secure,
|
|
88
|
+
httpOnly: cookieData.httpOnly,
|
|
89
|
+
expiry: cookieData.expiry
|
|
90
|
+
? cookieData.expiry.toSeconds()
|
|
91
|
+
: undefined,
|
|
92
|
+
sameSite: cookieData.sameSite,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
deleteAllCookies(): Promise<void> {
|
|
97
|
+
return this.browser.deleteCookies() as Promise<void>;
|
|
54
98
|
}
|
|
55
99
|
|
|
56
100
|
/**
|
|
57
101
|
* @desc
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
* such as {@link Navigate}.
|
|
102
|
+
* Navigate to a given destination, specified as an absolute URL
|
|
103
|
+
* or a path relative to WebdriverIO `baseUrl`.
|
|
61
104
|
*
|
|
62
|
-
* @param {
|
|
63
|
-
* @
|
|
105
|
+
* @param {string} destination
|
|
106
|
+
* @returns {Promise<void>}
|
|
64
107
|
*/
|
|
65
|
-
|
|
66
|
-
return
|
|
108
|
+
navigateTo(destination: string): Promise<void> {
|
|
109
|
+
return this.browser.url(destination) as any; // todo: check if this returns a string or is mistyped
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
navigateBack(): Promise<void> {
|
|
113
|
+
return this.browser.back();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
navigateForward(): Promise<void> {
|
|
117
|
+
return this.browser.forward();
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
reloadPage(): Promise<void> {
|
|
121
|
+
return this.browser.refresh();
|
|
67
122
|
}
|
|
68
123
|
|
|
69
124
|
/**
|
|
70
|
-
* @
|
|
125
|
+
* @desc
|
|
126
|
+
* Returns a {@link Page} representing the currently active top-level browsing context.
|
|
127
|
+
*
|
|
128
|
+
* @returns {Promise<Page>}
|
|
71
129
|
*/
|
|
72
|
-
|
|
130
|
+
async currentPage(): Promise<Page> {
|
|
131
|
+
|
|
132
|
+
const windowHandle = await this.browser.getWindowHandle();
|
|
133
|
+
|
|
134
|
+
return new WebdriverIOPage(this.browser, windowHandle);
|
|
73
135
|
}
|
|
74
136
|
|
|
75
137
|
/**
|
|
76
138
|
* @desc
|
|
77
|
-
*
|
|
78
|
-
*
|
|
139
|
+
* Returns an array of {@link Page} objects representing all the available
|
|
140
|
+
* top-level browsing context, e.g. all the open browser tabs.
|
|
79
141
|
*
|
|
80
|
-
* @
|
|
81
|
-
* @returns {Promise<void>}
|
|
142
|
+
* @returns {Promise<Array<Page>>}
|
|
82
143
|
*/
|
|
83
|
-
|
|
84
|
-
|
|
144
|
+
async allPages(): Promise<Array<Page>> {
|
|
145
|
+
const windowHandles = await this.browser.getWindowHandles();
|
|
146
|
+
|
|
147
|
+
return windowHandles.map(windowHandle => new WebdriverIOPage(this.browser, windowHandle));
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
async modalDialog(): Promise<ModalDialog> {
|
|
151
|
+
return new WebdriverIOModalDialog(this.browser);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// todo: remove
|
|
155
|
+
switchToFrame(targetOrIndex: PageElement | number | string): Promise<void> {
|
|
156
|
+
throw new Error('Not implemented, yet');
|
|
157
|
+
}
|
|
158
|
+
// todo: remove
|
|
159
|
+
switchToParentFrame(): Promise<void> {
|
|
160
|
+
throw new Error('Not implemented, yet');
|
|
161
|
+
}
|
|
162
|
+
// todo: remove
|
|
163
|
+
switchToDefaultContent(): Promise<void> {
|
|
164
|
+
throw new Error('Not implemented, yet');
|
|
85
165
|
}
|
|
86
166
|
|
|
87
167
|
/**
|
|
@@ -101,7 +181,7 @@ export class BrowseTheWeb implements Ability {
|
|
|
101
181
|
return key;
|
|
102
182
|
}
|
|
103
183
|
|
|
104
|
-
if (browser.isDevTools) {
|
|
184
|
+
if (this.browser.isDevTools) {
|
|
105
185
|
return key.devtoolsName;
|
|
106
186
|
}
|
|
107
187
|
|
|
@@ -162,12 +242,13 @@ export class BrowseTheWeb implements Ability {
|
|
|
162
242
|
*
|
|
163
243
|
* @see {@link BrowseTheWeb#getLastScriptExecutionResult}
|
|
164
244
|
*/
|
|
165
|
-
executeScript<Result, InnerArguments extends any[]>(
|
|
245
|
+
async executeScript<Result, InnerArguments extends any[]>(
|
|
166
246
|
script: string | ((...parameters: InnerArguments) => Result),
|
|
167
247
|
...args: InnerArguments
|
|
168
248
|
): Promise<Result> {
|
|
249
|
+
const nativeArguments = await Promise.all(args.map(arg => arg instanceof WebdriverIOPageElement ? arg.nativeElement() : arg)) as InnerArguments;
|
|
169
250
|
|
|
170
|
-
return this.browser.execute(script, ...
|
|
251
|
+
return this.browser.execute(script, ...nativeArguments)
|
|
171
252
|
.then(result => {
|
|
172
253
|
this.lastScriptExecutionSummary = new LastScriptExecutionSummary(
|
|
173
254
|
result,
|
|
@@ -188,7 +269,7 @@ export class BrowseTheWeb implements Ability {
|
|
|
188
269
|
* Arrays and objects may also be used as script arguments as long as each item adheres
|
|
189
270
|
* to the types previously mentioned.
|
|
190
271
|
*
|
|
191
|
-
* Unlike executing synchronous JavaScript with {@link
|
|
272
|
+
* Unlike executing synchronous JavaScript with {@link BrowseTheWebWithWebdriverIO#executeScript},
|
|
192
273
|
* scripts executed with this function must explicitly signal they are finished by invoking the provided callback.
|
|
193
274
|
*
|
|
194
275
|
* This callback will always be injected into the executed function as the last argument,
|
|
@@ -227,11 +308,13 @@ export class BrowseTheWeb implements Ability {
|
|
|
227
308
|
*
|
|
228
309
|
* @see {@link BrowseTheWeb#getLastScriptExecutionResult}
|
|
229
310
|
*/
|
|
230
|
-
executeAsyncScript<Result, Parameters extends any[]>(
|
|
311
|
+
async executeAsyncScript<Result, Parameters extends any[]>(
|
|
231
312
|
script: string | ((...args: [...parameters: Parameters, callback: (result: Result) => void]) => void),
|
|
232
313
|
...args: Parameters
|
|
233
314
|
): Promise<Result> {
|
|
234
|
-
|
|
315
|
+
const nativeArguments = await Promise.all(args.map(arg => arg instanceof WebdriverIOPageElement ? arg.nativeElement() : arg)) as Parameters;
|
|
316
|
+
|
|
317
|
+
return this.browser.executeAsync<Result, Parameters>(script, ...nativeArguments)
|
|
235
318
|
.then(result => {
|
|
236
319
|
this.lastScriptExecutionSummary = new LastScriptExecutionSummary<Result>(
|
|
237
320
|
result,
|
|
@@ -242,17 +325,32 @@ export class BrowseTheWeb implements Ability {
|
|
|
242
325
|
|
|
243
326
|
/**
|
|
244
327
|
* @desc
|
|
245
|
-
* Returns the last result of calling {@link
|
|
246
|
-
* or {@link
|
|
328
|
+
* Returns the last result of calling {@link BrowseTheWebWithWebdriverIO#executeAsyncScript}
|
|
329
|
+
* or {@link BrowseTheWebWithWebdriverIO#executeScript}
|
|
247
330
|
*
|
|
248
331
|
* @returns {any}
|
|
249
332
|
*/
|
|
250
|
-
|
|
333
|
+
lastScriptExecutionResult<Result = any>(): Result {
|
|
251
334
|
if (! this.lastScriptExecutionSummary) {
|
|
252
335
|
throw new LogicError(`Make sure to execute a script before checking on the result`);
|
|
253
336
|
}
|
|
254
337
|
|
|
255
|
-
|
|
338
|
+
// Selenium returns `null` when the script it executed returns `undefined`
|
|
339
|
+
// so we're mapping the result back.
|
|
340
|
+
return this.lastScriptExecutionSummary.result !== null
|
|
341
|
+
? this.lastScriptExecutionSummary.result as Result
|
|
342
|
+
: undefined;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
waitFor(duration: Duration): Promise<void> {
|
|
346
|
+
return this.browser.pause(duration.inMilliseconds()) as Promise<void>;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
waitUntil(condition: () => boolean | Promise<boolean>, timeout: Duration): Promise<void> {
|
|
350
|
+
return this.browser.waitUntil(condition, {
|
|
351
|
+
timeout: timeout.inMilliseconds(),
|
|
352
|
+
timeoutMsg: `Wait timed out after ${ timeout }`,
|
|
353
|
+
}) as Promise<void>;
|
|
256
354
|
}
|
|
257
355
|
}
|
|
258
356
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export * from './
|
|
1
|
+
export * from './BrowseTheWebWithWebdriverIO';
|
package/src/screenplay/index.ts
CHANGED