@serenity-js/webdriverio-8 3.31.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 (285) hide show
  1. package/CHANGELOG.md +1232 -0
  2. package/LICENSE.md +201 -0
  3. package/NOTICE.md +1 -0
  4. package/README.md +234 -0
  5. package/esm/adapter/TestRunnerLoader.d.ts +17 -0
  6. package/esm/adapter/TestRunnerLoader.d.ts.map +1 -0
  7. package/esm/adapter/TestRunnerLoader.js +63 -0
  8. package/esm/adapter/TestRunnerLoader.js.map +1 -0
  9. package/esm/adapter/WebdriverIOFrameworkAdapter.d.ts +25 -0
  10. package/esm/adapter/WebdriverIOFrameworkAdapter.d.ts.map +1 -0
  11. package/esm/adapter/WebdriverIOFrameworkAdapter.js +90 -0
  12. package/esm/adapter/WebdriverIOFrameworkAdapter.js.map +1 -0
  13. package/esm/adapter/WebdriverIOFrameworkAdapterFactory.d.ts +18 -0
  14. package/esm/adapter/WebdriverIOFrameworkAdapterFactory.d.ts.map +1 -0
  15. package/esm/adapter/WebdriverIOFrameworkAdapterFactory.js +18 -0
  16. package/esm/adapter/WebdriverIOFrameworkAdapterFactory.js.map +1 -0
  17. package/esm/adapter/WebdriverIONotifier.d.ts +71 -0
  18. package/esm/adapter/WebdriverIONotifier.d.ts.map +1 -0
  19. package/esm/adapter/WebdriverIONotifier.js +390 -0
  20. package/esm/adapter/WebdriverIONotifier.js.map +1 -0
  21. package/esm/adapter/index.d.ts +2 -0
  22. package/esm/adapter/index.d.ts.map +1 -0
  23. package/esm/adapter/index.js +2 -0
  24. package/esm/adapter/index.js.map +1 -0
  25. package/esm/adapter/reporter/BrowserCapabilitiesReporter.d.ts +18 -0
  26. package/esm/adapter/reporter/BrowserCapabilitiesReporter.d.ts.map +1 -0
  27. package/esm/adapter/reporter/BrowserCapabilitiesReporter.js +42 -0
  28. package/esm/adapter/reporter/BrowserCapabilitiesReporter.js.map +1 -0
  29. package/esm/adapter/reporter/InitialisesReporters.d.ts +8 -0
  30. package/esm/adapter/reporter/InitialisesReporters.d.ts.map +1 -0
  31. package/esm/adapter/reporter/InitialisesReporters.js +2 -0
  32. package/esm/adapter/reporter/InitialisesReporters.js.map +1 -0
  33. package/esm/adapter/reporter/OutputStreamBuffer.d.ts +13 -0
  34. package/esm/adapter/reporter/OutputStreamBuffer.d.ts.map +1 -0
  35. package/esm/adapter/reporter/OutputStreamBuffer.js +25 -0
  36. package/esm/adapter/reporter/OutputStreamBuffer.js.map +1 -0
  37. package/esm/adapter/reporter/OutputStreamBufferPrinter.d.ts +16 -0
  38. package/esm/adapter/reporter/OutputStreamBufferPrinter.d.ts.map +1 -0
  39. package/esm/adapter/reporter/OutputStreamBufferPrinter.js +24 -0
  40. package/esm/adapter/reporter/OutputStreamBufferPrinter.js.map +1 -0
  41. package/esm/adapter/reporter/ProvidesWriteStream.d.ts +8 -0
  42. package/esm/adapter/reporter/ProvidesWriteStream.d.ts.map +1 -0
  43. package/esm/adapter/reporter/ProvidesWriteStream.js +2 -0
  44. package/esm/adapter/reporter/ProvidesWriteStream.js.map +1 -0
  45. package/esm/adapter/reporter/TagPrinter.d.ts +17 -0
  46. package/esm/adapter/reporter/TagPrinter.d.ts.map +1 -0
  47. package/esm/adapter/reporter/TagPrinter.js +52 -0
  48. package/esm/adapter/reporter/TagPrinter.js.map +1 -0
  49. package/esm/adapter/reporter/index.d.ts +6 -0
  50. package/esm/adapter/reporter/index.d.ts.map +1 -0
  51. package/esm/adapter/reporter/index.js +6 -0
  52. package/esm/adapter/reporter/index.js.map +1 -0
  53. package/esm/api.d.ts +3 -0
  54. package/esm/api.d.ts.map +1 -0
  55. package/esm/api.js +2 -0
  56. package/esm/api.js.map +1 -0
  57. package/esm/config/WebdriverIOConfig.d.ts +95 -0
  58. package/esm/config/WebdriverIOConfig.d.ts.map +1 -0
  59. package/esm/config/WebdriverIOConfig.js +2 -0
  60. package/esm/config/WebdriverIOConfig.js.map +1 -0
  61. package/esm/config/index.d.ts +2 -0
  62. package/esm/config/index.d.ts.map +1 -0
  63. package/esm/config/index.js +2 -0
  64. package/esm/config/index.js.map +1 -0
  65. package/esm/index.d.ts +16 -0
  66. package/esm/index.d.ts.map +1 -0
  67. package/esm/index.js +14 -0
  68. package/esm/index.js.map +1 -0
  69. package/esm/screenplay/abilities/BrowseTheWebWithWebdriverIO.d.ts +40 -0
  70. package/esm/screenplay/abilities/BrowseTheWebWithWebdriverIO.d.ts.map +1 -0
  71. package/esm/screenplay/abilities/BrowseTheWebWithWebdriverIO.js +43 -0
  72. package/esm/screenplay/abilities/BrowseTheWebWithWebdriverIO.js.map +1 -0
  73. package/esm/screenplay/abilities/index.d.ts +2 -0
  74. package/esm/screenplay/abilities/index.d.ts.map +1 -0
  75. package/esm/screenplay/abilities/index.js +2 -0
  76. package/esm/screenplay/abilities/index.js.map +1 -0
  77. package/esm/screenplay/index.d.ts +3 -0
  78. package/esm/screenplay/index.d.ts.map +1 -0
  79. package/esm/screenplay/index.js +3 -0
  80. package/esm/screenplay/index.js.map +1 -0
  81. package/esm/screenplay/models/WebdriverIOBrowsingSession.d.ts +25 -0
  82. package/esm/screenplay/models/WebdriverIOBrowsingSession.d.ts.map +1 -0
  83. package/esm/screenplay/models/WebdriverIOBrowsingSession.js +125 -0
  84. package/esm/screenplay/models/WebdriverIOBrowsingSession.js.map +1 -0
  85. package/esm/screenplay/models/WebdriverIOCookie.d.ts +15 -0
  86. package/esm/screenplay/models/WebdriverIOCookie.d.ts.map +1 -0
  87. package/esm/screenplay/models/WebdriverIOCookie.js +42 -0
  88. package/esm/screenplay/models/WebdriverIOCookie.js.map +1 -0
  89. package/esm/screenplay/models/WebdriverIOErrorHandler.d.ts +9 -0
  90. package/esm/screenplay/models/WebdriverIOErrorHandler.d.ts.map +1 -0
  91. package/esm/screenplay/models/WebdriverIOErrorHandler.js +20 -0
  92. package/esm/screenplay/models/WebdriverIOErrorHandler.js.map +1 -0
  93. package/esm/screenplay/models/WebdriverIOModalDialogHandler.d.ts +27 -0
  94. package/esm/screenplay/models/WebdriverIOModalDialogHandler.d.ts.map +1 -0
  95. package/esm/screenplay/models/WebdriverIOModalDialogHandler.js +74 -0
  96. package/esm/screenplay/models/WebdriverIOModalDialogHandler.js.map +1 -0
  97. package/esm/screenplay/models/WebdriverIOPage.d.ts +50 -0
  98. package/esm/screenplay/models/WebdriverIOPage.d.ts.map +1 -0
  99. package/esm/screenplay/models/WebdriverIOPage.js +219 -0
  100. package/esm/screenplay/models/WebdriverIOPage.js.map +1 -0
  101. package/esm/screenplay/models/WebdriverIOPageElement.d.ts +34 -0
  102. package/esm/screenplay/models/WebdriverIOPageElement.d.ts.map +1 -0
  103. package/esm/screenplay/models/WebdriverIOPageElement.js +220 -0
  104. package/esm/screenplay/models/WebdriverIOPageElement.js.map +1 -0
  105. package/esm/screenplay/models/WebdriverIOPuppeteerModalDialogHandler.d.ts +30 -0
  106. package/esm/screenplay/models/WebdriverIOPuppeteerModalDialogHandler.d.ts.map +1 -0
  107. package/esm/screenplay/models/WebdriverIOPuppeteerModalDialogHandler.js +77 -0
  108. package/esm/screenplay/models/WebdriverIOPuppeteerModalDialogHandler.js.map +1 -0
  109. package/esm/screenplay/models/WebdriverProtocolErrorCode.d.ts +39 -0
  110. package/esm/screenplay/models/WebdriverProtocolErrorCode.d.ts.map +1 -0
  111. package/esm/screenplay/models/WebdriverProtocolErrorCode.js +40 -0
  112. package/esm/screenplay/models/WebdriverProtocolErrorCode.js.map +1 -0
  113. package/esm/screenplay/models/index.d.ts +5 -0
  114. package/esm/screenplay/models/index.d.ts.map +1 -0
  115. package/esm/screenplay/models/index.js +5 -0
  116. package/esm/screenplay/models/index.js.map +1 -0
  117. package/esm/screenplay/models/locators/WebdriverIOLocator.d.ts +33 -0
  118. package/esm/screenplay/models/locators/WebdriverIOLocator.d.ts.map +1 -0
  119. package/esm/screenplay/models/locators/WebdriverIOLocator.js +123 -0
  120. package/esm/screenplay/models/locators/WebdriverIOLocator.js.map +1 -0
  121. package/esm/screenplay/models/locators/WebdriverIORootLocator.d.ts +17 -0
  122. package/esm/screenplay/models/locators/WebdriverIORootLocator.d.ts.map +1 -0
  123. package/esm/screenplay/models/locators/WebdriverIORootLocator.js +30 -0
  124. package/esm/screenplay/models/locators/WebdriverIORootLocator.js.map +1 -0
  125. package/esm/screenplay/models/locators/index.d.ts +3 -0
  126. package/esm/screenplay/models/locators/index.d.ts.map +1 -0
  127. package/esm/screenplay/models/locators/index.js +3 -0
  128. package/esm/screenplay/models/locators/index.js.map +1 -0
  129. package/lib/adapter/TestRunnerLoader.d.ts +17 -0
  130. package/lib/adapter/TestRunnerLoader.d.ts.map +1 -0
  131. package/lib/adapter/TestRunnerLoader.js +67 -0
  132. package/lib/adapter/TestRunnerLoader.js.map +1 -0
  133. package/lib/adapter/WebdriverIOFrameworkAdapter.d.ts +25 -0
  134. package/lib/adapter/WebdriverIOFrameworkAdapter.d.ts.map +1 -0
  135. package/lib/adapter/WebdriverIOFrameworkAdapter.js +127 -0
  136. package/lib/adapter/WebdriverIOFrameworkAdapter.js.map +1 -0
  137. package/lib/adapter/WebdriverIOFrameworkAdapterFactory.d.ts +18 -0
  138. package/lib/adapter/WebdriverIOFrameworkAdapterFactory.d.ts.map +1 -0
  139. package/lib/adapter/WebdriverIOFrameworkAdapterFactory.js +22 -0
  140. package/lib/adapter/WebdriverIOFrameworkAdapterFactory.js.map +1 -0
  141. package/lib/adapter/WebdriverIONotifier.d.ts +71 -0
  142. package/lib/adapter/WebdriverIONotifier.d.ts.map +1 -0
  143. package/lib/adapter/WebdriverIONotifier.js +394 -0
  144. package/lib/adapter/WebdriverIONotifier.js.map +1 -0
  145. package/lib/adapter/index.d.ts +2 -0
  146. package/lib/adapter/index.d.ts.map +1 -0
  147. package/lib/adapter/index.js +18 -0
  148. package/lib/adapter/index.js.map +1 -0
  149. package/lib/adapter/reporter/BrowserCapabilitiesReporter.d.ts +18 -0
  150. package/lib/adapter/reporter/BrowserCapabilitiesReporter.d.ts.map +1 -0
  151. package/lib/adapter/reporter/BrowserCapabilitiesReporter.js +49 -0
  152. package/lib/adapter/reporter/BrowserCapabilitiesReporter.js.map +1 -0
  153. package/lib/adapter/reporter/InitialisesReporters.d.ts +8 -0
  154. package/lib/adapter/reporter/InitialisesReporters.d.ts.map +1 -0
  155. package/lib/adapter/reporter/InitialisesReporters.js +3 -0
  156. package/lib/adapter/reporter/InitialisesReporters.js.map +1 -0
  157. package/lib/adapter/reporter/OutputStreamBuffer.d.ts +13 -0
  158. package/lib/adapter/reporter/OutputStreamBuffer.d.ts.map +1 -0
  159. package/lib/adapter/reporter/OutputStreamBuffer.js +29 -0
  160. package/lib/adapter/reporter/OutputStreamBuffer.js.map +1 -0
  161. package/lib/adapter/reporter/OutputStreamBufferPrinter.d.ts +16 -0
  162. package/lib/adapter/reporter/OutputStreamBufferPrinter.d.ts.map +1 -0
  163. package/lib/adapter/reporter/OutputStreamBufferPrinter.js +28 -0
  164. package/lib/adapter/reporter/OutputStreamBufferPrinter.js.map +1 -0
  165. package/lib/adapter/reporter/ProvidesWriteStream.d.ts +8 -0
  166. package/lib/adapter/reporter/ProvidesWriteStream.d.ts.map +1 -0
  167. package/lib/adapter/reporter/ProvidesWriteStream.js +3 -0
  168. package/lib/adapter/reporter/ProvidesWriteStream.js.map +1 -0
  169. package/lib/adapter/reporter/TagPrinter.d.ts +17 -0
  170. package/lib/adapter/reporter/TagPrinter.d.ts.map +1 -0
  171. package/lib/adapter/reporter/TagPrinter.js +56 -0
  172. package/lib/adapter/reporter/TagPrinter.js.map +1 -0
  173. package/lib/adapter/reporter/index.d.ts +6 -0
  174. package/lib/adapter/reporter/index.d.ts.map +1 -0
  175. package/lib/adapter/reporter/index.js +22 -0
  176. package/lib/adapter/reporter/index.js.map +1 -0
  177. package/lib/api.d.ts +3 -0
  178. package/lib/api.d.ts.map +1 -0
  179. package/lib/api.js +18 -0
  180. package/lib/api.js.map +1 -0
  181. package/lib/config/WebdriverIOConfig.d.ts +95 -0
  182. package/lib/config/WebdriverIOConfig.d.ts.map +1 -0
  183. package/lib/config/WebdriverIOConfig.js +3 -0
  184. package/lib/config/WebdriverIOConfig.js.map +1 -0
  185. package/lib/config/index.d.ts +2 -0
  186. package/lib/config/index.d.ts.map +1 -0
  187. package/lib/config/index.js +18 -0
  188. package/lib/config/index.js.map +1 -0
  189. package/lib/index.d.ts +16 -0
  190. package/lib/index.d.ts.map +1 -0
  191. package/lib/index.js +52 -0
  192. package/lib/index.js.map +1 -0
  193. package/lib/package.json +1 -0
  194. package/lib/screenplay/abilities/BrowseTheWebWithWebdriverIO.d.ts +40 -0
  195. package/lib/screenplay/abilities/BrowseTheWebWithWebdriverIO.d.ts.map +1 -0
  196. package/lib/screenplay/abilities/BrowseTheWebWithWebdriverIO.js +47 -0
  197. package/lib/screenplay/abilities/BrowseTheWebWithWebdriverIO.js.map +1 -0
  198. package/lib/screenplay/abilities/index.d.ts +2 -0
  199. package/lib/screenplay/abilities/index.d.ts.map +1 -0
  200. package/lib/screenplay/abilities/index.js +18 -0
  201. package/lib/screenplay/abilities/index.js.map +1 -0
  202. package/lib/screenplay/index.d.ts +3 -0
  203. package/lib/screenplay/index.d.ts.map +1 -0
  204. package/lib/screenplay/index.js +19 -0
  205. package/lib/screenplay/index.js.map +1 -0
  206. package/lib/screenplay/models/WebdriverIOBrowsingSession.d.ts +25 -0
  207. package/lib/screenplay/models/WebdriverIOBrowsingSession.d.ts.map +1 -0
  208. package/lib/screenplay/models/WebdriverIOBrowsingSession.js +129 -0
  209. package/lib/screenplay/models/WebdriverIOBrowsingSession.js.map +1 -0
  210. package/lib/screenplay/models/WebdriverIOCookie.d.ts +15 -0
  211. package/lib/screenplay/models/WebdriverIOCookie.d.ts.map +1 -0
  212. package/lib/screenplay/models/WebdriverIOCookie.js +46 -0
  213. package/lib/screenplay/models/WebdriverIOCookie.js.map +1 -0
  214. package/lib/screenplay/models/WebdriverIOErrorHandler.d.ts +9 -0
  215. package/lib/screenplay/models/WebdriverIOErrorHandler.d.ts.map +1 -0
  216. package/lib/screenplay/models/WebdriverIOErrorHandler.js +24 -0
  217. package/lib/screenplay/models/WebdriverIOErrorHandler.js.map +1 -0
  218. package/lib/screenplay/models/WebdriverIOModalDialogHandler.d.ts +27 -0
  219. package/lib/screenplay/models/WebdriverIOModalDialogHandler.d.ts.map +1 -0
  220. package/lib/screenplay/models/WebdriverIOModalDialogHandler.js +78 -0
  221. package/lib/screenplay/models/WebdriverIOModalDialogHandler.js.map +1 -0
  222. package/lib/screenplay/models/WebdriverIOPage.d.ts +50 -0
  223. package/lib/screenplay/models/WebdriverIOPage.d.ts.map +1 -0
  224. package/lib/screenplay/models/WebdriverIOPage.js +256 -0
  225. package/lib/screenplay/models/WebdriverIOPage.js.map +1 -0
  226. package/lib/screenplay/models/WebdriverIOPageElement.d.ts +34 -0
  227. package/lib/screenplay/models/WebdriverIOPageElement.d.ts.map +1 -0
  228. package/lib/screenplay/models/WebdriverIOPageElement.js +257 -0
  229. package/lib/screenplay/models/WebdriverIOPageElement.js.map +1 -0
  230. package/lib/screenplay/models/WebdriverIOPuppeteerModalDialogHandler.d.ts +30 -0
  231. package/lib/screenplay/models/WebdriverIOPuppeteerModalDialogHandler.d.ts.map +1 -0
  232. package/lib/screenplay/models/WebdriverIOPuppeteerModalDialogHandler.js +81 -0
  233. package/lib/screenplay/models/WebdriverIOPuppeteerModalDialogHandler.js.map +1 -0
  234. package/lib/screenplay/models/WebdriverProtocolErrorCode.d.ts +39 -0
  235. package/lib/screenplay/models/WebdriverProtocolErrorCode.d.ts.map +1 -0
  236. package/lib/screenplay/models/WebdriverProtocolErrorCode.js +43 -0
  237. package/lib/screenplay/models/WebdriverProtocolErrorCode.js.map +1 -0
  238. package/lib/screenplay/models/index.d.ts +5 -0
  239. package/lib/screenplay/models/index.d.ts.map +1 -0
  240. package/lib/screenplay/models/index.js +21 -0
  241. package/lib/screenplay/models/index.js.map +1 -0
  242. package/lib/screenplay/models/locators/WebdriverIOLocator.d.ts +33 -0
  243. package/lib/screenplay/models/locators/WebdriverIOLocator.d.ts.map +1 -0
  244. package/lib/screenplay/models/locators/WebdriverIOLocator.js +128 -0
  245. package/lib/screenplay/models/locators/WebdriverIOLocator.js.map +1 -0
  246. package/lib/screenplay/models/locators/WebdriverIORootLocator.d.ts +17 -0
  247. package/lib/screenplay/models/locators/WebdriverIORootLocator.d.ts.map +1 -0
  248. package/lib/screenplay/models/locators/WebdriverIORootLocator.js +34 -0
  249. package/lib/screenplay/models/locators/WebdriverIORootLocator.js.map +1 -0
  250. package/lib/screenplay/models/locators/index.d.ts +3 -0
  251. package/lib/screenplay/models/locators/index.d.ts.map +1 -0
  252. package/lib/screenplay/models/locators/index.js +19 -0
  253. package/lib/screenplay/models/locators/index.js.map +1 -0
  254. package/package.json +122 -0
  255. package/src/adapter/TestRunnerLoader.ts +90 -0
  256. package/src/adapter/WebdriverIOFrameworkAdapter.ts +130 -0
  257. package/src/adapter/WebdriverIOFrameworkAdapterFactory.ts +39 -0
  258. package/src/adapter/WebdriverIONotifier.ts +480 -0
  259. package/src/adapter/index.ts +1 -0
  260. package/src/adapter/reporter/BrowserCapabilitiesReporter.ts +63 -0
  261. package/src/adapter/reporter/InitialisesReporters.ts +8 -0
  262. package/src/adapter/reporter/OutputStreamBuffer.ts +30 -0
  263. package/src/adapter/reporter/OutputStreamBufferPrinter.ts +30 -0
  264. package/src/adapter/reporter/ProvidesWriteStream.ts +8 -0
  265. package/src/adapter/reporter/TagPrinter.ts +69 -0
  266. package/src/adapter/reporter/index.ts +5 -0
  267. package/src/api.ts +2 -0
  268. package/src/config/WebdriverIOConfig.ts +94 -0
  269. package/src/config/index.ts +1 -0
  270. package/src/index.ts +32 -0
  271. package/src/screenplay/abilities/BrowseTheWebWithWebdriverIO.ts +46 -0
  272. package/src/screenplay/abilities/index.ts +1 -0
  273. package/src/screenplay/index.ts +2 -0
  274. package/src/screenplay/models/WebdriverIOBrowsingSession.ts +176 -0
  275. package/src/screenplay/models/WebdriverIOCookie.ts +51 -0
  276. package/src/screenplay/models/WebdriverIOErrorHandler.ts +25 -0
  277. package/src/screenplay/models/WebdriverIOModalDialogHandler.ts +99 -0
  278. package/src/screenplay/models/WebdriverIOPage.ts +311 -0
  279. package/src/screenplay/models/WebdriverIOPageElement.ts +280 -0
  280. package/src/screenplay/models/WebdriverIOPuppeteerModalDialogHandler.ts +100 -0
  281. package/src/screenplay/models/WebdriverProtocolErrorCode.ts +38 -0
  282. package/src/screenplay/models/index.ts +4 -0
  283. package/src/screenplay/models/locators/WebdriverIOLocator.ts +176 -0
  284. package/src/screenplay/models/locators/WebdriverIORootLocator.ts +34 -0
  285. package/src/screenplay/models/locators/index.ts +2 -0
