@serenity-js/webdriverio 3.0.0-rc.8 → 3.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/CHANGELOG.md +245 -119
- package/README.md +66 -45
- package/lib/adapter/TestRunnerLoader.d.ts +3 -4
- package/lib/adapter/TestRunnerLoader.d.ts.map +1 -0
- package/lib/adapter/TestRunnerLoader.js +1 -4
- package/lib/adapter/TestRunnerLoader.js.map +1 -1
- package/lib/adapter/WebdriverIOConfig.d.ts +115 -109
- package/lib/adapter/WebdriverIOConfig.d.ts.map +1 -0
- package/lib/adapter/WebdriverIOFrameworkAdapter.d.ts +1 -3
- package/lib/adapter/WebdriverIOFrameworkAdapter.d.ts.map +1 -0
- package/lib/adapter/WebdriverIOFrameworkAdapter.js +14 -8
- package/lib/adapter/WebdriverIOFrameworkAdapter.js.map +1 -1
- package/lib/adapter/WebdriverIOFrameworkAdapterFactory.d.ts +2 -1
- package/lib/adapter/WebdriverIOFrameworkAdapterFactory.d.ts.map +1 -0
- package/lib/adapter/WebdriverIOFrameworkAdapterFactory.js +1 -1
- package/lib/adapter/WebdriverIONotifier.d.ts +1 -0
- package/lib/adapter/WebdriverIONotifier.d.ts.map +1 -0
- package/lib/adapter/WebdriverIONotifier.js +5 -5
- package/lib/adapter/WebdriverIONotifier.js.map +1 -1
- package/lib/adapter/index.d.ts +1 -1
- package/lib/adapter/index.d.ts.map +1 -0
- package/lib/adapter/index.js +5 -2
- package/lib/adapter/index.js.map +1 -1
- package/lib/adapter/reporter/BrowserCapabilitiesReporter.d.ts +1 -0
- package/lib/adapter/reporter/BrowserCapabilitiesReporter.d.ts.map +1 -0
- package/lib/adapter/reporter/BrowserCapabilitiesReporter.js +4 -1
- package/lib/adapter/reporter/BrowserCapabilitiesReporter.js.map +1 -1
- package/lib/adapter/reporter/InitialisesReporters.d.ts +1 -0
- package/lib/adapter/reporter/InitialisesReporters.d.ts.map +1 -0
- package/lib/adapter/reporter/OutputStreamBuffer.d.ts +2 -1
- package/lib/adapter/reporter/OutputStreamBuffer.d.ts.map +1 -0
- package/lib/adapter/reporter/OutputStreamBufferPrinter.d.ts +2 -1
- package/lib/adapter/reporter/OutputStreamBufferPrinter.d.ts.map +1 -0
- package/lib/adapter/reporter/OutputStreamBufferPrinter.js.map +1 -1
- package/lib/adapter/reporter/ProvidesWriteStream.d.ts +2 -1
- package/lib/adapter/reporter/ProvidesWriteStream.d.ts.map +1 -0
- package/lib/adapter/reporter/TagPrinter.d.ts +1 -0
- package/lib/adapter/reporter/TagPrinter.d.ts.map +1 -0
- package/lib/adapter/reporter/index.d.ts +1 -0
- package/lib/adapter/reporter/index.d.ts.map +1 -0
- package/lib/adapter/reporter/index.js +5 -1
- package/lib/adapter/reporter/index.js.map +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +5 -1
- package/lib/index.js.map +1 -1
- package/lib/screenplay/abilities/BrowseTheWebWithWebdriverIO.d.ts +28 -197
- package/lib/screenplay/abilities/BrowseTheWebWithWebdriverIO.d.ts.map +1 -0
- package/lib/screenplay/abilities/BrowseTheWebWithWebdriverIO.js +29 -296
- package/lib/screenplay/abilities/BrowseTheWebWithWebdriverIO.js.map +1 -1
- package/lib/screenplay/abilities/index.d.ts +1 -0
- package/lib/screenplay/abilities/index.d.ts.map +1 -0
- package/lib/screenplay/abilities/index.js +5 -1
- package/lib/screenplay/abilities/index.js.map +1 -1
- package/lib/screenplay/index.d.ts +1 -0
- package/lib/screenplay/index.d.ts.map +1 -0
- package/lib/screenplay/index.js +5 -1
- package/lib/screenplay/index.js.map +1 -1
- package/lib/screenplay/models/WebdriverIOBrowsingSession.d.ts +24 -0
- package/lib/screenplay/models/WebdriverIOBrowsingSession.d.ts.map +1 -0
- package/lib/screenplay/models/WebdriverIOBrowsingSession.js +125 -0
- package/lib/screenplay/models/WebdriverIOBrowsingSession.js.map +1 -0
- package/lib/screenplay/models/WebdriverIOCookie.d.ts +6 -0
- package/lib/screenplay/models/WebdriverIOCookie.d.ts.map +1 -0
- package/lib/screenplay/models/WebdriverIOCookie.js +7 -2
- package/lib/screenplay/models/WebdriverIOCookie.js.map +1 -1
- package/lib/screenplay/models/WebdriverIOErrorHandler.d.ts +9 -0
- package/lib/screenplay/models/WebdriverIOErrorHandler.d.ts.map +1 -0
- package/lib/screenplay/models/WebdriverIOErrorHandler.js +23 -0
- package/lib/screenplay/models/WebdriverIOErrorHandler.js.map +1 -0
- package/lib/screenplay/models/WebdriverIOModalDialogHandler.d.ts +29 -0
- package/lib/screenplay/models/WebdriverIOModalDialogHandler.d.ts.map +1 -0
- package/lib/screenplay/models/WebdriverIOModalDialogHandler.js +77 -0
- package/lib/screenplay/models/WebdriverIOModalDialogHandler.js.map +1 -0
- package/lib/screenplay/models/WebdriverIOPage.d.ts +29 -5
- package/lib/screenplay/models/WebdriverIOPage.d.ts.map +1 -0
- package/lib/screenplay/models/WebdriverIOPage.js +166 -54
- package/lib/screenplay/models/WebdriverIOPage.js.map +1 -1
- package/lib/screenplay/models/WebdriverIOPageElement.d.ts +10 -10
- package/lib/screenplay/models/WebdriverIOPageElement.d.ts.map +1 -0
- package/lib/screenplay/models/WebdriverIOPageElement.js +164 -46
- package/lib/screenplay/models/WebdriverIOPageElement.js.map +1 -1
- package/lib/screenplay/models/WebdriverIOPuppeteerModalDialogHandler.d.ts +32 -0
- package/lib/screenplay/models/WebdriverIOPuppeteerModalDialogHandler.d.ts.map +1 -0
- package/lib/screenplay/models/WebdriverIOPuppeteerModalDialogHandler.js +82 -0
- package/lib/screenplay/models/WebdriverIOPuppeteerModalDialogHandler.js.map +1 -0
- package/lib/screenplay/models/WebdriverProtocolErrorCode.d.ts +39 -0
- package/lib/screenplay/models/WebdriverProtocolErrorCode.d.ts.map +1 -0
- package/lib/screenplay/models/WebdriverProtocolErrorCode.js +43 -0
- package/lib/screenplay/models/WebdriverProtocolErrorCode.js.map +1 -0
- package/lib/screenplay/models/index.d.ts +2 -1
- package/lib/screenplay/models/index.d.ts.map +1 -0
- package/lib/screenplay/models/index.js +6 -2
- package/lib/screenplay/models/index.js.map +1 -1
- package/lib/screenplay/models/locators/WebdriverIOLocator.d.ts +18 -5
- package/lib/screenplay/models/locators/WebdriverIOLocator.d.ts.map +1 -0
- package/lib/screenplay/models/locators/WebdriverIOLocator.js +84 -5
- package/lib/screenplay/models/locators/WebdriverIOLocator.js.map +1 -1
- package/lib/screenplay/models/locators/WebdriverIORootLocator.d.ts +17 -0
- package/lib/screenplay/models/locators/WebdriverIORootLocator.d.ts.map +1 -0
- package/lib/screenplay/models/locators/WebdriverIORootLocator.js +32 -0
- package/lib/screenplay/models/locators/WebdriverIORootLocator.js.map +1 -0
- package/lib/screenplay/models/locators/index.d.ts +2 -1
- package/lib/screenplay/models/locators/index.d.ts.map +1 -0
- package/lib/screenplay/models/locators/index.js +6 -2
- package/lib/screenplay/models/locators/index.js.map +1 -1
- package/package.json +31 -32
- package/src/adapter/TestRunnerLoader.ts +3 -5
- package/src/adapter/WebdriverIOConfig.ts +114 -109
- package/src/adapter/WebdriverIOFrameworkAdapter.ts +20 -12
- package/src/adapter/WebdriverIOFrameworkAdapterFactory.ts +1 -1
- package/src/adapter/WebdriverIONotifier.ts +8 -6
- package/src/adapter/index.ts +0 -1
- package/src/adapter/reporter/OutputStreamBuffer.ts +1 -1
- package/src/adapter/reporter/OutputStreamBufferPrinter.ts +1 -1
- package/src/adapter/reporter/ProvidesWriteStream.ts +1 -1
- package/src/screenplay/abilities/BrowseTheWebWithWebdriverIO.ts +29 -339
- package/src/screenplay/models/WebdriverIOBrowsingSession.ts +171 -0
- package/src/screenplay/models/WebdriverIOCookie.ts +7 -2
- package/src/screenplay/models/WebdriverIOErrorHandler.ts +25 -0
- package/src/screenplay/models/WebdriverIOModalDialogHandler.ts +100 -0
- package/src/screenplay/models/WebdriverIOPage.ts +222 -63
- package/src/screenplay/models/WebdriverIOPageElement.ts +181 -62
- package/src/screenplay/models/WebdriverIOPuppeteerModalDialogHandler.ts +97 -0
- package/src/screenplay/models/WebdriverProtocolErrorCode.ts +38 -0
- package/src/screenplay/models/index.ts +1 -1
- package/src/screenplay/models/locators/WebdriverIOLocator.ts +122 -24
- package/src/screenplay/models/locators/WebdriverIORootLocator.ts +33 -0
- package/src/screenplay/models/locators/index.ts +1 -1
- package/tsconfig.build.json +17 -0
- package/lib/screenplay/models/WebdriverIOModalDialog.d.ts +0 -11
- package/lib/screenplay/models/WebdriverIOModalDialog.js +0 -40
- package/lib/screenplay/models/WebdriverIOModalDialog.js.map +0 -1
- package/lib/screenplay/models/locators/WebdriverIONativeElementRoot.d.ts +0 -2
- package/lib/screenplay/models/locators/WebdriverIONativeElementRoot.js +0 -3
- package/lib/screenplay/models/locators/WebdriverIONativeElementRoot.js.map +0 -1
- package/src/screenplay/models/WebdriverIOModalDialog.ts +0 -45
- package/src/screenplay/models/locators/WebdriverIONativeElementRoot.ts +0 -3
- package/tsconfig.eslint.json +0 -10
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import { ArtifactArchiver, Serenity } from '@serenity-js/core';
|
|
2
|
-
import {
|
|
1
|
+
import { AnsiDiffFormatter, ArtifactArchiver, Cast, Serenity, TakeNotes } from '@serenity-js/core';
|
|
2
|
+
import { TestRunnerAdapter } from '@serenity-js/core/lib/adapter';
|
|
3
|
+
import { ModuleLoader, Path } from '@serenity-js/core/lib/io';
|
|
3
4
|
import type { Capabilities } from '@wdio/types';
|
|
4
5
|
import type { EventEmitter } from 'events';
|
|
5
|
-
import {
|
|
6
|
+
import { isRecord } from 'tiny-types/lib/objects';
|
|
6
7
|
|
|
8
|
+
import { BrowseTheWebWithWebdriverIO } from '../screenplay';
|
|
7
9
|
import { BrowserCapabilitiesReporter, InitialisesReporters, OutputStreamBuffer, ProvidesWriteStream } from './reporter';
|
|
8
10
|
import { OutputStreamBufferPrinter } from './reporter/OutputStreamBufferPrinter';
|
|
9
11
|
import { TestRunnerLoader } from './TestRunnerLoader';
|
|
@@ -11,9 +13,6 @@ import { WebdriverIOConfig } from './WebdriverIOConfig';
|
|
|
11
13
|
import { WebdriverIONotifier } from './WebdriverIONotifier';
|
|
12
14
|
import deepmerge = require('deepmerge');
|
|
13
15
|
|
|
14
|
-
/**
|
|
15
|
-
* @package
|
|
16
|
-
*/
|
|
17
16
|
export class WebdriverIOFrameworkAdapter {
|
|
18
17
|
|
|
19
18
|
private adapter: TestRunnerAdapter;
|
|
@@ -30,9 +29,15 @@ export class WebdriverIOFrameworkAdapter {
|
|
|
30
29
|
reporter: EventEmitter & ProvidesWriteStream & InitialisesReporters
|
|
31
30
|
) {
|
|
32
31
|
const config = deepmerge<WebdriverIOConfig>(this.defaultConfig(), webdriverIOConfig, {
|
|
33
|
-
isMergeableObject:
|
|
32
|
+
isMergeableObject: isRecord,
|
|
34
33
|
});
|
|
35
34
|
|
|
35
|
+
// SauceLabs service serialises the config object for debugging.
|
|
36
|
+
// However, since Serenity/JS Stage is a pub/sub mechanism,
|
|
37
|
+
// it contains cyclic references which are not serialisable.
|
|
38
|
+
// We get rid of them from the config object to avoid confusing other services.
|
|
39
|
+
delete webdriverIOConfig.serenity;
|
|
40
|
+
|
|
36
41
|
this.adapter = new TestRunnerLoader(this.loader, this.cwd, this.cid)
|
|
37
42
|
.runnerAdapterFor(config);
|
|
38
43
|
|
|
@@ -64,7 +69,11 @@ export class WebdriverIOFrameworkAdapter {
|
|
|
64
69
|
this.serenity.configure({
|
|
65
70
|
outputStream: outputStreamBuffer,
|
|
66
71
|
cueTimeout: config.serenity.cueTimeout,
|
|
67
|
-
actors: config.serenity.actors
|
|
72
|
+
actors: config.serenity.actors || Cast.where(actor => actor.whoCan(
|
|
73
|
+
BrowseTheWebWithWebdriverIO.using(browser),
|
|
74
|
+
TakeNotes.usingAnEmptyNotepad(),
|
|
75
|
+
)),
|
|
76
|
+
diffFormatter: config.serenity.diffFormatter ?? new AnsiDiffFormatter(),
|
|
68
77
|
crew: [
|
|
69
78
|
...config.serenity.crew,
|
|
70
79
|
this.notifier,
|
|
@@ -84,10 +93,9 @@ export class WebdriverIOFrameworkAdapter {
|
|
|
84
93
|
return this.adapter.scenarioCount() > 0;
|
|
85
94
|
}
|
|
86
95
|
|
|
87
|
-
run(): Promise<number> {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
);
|
|
96
|
+
async run(): Promise<number> {
|
|
97
|
+
await this.adapter.run();
|
|
98
|
+
return this.notifier.failureCount();
|
|
91
99
|
}
|
|
92
100
|
|
|
93
101
|
private defaultConfig(): Partial<WebdriverIOConfig> {
|
|
@@ -8,7 +8,7 @@ import { WebdriverIOConfig } from './WebdriverIOConfig';
|
|
|
8
8
|
import { WebdriverIOFrameworkAdapter } from './WebdriverIOFrameworkAdapter';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
* @
|
|
11
|
+
* @group Test Runner Adapter
|
|
12
12
|
*/
|
|
13
13
|
export class WebdriverIOFrameworkAdapterFactory {
|
|
14
14
|
constructor(
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
ExecutionFailedWithError,
|
|
9
9
|
ExecutionIgnored,
|
|
10
10
|
ExecutionSkipped,
|
|
11
|
-
ImplementationPending,
|
|
11
|
+
ImplementationPending, Name,
|
|
12
12
|
Outcome,
|
|
13
13
|
ProblemIndication,
|
|
14
14
|
TestSuiteDetails,
|
|
@@ -391,15 +391,17 @@ export class WebdriverIONotifier implements StageCrewMember {
|
|
|
391
391
|
args: InnerArguments
|
|
392
392
|
): Promise<Array<Result | Error>> {
|
|
393
393
|
|
|
394
|
-
const hooks =
|
|
395
|
-
?
|
|
396
|
-
: hookFunctions;
|
|
394
|
+
const hooks = Array.isArray(hookFunctions)
|
|
395
|
+
? hookFunctions
|
|
396
|
+
: [ hookFunctions ];
|
|
397
397
|
|
|
398
398
|
const asyncOperationId = CorrelationId.create();
|
|
399
399
|
|
|
400
400
|
this.stage.announce(new AsyncOperationAttempted(
|
|
401
|
-
new
|
|
401
|
+
new Name(`WebdriverIONotifier#invokeHooks`),
|
|
402
|
+
new Description(`Invoking ${ hookName } hook`),
|
|
402
403
|
asyncOperationId,
|
|
404
|
+
this.stage.currentTime(),
|
|
403
405
|
));
|
|
404
406
|
|
|
405
407
|
return Promise.all(hooks.map((hook) => new Promise<Result | Error>((resolve) => {
|
|
@@ -426,8 +428,8 @@ export class WebdriverIONotifier implements StageCrewMember {
|
|
|
426
428
|
then(results => {
|
|
427
429
|
|
|
428
430
|
this.stage.announce(new AsyncOperationCompleted(
|
|
429
|
-
new Description(`[WebdriverIONotifier#invokeHooks] Invoking ${ hookName } hook completed`),
|
|
430
431
|
asyncOperationId,
|
|
432
|
+
this.stage.currentTime(),
|
|
431
433
|
));
|
|
432
434
|
|
|
433
435
|
return results;
|
package/src/adapter/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Stage, StageCrewMember } from '@serenity-js/core';
|
|
2
|
+
import { OutputStream } from '@serenity-js/core/lib/adapter';
|
|
2
3
|
import { DomainEvent, SceneFinished } from '@serenity-js/core/lib/events';
|
|
3
|
-
import { OutputStream } from '@serenity-js/core/lib/io';
|
|
4
4
|
|
|
5
5
|
import { OutputStreamBuffer } from './OutputStreamBuffer';
|
|
6
6
|
|
|
@@ -1,362 +1,52 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { BrowserCapabilities, BrowseTheWeb, ByCss, ByCssContainingText, ById, ByTagName, ByXPath, Cookie, CookieData, Key, ModalDialog, Page, PageElement } from '@serenity-js/web';
|
|
1
|
+
import { BrowserCapabilities, BrowseTheWeb } from '@serenity-js/web';
|
|
3
2
|
import type * as wdio from 'webdriverio';
|
|
4
3
|
|
|
5
|
-
import {
|
|
6
|
-
import { WebdriverIOLocator, WebdriverIONativeElementRoot } from '../models/locators';
|
|
4
|
+
import { WebdriverIOBrowsingSession } from '../models';
|
|
7
5
|
|
|
8
6
|
/**
|
|
9
|
-
* @
|
|
10
|
-
*
|
|
11
|
-
* to interact with Web apps using [WebdriverIO](https://webdriver.io/).
|
|
7
|
+
* This implementation of the {@apilink Ability|ability} to {@apilink BrowseTheWeb}
|
|
8
|
+
* enables the {@apilink Actor} to interact with web front-ends using [WebdriverIO](https://webdriver.io/).
|
|
12
9
|
*
|
|
13
|
-
*
|
|
14
|
-
* This means that its interface can change without affecting the major version of Serenity/JS itself.
|
|
15
|
-
* In particular, please don't rely on the `browser` field to remain `public` in future releases.
|
|
10
|
+
* ## Using WebdriverIO to `BrowseTheWeb`
|
|
16
11
|
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
12
|
+
* ```ts
|
|
13
|
+
* import { actorCalled } from '@serenity-js/core'
|
|
14
|
+
* import { BrowseTheWebWithWebdriverIO } from '@serenity-js/webdriverio'
|
|
15
|
+
* import { By, Navigate, PageElement, Text } from '@serenity-js/web'
|
|
16
|
+
* import { Ensure, equals } from '@serenity-js/assertions'
|
|
21
17
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
18
|
+
* const HomePage = {
|
|
19
|
+
* title: () =>
|
|
20
|
+
* PageElement.located(By.css('h1')).describedAs('title')
|
|
21
|
+
* }
|
|
25
22
|
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
23
|
+
* await actorCalled('Wendy')
|
|
24
|
+
* .whoCan(BrowseTheWebWithWebdriverIO.using(browser)) // `browser` is global in WebdriverIO tests
|
|
25
|
+
* .attemptsTo(
|
|
26
|
+
* Navigate.to(`https://serenity-js.org`),
|
|
27
|
+
* Ensure.that(Text.of(HomePage.title()), equals('Serenity/JS')),
|
|
28
|
+
* );
|
|
29
|
+
* ```
|
|
29
30
|
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
31
|
+
* ## Learn more
|
|
32
|
+
* - [WebdriverIO website](https://webdriver.io/)
|
|
33
|
+
* - {@apilink BrowseTheWeb}
|
|
34
|
+
* - {@apilink Ability}
|
|
35
|
+
* - {@apilink Actor}
|
|
34
36
|
*
|
|
35
|
-
* @
|
|
36
|
-
*
|
|
37
|
-
* @public
|
|
38
|
-
* @implements {@serenity-js/core/lib/screenplay~Ability}
|
|
39
|
-
* @see {@link @serenity-js/core/lib/screenplay/actor~Actor}
|
|
37
|
+
* @group Abilities
|
|
40
38
|
*/
|
|
41
|
-
export class BrowseTheWebWithWebdriverIO extends BrowseTheWeb<wdio.Element<'async'
|
|
39
|
+
export class BrowseTheWebWithWebdriverIO extends BrowseTheWeb<wdio.Element<'async'>> {
|
|
42
40
|
|
|
43
|
-
/**
|
|
44
|
-
* @param {@wdio/types~Browser} browserInstance
|
|
45
|
-
* @returns {BrowseTheWebWithWebdriverIO}
|
|
46
|
-
*/
|
|
47
41
|
static using(browserInstance: wdio.Browser<'async'>): BrowseTheWebWithWebdriverIO {
|
|
48
42
|
return new BrowseTheWebWithWebdriverIO(browserInstance);
|
|
49
43
|
}
|
|
50
44
|
|
|
51
|
-
/**
|
|
52
|
-
* @private
|
|
53
|
-
*/
|
|
54
|
-
private lastScriptExecutionSummary: LastScriptExecutionSummary;
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* @param {@wdio/types~Browser} browser
|
|
58
|
-
*/
|
|
59
45
|
constructor(protected readonly browser: wdio.Browser<'async'>) {
|
|
60
|
-
super(new
|
|
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
|
-
}
|
|
46
|
+
super(new WebdriverIOBrowsingSession(browser));
|
|
71
47
|
}
|
|
72
48
|
|
|
73
49
|
browserCapabilities(): Promise<BrowserCapabilities> {
|
|
74
50
|
return Promise.resolve(this.browser.capabilities as BrowserCapabilities);
|
|
75
51
|
}
|
|
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>;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* @desc
|
|
102
|
-
* Navigate to a given destination, specified as an absolute URL
|
|
103
|
-
* or a path relative to WebdriverIO `baseUrl`.
|
|
104
|
-
*
|
|
105
|
-
* @param {string} destination
|
|
106
|
-
* @returns {Promise<void>}
|
|
107
|
-
*/
|
|
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();
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* @desc
|
|
126
|
-
* Returns a {@link Page} representing the currently active top-level browsing context.
|
|
127
|
-
*
|
|
128
|
-
* @returns {Promise<Page>}
|
|
129
|
-
*/
|
|
130
|
-
async currentPage(): Promise<Page> {
|
|
131
|
-
|
|
132
|
-
const windowHandle = await this.browser.getWindowHandle();
|
|
133
|
-
|
|
134
|
-
return new WebdriverIOPage(this.browser, windowHandle);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* @desc
|
|
139
|
-
* Returns an array of {@link Page} objects representing all the available
|
|
140
|
-
* top-level browsing context, e.g. all the open browser tabs.
|
|
141
|
-
*
|
|
142
|
-
* @returns {Promise<Array<Page>>}
|
|
143
|
-
*/
|
|
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');
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* @desc
|
|
169
|
-
* Send a sequence of {@link Key} strokes to the active element.
|
|
170
|
-
*
|
|
171
|
-
* @param {Array<Key | string>} keys
|
|
172
|
-
* Keys to enter
|
|
173
|
-
*
|
|
174
|
-
* @returns {Promise<void>}
|
|
175
|
-
*
|
|
176
|
-
* @see https://webdriver.io/docs/api/browser/keys/
|
|
177
|
-
*/
|
|
178
|
-
sendKeys(keys: Array<Key | string>): Promise<void> {
|
|
179
|
-
const keySequence = keys.map(key => {
|
|
180
|
-
if (! Key.isKey(key)) {
|
|
181
|
-
return key;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
if (this.browser.isDevTools) {
|
|
185
|
-
return key.devtoolsName;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
return key.utf16codePoint;
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
return this.browser.keys(keySequence);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* @desc
|
|
196
|
-
* Take a screenshot of the top-level browsing context's viewport.
|
|
197
|
-
*
|
|
198
|
-
* @return {Promise<string>}
|
|
199
|
-
* A promise that will resolve to a base64-encoded screenshot PNG
|
|
200
|
-
*/
|
|
201
|
-
takeScreenshot(): Promise<string> {
|
|
202
|
-
return this.browser.takeScreenshot();
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* @desc
|
|
207
|
-
* Schedules a command to execute JavaScript in the context of the currently selected frame or window.
|
|
208
|
-
* The script fragment will be executed as the body of an anonymous function.
|
|
209
|
-
* If the script is provided as a function object, that function will be converted to a string for injection
|
|
210
|
-
* into the target window.
|
|
211
|
-
*
|
|
212
|
-
* Any arguments provided in addition to the script will be included as script arguments and may be referenced
|
|
213
|
-
* using the `arguments` object. Arguments may be a `boolean`, `number`, `string` or `WebElement`.
|
|
214
|
-
* Arrays and objects may also be used as script arguments as long as each item adheres
|
|
215
|
-
* to the types previously mentioned.
|
|
216
|
-
*
|
|
217
|
-
* The script may refer to any variables accessible from the current window.
|
|
218
|
-
* Furthermore, the script will execute in the window's context, thus `document` may be used to refer
|
|
219
|
-
* to the current document. Any local variables will not be available once the script has finished executing,
|
|
220
|
-
* though global variables will persist.
|
|
221
|
-
*
|
|
222
|
-
* If the script has a return value (i.e. if the script contains a `return` statement),
|
|
223
|
-
* then the following steps will be taken for resolving this functions return value:
|
|
224
|
-
*
|
|
225
|
-
* For a HTML element, the value will resolve to a WebElement
|
|
226
|
-
* - Null and undefined return values will resolve to null
|
|
227
|
-
* - Booleans, numbers, and strings will resolve as is
|
|
228
|
-
* - Functions will resolve to their string representation
|
|
229
|
-
* - For arrays and objects, each member item will be converted according to the rules above
|
|
230
|
-
*
|
|
231
|
-
* @example <caption>Perform a sleep in the browser under test</caption>
|
|
232
|
-
* BrowseTheWeb.as(actor).executeAsyncScript(`
|
|
233
|
-
* return arguments[0].tagName;
|
|
234
|
-
* `, Target.the('header').located(by.css(h1))
|
|
235
|
-
*
|
|
236
|
-
* @see https://seleniumhq.github.io/selenium/docs/api/java/org/openqa/selenium/JavascriptExecutor.html#executeScript-java.lang.String-java.lang.Object...-
|
|
237
|
-
*
|
|
238
|
-
* @param {string | Function} script
|
|
239
|
-
* @param {any[]} args
|
|
240
|
-
*
|
|
241
|
-
* @returns {Promise<any>}
|
|
242
|
-
*
|
|
243
|
-
* @see {@link BrowseTheWeb#getLastScriptExecutionResult}
|
|
244
|
-
*/
|
|
245
|
-
async executeScript<Result, InnerArguments extends any[]>(
|
|
246
|
-
script: string | ((...parameters: InnerArguments) => Result),
|
|
247
|
-
...args: InnerArguments
|
|
248
|
-
): Promise<Result> {
|
|
249
|
-
const nativeArguments = await Promise.all(args.map(arg => arg instanceof WebdriverIOPageElement ? arg.nativeElement() : arg)) as InnerArguments;
|
|
250
|
-
|
|
251
|
-
return this.browser.execute(script, ...nativeArguments)
|
|
252
|
-
.then(result => {
|
|
253
|
-
this.lastScriptExecutionSummary = new LastScriptExecutionSummary(
|
|
254
|
-
result,
|
|
255
|
-
);
|
|
256
|
-
return result;
|
|
257
|
-
});
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
/**
|
|
261
|
-
* @desc
|
|
262
|
-
* Schedules a command to execute asynchronous JavaScript in the context of the currently selected frame or window.
|
|
263
|
-
* The script fragment will be executed as the body of an anonymous function.
|
|
264
|
-
* If the script is provided as a function object, that function will be converted to a string for injection
|
|
265
|
-
* into the target window.
|
|
266
|
-
*
|
|
267
|
-
* Any arguments provided in addition to the script will be included as script arguments and may be referenced
|
|
268
|
-
* using the `arguments` object. Arguments may be a `boolean`, `number`, `string` or `WebElement`
|
|
269
|
-
* Arrays and objects may also be used as script arguments as long as each item adheres
|
|
270
|
-
* to the types previously mentioned.
|
|
271
|
-
*
|
|
272
|
-
* Unlike executing synchronous JavaScript with {@link BrowseTheWebWithWebdriverIO#executeScript},
|
|
273
|
-
* scripts executed with this function must explicitly signal they are finished by invoking the provided callback.
|
|
274
|
-
*
|
|
275
|
-
* This callback will always be injected into the executed function as the last argument,
|
|
276
|
-
* and thus may be referenced with `arguments[arguments.length - 1]`.
|
|
277
|
-
*
|
|
278
|
-
* The following steps will be taken for resolving this functions return value against
|
|
279
|
-
* the first argument to the script's callback function:
|
|
280
|
-
*
|
|
281
|
-
* - For a HTML element, the value will resolve to a WebElement
|
|
282
|
-
* - Null and undefined return values will resolve to null
|
|
283
|
-
* - Booleans, numbers, and strings will resolve as is
|
|
284
|
-
* - Functions will resolve to their string representation
|
|
285
|
-
* - For arrays and objects, each member item will be converted according to the rules above
|
|
286
|
-
*
|
|
287
|
-
* @example <caption>Perform a sleep in the browser under test</caption>
|
|
288
|
-
* BrowseTheWeb.as(actor).executeAsyncScript(`
|
|
289
|
-
* var delay = arguments[0];
|
|
290
|
-
* var callback = arguments[arguments.length - 1];
|
|
291
|
-
*
|
|
292
|
-
* window.setTimeout(callback, delay);
|
|
293
|
-
* `, 500)
|
|
294
|
-
*
|
|
295
|
-
* @example <caption>Return a value asynchronously</caption>
|
|
296
|
-
* BrowseTheWeb.as(actor).executeAsyncScript(`
|
|
297
|
-
* var callback = arguments[arguments.length - 1];
|
|
298
|
-
*
|
|
299
|
-
* callback('some return value')
|
|
300
|
-
* `).then(value => doSomethingWithThe(value))
|
|
301
|
-
*
|
|
302
|
-
* @see https://seleniumhq.github.io/selenium/docs/api/java/org/openqa/selenium/JavascriptExecutor.html#executeAsyncScript-java.lang.String-java.lang.Object...-
|
|
303
|
-
*
|
|
304
|
-
* @param {string|Function} script
|
|
305
|
-
* @param {any[]} args
|
|
306
|
-
*
|
|
307
|
-
* @returns {Promise<any>}
|
|
308
|
-
*
|
|
309
|
-
* @see {@link BrowseTheWeb#getLastScriptExecutionResult}
|
|
310
|
-
*/
|
|
311
|
-
async executeAsyncScript<Result, Parameters extends any[]>(
|
|
312
|
-
script: string | ((...args: [...parameters: Parameters, callback: (result: Result) => void]) => void),
|
|
313
|
-
...args: Parameters
|
|
314
|
-
): Promise<Result> {
|
|
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)
|
|
318
|
-
.then(result => {
|
|
319
|
-
this.lastScriptExecutionSummary = new LastScriptExecutionSummary<Result>(
|
|
320
|
-
result,
|
|
321
|
-
);
|
|
322
|
-
return result;
|
|
323
|
-
});
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
/**
|
|
327
|
-
* @desc
|
|
328
|
-
* Returns the last result of calling {@link BrowseTheWebWithWebdriverIO#executeAsyncScript}
|
|
329
|
-
* or {@link BrowseTheWebWithWebdriverIO#executeScript}
|
|
330
|
-
*
|
|
331
|
-
* @returns {any}
|
|
332
|
-
*/
|
|
333
|
-
lastScriptExecutionResult<Result = any>(): Result {
|
|
334
|
-
if (! this.lastScriptExecutionSummary) {
|
|
335
|
-
throw new LogicError(`Make sure to execute a script before checking on the result`);
|
|
336
|
-
}
|
|
337
|
-
|
|
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>;
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
/**
|
|
358
|
-
* @package
|
|
359
|
-
*/
|
|
360
|
-
class LastScriptExecutionSummary<Result = any> {
|
|
361
|
-
constructor(public readonly result: Result) {}
|
|
362
52
|
}
|