@serenity-js/webdriverio 2.32.4 → 3.0.0-rc.2

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 (240) hide show
  1. package/CHANGELOG.md +70 -0
  2. package/lib/adapter/WebdriverIOFrameworkAdapter.js +1 -1
  3. package/lib/adapter/WebdriverIOFrameworkAdapter.js.map +1 -1
  4. package/lib/adapter/WebdriverIONotifier.d.ts +35 -1
  5. package/lib/adapter/WebdriverIONotifier.js +174 -13
  6. package/lib/adapter/WebdriverIONotifier.js.map +1 -1
  7. package/lib/index.d.ts +0 -3
  8. package/lib/index.js +0 -3
  9. package/lib/index.js.map +1 -1
  10. package/lib/screenplay/abilities/{BrowseTheWeb.d.ts → BrowseTheWebWithWebdriverIO.d.ts} +79 -23
  11. package/lib/screenplay/abilities/{BrowseTheWeb.js → BrowseTheWebWithWebdriverIO.js} +160 -25
  12. package/lib/screenplay/abilities/BrowseTheWebWithWebdriverIO.js.map +1 -0
  13. package/lib/screenplay/abilities/index.d.ts +1 -1
  14. package/lib/screenplay/abilities/index.js +1 -1
  15. package/lib/screenplay/abilities/index.js.map +1 -1
  16. package/lib/screenplay/index.d.ts +1 -2
  17. package/lib/screenplay/index.js +1 -2
  18. package/lib/screenplay/index.js.map +1 -1
  19. package/lib/screenplay/models/WebdriverIOCookie.d.ts +8 -0
  20. package/lib/screenplay/models/WebdriverIOCookie.js +39 -0
  21. package/lib/screenplay/models/WebdriverIOCookie.js.map +1 -0
  22. package/lib/screenplay/models/WebdriverIOModalDialog.d.ts +11 -0
  23. package/lib/screenplay/models/WebdriverIOModalDialog.js +40 -0
  24. package/lib/screenplay/models/WebdriverIOModalDialog.js.map +1 -0
  25. package/lib/screenplay/models/WebdriverIONativeElementRoot.d.ts +2 -0
  26. package/lib/screenplay/{interactions/EnterBuilder.js → models/WebdriverIONativeElementRoot.js} +1 -1
  27. package/lib/screenplay/models/WebdriverIONativeElementRoot.js.map +1 -0
  28. package/lib/screenplay/models/WebdriverIOPage.d.ts +24 -0
  29. package/lib/screenplay/models/WebdriverIOPage.js +98 -0
  30. package/lib/screenplay/models/WebdriverIOPage.js.map +1 -0
  31. package/lib/screenplay/models/WebdriverIOPageElement.d.ts +22 -0
  32. package/lib/screenplay/models/WebdriverIOPageElement.js +75 -0
  33. package/lib/screenplay/models/WebdriverIOPageElement.js.map +1 -0
  34. package/lib/screenplay/models/WebdriverIOPageElements.d.ts +15 -0
  35. package/lib/screenplay/models/WebdriverIOPageElements.js +65 -0
  36. package/lib/screenplay/models/WebdriverIOPageElements.js.map +1 -0
  37. package/lib/screenplay/models/index.d.ts +6 -0
  38. package/lib/{input → screenplay/models}/index.js +6 -1
  39. package/lib/screenplay/models/index.js.map +1 -0
  40. package/package.json +18 -28
  41. package/src/adapter/WebdriverIOFrameworkAdapter.ts +2 -0
  42. package/src/adapter/WebdriverIONotifier.ts +225 -23
  43. package/src/index.ts +0 -3
  44. package/src/screenplay/abilities/{BrowseTheWeb.ts → BrowseTheWebWithWebdriverIO.ts} +200 -31
  45. package/src/screenplay/abilities/index.ts +1 -1
  46. package/src/screenplay/index.ts +1 -2
  47. package/src/screenplay/models/WebdriverIOCookie.ts +44 -0
  48. package/src/screenplay/models/WebdriverIOModalDialog.ts +45 -0
  49. package/src/screenplay/models/WebdriverIONativeElementRoot.ts +3 -0
  50. package/src/screenplay/models/WebdriverIOPage.ts +120 -0
  51. package/src/screenplay/models/WebdriverIOPageElement.ts +92 -0
  52. package/src/screenplay/models/WebdriverIOPageElements.ts +91 -0
  53. package/src/screenplay/models/index.ts +6 -0
  54. package/lib/expectations/ElementExpectation.d.ts +0 -11
  55. package/lib/expectations/ElementExpectation.js +0 -27
  56. package/lib/expectations/ElementExpectation.js.map +0 -1
  57. package/lib/expectations/index.d.ts +0 -6
  58. package/lib/expectations/index.js +0 -19
  59. package/lib/expectations/index.js.map +0 -1
  60. package/lib/expectations/isActive.d.ts +0 -15
  61. package/lib/expectations/isActive.js +0 -21
  62. package/lib/expectations/isActive.js.map +0 -1
  63. package/lib/expectations/isClickable.d.ts +0 -20
  64. package/lib/expectations/isClickable.js +0 -26
  65. package/lib/expectations/isClickable.js.map +0 -1
  66. package/lib/expectations/isEnabled.d.ts +0 -14
  67. package/lib/expectations/isEnabled.js +0 -20
  68. package/lib/expectations/isEnabled.js.map +0 -1
  69. package/lib/expectations/isPresent.d.ts +0 -15
  70. package/lib/expectations/isPresent.js +0 -21
  71. package/lib/expectations/isPresent.js.map +0 -1
  72. package/lib/expectations/isSelected.d.ts +0 -14
  73. package/lib/expectations/isSelected.js +0 -20
  74. package/lib/expectations/isSelected.js.map +0 -1
  75. package/lib/expectations/isVisible.d.ts +0 -14
  76. package/lib/expectations/isVisible.js +0 -20
  77. package/lib/expectations/isVisible.js.map +0 -1
  78. package/lib/input/Key.d.ts +0 -73
  79. package/lib/input/Key.js +0 -84
  80. package/lib/input/Key.js.map +0 -1
  81. package/lib/input/index.d.ts +0 -1
  82. package/lib/input/index.js.map +0 -1
  83. package/lib/screenplay/abilities/BrowseTheWeb.js.map +0 -1
  84. package/lib/screenplay/interactions/Clear.d.ts +0 -79
  85. package/lib/screenplay/interactions/Clear.js +0 -97
  86. package/lib/screenplay/interactions/Clear.js.map +0 -1
  87. package/lib/screenplay/interactions/Click.d.ts +0 -73
  88. package/lib/screenplay/interactions/Click.js +0 -84
  89. package/lib/screenplay/interactions/Click.js.map +0 -1
  90. package/lib/screenplay/interactions/DoubleClick.d.ts +0 -90
  91. package/lib/screenplay/interactions/DoubleClick.js +0 -101
  92. package/lib/screenplay/interactions/DoubleClick.js.map +0 -1
  93. package/lib/screenplay/interactions/Enter.d.ts +0 -73
  94. package/lib/screenplay/interactions/Enter.js +0 -87
  95. package/lib/screenplay/interactions/Enter.js.map +0 -1
  96. package/lib/screenplay/interactions/EnterBuilder.d.ts +0 -25
  97. package/lib/screenplay/interactions/EnterBuilder.js.map +0 -1
  98. package/lib/screenplay/interactions/ExecuteScript.d.ts +0 -206
  99. package/lib/screenplay/interactions/ExecuteScript.js +0 -311
  100. package/lib/screenplay/interactions/ExecuteScript.js.map +0 -1
  101. package/lib/screenplay/interactions/Hover.d.ts +0 -78
  102. package/lib/screenplay/interactions/Hover.js +0 -89
  103. package/lib/screenplay/interactions/Hover.js.map +0 -1
  104. package/lib/screenplay/interactions/Navigate.d.ts +0 -141
  105. package/lib/screenplay/interactions/Navigate.js +0 -197
  106. package/lib/screenplay/interactions/Navigate.js.map +0 -1
  107. package/lib/screenplay/interactions/Press.d.ts +0 -84
  108. package/lib/screenplay/interactions/Press.js +0 -152
  109. package/lib/screenplay/interactions/Press.js.map +0 -1
  110. package/lib/screenplay/interactions/PressBuilder.d.ts +0 -26
  111. package/lib/screenplay/interactions/PressBuilder.js +0 -3
  112. package/lib/screenplay/interactions/PressBuilder.js.map +0 -1
  113. package/lib/screenplay/interactions/RightClick.d.ts +0 -89
  114. package/lib/screenplay/interactions/RightClick.js +0 -100
  115. package/lib/screenplay/interactions/RightClick.js.map +0 -1
  116. package/lib/screenplay/interactions/Scroll.d.ts +0 -75
  117. package/lib/screenplay/interactions/Scroll.js +0 -86
  118. package/lib/screenplay/interactions/Scroll.js.map +0 -1
  119. package/lib/screenplay/interactions/Wait.d.ts +0 -143
  120. package/lib/screenplay/interactions/Wait.js +0 -247
  121. package/lib/screenplay/interactions/Wait.js.map +0 -1
  122. package/lib/screenplay/interactions/WaitBuilder.d.ts +0 -32
  123. package/lib/screenplay/interactions/WaitBuilder.js +0 -3
  124. package/lib/screenplay/interactions/WaitBuilder.js.map +0 -1
  125. package/lib/screenplay/interactions/WebElementInteraction.d.ts +0 -37
  126. package/lib/screenplay/interactions/WebElementInteraction.js +0 -52
  127. package/lib/screenplay/interactions/WebElementInteraction.js.map +0 -1
  128. package/lib/screenplay/interactions/index.d.ts +0 -13
  129. package/lib/screenplay/interactions/index.js +0 -26
  130. package/lib/screenplay/interactions/index.js.map +0 -1
  131. package/lib/screenplay/questions/Attribute.d.ts +0 -82
  132. package/lib/screenplay/questions/Attribute.js +0 -102
  133. package/lib/screenplay/questions/Attribute.js.map +0 -1
  134. package/lib/screenplay/questions/CSSClasses.d.ts +0 -92
  135. package/lib/screenplay/questions/CSSClasses.js +0 -112
  136. package/lib/screenplay/questions/CSSClasses.js.map +0 -1
  137. package/lib/screenplay/questions/LastScriptExecution.d.ts +0 -14
  138. package/lib/screenplay/questions/LastScriptExecution.js +0 -22
  139. package/lib/screenplay/questions/LastScriptExecution.js.map +0 -1
  140. package/lib/screenplay/questions/NestedTargetBuilder.d.ts +0 -27
  141. package/lib/screenplay/questions/NestedTargetBuilder.js +0 -3
  142. package/lib/screenplay/questions/NestedTargetBuilder.js.map +0 -1
  143. package/lib/screenplay/questions/TargetBuilder.d.ts +0 -25
  144. package/lib/screenplay/questions/TargetBuilder.js +0 -3
  145. package/lib/screenplay/questions/TargetBuilder.js.map +0 -1
  146. package/lib/screenplay/questions/Text.d.ts +0 -95
  147. package/lib/screenplay/questions/Text.js +0 -130
  148. package/lib/screenplay/questions/Text.js.map +0 -1
  149. package/lib/screenplay/questions/Value.d.ts +0 -63
  150. package/lib/screenplay/questions/Value.js +0 -78
  151. package/lib/screenplay/questions/Value.js.map +0 -1
  152. package/lib/screenplay/questions/Website.d.ts +0 -21
  153. package/lib/screenplay/questions/Website.js +0 -31
  154. package/lib/screenplay/questions/Website.js.map +0 -1
  155. package/lib/screenplay/questions/index.d.ts +0 -10
  156. package/lib/screenplay/questions/index.js +0 -23
  157. package/lib/screenplay/questions/index.js.map +0 -1
  158. package/lib/screenplay/questions/lists.d.ts +0 -86
  159. package/lib/screenplay/questions/lists.js +0 -137
  160. package/lib/screenplay/questions/lists.js.map +0 -1
  161. package/lib/screenplay/questions/locators.d.ts +0 -196
  162. package/lib/screenplay/questions/locators.js +0 -219
  163. package/lib/screenplay/questions/locators.js.map +0 -1
  164. package/lib/screenplay/questions/targets.d.ts +0 -254
  165. package/lib/screenplay/questions/targets.js +0 -334
  166. package/lib/screenplay/questions/targets.js.map +0 -1
  167. package/lib/stage/crew/index.d.ts +0 -1
  168. package/lib/stage/crew/index.js +0 -14
  169. package/lib/stage/crew/index.js.map +0 -1
  170. package/lib/stage/crew/photographer/Photographer.d.ts +0 -83
  171. package/lib/stage/crew/photographer/Photographer.js +0 -102
  172. package/lib/stage/crew/photographer/Photographer.js.map +0 -1
  173. package/lib/stage/crew/photographer/index.d.ts +0 -2
  174. package/lib/stage/crew/photographer/index.js +0 -15
  175. package/lib/stage/crew/photographer/index.js.map +0 -1
  176. package/lib/stage/crew/photographer/strategies/PhotoTakingStrategy.d.ts +0 -28
  177. package/lib/stage/crew/photographer/strategies/PhotoTakingStrategy.js +0 -65
  178. package/lib/stage/crew/photographer/strategies/PhotoTakingStrategy.js.map +0 -1
  179. package/lib/stage/crew/photographer/strategies/TakePhotosBeforeAndAfterInteractions.d.ts +0 -18
  180. package/lib/stage/crew/photographer/strategies/TakePhotosBeforeAndAfterInteractions.js +0 -30
  181. package/lib/stage/crew/photographer/strategies/TakePhotosBeforeAndAfterInteractions.js.map +0 -1
  182. package/lib/stage/crew/photographer/strategies/TakePhotosOfFailures.d.ts +0 -17
  183. package/lib/stage/crew/photographer/strategies/TakePhotosOfFailures.js +0 -28
  184. package/lib/stage/crew/photographer/strategies/TakePhotosOfFailures.js.map +0 -1
  185. package/lib/stage/crew/photographer/strategies/TakePhotosOfInteractions.d.ts +0 -19
  186. package/lib/stage/crew/photographer/strategies/TakePhotosOfInteractions.js +0 -28
  187. package/lib/stage/crew/photographer/strategies/TakePhotosOfInteractions.js.map +0 -1
  188. package/lib/stage/crew/photographer/strategies/index.d.ts +0 -4
  189. package/lib/stage/crew/photographer/strategies/index.js +0 -17
  190. package/lib/stage/crew/photographer/strategies/index.js.map +0 -1
  191. package/lib/stage/index.d.ts +0 -1
  192. package/lib/stage/index.js +0 -14
  193. package/lib/stage/index.js.map +0 -1
  194. package/src/expectations/ElementExpectation.ts +0 -31
  195. package/src/expectations/index.ts +0 -6
  196. package/src/expectations/isActive.ts +0 -21
  197. package/src/expectations/isClickable.ts +0 -26
  198. package/src/expectations/isEnabled.ts +0 -19
  199. package/src/expectations/isPresent.ts +0 -20
  200. package/src/expectations/isSelected.ts +0 -19
  201. package/src/expectations/isVisible.ts +0 -19
  202. package/src/input/Key.ts +0 -83
  203. package/src/input/index.ts +0 -1
  204. package/src/screenplay/interactions/Clear.ts +0 -102
  205. package/src/screenplay/interactions/Click.ts +0 -85
  206. package/src/screenplay/interactions/DoubleClick.ts +0 -102
  207. package/src/screenplay/interactions/Enter.ts +0 -93
  208. package/src/screenplay/interactions/EnterBuilder.ts +0 -27
  209. package/src/screenplay/interactions/ExecuteScript.ts +0 -344
  210. package/src/screenplay/interactions/Hover.ts +0 -90
  211. package/src/screenplay/interactions/Navigate.ts +0 -208
  212. package/src/screenplay/interactions/Press.ts +0 -172
  213. package/src/screenplay/interactions/PressBuilder.ts +0 -28
  214. package/src/screenplay/interactions/RightClick.ts +0 -100
  215. package/src/screenplay/interactions/Scroll.ts +0 -87
  216. package/src/screenplay/interactions/Wait.ts +0 -267
  217. package/src/screenplay/interactions/WaitBuilder.ts +0 -34
  218. package/src/screenplay/interactions/WebElementInteraction.ts +0 -56
  219. package/src/screenplay/interactions/index.ts +0 -13
  220. package/src/screenplay/questions/Attribute.ts +0 -112
  221. package/src/screenplay/questions/CSSClasses.ts +0 -116
  222. package/src/screenplay/questions/LastScriptExecution.ts +0 -21
  223. package/src/screenplay/questions/NestedTargetBuilder.ts +0 -30
  224. package/src/screenplay/questions/TargetBuilder.ts +0 -27
  225. package/src/screenplay/questions/Text.ts +0 -140
  226. package/src/screenplay/questions/Value.ts +0 -82
  227. package/src/screenplay/questions/Website.ts +0 -34
  228. package/src/screenplay/questions/index.ts +0 -10
  229. package/src/screenplay/questions/lists.ts +0 -161
  230. package/src/screenplay/questions/locators.ts +0 -254
  231. package/src/screenplay/questions/targets.ts +0 -401
  232. package/src/stage/crew/index.ts +0 -1
  233. package/src/stage/crew/photographer/Photographer.ts +0 -108
  234. package/src/stage/crew/photographer/index.ts +0 -2
  235. package/src/stage/crew/photographer/strategies/PhotoTakingStrategy.ts +0 -103
  236. package/src/stage/crew/photographer/strategies/TakePhotosBeforeAndAfterInteractions.ts +0 -28
  237. package/src/stage/crew/photographer/strategies/TakePhotosOfFailures.ts +0 -26
  238. package/src/stage/crew/photographer/strategies/TakePhotosOfInteractions.ts +0 -26
  239. package/src/stage/crew/photographer/strategies/index.ts +0 -4
  240. package/src/stage/index.ts +0 -1