@@ -0,0 +1,69 @@
1
+ import type { Tag } from '@serenity-js/core/lib/model/index.js';
2
+ import { BrowserTag, PlatformTag } from '@serenity-js/core/lib/model/index.js';
3
+ import type { Capabilities } from '@wdio/types';
4
+
5
+ /**
6
+ * @package
7
+ */
8
+ export class TagPrinter {
9
+ tagsFor(capability: Capabilities.DesiredCapabilities | Capabilities.W3CCapabilities): Tag[] {
10
+ const desiredCapabilities = this.desired(capability);
11
+
12
+ return [
13
+ this.browserTagFor(desiredCapabilities),
14
+ this.platformTagFor(desiredCapabilities),
15
+ ];
16
+ }
17
+
18
+ private browserTagFor(capabilities: Capabilities.DesiredCapabilities): Tag {
19
+ return new BrowserTag(
20
+ this.browserNameFrom(capabilities),
21
+ this.browserVersionFrom(capabilities),
22
+ );
23
+ }
24
+
25
+ private platformTagFor(capabilities: Capabilities.DesiredCapabilities): Tag {
26
+ return new PlatformTag(
27
+ this.platformNameFrom(capabilities),
28
+ this.platformVersionFrom(capabilities),
29
+ );
30
+ }
31
+
32
+ private browserNameFrom(capabilities: Capabilities.DesiredCapabilities): string {
33
+ return capabilities.browserName
34
+ || capabilities.browser
35
+ || (capabilities['appium:app'] && capabilities['appium:app'].replace('sauce-storage:', ''))
36
+ || 'unknown';
37
+ }
38
+
39
+ private browserVersionFrom(capabilities: Capabilities.DesiredCapabilities): string | undefined {
40
+ return capabilities.deviceName // mobile web
41
+ || capabilities['appium:deviceName']
42
+ || capabilities.browserVersion // W3C format
43
+ || capabilities.version // JSONWP format
44
+ || capabilities.browser_version; // BrowserStack
45
+ }
46
+
47
+ private platformNameFrom(capabilities: Capabilities.DesiredCapabilities): string {
48
+ return capabilities.platformName
49
+ || capabilities['appium:platformName']
50
+ || capabilities.platform
51
+ || capabilities.os
52
+ || 'unknown';
53
+ }
54
+
55
+ private platformVersionFrom(capabilities: Capabilities.DesiredCapabilities): string | undefined {
56
+ return capabilities['appium:platformVersion']
57
+ || capabilities.os_version;
58
+ }
59
+
60
+ private desired(capabilities: Capabilities.RemoteCapability): Capabilities.DesiredCapabilities {
61
+ return this.isW3C(capabilities)
62
+ ? capabilities.alwaysMatch
63
+ : capabilities;
64
+ }
65
+
66
+ private isW3C(capabilities: Capabilities.RemoteCapability): capabilities is Capabilities.W3CCapabilities {
67
+ return !!(capabilities as Capabilities.W3CCapabilities).alwaysMatch;
68
+ }
69
+ }
@@ -0,0 +1,5 @@
1
+ export * from './BrowserCapabilitiesReporter.js';
2
+ export * from './InitialisesReporters.js';
3
+ export * from './OutputStreamBuffer.js';
4
+ export * from './ProvidesWriteStream.js';
5
+ export * from './TagPrinter.js';
package/src/api.ts ADDED
@@ -0,0 +1,2 @@
1
+ export { WebdriverIOConfig } from './config/index.js';
2
+ export * from './screenplay/index.js';
@@ -0,0 +1,94 @@
1
+ import type { SerenityConfig } from '@serenity-js/core';
2
+ import type { Options } from '@wdio/types';
3
+
4
+ /**
5
+ * [WebdriverIO configuration object](https://webdriver.io/docs/configurationfile/),
6
+ * with [Serenity/JS-specific additions](https://serenity-js.orgapi/core/class/SerenityConfig/).
7
+ *
8
+ * ## Integrating WebdriverIO with Serenity/JS
9
+ *
10
+ * ```ts
11
+ * // wdio.conf.ts
12
+ * import { WebdriverIOConfig } from '@serenity-js/webdriverio-8'
13
+ *
14
+ * export const config: WebdriverIOConfig = {
15
+ *
16
+ * framework: '@serenity-js/webdriverio-8',
17
+ *
18
+ * serenity: {
19
+ * runner: 'cucumber',
20
+ * // runner: 'mocha',
21
+ * // runner: 'jasmine',
22
+ *
23
+ * crew: [
24
+ * // Optional, print test execution results to standard output
25
+ * '@serenity-js/console-reporter',
26
+ *
27
+ * // Optional, produce Serenity BDD reports
28
+ * // and living documentation (HTML)
29
+ * '@serenity-js/serenity-bdd',
30
+ * [ '@serenity-js/core:ArtifactArchiver', {
31
+ * outputDirectory: 'target/site/serenity'
32
+ * } ],
33
+ *
34
+ * // Optional, automatically capture screenshots
35
+ * // upon interaction failure
36
+ * [ '@serenity-js/web:Photographer', {
37
+ * strategy: 'TakePhotosOfFailures'
38
+ * // strategy: 'TakePhotosOfInteractions'
39
+ * } ],
40
+ * ]
41
+ * },
42
+ *
43
+ * // Configure your Cucumber runner
44
+ * cucumberOpts: {
45
+ * // see Cucumber configuration options below
46
+ * },
47
+ *
48
+ * // ... or Jasmine runner
49
+ * jasmineOpts: {
50
+ * // see Jasmine configuration options below
51
+ * },
52
+ *
53
+ * // ... or Mocha runner
54
+ * mochaOpts: {
55
+ * // see Mocha configuration options below
56
+ * },
57
+ *
58
+ * runner: 'local',
59
+ *
60
+ * specs: [
61
+ * './features/*.feature',
62
+ *
63
+ * // or for Mocha/Jasmine
64
+ * // './*.spec.ts'
65
+ * ],
66
+ *
67
+ * // Any other WebdriverIO configuration
68
+ * }
69
+ * ```
70
+ *
71
+ * ## Learn more
72
+ *
73
+ * - [WebdriverIO configuration file](https://webdriver.io/docs/configurationfile/)
74
+ * - [`CucumberConfig`](https://serenity-js.org/api/cucumber-adapter/interface/CucumberConfig/)
75
+ * - [`JasmineConfig`](https://serenity-js.org/api/jasmine-adapter/interface/JasmineConfig/)
76
+ * - [`MochaConfig`](https://serenity-js.org/api/mocha-adapter/interface/MochaConfig/)
77
+ *
78
+ * @group Configuration
79
+ */
80
+ export interface WebdriverIOConfig extends Options.Testrunner {
81
+
82
+ /**
83
+ * Serenity/JS configuration with an additional `runner` entry
84
+ * allowing to specify the test runner, such as `cucumber`, `mocha`, or `jasmine`.
85
+ *
86
+ * #### Learn more
87
+ *
88
+ * - [WebdriverIO configuration file](https://webdriver.io/docs/configurationfile/)
89
+ * - [`CucumberConfig`](https://serenity-js.org/api/cucumber-adapter/interface/CucumberConfig/)
90
+ * - [`JasmineConfig`](https://serenity-js.org/api/jasmine-adapter/interface/JasmineConfig/)
91
+ * - [`MochaConfig`](https://serenity-js.org/api/mocha-adapter/interface/MochaConfig/)
92
+ */
93
+ serenity?: SerenityConfig & { runner?: string };
94
+ }
@@ -0,0 +1 @@
1
+ export * from './WebdriverIOConfig.js';
package/src/index.ts ADDED
@@ -0,0 +1,32 @@
1
+ import { serenity } from '@serenity-js/core';
2
+ import { ModuleLoader, Path } from '@serenity-js/core/lib/io/index.js';
3
+ import type { Capabilities } from '@wdio/types';
4
+ import type { EventEmitter } from 'events';
5
+
6
+ import type { InitialisesReporters, ProvidesWriteStream } from './adapter/reporter/index.js';
7
+ import type { WebdriverIOConfig } from './config/index.js';
8
+
9
+ /**
10
+ * WebdriverIO Framework Adapter integrates WebdriverIO with Serenity/JS
11
+ */
12
+ export default {
13
+ async init(
14
+ cid: string,
15
+ config: WebdriverIOConfig,
16
+ specs: string[],
17
+ capabilities: Capabilities.RemoteCapability,
18
+ reporter: EventEmitter & ProvidesWriteStream & InitialisesReporters
19
+ ): Promise<{ hasTests: () => boolean, run: () => Promise<number> }> {
20
+ const { WebdriverIOFrameworkAdapterFactory } = await import('./adapter/index.js');
21
+
22
+ const adapterFactory = new WebdriverIOFrameworkAdapterFactory(
23
+ serenity,
24
+ new ModuleLoader(process.cwd()),
25
+ Path.from(process.cwd()),
26
+ );
27
+
28
+ return adapterFactory.init(cid, config, specs, capabilities, reporter);
29
+ }
30
+ };
31
+
32
+ export * from './api.js';
@@ -0,0 +1,46 @@
1
+ import 'webdriverio';
2
+
3
+ import { BrowseTheWeb } from '@serenity-js/web';
4
+
5
+ import { WebdriverIOBrowsingSession } from '../models/index.js';
6
+
7
+ /**
8
+ * This implementation of the [ability](https://serenity-js.org/api/core/class/Ability/) to [`BrowseTheWeb`](https://serenity-js.org/api/web/class/BrowseTheWeb/)
9
+ * enables the [`Actor`](https://serenity-js.org/api/core/class/Actor/) to interact with web front-ends using [WebdriverIO](https://webdriver.io/).
10
+ *
11
+ * ## Using WebdriverIO to `BrowseTheWeb`
12
+ *
13
+ * ```ts
14
+ * import { actorCalled } from '@serenity-js/core'
15
+ * import { BrowseTheWebWithWebdriverIO } from '@serenity-js/webdriverio-8'
16
+ * import { By, Navigate, PageElement, Text } from '@serenity-js/web'
17
+ * import { Ensure, equals } from '@serenity-js/assertions'
18
+ * import { browser } from '@wdio/globals'
19
+ *
20
+ * const HomePage = {
21
+ * title: () =>
22
+ * PageElement.located(By.css('h1')).describedAs('title')
23
+ * }
24
+ *
25
+ * await actorCalled('Wendy')
26
+ * .whoCan(BrowseTheWebWithWebdriverIO.using(browser)) // `browser` is global in WebdriverIO tests
27
+ * .attemptsTo(
28
+ * Navigate.to(`https://serenity-js.org`),
29
+ * Ensure.that(Text.of(HomePage.title()), equals('Serenity/JS')),
30
+ * );
31
+ * ```
32
+ *
33
+ * ## Learn more
34
+ * - [WebdriverIO website](https://webdriver.io/)
35
+ * - [`BrowseTheWeb`](https://serenity-js.org/api/web/class/BrowseTheWeb/)
36
+ * - [`Ability`](https://serenity-js.org/api/core/class/Ability/)
37
+ * - [`Actor`](https://serenity-js.org/api/core/class/Actor/)
38
+ *
39
+ * @group Abilities
40
+ */
41
+ export class BrowseTheWebWithWebdriverIO extends BrowseTheWeb<WebdriverIO.Element> {
42
+
43
+ static using(browserInstance: WebdriverIO.Browser): BrowseTheWebWithWebdriverIO {
44
+ return new BrowseTheWebWithWebdriverIO(new WebdriverIOBrowsingSession(browserInstance));
45
+ }
46
+ }
@@ -0,0 +1 @@
1
+ export * from './BrowseTheWebWithWebdriverIO.js';
@@ -0,0 +1,2 @@
1
+ export * from './abilities/index.js';
2
+ export * from './models/index.js';
@@ -0,0 +1,176 @@
1
+ import 'webdriverio';
2
+
3
+ import { LogicError } from '@serenity-js/core';
4
+ import { CorrelationId } from '@serenity-js/core/lib/model/index.js';
5
+ import type { BrowserCapabilities, ModalDialogHandler } from '@serenity-js/web';
6
+ import { BrowsingSession } from '@serenity-js/web';
7
+ import type { Page } from 'puppeteer-core';
8
+
9
+ import { WebdriverIOPage } from '../models/index.js';
10
+ import { WebdriverIOErrorHandler } from './WebdriverIOErrorHandler.js';
11
+ import { WebdriverIOModalDialogHandler } from './WebdriverIOModalDialogHandler.js';
12
+ import { WebdriverIOPuppeteerModalDialogHandler } from './WebdriverIOPuppeteerModalDialogHandler.js';
13
+
14
+ /**
15
+ * WebdriverIO-specific implementation of [`BrowsingSession`](https://serenity-js.org/api/web/class/BrowsingSession/).
16
+ *
17
+ * @group Models
18
+ */
19
+ export class WebdriverIOBrowsingSession extends BrowsingSession<WebdriverIOPage> {
20
+
21
+ constructor(protected readonly browser: WebdriverIO.Browser) {
22
+ super();
23
+
24
+ if (! browser.$ || ! browser.$$) {
25
+ 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?`)
26
+ }
27
+ }
28
+
29
+ override async allPages(): Promise<Array<WebdriverIOPage>> {
30
+ // scan all the active window handles and add any newly opened windows if needed
31
+ const windowHandles: string[] = await this.browser.getWindowHandles();
32
+
33
+ // remove pages that are no longer open
34
+ const closedPageIds = this.registeredPageIds()
35
+ .filter(id => ! windowHandles.includes(id.value));
36
+
37
+ this.deregister(...closedPageIds);
38
+
39
+ // add any new pages that might have been opened (e.g. popup windows)
40
+ const registeredWindowHandles = new Set(this.registeredPageIds().map(id => id.value));
41
+ const newlyOpenedWindowHandles = windowHandles.filter(windowHandle => ! registeredWindowHandles.has(windowHandle));
42
+
43
+ for (const newlyOpenedWindowHandle of newlyOpenedWindowHandles) {
44
+ const errorHandler = new WebdriverIOErrorHandler();
45
+ this.register(
46
+ new WebdriverIOPage(
47
+ this,
48
+ this.browser,
49
+ await this.modalDialogHandlerFor(newlyOpenedWindowHandle, errorHandler),
50
+ errorHandler,
51
+ new CorrelationId(newlyOpenedWindowHandle)
52
+ )
53
+ );
54
+ }
55
+
56
+ return super.allPages();
57
+ }
58
+
59
+ /**
60
+ * @param page
61
+ */
62
+ override async changeCurrentPageTo(page: WebdriverIOPage): Promise<void> {
63
+ const currentPage = await this.currentPage();
64
+
65
+ // are we already on this page?
66
+ if (currentPage.id.equals(page.id)) {
67
+ return void 0;
68
+ }
69
+
70
+ // does the new page exist, or has it been closed in the meantime by user action, script, or similar?
71
+ if (! await page.isPresent()) {
72
+ return void 0;
73
+ }
74
+
75
+ // the page seems to be legit, switch to it
76
+ await this.browser.switchToWindow(page.id.value);
77
+
78
+ // and update the cached reference
79
+ await super.changeCurrentPageTo(page);
80
+ }
81
+
82
+ private async activeWindowHandle(): Promise<string> {
83
+ try {
84
+ return await this.browser.getWindowHandle();
85
+ }
86
+ catch (error) {
87
+ // If the window is closed by user action Webdriver will still hold the reference to the closed window.
88
+ if (['NoSuchWindowError', 'no such window'].includes(error.name)) {
89
+ const allHandles = await this.browser.getWindowHandles();
90
+ if (allHandles.length > 0) {
91
+ const handle = allHandles.at(-1);
92
+ await this.browser.switchToWindow(handle);
93
+
94
+ return handle;
95
+ }
96
+ }
97
+ throw error;
98
+ }
99
+ }
100
+
101
+ override async currentPage(): Promise<WebdriverIOPage> {
102
+ const actualCurrentPageHandle = await this.activeWindowHandle();
103
+ const actualCurrentPageId = CorrelationId.fromJSON(actualCurrentPageHandle);
104
+
105
+ if (this.currentBrowserPage && this.currentBrowserPage.id.equals(actualCurrentPageId)) {
106
+ return this.currentBrowserPage;
107
+ }
108
+
109
+ // Looks like the actual current page is not what we thought the current page was.
110
+ // Is it one of the pages we are aware of?
111
+
112
+ const allPages = await this.allPages();
113
+ const found = allPages.find(page => page.id.equals(actualCurrentPageId));
114
+ if (found) {
115
+ this.currentBrowserPage = found;
116
+ return this.currentBrowserPage;
117
+ }
118
+
119
+ // OK, so that's a handle that we haven't seen before, let's register it and set as current page.
120
+ this.currentBrowserPage = await this.registerCurrentPage();
121
+
122
+ return this.currentBrowserPage;
123
+ }
124
+
125
+ protected override async registerCurrentPage(): Promise<WebdriverIOPage> {
126
+ const windowHandle = await this.browser.getWindowHandle();
127
+
128
+ const errorHandler = new WebdriverIOErrorHandler();
129
+
130
+ const page = new WebdriverIOPage(
131
+ this,
132
+ this.browser,
133
+ await this.modalDialogHandlerFor(windowHandle, errorHandler),
134
+ errorHandler,
135
+ new CorrelationId(windowHandle)
136
+ );
137
+
138
+ this.register(page)
139
+
140
+ return page;
141
+ }
142
+
143
+ private async modalDialogHandlerFor(windowHandle: string, errorHandler: WebdriverIOErrorHandler): Promise<ModalDialogHandler> {
144
+ return this.browser.isDevTools
145
+ ? new WebdriverIOPuppeteerModalDialogHandler(await this.puppeteerPageFor(windowHandle))
146
+ : new WebdriverIOModalDialogHandler(this.browser, errorHandler);
147
+ }
148
+
149
+ private async puppeteerPageFor(windowHandle: string): Promise<Page> {
150
+ const puppeteer = await this.browser.getPuppeteer();
151
+ const pages = await puppeteer.pages();
152
+
153
+ const handles = await this.browser.getWindowHandles();
154
+
155
+ if (handles.length !== pages.length) {
156
+ throw new LogicError(`The number of registered Puppeteer pages doesn't match WebdriverIO window handles`)
157
+ }
158
+
159
+ const index = handles.indexOf(windowHandle);
160
+
161
+ // We cast to `unknown` first because the version of Page in Puppeteer-core
162
+ // might be slightly out-of-sync with what the WebdriverIO uses.
163
+ // This doesn't really matter since we're only using it to work with Dialogs.
164
+ const page = pages[index] as unknown as Page;
165
+
166
+ if (! page) {
167
+ throw new LogicError(`Couldn't find Puppeteer page for WebdriverIO window handle ${ windowHandle }`)
168
+ }
169
+
170
+ return page;
171
+ }
172
+
173
+ override browserCapabilities(): Promise<BrowserCapabilities> {
174
+ return Promise.resolve(this.browser.capabilities as BrowserCapabilities);
175
+ }
176
+ }
@@ -0,0 +1,51 @@
1
+ import 'webdriverio';
2
+
3
+ import { Timestamp } from '@serenity-js/core';
4
+ import type { CookieData} from '@serenity-js/web';
5
+ import { Cookie, CookieMissingError } from '@serenity-js/web';
6
+ import { ensure, isDefined } from 'tiny-types';
7
+
8
+ /**
9
+ * WebdriverIO-specific implementation of [`Cookie`](https://serenity-js.org/api/web/class/Cookie/).
10
+ *
11
+ * @group Models
12
+ */
13
+ export class WebdriverIOCookie extends Cookie {
14
+
15
+ constructor(
16
+ private readonly browser: WebdriverIO.Browser,
17
+ cookieName: string,
18
+ ) {
19
+ super(cookieName);
20
+ ensure('browser', browser, isDefined());
21
+ }
22
+
23
+ async delete(): Promise<void> {
24
+ await this.browser.deleteCookies(this.cookieName);
25
+ }
26
+
27
+ protected async read(): Promise<CookieData> {
28
+ const [ cookie ] = await this.browser.getCookies(this.cookieName);
29
+
30
+ if (! cookie) {
31
+ throw new CookieMissingError(`Cookie '${ this.cookieName }' not set`);
32
+ }
33
+
34
+ // There _might_ be a bug in WDIO where the expiry date is set on "expires" rather than the "expiry" key
35
+ // and possibly another one around deserialising the timestamp, since WDIO seems to add several hundred milliseconds
36
+ // to the original expiry date
37
+ const expiry: number | undefined = cookie.expiry || (cookie as any).expires;
38
+
39
+ return {
40
+ name: cookie.name,
41
+ value: cookie.value,
42
+ domain: cookie.domain,
43
+ path: cookie.path,
44
+ expiry: typeof expiry === 'number' && expiry >= 0
45
+ ? Timestamp.fromTimestampInSeconds(Math.round(expiry))
46
+ : undefined,
47
+ httpOnly: cookie.httpOnly,
48
+ secure: cookie.secure,
49
+ }
50
+ }
51
+ }
@@ -0,0 +1,25 @@
1
+ import type { WebdriverProtocolErrorCode } from './WebdriverProtocolErrorCode.js';
2
+
3
+ export class WebdriverIOErrorHandler {
4
+
5
+ constructor(private readonly handlers: Map<WebdriverProtocolErrorCode, (error: Error) => Promise<void> | void> = new Map()) {
6
+ }
7
+
8
+ async executeIfHandled<T>(error: Error, action: () => Promise<T> | T): Promise<T> {
9
+ if (! this.handlers.has(error.name as WebdriverProtocolErrorCode)) {
10
+ throw error;
11
+ }
12
+
13
+ await this.handlers.get(error.name as WebdriverProtocolErrorCode)(error);
14
+
15
+ return action();
16
+ }
17
+
18
+ setHandlerFor(errorType: WebdriverProtocolErrorCode, handler: (error: Error) => Promise<void> | void): void {
19
+ this.handlers.set(errorType, handler);
20
+ }
21
+
22
+ unsetHandlerFor(errorType: WebdriverProtocolErrorCode): void {
23
+ this.handlers.delete(errorType);
24
+ }
25
+ }
@@ -0,0 +1,99 @@
1
+ import 'webdriverio';
2
+
3
+ import type { ModalDialog} from '@serenity-js/web';
4
+ import { AbsentModalDialog, AcceptedModalDialog, DismissedModalDialog, ModalDialogHandler } from '@serenity-js/web';
5
+
6
+ import type { WebdriverIOErrorHandler } from './WebdriverIOErrorHandler.js';
7
+ import { WebdriverProtocolErrorCode } from './WebdriverProtocolErrorCode.js';
8
+
9
+ /**
10
+ * WebdriverIO-specific implementation of [`ModalDialogHandler`](https://serenity-js.org/api/web/class/ModalDialogHandler/),
11
+ * used with the [WebDriver protocol](https://webdriver.io/docs/api/webdriver).
12
+ *
13
+ * @group Models
14
+ */
15
+ export class WebdriverIOModalDialogHandler extends ModalDialogHandler {
16
+
17
+ private readonly defaultHandler: () => Promise<void> =
18
+ async () => {
19
+ const message = await this.browser.getAlertText();
20
+
21
+ await this.browser.dismissAlert();
22
+
23
+ this.modalDialog = new DismissedModalDialog(message);
24
+ }
25
+
26
+ private currentHandler: () => Promise<void>;
27
+
28
+ constructor(
29
+ private readonly browser: WebdriverIO.Browser,
30
+ private readonly errorHandler: WebdriverIOErrorHandler,
31
+ ) {
32
+ super();
33
+
34
+ this.currentHandler = this.defaultHandler;
35
+
36
+ this.errorHandler.setHandlerFor(WebdriverProtocolErrorCode.UnexpectedAlertOpenError, error_ => this.tryToHandleDialog());
37
+ }
38
+
39
+ async tryToHandleDialog(): Promise<void> {
40
+ try {
41
+ await this.currentHandler()
42
+ }
43
+ catch (error) {
44
+ if (error.name === WebdriverProtocolErrorCode.NoSuchAlertError) {
45
+ this.modalDialog = new AbsentModalDialog();
46
+ return;
47
+ }
48
+ throw error;
49
+ }
50
+ }
51
+
52
+ async acceptNext(): Promise<void> {
53
+ this.currentHandler = async () => {
54
+ const message = await this.browser.getAlertText();
55
+
56
+ await this.browser.acceptAlert();
57
+
58
+ this.modalDialog = new AcceptedModalDialog(message);
59
+ };
60
+ }
61
+
62
+ async acceptNextWithValue(text: string | number): Promise<void> {
63
+ this.currentHandler = async () => {
64
+ await this.browser.sendAlertText(String(text));
65
+ const message = await this.browser.getAlertText();
66
+
67
+ await this.browser.acceptAlert();
68
+
69
+ this.modalDialog = new AcceptedModalDialog(message);
70
+ };
71
+ }
72
+
73
+ async dismissNext(): Promise<void> {
74
+ this.currentHandler = async () => {
75
+ const message = await this.browser.getAlertText();
76
+
77
+ await this.browser.dismissAlert();
78
+
79
+ this.modalDialog = new DismissedModalDialog(message);
80
+ }
81
+ }
82
+
83
+ async reset(): Promise<void> {
84
+ this.modalDialog = new AbsentModalDialog();
85
+ this.currentHandler = this.defaultHandler;
86
+ }
87
+
88
+ /**
89
+ * @override
90
+ */
91
+ async last(): Promise<ModalDialog> {
92
+
93
+ if (this.modalDialog instanceof AbsentModalDialog) {
94
+ await this.tryToHandleDialog();
95
+ }
96
+
97
+ return this.modalDialog;
98
+ }
99
+ }