@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.
Files changed (139) hide show
  1. package/CHANGELOG.md +245 -119
  2. package/README.md +66 -45
  3. package/lib/adapter/TestRunnerLoader.d.ts +3 -4
  4. package/lib/adapter/TestRunnerLoader.d.ts.map +1 -0
  5. package/lib/adapter/TestRunnerLoader.js +1 -4
  6. package/lib/adapter/TestRunnerLoader.js.map +1 -1
  7. package/lib/adapter/WebdriverIOConfig.d.ts +115 -109
  8. package/lib/adapter/WebdriverIOConfig.d.ts.map +1 -0
  9. package/lib/adapter/WebdriverIOFrameworkAdapter.d.ts +1 -3
  10. package/lib/adapter/WebdriverIOFrameworkAdapter.d.ts.map +1 -0
  11. package/lib/adapter/WebdriverIOFrameworkAdapter.js +14 -8
  12. package/lib/adapter/WebdriverIOFrameworkAdapter.js.map +1 -1
  13. package/lib/adapter/WebdriverIOFrameworkAdapterFactory.d.ts +2 -1
  14. package/lib/adapter/WebdriverIOFrameworkAdapterFactory.d.ts.map +1 -0
  15. package/lib/adapter/WebdriverIOFrameworkAdapterFactory.js +1 -1
  16. package/lib/adapter/WebdriverIONotifier.d.ts +1 -0
  17. package/lib/adapter/WebdriverIONotifier.d.ts.map +1 -0
  18. package/lib/adapter/WebdriverIONotifier.js +5 -5
  19. package/lib/adapter/WebdriverIONotifier.js.map +1 -1
  20. package/lib/adapter/index.d.ts +1 -1
  21. package/lib/adapter/index.d.ts.map +1 -0
  22. package/lib/adapter/index.js +5 -2
  23. package/lib/adapter/index.js.map +1 -1
  24. package/lib/adapter/reporter/BrowserCapabilitiesReporter.d.ts +1 -0
  25. package/lib/adapter/reporter/BrowserCapabilitiesReporter.d.ts.map +1 -0
  26. package/lib/adapter/reporter/BrowserCapabilitiesReporter.js +4 -1
  27. package/lib/adapter/reporter/BrowserCapabilitiesReporter.js.map +1 -1
  28. package/lib/adapter/reporter/InitialisesReporters.d.ts +1 -0
  29. package/lib/adapter/reporter/InitialisesReporters.d.ts.map +1 -0
  30. package/lib/adapter/reporter/OutputStreamBuffer.d.ts +2 -1
  31. package/lib/adapter/reporter/OutputStreamBuffer.d.ts.map +1 -0
  32. package/lib/adapter/reporter/OutputStreamBufferPrinter.d.ts +2 -1
  33. package/lib/adapter/reporter/OutputStreamBufferPrinter.d.ts.map +1 -0
  34. package/lib/adapter/reporter/OutputStreamBufferPrinter.js.map +1 -1
  35. package/lib/adapter/reporter/ProvidesWriteStream.d.ts +2 -1
  36. package/lib/adapter/reporter/ProvidesWriteStream.d.ts.map +1 -0
  37. package/lib/adapter/reporter/TagPrinter.d.ts +1 -0
  38. package/lib/adapter/reporter/TagPrinter.d.ts.map +1 -0
  39. package/lib/adapter/reporter/index.d.ts +1 -0
  40. package/lib/adapter/reporter/index.d.ts.map +1 -0
  41. package/lib/adapter/reporter/index.js +5 -1
  42. package/lib/adapter/reporter/index.js.map +1 -1
  43. package/lib/index.d.ts +1 -0
  44. package/lib/index.d.ts.map +1 -0
  45. package/lib/index.js +5 -1
  46. package/lib/index.js.map +1 -1
  47. package/lib/screenplay/abilities/BrowseTheWebWithWebdriverIO.d.ts +28 -197
  48. package/lib/screenplay/abilities/BrowseTheWebWithWebdriverIO.d.ts.map +1 -0
  49. package/lib/screenplay/abilities/BrowseTheWebWithWebdriverIO.js +29 -296
  50. package/lib/screenplay/abilities/BrowseTheWebWithWebdriverIO.js.map +1 -1
  51. package/lib/screenplay/abilities/index.d.ts +1 -0
  52. package/lib/screenplay/abilities/index.d.ts.map +1 -0
  53. package/lib/screenplay/abilities/index.js +5 -1
  54. package/lib/screenplay/abilities/index.js.map +1 -1
  55. package/lib/screenplay/index.d.ts +1 -0
  56. package/lib/screenplay/index.d.ts.map +1 -0
  57. package/lib/screenplay/index.js +5 -1
  58. package/lib/screenplay/index.js.map +1 -1
  59. package/lib/screenplay/models/WebdriverIOBrowsingSession.d.ts +24 -0
  60. package/lib/screenplay/models/WebdriverIOBrowsingSession.d.ts.map +1 -0
  61. package/lib/screenplay/models/WebdriverIOBrowsingSession.js +125 -0
  62. package/lib/screenplay/models/WebdriverIOBrowsingSession.js.map +1 -0
  63. package/lib/screenplay/models/WebdriverIOCookie.d.ts +6 -0
  64. package/lib/screenplay/models/WebdriverIOCookie.d.ts.map +1 -0
  65. package/lib/screenplay/models/WebdriverIOCookie.js +7 -2
  66. package/lib/screenplay/models/WebdriverIOCookie.js.map +1 -1
  67. package/lib/screenplay/models/WebdriverIOErrorHandler.d.ts +9 -0
  68. package/lib/screenplay/models/WebdriverIOErrorHandler.d.ts.map +1 -0
  69. package/lib/screenplay/models/WebdriverIOErrorHandler.js +23 -0
  70. package/lib/screenplay/models/WebdriverIOErrorHandler.js.map +1 -0
  71. package/lib/screenplay/models/WebdriverIOModalDialogHandler.d.ts +29 -0
  72. package/lib/screenplay/models/WebdriverIOModalDialogHandler.d.ts.map +1 -0
  73. package/lib/screenplay/models/WebdriverIOModalDialogHandler.js +77 -0
  74. package/lib/screenplay/models/WebdriverIOModalDialogHandler.js.map +1 -0
  75. package/lib/screenplay/models/WebdriverIOPage.d.ts +29 -5
  76. package/lib/screenplay/models/WebdriverIOPage.d.ts.map +1 -0
  77. package/lib/screenplay/models/WebdriverIOPage.js +166 -54
  78. package/lib/screenplay/models/WebdriverIOPage.js.map +1 -1
  79. package/lib/screenplay/models/WebdriverIOPageElement.d.ts +10 -10
  80. package/lib/screenplay/models/WebdriverIOPageElement.d.ts.map +1 -0
  81. package/lib/screenplay/models/WebdriverIOPageElement.js +164 -46
  82. package/lib/screenplay/models/WebdriverIOPageElement.js.map +1 -1
  83. package/lib/screenplay/models/WebdriverIOPuppeteerModalDialogHandler.d.ts +32 -0
  84. package/lib/screenplay/models/WebdriverIOPuppeteerModalDialogHandler.d.ts.map +1 -0
  85. package/lib/screenplay/models/WebdriverIOPuppeteerModalDialogHandler.js +82 -0
  86. package/lib/screenplay/models/WebdriverIOPuppeteerModalDialogHandler.js.map +1 -0
  87. package/lib/screenplay/models/WebdriverProtocolErrorCode.d.ts +39 -0
  88. package/lib/screenplay/models/WebdriverProtocolErrorCode.d.ts.map +1 -0
  89. package/lib/screenplay/models/WebdriverProtocolErrorCode.js +43 -0
  90. package/lib/screenplay/models/WebdriverProtocolErrorCode.js.map +1 -0
  91. package/lib/screenplay/models/index.d.ts +2 -1
  92. package/lib/screenplay/models/index.d.ts.map +1 -0
  93. package/lib/screenplay/models/index.js +6 -2
  94. package/lib/screenplay/models/index.js.map +1 -1
  95. package/lib/screenplay/models/locators/WebdriverIOLocator.d.ts +18 -5
  96. package/lib/screenplay/models/locators/WebdriverIOLocator.d.ts.map +1 -0
  97. package/lib/screenplay/models/locators/WebdriverIOLocator.js +84 -5
  98. package/lib/screenplay/models/locators/WebdriverIOLocator.js.map +1 -1
  99. package/lib/screenplay/models/locators/WebdriverIORootLocator.d.ts +17 -0
  100. package/lib/screenplay/models/locators/WebdriverIORootLocator.d.ts.map +1 -0
  101. package/lib/screenplay/models/locators/WebdriverIORootLocator.js +32 -0
  102. package/lib/screenplay/models/locators/WebdriverIORootLocator.js.map +1 -0
  103. package/lib/screenplay/models/locators/index.d.ts +2 -1
  104. package/lib/screenplay/models/locators/index.d.ts.map +1 -0
  105. package/lib/screenplay/models/locators/index.js +6 -2
  106. package/lib/screenplay/models/locators/index.js.map +1 -1
  107. package/package.json +31 -32
  108. package/src/adapter/TestRunnerLoader.ts +3 -5
  109. package/src/adapter/WebdriverIOConfig.ts +114 -109
  110. package/src/adapter/WebdriverIOFrameworkAdapter.ts +20 -12
  111. package/src/adapter/WebdriverIOFrameworkAdapterFactory.ts +1 -1
  112. package/src/adapter/WebdriverIONotifier.ts +8 -6
  113. package/src/adapter/index.ts +0 -1
  114. package/src/adapter/reporter/OutputStreamBuffer.ts +1 -1
  115. package/src/adapter/reporter/OutputStreamBufferPrinter.ts +1 -1
  116. package/src/adapter/reporter/ProvidesWriteStream.ts +1 -1
  117. package/src/screenplay/abilities/BrowseTheWebWithWebdriverIO.ts +29 -339
  118. package/src/screenplay/models/WebdriverIOBrowsingSession.ts +171 -0
  119. package/src/screenplay/models/WebdriverIOCookie.ts +7 -2
  120. package/src/screenplay/models/WebdriverIOErrorHandler.ts +25 -0
  121. package/src/screenplay/models/WebdriverIOModalDialogHandler.ts +100 -0
  122. package/src/screenplay/models/WebdriverIOPage.ts +222 -63
  123. package/src/screenplay/models/WebdriverIOPageElement.ts +181 -62
  124. package/src/screenplay/models/WebdriverIOPuppeteerModalDialogHandler.ts +97 -0
  125. package/src/screenplay/models/WebdriverProtocolErrorCode.ts +38 -0
  126. package/src/screenplay/models/index.ts +1 -1
  127. package/src/screenplay/models/locators/WebdriverIOLocator.ts +122 -24
  128. package/src/screenplay/models/locators/WebdriverIORootLocator.ts +33 -0
  129. package/src/screenplay/models/locators/index.ts +1 -1
  130. package/tsconfig.build.json +17 -0
  131. package/lib/screenplay/models/WebdriverIOModalDialog.d.ts +0 -11
  132. package/lib/screenplay/models/WebdriverIOModalDialog.js +0 -40
  133. package/lib/screenplay/models/WebdriverIOModalDialog.js.map +0 -1
  134. package/lib/screenplay/models/locators/WebdriverIONativeElementRoot.d.ts +0 -2
  135. package/lib/screenplay/models/locators/WebdriverIONativeElementRoot.js +0 -3
  136. package/lib/screenplay/models/locators/WebdriverIONativeElementRoot.js.map +0 -1
  137. package/src/screenplay/models/WebdriverIOModalDialog.ts +0 -45
  138. package/src/screenplay/models/locators/WebdriverIONativeElementRoot.ts +0 -3
  139. package/tsconfig.eslint.json +0 -10
