@serenity-js/web 3.0.0-rc.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 (250) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/LICENSE.md +201 -0
  3. package/NOTICE.md +1 -0
  4. package/README.md +21 -0
  5. package/lib/errors/CookieMissingError.d.ts +4 -0
  6. package/lib/errors/CookieMissingError.js +11 -0
  7. package/lib/errors/CookieMissingError.js.map +1 -0
  8. package/lib/errors/index.d.ts +1 -0
  9. package/lib/errors/index.js +14 -0
  10. package/lib/errors/index.js.map +1 -0
  11. package/lib/expectations/ElementExpectation.d.ts +11 -0
  12. package/lib/expectations/ElementExpectation.js +27 -0
  13. package/lib/expectations/ElementExpectation.js.map +1 -0
  14. package/lib/expectations/index.d.ts +6 -0
  15. package/lib/expectations/index.js +19 -0
  16. package/lib/expectations/index.js.map +1 -0
  17. package/lib/expectations/isActive.d.ts +15 -0
  18. package/lib/expectations/isActive.js +22 -0
  19. package/lib/expectations/isActive.js.map +1 -0
  20. package/lib/expectations/isClickable.d.ts +20 -0
  21. package/lib/expectations/isClickable.js +30 -0
  22. package/lib/expectations/isClickable.js.map +1 -0
  23. package/lib/expectations/isEnabled.d.ts +14 -0
  24. package/lib/expectations/isEnabled.js +20 -0
  25. package/lib/expectations/isEnabled.js.map +1 -0
  26. package/lib/expectations/isPresent.d.ts +15 -0
  27. package/lib/expectations/isPresent.js +22 -0
  28. package/lib/expectations/isPresent.js.map +1 -0
  29. package/lib/expectations/isSelected.d.ts +14 -0
  30. package/lib/expectations/isSelected.js +23 -0
  31. package/lib/expectations/isSelected.js.map +1 -0
  32. package/lib/expectations/isVisible.d.ts +14 -0
  33. package/lib/expectations/isVisible.js +26 -0
  34. package/lib/expectations/isVisible.js.map +1 -0
  35. package/lib/index.d.ts +5 -0
  36. package/lib/index.js +18 -0
  37. package/lib/index.js.map +1 -0
  38. package/lib/input/Key.d.ts +73 -0
  39. package/lib/input/Key.js +84 -0
  40. package/lib/input/Key.js.map +1 -0
  41. package/lib/input/index.d.ts +1 -0
  42. package/lib/input/index.js +14 -0
  43. package/lib/input/index.js.map +1 -0
  44. package/lib/screenplay/abilities/BrowseTheWeb.d.ts +58 -0
  45. package/lib/screenplay/abilities/BrowseTheWeb.js +19 -0
  46. package/lib/screenplay/abilities/BrowseTheWeb.js.map +1 -0
  47. package/lib/screenplay/abilities/BrowserCapabilities.d.ts +5 -0
  48. package/lib/screenplay/abilities/BrowserCapabilities.js +3 -0
  49. package/lib/screenplay/abilities/BrowserCapabilities.js.map +1 -0
  50. package/lib/screenplay/abilities/index.d.ts +2 -0
  51. package/lib/screenplay/abilities/index.js +15 -0
  52. package/lib/screenplay/abilities/index.js.map +1 -0
  53. package/lib/screenplay/index.d.ts +4 -0
  54. package/lib/screenplay/index.js +17 -0
  55. package/lib/screenplay/index.js.map +1 -0
  56. package/lib/screenplay/interactions/Clear.d.ts +79 -0
  57. package/lib/screenplay/interactions/Clear.js +97 -0
  58. package/lib/screenplay/interactions/Clear.js.map +1 -0
  59. package/lib/screenplay/interactions/Click.d.ts +73 -0
  60. package/lib/screenplay/interactions/Click.js +85 -0
  61. package/lib/screenplay/interactions/Click.js.map +1 -0
  62. package/lib/screenplay/interactions/DoubleClick.d.ts +90 -0
  63. package/lib/screenplay/interactions/DoubleClick.js +101 -0
  64. package/lib/screenplay/interactions/DoubleClick.js.map +1 -0
  65. package/lib/screenplay/interactions/Enter.d.ts +73 -0
  66. package/lib/screenplay/interactions/Enter.js +86 -0
  67. package/lib/screenplay/interactions/Enter.js.map +1 -0
  68. package/lib/screenplay/interactions/EnterBuilder.d.ts +25 -0
  69. package/lib/screenplay/interactions/EnterBuilder.js +3 -0
  70. package/lib/screenplay/interactions/EnterBuilder.js.map +1 -0
  71. package/lib/screenplay/interactions/ExecuteScript.d.ts +206 -0
  72. package/lib/screenplay/interactions/ExecuteScript.js +312 -0
  73. package/lib/screenplay/interactions/ExecuteScript.js.map +1 -0
  74. package/lib/screenplay/interactions/Hover.d.ts +78 -0
  75. package/lib/screenplay/interactions/Hover.js +89 -0
  76. package/lib/screenplay/interactions/Hover.js.map +1 -0
  77. package/lib/screenplay/interactions/Navigate.d.ts +142 -0
  78. package/lib/screenplay/interactions/Navigate.js +198 -0
  79. package/lib/screenplay/interactions/Navigate.js.map +1 -0
  80. package/lib/screenplay/interactions/PageElementInteraction.d.ts +39 -0
  81. package/lib/screenplay/interactions/PageElementInteraction.js +54 -0
  82. package/lib/screenplay/interactions/PageElementInteraction.js.map +1 -0
  83. package/lib/screenplay/interactions/Press.d.ts +84 -0
  84. package/lib/screenplay/interactions/Press.js +171 -0
  85. package/lib/screenplay/interactions/Press.js.map +1 -0
  86. package/lib/screenplay/interactions/PressBuilder.d.ts +26 -0
  87. package/lib/screenplay/interactions/PressBuilder.js +3 -0
  88. package/lib/screenplay/interactions/PressBuilder.js.map +1 -0
  89. package/lib/screenplay/interactions/RightClick.d.ts +89 -0
  90. package/lib/screenplay/interactions/RightClick.js +100 -0
  91. package/lib/screenplay/interactions/RightClick.js.map +1 -0
  92. package/lib/screenplay/interactions/Scroll.d.ts +83 -0
  93. package/lib/screenplay/interactions/Scroll.js +97 -0
  94. package/lib/screenplay/interactions/Scroll.js.map +1 -0
  95. package/lib/screenplay/interactions/Select.d.ts +212 -0
  96. package/lib/screenplay/interactions/Select.js +291 -0
  97. package/lib/screenplay/interactions/Select.js.map +1 -0
  98. package/lib/screenplay/interactions/SelectBuilder.d.ts +33 -0
  99. package/lib/screenplay/interactions/SelectBuilder.js +3 -0
  100. package/lib/screenplay/interactions/SelectBuilder.js.map +1 -0
  101. package/lib/screenplay/interactions/Switch.d.ts +150 -0
  102. package/lib/screenplay/interactions/Switch.js +209 -0
  103. package/lib/screenplay/interactions/Switch.js.map +1 -0
  104. package/lib/screenplay/interactions/TakeScreenshot.d.ts +67 -0
  105. package/lib/screenplay/interactions/TakeScreenshot.js +86 -0
  106. package/lib/screenplay/interactions/TakeScreenshot.js.map +1 -0
  107. package/lib/screenplay/interactions/Wait.d.ts +143 -0
  108. package/lib/screenplay/interactions/Wait.js +242 -0
  109. package/lib/screenplay/interactions/Wait.js.map +1 -0
  110. package/lib/screenplay/interactions/WaitBuilder.d.ts +32 -0
  111. package/lib/screenplay/interactions/WaitBuilder.js +3 -0
  112. package/lib/screenplay/interactions/WaitBuilder.js.map +1 -0
  113. package/lib/screenplay/interactions/index.d.ts +16 -0
  114. package/lib/screenplay/interactions/index.js +29 -0
  115. package/lib/screenplay/interactions/index.js.map +1 -0
  116. package/lib/screenplay/models/Cookie.d.ts +117 -0
  117. package/lib/screenplay/models/Cookie.js +176 -0
  118. package/lib/screenplay/models/Cookie.js.map +1 -0
  119. package/lib/screenplay/models/CookieData.d.ts +89 -0
  120. package/lib/screenplay/models/CookieData.js +3 -0
  121. package/lib/screenplay/models/CookieData.js.map +1 -0
  122. package/lib/screenplay/models/ModalDialog.d.ts +9 -0
  123. package/lib/screenplay/models/ModalDialog.js +14 -0
  124. package/lib/screenplay/models/ModalDialog.js.map +1 -0
  125. package/lib/screenplay/models/Page.d.ts +83 -0
  126. package/lib/screenplay/models/Page.js +52 -0
  127. package/lib/screenplay/models/Page.js.map +1 -0
  128. package/lib/screenplay/models/PageElement.d.ts +30 -0
  129. package/lib/screenplay/models/PageElement.js +62 -0
  130. package/lib/screenplay/models/PageElement.js.map +1 -0
  131. package/lib/screenplay/models/PageElements.d.ts +20 -0
  132. package/lib/screenplay/models/PageElements.js +49 -0
  133. package/lib/screenplay/models/PageElements.js.map +1 -0
  134. package/lib/screenplay/models/index.d.ts +6 -0
  135. package/lib/screenplay/models/index.js +19 -0
  136. package/lib/screenplay/models/index.js.map +1 -0
  137. package/lib/screenplay/questions/Attribute.d.ts +83 -0
  138. package/lib/screenplay/questions/Attribute.js +103 -0
  139. package/lib/screenplay/questions/Attribute.js.map +1 -0
  140. package/lib/screenplay/questions/CssClasses.d.ts +93 -0
  141. package/lib/screenplay/questions/CssClasses.js +113 -0
  142. package/lib/screenplay/questions/CssClasses.js.map +1 -0
  143. package/lib/screenplay/questions/ElementQuestion.d.ts +34 -0
  144. package/lib/screenplay/questions/ElementQuestion.js +53 -0
  145. package/lib/screenplay/questions/ElementQuestion.js.map +1 -0
  146. package/lib/screenplay/questions/LastScriptExecution.d.ts +14 -0
  147. package/lib/screenplay/questions/LastScriptExecution.js +22 -0
  148. package/lib/screenplay/questions/LastScriptExecution.js.map +1 -0
  149. package/lib/screenplay/questions/Selected.d.ts +185 -0
  150. package/lib/screenplay/questions/Selected.js +210 -0
  151. package/lib/screenplay/questions/Selected.js.map +1 -0
  152. package/lib/screenplay/questions/Text.d.ts +99 -0
  153. package/lib/screenplay/questions/Text.js +131 -0
  154. package/lib/screenplay/questions/Text.js.map +1 -0
  155. package/lib/screenplay/questions/Value.d.ts +64 -0
  156. package/lib/screenplay/questions/Value.js +78 -0
  157. package/lib/screenplay/questions/Value.js.map +1 -0
  158. package/lib/screenplay/questions/index.d.ts +6 -0
  159. package/lib/screenplay/questions/index.js +19 -0
  160. package/lib/screenplay/questions/index.js.map +1 -0
  161. package/lib/stage/crew/index.d.ts +1 -0
  162. package/lib/stage/crew/index.js +14 -0
  163. package/lib/stage/crew/index.js.map +1 -0
  164. package/lib/stage/crew/photographer/Photographer.d.ts +83 -0
  165. package/lib/stage/crew/photographer/Photographer.js +102 -0
  166. package/lib/stage/crew/photographer/Photographer.js.map +1 -0
  167. package/lib/stage/crew/photographer/index.d.ts +2 -0
  168. package/lib/stage/crew/photographer/index.js +15 -0
  169. package/lib/stage/crew/photographer/index.js.map +1 -0
  170. package/lib/stage/crew/photographer/strategies/PhotoTakingStrategy.d.ts +28 -0
  171. package/lib/stage/crew/photographer/strategies/PhotoTakingStrategy.js +81 -0
  172. package/lib/stage/crew/photographer/strategies/PhotoTakingStrategy.js.map +1 -0
  173. package/lib/stage/crew/photographer/strategies/TakePhotosBeforeAndAfterInteractions.d.ts +18 -0
  174. package/lib/stage/crew/photographer/strategies/TakePhotosBeforeAndAfterInteractions.js +30 -0
  175. package/lib/stage/crew/photographer/strategies/TakePhotosBeforeAndAfterInteractions.js.map +1 -0
  176. package/lib/stage/crew/photographer/strategies/TakePhotosOfFailures.d.ts +17 -0
  177. package/lib/stage/crew/photographer/strategies/TakePhotosOfFailures.js +28 -0
  178. package/lib/stage/crew/photographer/strategies/TakePhotosOfFailures.js.map +1 -0
  179. package/lib/stage/crew/photographer/strategies/TakePhotosOfInteractions.d.ts +19 -0
  180. package/lib/stage/crew/photographer/strategies/TakePhotosOfInteractions.js +28 -0
  181. package/lib/stage/crew/photographer/strategies/TakePhotosOfInteractions.js.map +1 -0
  182. package/lib/stage/crew/photographer/strategies/index.d.ts +4 -0
  183. package/lib/stage/crew/photographer/strategies/index.js +17 -0
  184. package/lib/stage/crew/photographer/strategies/index.js.map +1 -0
  185. package/lib/stage/index.d.ts +1 -0
  186. package/lib/stage/index.js +14 -0
  187. package/lib/stage/index.js.map +1 -0
  188. package/package.json +85 -0
  189. package/src/errors/CookieMissingError.ts +7 -0
  190. package/src/errors/index.ts +1 -0
  191. package/src/expectations/ElementExpectation.ts +32 -0
  192. package/src/expectations/index.ts +6 -0
  193. package/src/expectations/isActive.ts +22 -0
  194. package/src/expectations/isClickable.ts +32 -0
  195. package/src/expectations/isEnabled.ts +19 -0
  196. package/src/expectations/isPresent.ts +21 -0
  197. package/src/expectations/isSelected.ts +24 -0
  198. package/src/expectations/isVisible.ts +28 -0
  199. package/src/index.ts +5 -0
  200. package/src/input/Key.ts +83 -0
  201. package/src/input/index.ts +1 -0
  202. package/src/screenplay/abilities/BrowseTheWeb.ts +89 -0
  203. package/src/screenplay/abilities/BrowserCapabilities.ts +5 -0
  204. package/src/screenplay/abilities/index.ts +2 -0
  205. package/src/screenplay/index.ts +4 -0
  206. package/src/screenplay/interactions/Clear.ts +102 -0
  207. package/src/screenplay/interactions/Click.ts +86 -0
  208. package/src/screenplay/interactions/DoubleClick.ts +102 -0
  209. package/src/screenplay/interactions/Enter.ts +92 -0
  210. package/src/screenplay/interactions/EnterBuilder.ts +28 -0
  211. package/src/screenplay/interactions/ExecuteScript.ts +345 -0
  212. package/src/screenplay/interactions/Hover.ts +90 -0
  213. package/src/screenplay/interactions/Navigate.ts +209 -0
  214. package/src/screenplay/interactions/PageElementInteraction.ts +59 -0
  215. package/src/screenplay/interactions/Press.ts +194 -0
  216. package/src/screenplay/interactions/PressBuilder.ts +29 -0
  217. package/src/screenplay/interactions/RightClick.ts +100 -0
  218. package/src/screenplay/interactions/Scroll.ts +99 -0
  219. package/src/screenplay/interactions/Select.ts +317 -0
  220. package/src/screenplay/interactions/SelectBuilder.ts +36 -0
  221. package/src/screenplay/interactions/Switch.ts +225 -0
  222. package/src/screenplay/interactions/TakeScreenshot.ts +89 -0
  223. package/src/screenplay/interactions/Wait.ts +264 -0
  224. package/src/screenplay/interactions/WaitBuilder.ts +34 -0
  225. package/src/screenplay/interactions/index.ts +16 -0
  226. package/src/screenplay/models/Cookie.ts +219 -0
  227. package/src/screenplay/models/CookieData.ts +97 -0
  228. package/src/screenplay/models/ModalDialog.ts +19 -0
  229. package/src/screenplay/models/Page.ts +147 -0
  230. package/src/screenplay/models/PageElement.ts +95 -0
  231. package/src/screenplay/models/PageElements.ts +70 -0
  232. package/src/screenplay/models/index.ts +6 -0
  233. package/src/screenplay/questions/Attribute.ts +112 -0
  234. package/src/screenplay/questions/CssClasses.ts +118 -0
  235. package/src/screenplay/questions/ElementQuestion.ts +60 -0
  236. package/src/screenplay/questions/LastScriptExecution.ts +21 -0
  237. package/src/screenplay/questions/Selected.ts +212 -0
  238. package/src/screenplay/questions/Text.ts +153 -0
  239. package/src/screenplay/questions/Value.ts +82 -0
  240. package/src/screenplay/questions/index.ts +6 -0
  241. package/src/stage/crew/index.ts +1 -0
  242. package/src/stage/crew/photographer/Photographer.ts +108 -0
  243. package/src/stage/crew/photographer/index.ts +2 -0
  244. package/src/stage/crew/photographer/strategies/PhotoTakingStrategy.ts +116 -0
  245. package/src/stage/crew/photographer/strategies/TakePhotosBeforeAndAfterInteractions.ts +28 -0
  246. package/src/stage/crew/photographer/strategies/TakePhotosOfFailures.ts +26 -0
  247. package/src/stage/crew/photographer/strategies/TakePhotosOfInteractions.ts +26 -0
  248. package/src/stage/crew/photographer/strategies/index.ts +4 -0
  249. package/src/stage/index.ts +1 -0
  250. package/tsconfig.eslint.json +10 -0