@@ -1,401 +0,0 @@
1
- /* eslint-disable @typescript-eslint/explicit-module-boundary-types */
2
- import { Answerable, AnswersQuestions, Expectation, List, LogicError, MetaQuestion, Question, UsesAbilities } from '@serenity-js/core';
3
- import { formatted } from '@serenity-js/core/lib/io';
4
- import type { Element, ElementArray } from 'webdriverio';
5
-
6
- import { ElementArrayListAdapter } from './lists';
7
- import { Locator } from './locators';
8
- import { NestedTargetBuilder } from './NestedTargetBuilder';
9
- import { TargetBuilder } from './TargetBuilder';
10
-
11
- /**
12
- * @desc
13
- * A type alias representing a {@link @serenity-js/core/lib/screenplay/questions~List} of WebdriverIO Web elements.
14
- *
15
- * @public
16
- *
17
- * @see {@link @serenity-js/core/lib/screenplay/questions~List}
18
- *
19
- * @typedef {List<ElementArrayListAdapter, Promise<Element<'async'>>, Promise<ElementArray>>} TargetList
20
- */
21
- export type TargetList = List<ElementArrayListAdapter, Promise<Element<'async'>>, Promise<ElementArray>>;
22
-
23
- /**
24
- * @desc
25
- * Provides a convenient way to retrieve a single web element or multiple web elements,
26
- * so that they can be used with Serenity/JS {@link @serenity-js/core/lib/screenplay~Interaction}s.
27
- *
28
- * Check out the examples below, as well as the unit tests demonstrating the usage.
29
- *
30
- * @example <caption>Imaginary website under test</caption>
31
- * <body>
32
- * <ul id="basket">
33
- * <li><a href="#">Apple</a></li>
34
- * <li><a href="#">Banana</a></li>
35
- * <li><a href="#">Coconut</a></li>
36
- * <li><a href="#" class="has-discount">Date</a></li>
37
- * </ul>
38
- * <div id="summary">
39
- * <strong class="out-of-stock">Coconut</strong> is not available
40
- * </div>
41
- * <button type="submit">Proceed to Checkout</button>
42
- * </body>
43
- *
44
- * @example <caption>Locating a single element</caption>
45
- * import { by, Target, TargetElement } from '@serenity-js/webdriverio';
46
- *
47
- * const proceedToCheckoutButton: TargetElement =
48
- * Target.the('Proceed to Checkout button').located(by.css(`button[type='submit']`));
49
- *
50
- * @example <caption>Locating multiple elements</caption>
51
- * import { by, Target, TargetElements } from '@serenity-js/webdriverio';
52
- *
53
- * const basketItems: TargetElements =
54
- * Target.all('items in the basket').located(by.css('ul#basket li'));
55
- *
56
- * @example <caption>Locating element relative to another element</caption>
57
- * import { by, Target, TargetElement } from '@serenity-js/webdriverio';
58
- *
59
- * const summary: TargetElement =
60
- * Target.the('summary').located(by.id('message'));
61
- *
62
- * const outOfStockItem: TargetElement =
63
- * Target.the('out of stock item').of(summary).located(by.css('.out-of-stock'))
64
- *
65
- * @example <caption>Filtering elements matched by a locator</caption>
66
- * import { by, Target, Text } from '@serenity-js/webdriverio';
67
- * import { endsWith } from '@serenity-js/assertions';
68
- *
69
- * const basketItems =
70
- * Target.all('items in the basket').located(by.css('ul#basket li'))
71
- * .where(Text, endsWith('e')); // Apple, Date
72
- *
73
- * @example <caption>Counting items matched by a locator</caption>
74
- * import { endsWith } from '@serenity-js/assertions';
75
- * import { Question } from '@serenity-js/core';
76
- * import { by, Target, Text } from '@serenity-js/webdriverio';
77
- *
78
- * const basketItemsCount: Question<Promise<number>> =
79
- * Target.all('items in the basket').located(by.css('ul#basket li'))
80
- * .count() // 4
81
- *
82
- * @example <caption>Getting first item matched by a locator</caption>
83
- * import { Question } from '@serenity-js/core';
84
- * import { by, Target } from '@serenity-js/webdriverio';
85
- * import { Element } from 'webdriverio';
86
- *
87
- * const apple: Question<Promise<Element<'async'>>> =
88
- * Target.all('items in the basket').located(by.css('ul#basket li'))
89
- * .first()
90
- *
91
- * @example <caption>Getting last item matched by a locator</caption>
92
- * import { Question } from '@serenity-js/core';
93
- * import { by, Target } from '@serenity-js/webdriverio';
94
- * import { endsWith } from '@serenity-js/assertions';
95
- * import { Element } from 'webdriverio';
96
- *
97
- * const date: Question<Promise<Element<'async'>>> =
98
- * Target.all('items in the basket').located(by.css('ul#basket li'))
99
- * .last()
100
- *
101
- * @example <caption>Getting nth item matched by a locator</caption>
102
- * import { Question } from '@serenity-js/core';
103
- * import { by, Target } from '@serenity-js/webdriverio';
104
- * import { Element } from 'webdriverio';
105
- *
106
- * const banana: Question<Promise<Element<'async'>>> =
107
- * Target.all('items in the basket').located(by.css('ul#basket li'))
108
- * .get(1)
109
- *
110
- * @example <caption>Using multiple filters and nested targets</caption>
111
- * import { Question } from '@serenity-js/core';
112
- * import { contain, endsWith } from '@serenity-js/assertions';
113
- * import { by, CSSClasses, Target, Text } from '@serenity-js/webdriverio';
114
- * import { Element } from 'webdriverio';
115
- *
116
- * class Basket {
117
- * static component = Target.the('basket').located(by.id('basket'));
118
- *
119
- * static items = Target.all('items').located(by.css('li'))
120
- * .of(Basket.component);
121
- *
122
- * static link = Target.the('link').located(by.css('a'));
123
- * }
124
- *
125
- * const date: Question<Promise<Element<'async'>>> =
126
- * Basket.items
127
- * .where(Text, endsWith('e'))
128
- * .where(CSSClasses.of(Basket.link), contain('has-discount'))
129
- * .first()
130
- *
131
- * @example <caption>Clicking on an element</caption>
132
- * import { actorCalled } from '@serenity-js/core';
133
- * import { BrowseTheWeb, Click } from '@serenity-js/webdriverio';
134
- *
135
- * actorCalled('Jane')
136
- * .whoCan(BrowseTheWeb.using(browser))
137
- * .attemptsTo(
138
- * Click.on(proceedToCheckoutButton),
139
- * );
140
- *
141
- * @example <caption>Retrieving text of multiple elements and performing an assertion</caption>
142
- * import { Ensure, contain } from '@serenity-js/assertions';
143
- * import { actorCalled } from '@serenity-js/core';
144
- * import { BrowseTheWeb, Text } from '@serenity-js/webdriverio';
145
- *
146
- * const basketItemNames = Text.ofAll(basketItems);
147
- *
148
- * actorCalled('Jane')
149
- * .whoCan(BrowseTheWeb.using(browser))
150
- * .attemptsTo(
151
- * Ensure.that(basketItemNames, contain('Apple'))
152
- * );
153
- *
154
- * @example <caption>Waiting on an element</caption>
155
- * import { actorCalled } from '@serenity-js/core';
156
- * import { BrowseTheWeb, Wait, isClickable } from '@serenity-js/webdriverio';
157
- *
158
- * actorCalled('Jane')
159
- * .whoCan(BrowseTheWeb.using(browser))
160
- * .attemptsTo(
161
- * Wait.until(proceedToCheckoutButton, isClickable()),
162
- * );
163
- */
164
- export class Target {
165
-
166
- /**
167
- * @desc
168
- * Locates a single Web element
169
- *
170
- * @param {string} description
171
- * A human-readable name of the element, which will be used in the report
172
- *
173
- * @returns {TargetBuilder<TargetElement> & NestedTargetBuilder<TargetNestedElement>}
174
- */
175
- static the(description: string): TargetBuilder<TargetElement> & NestedTargetBuilder<TargetNestedElement> {
176
- return {
177
- located(locator: Locator): TargetElement {
178
- return new TargetElement(`the ${ description }`, locator);
179
- },
180
-
181
- of(parent: Answerable<Element<'async'>>) {
182
- return {
183
- located(locator: Locator): TargetNestedElement {
184
- return new TargetNestedElement(parent, new TargetElement(description, locator));
185
- }
186
- }
187
- }
188
- }
189
- }
190
-
191
- /**
192
- * @desc
193
- * Locates a group of Web elements
194
- *
195
- * @param {string} description
196
- * A human-readable name of the group of elements, which will be used in the report
197
- *
198
- * @returns {TargetBuilder<TargetElements> & NestedTargetBuilder<TargetNestedElements>}
199
- */
200
- static all(description: string): TargetBuilder<TargetElements> & NestedTargetBuilder<TargetNestedElements> {
201
- return {
202
- located(locator: Locator): TargetElements {
203
- return new TargetElements(description, locator);
204
- },
205
-
206
- of(parent: Answerable<Element<'async'>>) {
207
- return {
208
- located(locator: Locator): TargetNestedElements {
209
- return new TargetNestedElements(parent, new TargetElements(description, locator));
210
- }
211
- }
212
- }
213
- }
214
- }
215
- }
216
-
217
- /**
218
- * @desc
219
- * You probably don't want to use this class directly. See {@link Target} instead.
220
- *
221
- * @extends {@serenity-js/core/lib/screenplay~Question}
222
- * @implements {@serenity-js/core/lib/screenplay/questions~MetaQuestion}
223
- *
224
- * @see {@link Target}
225
- */
226
- export class TargetElements
227
- extends Question<Promise<ElementArray>>
228
- implements MetaQuestion<Answerable<Element<'async'>>, Promise<ElementArray>>
229
- {
230
- private readonly list: List<ElementArrayListAdapter, Promise<Element<'async'>>, Promise<ElementArray>>;
231
-
232
- constructor(
233
- description: string,
234
- private readonly locator: Locator,
235
- ) {
236
- super(description);
237
- this.list = new List(new ElementArrayListAdapter(this));
238
- }
239
-
240
- of(parent: Answerable<Element<'async'>>): TargetNestedElements {
241
- return new TargetNestedElements(parent, this);
242
- }
243
-
244
- count(): Question<Promise<number>> {
245
- return this.list.count();
246
- }
247
-
248
- first(): Question<Promise<Element<'async'>>> {
249
- return this.list.first()
250
- }
251
-
252
- last(): Question<Promise<Element<'async'>>> {
253
- return this.list.last()
254
- }
255
-
256
- get(index: number): Question<Promise<Element<'async'>>> {
257
- return this.list.get(index);
258
- }
259
-
260
- where<Answer_Type>(
261
- question: MetaQuestion<Answerable<Element<'async'>>, Promise<Answer_Type> | Answer_Type>,
262
- expectation: Expectation<any, Answer_Type>,
263
- ): TargetList {
264
- return this.list.where(question, expectation);
265
- }
266
-
267
- answeredBy(actor: AnswersQuestions & UsesAbilities): Promise<ElementArray> {
268
- return this.locator.allMatching()
269
- .describedAs(this.subject)
270
- .answeredBy(actor);
271
- }
272
- }
273
-
274
- /**
275
- * @desc
276
- * You probably don't want to use this class directly. See {@link Target} instead.
277
- *
278
- * @extends {@serenity-js/core/lib/screenplay~Question}
279
- * @implements {@serenity-js/core/lib/screenplay/questions~MetaQuestion}
280
- *
281
- * @see {@link Target}
282
- */
283
- export class TargetNestedElements
284
- extends Question<Promise<ElementArray>>
285
- implements MetaQuestion<Answerable<Element<'async'>>, Promise<ElementArray>>
286
- {
287
- private readonly list: List<ElementArrayListAdapter, Promise<Element<'async'>>, Promise<ElementArray>>;
288
-
289
- constructor(
290
- private readonly parent: Answerable<Element<'async'>>,
291
- private readonly children: Answerable<ElementArray>,
292
- ) {
293
- super(`${ children } of ${ parent }`);
294
- this.list = new List(new ElementArrayListAdapter(this));
295
- }
296
-
297
- of(parent: Answerable<Element<'async'>>): Question<Promise<ElementArray>> {
298
- return new TargetNestedElements(parent, this);
299
- }
300
-
301
- count(): Question<Promise<number>> {
302
- return this.list.count();
303
- }
304
-
305
- first(): Question<Promise<Element<'async'>>> {
306
- return this.list.first()
307
- }
308
-
309
- last(): Question<Promise<Element<'async'>>> {
310
- return this.list.last()
311
- }
312
-
313
- get(index: number): Question<Promise<Element<'async'>>> {
314
- return this.list.get(index);
315
- }
316
-
317
- where<Answer_Type>(
318
- question: MetaQuestion<Answerable<Element<'async'>>, Promise<Answer_Type> | Answer_Type>,
319
- expectation: Expectation<any, Answer_Type>,
320
- ): TargetList {
321
- return this.list.where(question, expectation);
322
- }
323
-
324
- async answeredBy(actor: AnswersQuestions & UsesAbilities): Promise<ElementArray> {
325
- const parent = await actor.answer(this.parent);
326
- const children = await actor.answer(this.children);
327
-
328
- if (! parent) {
329
- throw new LogicError(formatted `Couldn't find ${ this.parent }`);
330
- }
331
-
332
- return parent.$$(children.selector);
333
- }
334
- }
335
-
336
- /**
337
- * @desc
338
- * You probably don't want to use this class directly. See {@link Target} instead.
339
- *
340
- * @extends {@serenity-js/core/lib/screenplay~Question}
341
- * @implements {@serenity-js/core/lib/screenplay/questions~MetaQuestion}
342
- *
343
- * @see {@link Target}
344
- */
345
- export class TargetElement
346
- extends Question<Promise<Element<'async'>>>
347
- implements MetaQuestion<Answerable<Element<'async'>>, Promise<Element<'async'>>>
348
- {
349
- constructor(
350
- description: string,
351
- private readonly locator: Locator,
352
- ) {
353
- super(description);
354
- }
355
-
356
- of(parent: Answerable<Element<'async'>>): Question<Promise<Element<'async'>>> {
357
- return new TargetNestedElement(parent, this);
358
- }
359
-
360
- answeredBy(actor: AnswersQuestions & UsesAbilities): Promise<Element<'async'>> {
361
- return this.locator.firstMatching()
362
- .describedAs(this.subject)
363
- .answeredBy(actor);
364
- }
365
- }
366
-
367
- /**
368
- * @desc
369
- * You probably don't want to use this class directly. See {@link Target} instead.
370
- *
371
- * @extends {@serenity-js/core/lib/screenplay~Question}
372
- * @implements {@serenity-js/core/lib/screenplay/questions~MetaQuestion}
373
- *
374
- * @see {@link Target}
375
- */
376
- export class TargetNestedElement
377
- extends Question<Promise<Element<'async'>>>
378
- implements MetaQuestion<Answerable<Element<'async'>>, Promise<Element<'async'>>>
379
- {
380
- constructor(
381
- private readonly parent: Answerable<Element<'async'>>,
382
- private readonly child: Answerable<Element<'async'>>,
383
- ) {
384
- super(`${ child } of ${ parent }`);
385
- }
386
-
387
- of(parent: Answerable<Element<'async'>>): Question<Promise<Element<'async'>>> {
388
- return new TargetNestedElement(parent, this);
389
- }
390
-
391
- async answeredBy(actor: AnswersQuestions & UsesAbilities): Promise<Element<'async'>> {
392
- const parent = await actor.answer(this.parent);
393
- const child = await actor.answer(this.child);
394
-
395
- if (! parent) {
396
- throw new LogicError(formatted `Couldn't find ${ this.parent }`);
397
- }
398
-
399
- return parent.$(child.selector);
400
- }
401
- }
@@ -1 +0,0 @@
1
- export * from './photographer';
@@ -1,108 +0,0 @@
1
- import { LogicError } from '@serenity-js/core';
2
- import { ActivityFinished, ActivityStarts, DomainEvent } from '@serenity-js/core/lib/events';
3
- import { Stage, StageCrewMember } from '@serenity-js/core/lib/stage';
4
-
5
- import { PhotoTakingStrategy } from './strategies';
6
-
7
- /**
8
- * @desc
9
- * The Photographer is a {@link @serenity-js/core/lib/stage~StageCrewMember} who takes screenshots
10
- * of the web browser that the {@link @serenity-js/core/lib/screenplay/actor~Actor} in the spotlight is using.
11
- *
12
- * @example <caption>Assigning the Photographer to the Stage</caption>
13
- * // wdio.conf.ts
14
- * import { ArtifactArchiver } from '@serenity-js/core';
15
- * import { Photographer, TakePhotosOfFailures } from '@serenity-js/webdriverio';
16
- *
17
- * export const config = {
18
- *
19
- * serenity: {
20
- * crew: [
21
- * ArtifactArchiver.storingArtifactsAt(process.cwd(), 'target/site/serenity'),
22
- * Photographer.whoWill(TakePhotosOfFailures),
23
- * ]
24
- * },
25
- *
26
- * // ... rest of the config omitted for brevity
27
- * };
28
- *
29
- * @example <caption>Taking photos upon failures only</caption>
30
- *
31
- * import { Photographer, TakePhotosOfFailures } from '@serenity-js/webdriverio';
32
- *
33
- * Photographer.whoWill(TakePhotosOfFailures)
34
- *
35
- * @example <caption>Taking photos of all the interactions</caption>
36
- *
37
- * import { Photographer, TakePhotosOfInteractions } from '@serenity-js/webdriverio';
38
- *
39
- * Photographer.whoWill(TakePhotosOfInteractions)
40
- *
41
- * @example <caption>Taking photos before and after all the interactions</caption>
42
- *
43
- * import { Photographer, TakePhotosBeforeAndAfterInteractions } from '@serenity-js/webdriverio';
44
- *
45
- * Photographer.whoWill(TakePhotosBeforeAndAfterInteractions)
46
- *
47
- * @see {@link @serenity-js/core/lib/stage~Stage}
48
- * @see {@link TakePhotosBeforeAndAfterInteractions}
49
- * @see {@link TakePhotosOfFailures}
50
- * @see {@link TakePhotosOfInteractions}
51
- */
52
- export class Photographer implements StageCrewMember {
53
-
54
- /**
55
- * @desc
56
- * Instantiates a new {@link Photographer} configured to take photos (screenshots)
57
- * as per the specified {@link PhotoTakingStrategy}.
58
- *
59
- * @param {Function} strategy - A no-arg constructor function that instantiates a {@link PhotoTakingStrategy}.
60
- * @returns {StageCrewMember}
61
- */
62
- static whoWill(strategy: new () => PhotoTakingStrategy): StageCrewMember {
63
- return new Photographer(new strategy());
64
- }
65
-
66
- /**
67
- * @param {PhotoTakingStrategy} photoTakingStrategy
68
- * @param {Stage} stage
69
- */
70
- constructor(
71
- private readonly photoTakingStrategy: PhotoTakingStrategy,
72
- private stage?: Stage,
73
- ) {
74
- }
75
-
76
- /**
77
- * @desc
78
- * Creates a new instance of this {@link StageCrewMember} and assigns it to a given {@link Stage}.
79
- *
80
- * @param {Stage} stage - An instance of a {@link Stage} this {@link StageCrewMember} will be assigned to
81
- * @returns {StageCrewMember} - A new instance of this {@link StageCrewMember}
82
- */
83
- assignedTo(stage: Stage): StageCrewMember {
84
- return new Photographer(this.photoTakingStrategy, stage);
85
- }
86
-
87
- /**
88
- * @desc
89
- * Handles {@link DomainEvent} objects emitted by the {@link Stage}
90
- * this {@link StageCrewMember} is assigned to.
91
- *
92
- * @param {DomainEvent} event
93
- * @returns {void}
94
- */
95
- notifyOf(event: DomainEvent): void {
96
- if (! this.stage) {
97
- throw new LogicError(`Photographer needs to be assigned to the Stage before it can be notified of any DomainEvents`);
98
- }
99
-
100
- if (! this.stage.theShowHasStarted()) {
101
- return void 0;
102
- }
103
-
104
- if (event instanceof ActivityStarts || event instanceof ActivityFinished) {
105
- this.photoTakingStrategy.considerTakingPhoto(event, this.stage);
106
- }
107
- }
108
- }
@@ -1,2 +0,0 @@
1
- export * from './Photographer';
2
- export * from './strategies';
@@ -1,103 +0,0 @@
1
- import { Stage } from '@serenity-js/core';
2
- import {
3
- ActivityFinished,
4
- ActivityRelatedArtifactGenerated,
5
- ActivityStarts,
6
- AsyncOperationAttempted,
7
- AsyncOperationCompleted,
8
- AsyncOperationFailed,
9
- DomainEvent,
10
- } from '@serenity-js/core/lib/events';
11
- import { CorrelationId, Description, Name, Photo } from '@serenity-js/core/lib/model';
12
- import { Capabilities } from '@wdio/types';
13
-
14
- import { BrowseTheWeb } from '../../../../screenplay';
15
-
16
- /**
17
- * @desc
18
- * Configures the {@link Photographer} to take photos (a.k.a. screenshots)
19
- * of the {@link @serenity-js/core/lib/screenplay~Activity} performed
20
- * by the {@link @serenity-js/core/lib/screenplay/actor~Actor} in the spotlight
21
- * under specific conditions.
22
- *
23
- * @abstract
24
- */
25
- export abstract class PhotoTakingStrategy {
26
-
27
- /**
28
- * @desc
29
- * Takes a photo of the web browser held by the {@link @serenity-js/core/lib/screenplay/actor~Actor} in the spotlight.
30
- *
31
- * @param {@serenity-js/core/lib/events~ActivityStarts | @serenity-js/core/lib/events~ActivityFinished} event
32
- * @param {@serenity-js/core/lib/stage~Stage} stage - the Stage that holds reference to the Actor in the spotlight
33
- * @returns {void}
34
- *
35
- * @see {@link @serenity-js/core/lib/stage~Stage#theActorInTheSpotlight}
36
- */
37
- considerTakingPhoto(event: ActivityStarts | ActivityFinished, stage: Stage): void {
38
- if (this.shouldTakeAPhotoOf(event)) {
39
- let browseTheWeb: BrowseTheWeb;
40
-
41
- try {
42
- browseTheWeb = BrowseTheWeb.as(stage.theActorInTheSpotlight());
43
- } catch {
44
- return void 0;
45
- }
46
-
47
- const
48
- id = CorrelationId.create(),
49
- nameSuffix = this.photoNameFor(event),
50
- // todo: test if this type def is really DesiredCapabilities when multi-capabilities are used
51
- capabilities = browseTheWeb.browser.capabilities as Capabilities.DesiredCapabilities;
52
-
53
- stage.announce(new AsyncOperationAttempted(
54
- new Description(`[Photographer:${ this.constructor.name }] Taking screenshot of '${ nameSuffix }'...`),
55
- id,
56
- ));
57
-
58
- browseTheWeb.takeScreenshot().then(screenshot => {
59
-
60
- const
61
- context = [ capabilities.platformName, capabilities.browserName, capabilities.browserVersion ],
62
- photoName = this.combinedNameFrom(...context, nameSuffix);
63
-
64
- stage.announce(new ActivityRelatedArtifactGenerated(
65
- event.sceneId,
66
- event.activityId,
67
- photoName,
68
- Photo.fromBase64(screenshot),
69
- ));
70
-
71
- stage.announce(new AsyncOperationCompleted(
72
- new Description(`[${ this.constructor.name }] Took screenshot of '${ nameSuffix }' on ${ context }`),
73
- id,
74
- ));
75
- }).catch(error => {
76
- if (this.shouldIgnore(error)) {
77
- stage.announce(new AsyncOperationCompleted(
78
- new Description(`[${ this.constructor.name }] Aborted taking screenshot of '${ nameSuffix }' because of ${ error.constructor && error.constructor.name }`),
79
- id,
80
- ));
81
- }
82
- else {
83
- stage.announce(new AsyncOperationFailed(error, id));
84
- }
85
- });
86
- }
87
- }
88
-
89
- protected abstract shouldTakeAPhotoOf(event: DomainEvent): boolean;
90
-
91
- protected abstract photoNameFor(event: DomainEvent): string;
92
-
93
- private combinedNameFrom(...parts: string[]): Name {
94
- return new Name(parts.filter(v => !! v).join('-'));
95
- }
96
-
97
- private shouldIgnore(error: Error) {
98
- // todo
99
- // return error instanceof webdriver.NoSuchSessionError
100
- // || error instanceof webdriver.UnexpectedAlertOpenError
101
- return false;
102
- }
103
- }
@@ -1,28 +0,0 @@
1
- import { DomainEvent, InteractionFinished, InteractionStarts } from '@serenity-js/core/lib/events';
2
-
3
- import { PhotoTakingStrategy } from './PhotoTakingStrategy';
4
-
5
- /**
6
- * @desc
7
- * Configures the {@link Photographer} to take photos (a.k.a. screenshots) both before and after
8
- * every single {@link @serenity-js/core/lib/screenplay~Interaction} performed
9
- * by the {@link @serenity-js/core/lib/screenplay/actor~Actor} in the spotlight.
10
- *
11
- * *Please note* that this strategy will result in _a lot_ of screenshots being taken,
12
- * which will seriously affect the performance of your tests.
13
- * For this reason, it's best to use it only for debugging purposes.
14
- *
15
- * @extends {PhotoTakingStrategy}
16
- */
17
- export class TakePhotosBeforeAndAfterInteractions extends PhotoTakingStrategy {
18
- protected shouldTakeAPhotoOf(event: DomainEvent): boolean {
19
- return event instanceof InteractionStarts
20
- || event instanceof InteractionFinished;
21
- }
22
-
23
- protected photoNameFor(event: InteractionStarts | InteractionFinished): string {
24
- return event instanceof InteractionStarts
25
- ? `Before ${ event.details.name.value }`
26
- : `After ${ event.details.name.value }`;
27
- }
28
- }
@@ -1,26 +0,0 @@
1
- import { DomainEvent, InteractionFinished } from '@serenity-js/core/lib/events';
2
- import { ImplementationPending } from '@serenity-js/core/lib/model';
3
-
4
- import { PhotoTakingStrategy } from './PhotoTakingStrategy';
5
-
6
- /**
7
- * @desc
8
- * Configures the {@link Photographer} to take photos (a.k.a. screenshots) when
9
- * the {@link @serenity-js/core/lib/screenplay~Interaction} performed
10
- * by the {@link @serenity-js/core/lib/screenplay/actor~Actor} in the spotlight results in an error.
11
- *
12
- * This strategy works best when you are interested in the screenshots only when
13
- * a scenario fails.
14
- *
15
- * @extends {PhotoTakingStrategy}
16
- */
17
- export class TakePhotosOfFailures extends PhotoTakingStrategy {
18
- protected shouldTakeAPhotoOf(event: DomainEvent): boolean {
19
- return event instanceof InteractionFinished
20
- && event.outcome.isWorseThan(ImplementationPending);
21
- }
22
-
23
- protected photoNameFor(event: InteractionFinished): string {
24
- return event.details.name.value;
25
- }
26
- }