@@ -1,9 +1,11 @@
1
- import { ArtifactArchiver, Serenity } from '@serenity-js/core';
2
- import { ModuleLoader, Path, TestRunnerAdapter } from '@serenity-js/core/lib/io';
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 { isPlainObject } from 'is-plain-object';
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: isPlainObject,
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
- return this.adapter.run().then(() =>
89
- this.notifier.failureCount()
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
- * @package
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 = ! Array.isArray(hookFunctions)
395
- ? [ hookFunctions ]
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 Description(`[WebdriverIONotifier#invokeHooks] Invoking ${ hookName } hook`),
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;
@@ -1,3 +1,2 @@
1
- export * from './TestRunnerLoader';
2
1
  export * from './WebdriverIOConfig';
3
2
  export * from './WebdriverIOFrameworkAdapterFactory';
@@ -1,4 +1,4 @@
1
- import { OutputStream } from '@serenity-js/core/lib/io';
1
+ import { OutputStream } from '@serenity-js/core/lib/adapter';
2
2
 
3
3
  /**
4
4
  * @package
@@ -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,4 +1,4 @@
1
- import { OutputStream } from '@serenity-js/core/lib/io';
1
+ import { OutputStream } from '@serenity-js/core/lib/adapter';
2
2
 
3
3
  /**
4
4
  * @package
@@ -1,362 +1,52 @@
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';
1
+ import { BrowserCapabilities, BrowseTheWeb } from '@serenity-js/web';
3
2
  import type * as wdio from 'webdriverio';
4
3
 
5
- import { WebdriverIOCookie, WebdriverIOModalDialog, WebdriverIOPage, WebdriverIOPageElement } from '../models';
6
- import { WebdriverIOLocator, WebdriverIONativeElementRoot } from '../models/locators';
4
+ import { WebdriverIOBrowsingSession } from '../models';
7
5
 
8
6
  /**
9
- * @desc
10
- * An {@link @serenity-js/core/lib/screenplay~Ability} that enables the {@link @serenity-js/core/lib/screenplay/actor~Actor}
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
- * *Please note*: this class is still marked as experimental while new WebdriverIO Interactions and Questions are being developed.
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
- * @example <caption>Using the WebdriverIO browser</caption>
18
- * import { Actor } from '@serenity-js/core';
19
- * import { BrowseTheWeb, by, Navigate, Target } from '@serenity-js/webdriverio'
20
- * import { Ensure, equals } from '@serenity-js/assertions';
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
- * const actor = Actor.named('Wendy').whoCan(
23
- * BrowseTheWeb.using(browser),
24
- * );
18
+ * const HomePage = {
19
+ * title: () =>
20
+ * PageElement.located(By.css('h1')).describedAs('title')
21
+ * }
25
22
  *
26
- * const HomePage = {
27
- * Title: Target.the('title').located(by.css('h1')),
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
- * actor.attemptsTo(
31
- * Navigate.to(`https://serenity-js.org`),
32
- * Ensure.that(Text.of(HomePage.Title), equals('Serenity/JS')),
33
- * );
31
+ * ## Learn more
32
+ * - [WebdriverIO website](https://webdriver.io/)
33
+ * - {@apilink BrowseTheWeb}
34
+ * - {@apilink Ability}
35
+ * - {@apilink Actor}
34
36
  *
35
- * @see https://webdriver.io/
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'>, WebdriverIONativeElementRoot> {
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 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
- }
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
  }