@@ -0,0 +1,32 @@
1
+ import { AnswersQuestions, Expectation, ExpectationMet, ExpectationNotMet, ExpectationOutcome } from '@serenity-js/core';
2
+
3
+ import { PageElement } from '../screenplay';
4
+
5
+ /**
6
+ * @access private
7
+ */
8
+ export class ElementExpectation extends Expectation<any, PageElement> {
9
+ static forElementTo(message: string, fn: (actual: PageElement) => Promise<boolean>): Expectation<any, PageElement> {
10
+ return new ElementExpectation(message, fn);
11
+ }
12
+
13
+ constructor(
14
+ subject: string,
15
+ private readonly fn: (actual: PageElement) => Promise<boolean>,
16
+ ) {
17
+ super(subject);
18
+ }
19
+
20
+ answeredBy(actor: AnswersQuestions): (actual: PageElement) => Promise<ExpectationOutcome<boolean, PageElement>> {
21
+ return (actual: PageElement) =>
22
+ this.fn(actual)
23
+ .then(expectationMet =>
24
+ expectationMet
25
+ ? new ExpectationMet(this.toString(), undefined, actual)
26
+ : new ExpectationNotMet(this.toString(), undefined, actual),
27
+ )
28
+ .catch(error => {
29
+ return new ExpectationNotMet(`${ this.toString() } (${ error.message })`, undefined, actual);
30
+ });
31
+ }
32
+ }
@@ -0,0 +1,6 @@
1
+ export * from './isActive';
2
+ export * from './isClickable';
3
+ export * from './isEnabled';
4
+ export * from './isPresent';
5
+ export * from './isSelected';
6
+ export * from './isVisible';
@@ -0,0 +1,22 @@
1
+ import { Expectation } from '@serenity-js/core';
2
+
3
+ import { PageElement } from '../screenplay';
4
+ import { ElementExpectation } from './ElementExpectation';
5
+
6
+ /**
7
+ * @desc
8
+ * Expectation that the element is active (has focus).
9
+ * If the selector matches multiple elements, it will return true if one of the elements has focus.
10
+ *
11
+ * @returns {@serenity-js/core/lib/screenplay/questions~Expectation<boolean, Element<'async'>>}
12
+ *
13
+ * @see https://webdriver.io/docs/api/element/isFocused/
14
+ * @see {@link @serenity-js/assertions~Ensure}
15
+ * @see {@link @serenity-js/core/lib/screenplay/questions~Check}
16
+ * @see {@link Wait}
17
+ */
18
+ // todo: isFocused?
19
+ export function isActive(): Expectation<boolean, PageElement> {
20
+ return ElementExpectation.forElementTo('become active', actual => actual.isActive());
21
+ }
22
+
@@ -0,0 +1,32 @@
1
+ import { and } from '@serenity-js/assertions';
2
+ import { Expectation } from '@serenity-js/core';
3
+
4
+ import { PageElement } from '../screenplay';
5
+ import { ElementExpectation } from './ElementExpectation';
6
+ import { isEnabled } from './isEnabled';
7
+ import { isVisible } from './isVisible';
8
+
9
+ /**
10
+ * @desc
11
+ * Expectation that an element is clickable, which means:
12
+ * - it exists
13
+ * - it is visible
14
+ * - it is within viewport (if not, try to scroll to it)
15
+ * - its center is not overlapped with another element
16
+ * - it is not disabled
17
+ * otherwise return false.
18
+ *
19
+ * @returns {@serenity-js/core/lib/screenplay/questions~Expectation<boolean, Element<'async'>>}
20
+ *
21
+ * @see https://webdriver.io/docs/api/element/isClickable/
22
+ * @see {@link @serenity-js/assertions~Ensure}
23
+ * @see {@link @serenity-js/core/lib/screenplay/questions~Check}
24
+ * @see {@link Wait}
25
+ */
26
+ export function isClickable(): Expectation<boolean, PageElement> {
27
+ return Expectation.to<PageElement>('become clickable').soThatActual(and(
28
+ isVisible(),
29
+ isEnabled(),
30
+ ElementExpectation.forElementTo('become clickable', actual => actual.isClickable())
31
+ ));
32
+ }
@@ -0,0 +1,19 @@
1
+ import { Expectation } from '@serenity-js/core';
2
+
3
+ import { PageElement } from '../screenplay';
4
+ import { ElementExpectation } from './ElementExpectation';
5
+
6
+ /**
7
+ * @desc
8
+ * Expectation that the element is enabled.
9
+ *
10
+ * @returns {@serenity-js/core/lib/screenplay/questions~Expectation<boolean, Element<'async'>>}
11
+ *
12
+ * @see https://webdriver.io/docs/api/element/isEnabled/
13
+ * @see {@link @serenity-js/assertions~Ensure}
14
+ * @see {@link @serenity-js/core/lib/screenplay/questions~Check}
15
+ * @see {@link Wait}
16
+ */
17
+ export function isEnabled(): Expectation<boolean, PageElement> {
18
+ return ElementExpectation.forElementTo('become enabled', actual => actual.isEnabled());
19
+ }
@@ -0,0 +1,21 @@
1
+ import { Expectation } from '@serenity-js/core';
2
+
3
+ import { PageElement } from '../screenplay';
4
+ import { ElementExpectation } from './ElementExpectation';
5
+
6
+ /**
7
+ * @desc
8
+ * Expectation that the element is present in the DOM of a page.
9
+ * Please note that this does not necessarily mean that the element is visible.
10
+ *
11
+ * @returns {@serenity-js/core/lib/screenplay/questions~Expectation<boolean, Element<'async'>>}
12
+ *
13
+ * @see https://webdriver.io/docs/api/element/isExisting/
14
+ * @see {@link @serenity-js/assertions~Ensure}
15
+ * @see {@link @serenity-js/core/lib/screenplay/questions~Check}
16
+ * @see {@link Wait}
17
+ */
18
+ // todo: make it generic isPresent: Promise<boolean> | boolean
19
+ export function isPresent(): Expectation<boolean, PageElement> {
20
+ return ElementExpectation.forElementTo('become present', actual => actual.isPresent());
21
+ }
@@ -0,0 +1,24 @@
1
+ import { and } from '@serenity-js/assertions';
2
+ import { Expectation } from '@serenity-js/core';
3
+
4
+ import { PageElement } from '../screenplay';
5
+ import { ElementExpectation } from './ElementExpectation';
6
+ import { isPresent } from './isPresent';
7
+
8
+ /**
9
+ * @desc
10
+ * Expectation that an `<option>` or `<input>` element of type checkbox or radio is currently selected.
11
+ *
12
+ * @returns {@serenity-js/core/lib/screenplay/questions~Expectation<boolean, Element<'async'>>}
13
+ *
14
+ * @see https://webdriver.io/docs/api/element/isSelected/
15
+ * @see {@link @serenity-js/assertions~Ensure}
16
+ * @see {@link @serenity-js/core/lib/screenplay/questions~Check}
17
+ * @see {@link Wait}
18
+ */
19
+ export function isSelected(): Expectation<boolean, PageElement> {
20
+ return Expectation.to<PageElement>('become selected').soThatActual(and(
21
+ isPresent(),
22
+ ElementExpectation.forElementTo('become selected', actual => actual.isSelected()),
23
+ ));
24
+ }
@@ -0,0 +1,28 @@
1
+ import { and } from '@serenity-js/assertions';
2
+ import { Expectation } from '@serenity-js/core';
3
+
4
+ import { PageElement } from '../screenplay';
5
+ import { ElementExpectation } from './ElementExpectation';
6
+ import { isPresent } from './isPresent';
7
+
8
+ /**
9
+ * @desc
10
+ * Expectation that the element is present in the DOM of the page and visible.
11
+ *
12
+ * @returns {@serenity-js/core/lib/screenplay/questions~Expectation<boolean, Element<'async'>>}
13
+ *
14
+ * @see https://webdriver.io/docs/api/element/isDisplayed/
15
+ * @see {@link @serenity-js/assertions~Ensure}
16
+ * @see {@link @serenity-js/core/lib/screenplay/questions~Check}
17
+ * @see {@link Wait}
18
+ */
19
+ export function isVisible(): Expectation<boolean, PageElement> {
20
+ return Expectation.to<PageElement>('become visible').soThatActual(and(
21
+ isPresent(),
22
+ isDisplayed(),
23
+ ));
24
+ }
25
+
26
+ function isDisplayed(): Expectation<any, PageElement> {
27
+ return ElementExpectation.forElementTo('become displayed', actual => actual.isDisplayed());
28
+ }
package/src/index.ts ADDED
@@ -0,0 +1,5 @@
1
+ export * from './errors';
2
+ export * from './expectations';
3
+ export * from './input';
4
+ export * from './screenplay';
5
+ export * from './stage';
@@ -0,0 +1,83 @@
1
+ /**
2
+ * @desc
3
+ * Represents pressable keys that aren't text to be used with {@link Press}.
4
+ *
5
+ * Note that modifier like Shift, Alt and Meta (a.k.a. Command on Mac) will stay pressed
6
+ *
7
+ * @enum {string}
8
+ * @see {@link Press}
9
+ * @see https://w3c.github.io/webdriver/webdriver-spec.html#keyboard-actions
10
+ * @see https://github.com/puppeteer/puppeteer/blob/v7.1.0/src/common/USKeyboardLayout.ts
11
+ * @see https://github.com/SeleniumHQ/selenium/blob/trunk/javascript/node/selenium-webdriver/lib/input.js#L46
12
+ * @see https://github.com/webdriverio/webdriverio/blob/main/packages/wdio-utils/src/constants.ts#L5
13
+ */
14
+ export class Key {
15
+ public static Alt = new Key('Alt', '\uE00A', true);
16
+ public static ArrowDown = new Key('ArrowDown', '\uE015');
17
+ public static ArrowLeft = new Key('ArrowLeft', '\uE012');
18
+ public static ArrowRight = new Key('ArrowRight', '\uE014');
19
+ public static ArrowUp = new Key('ArrowUp', '\uE013');
20
+ public static Backspace = new Key('Backspace', '\uE003');
21
+ public static Cancel = new Key('Cancel', '\uE001');
22
+ public static Clear = new Key('Clear', '\uE005');
23
+ public static Control = new Key('Control', '\uE009', true);
24
+ public static Delete = new Key('Delete', '\uE017');
25
+ public static End = new Key('End', '\uE010');
26
+ public static Enter = new Key('Enter', '\uE007');
27
+ public static Escape = new Key('Escape', '\uE00C');
28
+ public static F1 = new Key('F1', '\uE031');
29
+ public static F2 = new Key('F2', '\uE032');
30
+ public static F3 = new Key('F3', '\uE033');
31
+ public static F4 = new Key('F4', '\uE034');
32
+ public static F5 = new Key('F5', '\uE035');
33
+ public static F6 = new Key('F6', '\uE036');
34
+ public static F7 = new Key('F7', '\uE037');
35
+ public static F8 = new Key('F8', '\uE038');
36
+ public static F9 = new Key('F9', '\uE039');
37
+ public static F10 = new Key('F10', '\uE03A');
38
+ public static F11 = new Key('F11', '\uE03B');
39
+ public static F12 = new Key('F12', '\uE03C');
40
+ public static Help = new Key('Help', '\uE002');
41
+ public static Home = new Key('Home', '\uE011');
42
+ public static Insert = new Key('Insert', '\uE016');
43
+ public static Meta = new Key('Meta', '\uE03D', true);
44
+ public static Numpad0 = new Key('Numpad0', '\uE01A');
45
+ public static Numpad1 = new Key('Numpad1', '\uE01B');
46
+ public static Numpad2 = new Key('Numpad2', '\uE01C');
47
+ public static Numpad3 = new Key('Numpad3', '\uE01D');
48
+ public static Numpad4 = new Key('Numpad4', '\uE01E');
49
+ public static Numpad5 = new Key('Numpad5', '\uE01F');
50
+ public static Numpad6 = new Key('Numpad6', '\uE020');
51
+ public static Numpad7 = new Key('Numpad7', '\uE021');
52
+ public static Numpad8 = new Key('Numpad8', '\uE022');
53
+ public static Numpad9 = new Key('Numpad9', '\uE023');
54
+ public static NumpadAdd = new Key('NumpadAdd', '\uE025');
55
+ public static NumpadDecimal = new Key('NumpadDecimal', '\uE028');
56
+ public static NumpadDivide = new Key('NumpadDivide', '\uE029');
57
+ public static NumpadEqual = new Key('NumpadEqual', '\uE019');
58
+ public static NumpadMultiply = new Key('NumpadMultiply', '\uE024');
59
+ public static NumpadSubtract = new Key('NumpadSubtract', '\uE027');
60
+ public static PageDown = new Key('PageDown', '\uE00F');
61
+ public static PageUp = new Key('PageUp', '\uE00E');
62
+ public static Pause = new Key('Pause', '\uE00B');
63
+ public static Semicolon = new Key('Semicolon', '\uE018');
64
+ public static Shift = new Key('Shift', '\uE008', true);
65
+ public static Space = new Key('Space', '\uE00D');
66
+ public static Tab = new Key('Tab', '\uE004');
67
+
68
+ public static isKey(maybeKey: unknown): maybeKey is Key {
69
+ return !! maybeKey
70
+ && maybeKey instanceof Key;
71
+ }
72
+
73
+ constructor(
74
+ public readonly devtoolsName: string,
75
+ public readonly utf16codePoint: string,
76
+ public readonly isModifier: boolean = false,
77
+ ) {
78
+ }
79
+
80
+ toString(): string {
81
+ return this.devtoolsName.replace(/([a-z])([\dA-Z])/g, '$1 $2');
82
+ }
83
+ }
@@ -0,0 +1 @@
1
+ export * from './Key';
@@ -0,0 +1,89 @@
1
+ import { Ability, Duration, UsesAbilities } from '@serenity-js/core';
2
+
3
+ import { Key } from '../../input';
4
+ import { Cookie, CookieData, ModalDialog, Page, PageElement, PageElements } from '../models';
5
+ import { BrowserCapabilities } from './BrowserCapabilities';
6
+
7
+ export abstract class BrowseTheWeb implements Ability {
8
+ /**
9
+ * @desc
10
+ * Used to access the Actor's ability to {@link BrowseTheWeb}
11
+ * from within the {@link @serenity-js/core/lib/screenplay~Interaction} classes,
12
+ * such as {@link Click}.
13
+ *
14
+ * @param {@serenity-js/core/lib/screenplay/actor~UsesAbilities} actor
15
+ * @return {BrowseTheWeb}
16
+ */
17
+ static as(actor: UsesAbilities): BrowseTheWeb {
18
+ return actor.abilityTo(BrowseTheWeb);
19
+ }
20
+
21
+ abstract navigateTo(destination: string): Promise<void>;
22
+
23
+ abstract navigateBack(): Promise<void>;
24
+
25
+ abstract navigateForward(): Promise<void>;
26
+
27
+ abstract reloadPage(): Promise<void>;
28
+
29
+ abstract waitFor(duration: Duration): Promise<void>;
30
+
31
+ abstract waitUntil(condition: () => boolean | Promise<boolean>, timeout: Duration): Promise<void>;
32
+
33
+ abstract findByCss(selector: string): PageElement;
34
+ abstract findByCssContainingText(selector: string, text: string): PageElement;
35
+ abstract findById(selector: string): PageElement;
36
+ abstract findByTagName(selector: string): PageElement;
37
+ abstract findByXPath(selector: string): PageElement;
38
+
39
+ abstract findAllByCss(selector: string): PageElements;
40
+ abstract findAllByTagName(selector: string): PageElements;
41
+ abstract findAllByXPath(selector: string): PageElements;
42
+
43
+ abstract browserCapabilities(): Promise<BrowserCapabilities>;
44
+
45
+ abstract sendKeys(keys: Array<Key | string>): Promise<void>;
46
+
47
+ abstract executeScript<Result, InnerArguments extends any[]>(
48
+ script: string | ((...parameters: InnerArguments) => Result),
49
+ ...args: InnerArguments
50
+ ): Promise<Result>;
51
+
52
+ abstract executeAsyncScript<Result, Parameters extends any[]>(
53
+ script: string | ((...args: [ ...parameters: Parameters, callback: (result: Result) => void ]) => void),
54
+ ...args: Parameters
55
+ ): Promise<Result>;
56
+
57
+ abstract lastScriptExecutionResult<R = any>(): R;
58
+
59
+ abstract takeScreenshot(): Promise<string>;
60
+
61
+ /**
62
+ * @desc
63
+ * Returns a {@link Page} representing the currently active top-level browsing context.
64
+ *
65
+ * @returns {Promise<Page>}
66
+ */
67
+ abstract currentPage(): Promise<Page>;
68
+
69
+ /**
70
+ * @desc
71
+ * Returns an array of {@link Page} objects representing all the available
72
+ * top-level browsing context, e.g. all the open browser tabs.
73
+ *
74
+ * @returns {Promise<Array<Page>>}
75
+ */
76
+ abstract allPages(): Promise<Array<Page>>;
77
+
78
+ abstract cookie(name: string): Promise<Cookie>;
79
+ abstract setCookie(cookieData: CookieData): Promise<void>;
80
+ abstract deleteAllCookies(): Promise<void>;
81
+
82
+ abstract modalDialog(): Promise<ModalDialog>;
83
+
84
+ // todo: remove
85
+ abstract switchToFrame(targetOrIndex: PageElement | number | string): Promise<void>;
86
+ abstract switchToParentFrame(): Promise<void>;
87
+ abstract switchToDefaultContent(): Promise<void>;
88
+ }
89
+
@@ -0,0 +1,5 @@
1
+ export interface BrowserCapabilities {
2
+ platformName?: string;
3
+ browserName?: string;
4
+ browserVersion?: string;
5
+ }
@@ -0,0 +1,2 @@
1
+ export * from './BrowserCapabilities';
2
+ export * from './BrowseTheWeb';
@@ -0,0 +1,4 @@
1
+ export * from './abilities';
2
+ export * from './interactions';
3
+ export * from './models';
4
+ export * from './questions';
@@ -0,0 +1,102 @@
1
+ import { Answerable, AnswersQuestions, Interaction, LogicError, UsesAbilities } from '@serenity-js/core';
2
+ import { formatted } from '@serenity-js/core/lib/io';
3
+
4
+ import { PageElement } from '../models';
5
+ import { PageElementInteraction } from './PageElementInteraction';
6
+
7
+ /**
8
+ * @desc
9
+ * Instructs the {@link @serenity-js/core/lib/screenplay/actor~Actor} to
10
+ * clear the `value` of a [form `input`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input).
11
+ *
12
+ * @example <caption>Example widget</caption>
13
+ * <form>
14
+ * <input type="text" name="example" id="example" />
15
+ * </form>
16
+ *
17
+ * @example <caption>Lean Page Object describing the widget</caption>
18
+ * import { by, Target } from '@serenity-js/webdriverio';
19
+ *
20
+ * class Form {
21
+ * static exampleInput = Target.the('example input')
22
+ * .located(by.id('example'));
23
+ * }
24
+ *
25
+ * @example <caption>Clearing the value of an input field</caption>
26
+ * import { actorCalled } from '@serenity-js/core';
27
+ * import { BrowseTheWeb, Clear, Enter, Value } from '@serenity-js/webdriverio';
28
+ * import { Ensure, equals } from '@serenity-js/assertions';
29
+ *
30
+ * actorCalled('Inés')
31
+ * .whoCan(BrowseTheWeb.using(browser))
32
+ * .attemptsTo(
33
+ * Enter.theValue('Hello world!').into(Form.exampleInput),
34
+ * Ensure.that(Value.of(Form.exampleInput), equals('Hello world!')),
35
+ *
36
+ * Clear.theValueOf(Form.exampleInput),
37
+ * Ensure.that(Value.of(Form.exampleInput), equals('')),
38
+ * );
39
+ *
40
+ * @see {@link BrowseTheWeb}
41
+ * @see {@link Enter}
42
+ * @see {@link Value}
43
+ * @see {@link Target}
44
+ * @see {@link @serenity-js/assertions~Ensure}
45
+ * @see {@link @serenity-js/assertions/lib/expectations~equals}
46
+ *
47
+ * @extends {@serenity-js/core/lib/screenplay~Interaction}
48
+ */
49
+ export class Clear extends PageElementInteraction {
50
+
51
+ /**
52
+ * @desc
53
+ * Instantiates this {@link @serenity-js/core/lib/screenplay~Interaction}.
54
+ *
55
+ * @param {Answerable<PageElement>} field
56
+ * The field to be cleared
57
+ *
58
+ * @returns {@serenity-js/core/lib/screenplay~Interaction}
59
+ */
60
+ static theValueOf(field: Answerable<PageElement>): Interaction {
61
+ return new Clear(field);
62
+ }
63
+
64
+ /**
65
+ * @param {Answerable<PageElement>} field
66
+ * The element to be clicked on
67
+ */
68
+ constructor(private readonly field: Answerable<PageElement>) {
69
+ super(formatted `#actor clears the value of ${ field }`);
70
+ }
71
+
72
+ /**
73
+ * @desc
74
+ * Makes the provided {@link @serenity-js/core/lib/screenplay/actor~Actor}
75
+ * perform this {@link @serenity-js/core/lib/screenplay~Interaction}.
76
+ *
77
+ * @param {UsesAbilities & AnswersQuestions} actor
78
+ * An {@link @serenity-js/core/lib/screenplay/actor~Actor} to perform this {@link @serenity-js/core/lib/screenplay~Interaction}
79
+ *
80
+ * @returns {PromiseLike<void>}
81
+ *
82
+ * @see {@link @serenity-js/core/lib/screenplay/actor~Actor}
83
+ * @see {@link @serenity-js/core/lib/screenplay/actor~UsesAbilities}
84
+ * @see {@link @serenity-js/core/lib/screenplay/actor~AnswersQuestions}
85
+ */
86
+ async performAs(actor: UsesAbilities & AnswersQuestions): Promise<void> {
87
+ const element = await this.resolve(actor, this.field);
88
+ const value = await element.value();
89
+
90
+ if (value === null || value === undefined) {
91
+ throw new LogicError(
92
+ this.capitaliseFirstLetter(formatted `${ this.field } doesn't seem to have a 'value' attribute that could be cleared.`),
93
+ );
94
+ }
95
+
96
+ return element.clearValue();
97
+ }
98
+
99
+ private capitaliseFirstLetter(text: string) {
100
+ return text.charAt(0).toUpperCase() + text.slice(1);
101
+ }
102
+ }
@@ -0,0 +1,86 @@
1
+ import { Answerable, AnswersQuestions, Interaction, UsesAbilities } from '@serenity-js/core';
2
+ import { formatted } from '@serenity-js/core/lib/io';
3
+
4
+ import { PageElement } from '../models';
5
+ import { PageElementInteraction } from './PageElementInteraction';
6
+
7
+ /**
8
+ * @desc
9
+ * Instructs the {@link @serenity-js/core/lib/screenplay/actor~Actor} to
10
+ * [click](https://developer.mozilla.org/en-US/docs/Web/API/Element/click_event) on a given Web element.
11
+ *
12
+ * @example <caption>Example widget</caption>
13
+ * <form>
14
+ * <input type="text" name="example" id="example" />
15
+ * </form>
16
+ *
17
+ * @example <caption>Lean Page Object describing the widget</caption>
18
+ * import { by, Target } from '@serenity-js/webdriverio';
19
+ *
20
+ * class Form {
21
+ * static exampleInput = Target.the('example input')
22
+ * .located(by.id('example'));
23
+ * }
24
+ *
25
+ * @example <caption>Clicking on an element</caption>
26
+ * import { actorCalled } from '@serenity-js/core';
27
+ * import { BrowseTheWeb, Click, isSelected } from '@serenity-js/webdriverio';
28
+ * import { Ensure } from '@serenity-js/assertions';
29
+ *
30
+ * actorCalled('Chloé')
31
+ * .whoCan(BrowseTheWeb.using(browser))
32
+ * .attemptsTo(
33
+ * Click.on(Form.exampleInput),
34
+ * Ensure.that(Form.exampleInput, isSelected()),
35
+ * );
36
+ *
37
+ * @see {@link BrowseTheWeb}
38
+ * @see {@link Target}
39
+ * @see {@link @serenity-js/assertions~Ensure}
40
+ * @see {@link isSelected}
41
+ *
42
+ * @extends {ElementInteraction}
43
+ */
44
+ export class Click extends PageElementInteraction {
45
+
46
+ /**
47
+ * @desc
48
+ * Instantiates this {@link @serenity-js/core/lib/screenplay~Interaction}.
49
+ *
50
+ * @param {Answerable<PageElement>} pageElement
51
+ * The element to be clicked on
52
+ *
53
+ * @returns {@serenity-js/core/lib/screenplay~Interaction}
54
+ */
55
+ static on(pageElement: Answerable<PageElement>): Interaction {
56
+ return new Click(pageElement);
57
+ }
58
+
59
+ /**
60
+ * @param {Answerable<PageElement>} element
61
+ * The element to be clicked on
62
+ */
63
+ constructor(private readonly element: Answerable<PageElement>) {
64
+ super(formatted `#actor clicks on ${ element }`);
65
+ }
66
+
67
+ /**
68
+ * @desc
69
+ * Makes the provided {@link @serenity-js/core/lib/screenplay/actor~Actor}
70
+ * perform this {@link @serenity-js/core/lib/screenplay~Interaction}.
71
+ *
72
+ * @param {UsesAbilities & AnswersQuestions} actor
73
+ * An {@link @serenity-js/core/lib/screenplay/actor~Actor} to perform this {@link @serenity-js/core/lib/screenplay~Interaction}
74
+ *
75
+ * @returns {PromiseLike<void>}
76
+ *
77
+ * @see {@link @serenity-js/core/lib/screenplay/actor~Actor}
78
+ * @see {@link @serenity-js/core/lib/screenplay/actor~UsesAbilities}
79
+ * @see {@link @serenity-js/core/lib/screenplay/actor~AnswersQuestions}
80
+ */
81
+ async performAs(actor: UsesAbilities & AnswersQuestions): Promise<void> {
82
+ const element = await this.resolve(actor, this.element);
83
+ await element.scrollIntoView();
84
+ return element.click();
85
+ }
86
+ }