@vardot/varbase-e2e 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (301) hide show
  1. package/AGENTS.md +148 -0
  2. package/CLAUDE.md +544 -0
  3. package/README.md +22 -0
  4. package/bin/generate-reports.js +363 -0
  5. package/bin/init-varbase-e2e.js +330 -0
  6. package/bin/postinstall.js +26 -0
  7. package/cucumber.js +125 -0
  8. package/docs/00-quick-start.md +102 -0
  9. package/docs/01-getting-started.md +102 -0
  10. package/docs/02-bbr-smart-waits.md +77 -0
  11. package/docs/03-selector-registry.md +95 -0
  12. package/docs/04-step-reference.md +801 -0
  13. package/docs/05-web-first-assertions.md +91 -0
  14. package/docs/06-network-and-dialogs.md +83 -0
  15. package/docs/07-auth-state.md +75 -0
  16. package/docs/08-clock-mocking.md +59 -0
  17. package/docs/09-api-testing.md +114 -0
  18. package/docs/10-accessibility.md +167 -0
  19. package/docs/11-debugging.md +129 -0
  20. package/docs/12-ai-agent-guide.md +338 -0
  21. package/docs/13-faq.md +236 -0
  22. package/docs/14-recipes-cookbook.md +255 -0
  23. package/docs/15-tag-conventions.md +76 -0
  24. package/docs/16-ci-cd.md +90 -0
  25. package/docs/README.md +125 -0
  26. package/docs/advanced-screenshots/then-i-save-fullscreen-screenshot.md +36 -0
  27. package/docs/advanced-screenshots/then-i-save-width-x-height-screenshot.md +34 -0
  28. package/docs/advanced-screenshots/when-i-save-screenshot-name-filename.md +45 -0
  29. package/docs/advanced-screenshots.md +52 -0
  30. package/docs/advanced-selectors.md +18 -0
  31. package/docs/api-step-definitions.md +45 -0
  32. package/docs/global-settings.md +267 -0
  33. package/docs/install-varbase-e2e/ddev-varbase-e2e.md +52 -0
  34. package/docs/install-varbase-e2e.md +34 -0
  35. package/docs/overview.md +40 -0
  36. package/docs/step-definitions/given-i-am-anonymous-user.md +67 -0
  37. package/docs/step-definitions/given-i-am-homepage.md +68 -0
  38. package/docs/step-definitions/given-i-am-specific-page.md +72 -0
  39. package/docs/step-definitions/then-i-should-be.md +56 -0
  40. package/docs/step-definitions/then-i-should-see.md +62 -0
  41. package/docs/step-definitions/then-item-checkbox.md +54 -0
  42. package/docs/step-definitions/then-item-link-should-contain-url.md +84 -0
  43. package/docs/step-definitions/then-item-should-contain.md +67 -0
  44. package/docs/step-definitions/then-radio-button-value-should-be-selected.md +68 -0
  45. package/docs/step-definitions/then-response-status-code-should-be-number.md +69 -0
  46. package/docs/step-definitions/then-value-radio-button-selected.md +62 -0
  47. package/docs/step-definitions/when-i-attach-file-file-name-element.md +71 -0
  48. package/docs/step-definitions/when-i-check-checkbox.md +60 -0
  49. package/docs/step-definitions/when-i-click-link.md +51 -0
  50. package/docs/step-definitions/when-i-click-operation-text-row.md +71 -0
  51. package/docs/step-definitions/when-i-fill.md +59 -0
  52. package/docs/step-definitions/when-i-go-homepage.md +60 -0
  53. package/docs/step-definitions/when-i-go-specific-page.md +67 -0
  54. package/docs/step-definitions/when-i-move-backward-one-page.md +49 -0
  55. package/docs/step-definitions/when-i-move-forward-one-page.md +58 -0
  56. package/docs/step-definitions/when-i-press-button.md +58 -0
  57. package/docs/step-definitions/when-i-reload-page.md +51 -0
  58. package/docs/step-definitions/when-i-scroll.md +73 -0
  59. package/docs/step-definitions/when-i-select-option-select-list.md +53 -0
  60. package/docs/step-definitions/when-i-select-radio-button-value.md +62 -0
  61. package/docs/step-definitions/when-i-uncheck-checkbox.md +57 -0
  62. package/docs/step-definitions/when-i-wait-ajax-finish.md +64 -0
  63. package/docs/step-definitions/when-i-wait.md +62 -0
  64. package/docs/step-definitions.md +82 -0
  65. package/docs/steps/README.md +137 -0
  66. package/docs/steps/a11y.md +731 -0
  67. package/docs/steps/action.md +181 -0
  68. package/docs/steps/api.md +679 -0
  69. package/docs/steps/assertion.md +328 -0
  70. package/docs/steps/auth.md +108 -0
  71. package/docs/steps/clock.md +171 -0
  72. package/docs/steps/cookie.md +293 -0
  73. package/docs/steps/debug.md +52 -0
  74. package/docs/steps/dialog.md +226 -0
  75. package/docs/steps/drupal-canvas.md +414 -0
  76. package/docs/steps/drupal-ckeditor.md +118 -0
  77. package/docs/steps/drupal-core.md +688 -0
  78. package/docs/steps/drupal-layout-builder.md +437 -0
  79. package/docs/steps/drupal-media.md +107 -0
  80. package/docs/steps/drupal-moderation.md +81 -0
  81. package/docs/steps/drupal-paragraphs.md +36 -0
  82. package/docs/steps/element.md +455 -0
  83. package/docs/steps/field.md +648 -0
  84. package/docs/steps/file-download.md +235 -0
  85. package/docs/steps/form.md +344 -0
  86. package/docs/steps/iframe.md +248 -0
  87. package/docs/steps/input.md +220 -0
  88. package/docs/steps/javascript.md +111 -0
  89. package/docs/steps/keyboard.md +107 -0
  90. package/docs/steps/link.md +217 -0
  91. package/docs/steps/metatag.md +99 -0
  92. package/docs/steps/modal.md +232 -0
  93. package/docs/steps/navigation.md +275 -0
  94. package/docs/steps/network.md +284 -0
  95. package/docs/steps/path.md +203 -0
  96. package/docs/steps/response.md +102 -0
  97. package/docs/steps/responsive.md +139 -0
  98. package/docs/steps/rest.md +140 -0
  99. package/docs/steps/screenshot.md +211 -0
  100. package/docs/steps/scroll.md +266 -0
  101. package/docs/steps/selectors.md +848 -0
  102. package/docs/steps/storage.md +254 -0
  103. package/docs/steps/table.md +216 -0
  104. package/docs/steps/varbase.md +391 -0
  105. package/docs/steps/video.md +111 -0
  106. package/docs/steps/wait.md +553 -0
  107. package/docs/steps/web-first.md +289 -0
  108. package/docs/steps/xml.md +505 -0
  109. package/docs/steps/yaml.md +951 -0
  110. package/examples/a11y.html +31 -0
  111. package/examples/about-us.html +11 -0
  112. package/examples/account.html +32 -0
  113. package/examples/ajax-wait-examples.html +147 -0
  114. package/examples/contact-us.html +10 -0
  115. package/examples/cookies.html +10 -0
  116. package/examples/date.html +12 -0
  117. package/examples/dynamic-examples.html +498 -0
  118. package/examples/element.html +11 -0
  119. package/examples/example-api.json +28 -0
  120. package/examples/existing-page.html +11 -0
  121. package/examples/field.html +24 -0
  122. package/examples/index.html +37 -0
  123. package/examples/keyboard.html +11 -0
  124. package/examples/links.html +9 -0
  125. package/examples/modal.html +14 -0
  126. package/examples/path.html +3 -0
  127. package/examples/table.html +13 -0
  128. package/examples/test--modal-dialogs.html +252 -0
  129. package/examples/test--then--i-should--not--see-text-in-element.html +48 -0
  130. package/examples/test--then--i-should--see-text-in-element.html +48 -0
  131. package/examples/test--then--i-should--see-text-matching-pattern.html +31 -0
  132. package/examples/test--then--i-should-see-text-in-table-row.html +232 -0
  133. package/examples/test--then--the-checkbox-checked.html +68 -0
  134. package/examples/test--then--the-element-should_not-contain-cssproperty.html +47 -0
  135. package/examples/test--then--the-link-should-contain.html +21 -0
  136. package/examples/test--when--i-additionally-select.html +27 -0
  137. package/examples/test--when--i-attach-file-to-feild.html +50 -0
  138. package/examples/test--when--i-check-uncheck-checkbox.html +47 -0
  139. package/examples/test--when--i-click-link.html +18 -0
  140. package/examples/test--when--i-click-text-in-table-row.html +178 -0
  141. package/examples/test--when--i-fill-in.html +48 -0
  142. package/examples/test--when--i-press-button.html +31 -0
  143. package/examples/test--when--i-reload-page.html +27 -0
  144. package/examples/test--when--i-scroll-functionality.html +177 -0
  145. package/examples/test--when--i-scroll-left-right-functionality.html +149 -0
  146. package/examples/test--when--i-select-option-from-dropdownlist.html +35 -0
  147. package/examples/test--when--i-select-radio-button.html +95 -0
  148. package/examples/test--when-i-wait-max-of-time.html +39 -0
  149. package/examples/test--when-i-wait-page-until-is-loaded.html +47 -0
  150. package/examples/test--when-i-wait-specific-time.html +39 -0
  151. package/examples/test-acceptable-url-path.html +11 -0
  152. package/examples/video-demo.html +43 -0
  153. package/package.json +56 -0
  154. package/playwright.config.ts +39 -0
  155. package/tests/assets/test-document.pdf +14 -0
  156. package/tests/assets/vardot.png +0 -0
  157. package/tests/features/a11y.feature +39 -0
  158. package/tests/features/ajax-wait-examples.feature +24 -0
  159. package/tests/features/api-step-definitions-individual.feature +185 -0
  160. package/tests/features/complete-api-testing-examples.feature +205 -0
  161. package/tests/features/cookie.feature +13 -0
  162. package/tests/features/date.feature +11 -0
  163. package/tests/features/dynamic-content-examples.feature +156 -0
  164. package/tests/features/element.feature +16 -0
  165. package/tests/features/field.feature +25 -0
  166. package/tests/features/keyboard.feature +10 -0
  167. package/tests/features/link.feature +11 -0
  168. package/tests/features/modal-advanced-example.feature +54 -0
  169. package/tests/features/modal-basic-example.feature +42 -0
  170. package/tests/features/modal-error-handling-example.feature +37 -0
  171. package/tests/features/modal.feature +11 -0
  172. package/tests/features/path.feature +16 -0
  173. package/tests/features/response.feature +8 -0
  174. package/tests/features/responsive.feature +10 -0
  175. package/tests/features/table.feature +18 -0
  176. package/tests/features/test--given--i-am-an-anonymous-user.feature +10 -0
  177. package/tests/features/test--given--i-am-on-homepage.feature +16 -0
  178. package/tests/features/test--then--i-save-screenshot.feature +33 -0
  179. package/tests/features/test--then--i-see-locator.feature +320 -0
  180. package/tests/features/test--then--i-should--not--see-text-in-element.feature +13 -0
  181. package/tests/features/test--then--i-should--see-text-in-element-by-attr.feature +10 -0
  182. package/tests/features/test--then--i-should--see-text-in-element.feature +10 -0
  183. package/tests/features/test--then--i-should--see-text-matching-pattern-in-element.feature +13 -0
  184. package/tests/features/test--then--i-should--see-text-matching-pattern.feature +18 -0
  185. package/tests/features/test--then--i-should-be-on-page.feature +10 -0
  186. package/tests/features/test--then--i-should-be-on-the-homepage.feature +10 -0
  187. package/tests/features/test--then--i-should-not-see-an-element-by-attr.feature +8 -0
  188. package/tests/features/test--then--i-should-not-see-an-element.feature +8 -0
  189. package/tests/features/test--then--i-should-see-an-element-by-attr.feature +8 -0
  190. package/tests/features/test--then--i-should-see-an-element.feature +8 -0
  191. package/tests/features/test--then--i-should-see-n-elements.feature +24 -0
  192. package/tests/features/test--then--i-should-see-text-in-table-row.feature +96 -0
  193. package/tests/features/test--then--print-current-url-and-response.feature +21 -0
  194. package/tests/features/test--then--the-checkbox-is-checked.feature +18 -0
  195. package/tests/features/test--then--the-checkbox-should-be-checked.feature +16 -0
  196. package/tests/features/test--then--the-element-should-contain-cssproperty.feature +9 -0
  197. package/tests/features/test--then--the-element-should-not-contain-cssproperty.feature +10 -0
  198. package/tests/features/test--then--the-field-should-contain-value.feature +11 -0
  199. package/tests/features/test--then--the-response-should-contain.feature +11 -0
  200. package/tests/features/test--then--the-response-status-code-should-be.feature +31 -0
  201. package/tests/features/test--then--the-url-should-match.feature +7 -0
  202. package/tests/features/test--then-the-link-should-contain-by-attribute.feature +18 -0
  203. package/tests/features/test--then-the-link-should-contain.feature +7 -0
  204. package/tests/features/test--when--i-additionally-select.feature +30 -0
  205. package/tests/features/test--when--i-attach-file-to-feild.feature +9 -0
  206. package/tests/features/test--when--i-check-checkbox.feature +21 -0
  207. package/tests/features/test--when--i-click-link-by-attribute.feature +21 -0
  208. package/tests/features/test--when--i-click-link.feature +9 -0
  209. package/tests/features/test--when--i-click-text-in-table-row.feature +37 -0
  210. package/tests/features/test--when--i-fill-in-by-attr.feature +31 -0
  211. package/tests/features/test--when--i-fill-in-table-by-attr.feature +19 -0
  212. package/tests/features/test--when--i-fill-in.feature +32 -0
  213. package/tests/features/test--when--i-follow.feature +22 -0
  214. package/tests/features/test--when--i-go-to-homepage.feature +9 -0
  215. package/tests/features/test--when--i-move-forward-backward-one-page.feature +14 -0
  216. package/tests/features/test--when--i-press-button-by-attribute.feature +18 -0
  217. package/tests/features/test--when--i-press-button.feature +13 -0
  218. package/tests/features/test--when--i-reload-page.feature +11 -0
  219. package/tests/features/test--when--i-scroll-left-right.feature +48 -0
  220. package/tests/features/test--when--i-scroll.feature +48 -0
  221. package/tests/features/test--when--i-select-option-from-dropdownlist.feature +21 -0
  222. package/tests/features/test--when--i-select-radio-button.feature +37 -0
  223. package/tests/features/test--when--i-wait-page-is-loaded.feature +8 -0
  224. package/tests/features/test--when--i-wait-time.feature +21 -0
  225. package/tests/features/video.feature +18 -0
  226. package/tests/features/wait.feature +7 -0
  227. package/tests/features/yaml.feature +102 -0
  228. package/tests/selectors/_canonical-keys.json +113 -0
  229. package/tests/selectors/back-end-selectors.json +19 -0
  230. package/tests/selectors/cms-contentful-admin.json +35 -0
  231. package/tests/selectors/cms-craft-admin.json +39 -0
  232. package/tests/selectors/cms-drupal-cms-gin.json +56 -0
  233. package/tests/selectors/cms-drupal-core-claro.json +50 -0
  234. package/tests/selectors/cms-generic-admin.json +34 -0
  235. package/tests/selectors/cms-ghost-admin.json +34 -0
  236. package/tests/selectors/cms-joomla-admin.json +41 -0
  237. package/tests/selectors/cms-magento2-admin.json +32 -0
  238. package/tests/selectors/cms-prestashop-admin.json +38 -0
  239. package/tests/selectors/cms-shopify-admin.json +25 -0
  240. package/tests/selectors/cms-strapi-admin.json +42 -0
  241. package/tests/selectors/cms-typo3-admin.json +41 -0
  242. package/tests/selectors/cms-woocommerce-front.json +50 -0
  243. package/tests/selectors/cms-wordpress-admin.json +31 -0
  244. package/tests/selectors/framework-ant-design.json +80 -0
  245. package/tests/selectors/framework-bootstrap.json +86 -0
  246. package/tests/selectors/framework-bulma.json +74 -0
  247. package/tests/selectors/framework-chakra.json +58 -0
  248. package/tests/selectors/framework-foundation.json +51 -0
  249. package/tests/selectors/framework-material-ui.json +72 -0
  250. package/tests/selectors/framework-shadcn.json +51 -0
  251. package/tests/selectors/framework-tailwind.json +40 -0
  252. package/tests/selectors/framework-vuetify.json +61 -0
  253. package/tests/selectors/front-end-selectors.json +16 -0
  254. package/tests/selectors/homepage-selectors.json +13 -0
  255. package/tests/step-definitions/a11y.steps.js +800 -0
  256. package/tests/step-definitions/action.steps.js +167 -0
  257. package/tests/step-definitions/api.steps.js +732 -0
  258. package/tests/step-definitions/assertion.steps.js +352 -0
  259. package/tests/step-definitions/auth.steps.js +126 -0
  260. package/tests/step-definitions/clock.steps.js +128 -0
  261. package/tests/step-definitions/cookie.steps.js +216 -0
  262. package/tests/step-definitions/debug.steps.js +39 -0
  263. package/tests/step-definitions/dialog.steps.js +193 -0
  264. package/tests/step-definitions/drupal-canvas.steps.js +764 -0
  265. package/tests/step-definitions/drupal-ckeditor.steps.js +108 -0
  266. package/tests/step-definitions/drupal-core.steps.js +665 -0
  267. package/tests/step-definitions/drupal-helpers.js +371 -0
  268. package/tests/step-definitions/drupal-layout-builder.steps.js +466 -0
  269. package/tests/step-definitions/drupal-media.steps.js +99 -0
  270. package/tests/step-definitions/drupal-moderation.steps.js +71 -0
  271. package/tests/step-definitions/drupal-paragraphs.steps.js +50 -0
  272. package/tests/step-definitions/element.steps.js +356 -0
  273. package/tests/step-definitions/field.steps.js +653 -0
  274. package/tests/step-definitions/file-download.steps.js +211 -0
  275. package/tests/step-definitions/form.steps.js +333 -0
  276. package/tests/step-definitions/iframe.steps.js +228 -0
  277. package/tests/step-definitions/input.steps.js +202 -0
  278. package/tests/step-definitions/javascript.steps.js +232 -0
  279. package/tests/step-definitions/keyboard.steps.js +112 -0
  280. package/tests/step-definitions/link.steps.js +142 -0
  281. package/tests/step-definitions/metatag.steps.js +91 -0
  282. package/tests/step-definitions/modal.steps.js +244 -0
  283. package/tests/step-definitions/navigation.steps.js +218 -0
  284. package/tests/step-definitions/network.steps.js +280 -0
  285. package/tests/step-definitions/path.steps.js +141 -0
  286. package/tests/step-definitions/response.steps.js +98 -0
  287. package/tests/step-definitions/responsive.steps.js +125 -0
  288. package/tests/step-definitions/rest.steps.js +111 -0
  289. package/tests/step-definitions/screenshot.steps.js +423 -0
  290. package/tests/step-definitions/scroll.steps.js +189 -0
  291. package/tests/step-definitions/selectors.steps.js +1003 -0
  292. package/tests/step-definitions/storage.steps.js +194 -0
  293. package/tests/step-definitions/table.steps.js +181 -0
  294. package/tests/step-definitions/varbase-e2e.js +897 -0
  295. package/tests/step-definitions/varbase.steps.js +458 -0
  296. package/tests/step-definitions/video.steps.js +178 -0
  297. package/tests/step-definitions/wait.steps.js +400 -0
  298. package/tests/step-definitions/web-first.steps.js +298 -0
  299. package/tests/step-definitions/xml.steps.js +411 -0
  300. package/tests/step-definitions/yaml.steps.js +913 -0
  301. package/tsconfig.json +26 -0
@@ -0,0 +1,455 @@
1
+ # Element interactions steps
2
+
3
+ 19 steps, defined in `tests/step-definitions/element.steps.js`.
4
+
5
+ Cucumber-js loads every `*.steps.js` in that directory automatically — you never `require()` a step file from a feature.
6
+
7
+ | # | Step |
8
+ | --- | --- |
9
+ | 1 | `Then the element "#footer" should appear after the element "#main"` |
10
+ | 2 | `Then the text "Sign in" should appear after the text "Welcome"` |
11
+ | 3 | `Then the element "a" with the attribute "href" and the value "/about" should exist` |
12
+ | 4 | `Then the element "a" with the attribute "href" and the value containing "/about" should exist` |
13
+ | 5 | `Then the element "a" with the attribute "href" and the value "/admin" should not exist` |
14
+ | 6 | `Then the element "a" with the attribute "href" and the value containing "/old" should not exist` |
15
+ | 7 | `Then the element "#header" should be at the top of the viewport` |
16
+ | 8 | `Then the element ".hero" should be centered in the viewport` |
17
+ | 9 | `When I click on the element "#sign-in"` |
18
+ | 10 | `When I trigger the JS event "click" on the element "#cta"` |
19
+ | 11 | `When I scroll to the element "#footer"` |
20
+ | 12 | `When I hover over the element ".tooltip-trigger"` |
21
+ | 13 | `When I focus on the element "#email"` |
22
+ | 14 | `Then the element "#dashboard" should be displayed` |
23
+ | 15 | `Then the element "#loading-spinner" should not be displayed` |
24
+ | 16 | `Then the element "#hero" should be displayed within a viewport` |
25
+ | 17 | `Then the element "#hero" should be displayed within a viewport with a top offset of 60 pixels` |
26
+ | 18 | `Then the element "#footer" should not be displayed within a viewport with a top offset of 60 pixels` |
27
+ | 19 | `Then the element "#footer" should not be displayed within a viewport` |
28
+
29
+ ---
30
+
31
+ ## 1. Then the element "#footer" should appear after the element "#main"
32
+
33
+ Assert element A is positioned vertically below element B (greater Y).
34
+
35
+ **Keyword**: `Then`
36
+
37
+ **Pattern**
38
+
39
+ ```js
40
+ 'the element {string} should appear after the element {string}'
41
+ ```
42
+
43
+ **Examples**
44
+
45
+ ```gherkin
46
+ Then the element "#footer" should appear after the element "#main"
47
+ Then the element ".checkout" should appear after the element ".cart"
48
+ And the element "#summary" should appear after the element "#details"
49
+ Then the element "h2" should appear after the element "h1"
50
+ Then the element "[data-testid=cta]" should appear after the element ".hero"
51
+ ```
52
+
53
+ ## 2. Then the text "Sign in" should appear after the text "Welcome"
54
+
55
+ Assert text A appears after text B in the document body's text order.
56
+
57
+ **Keyword**: `Then`
58
+
59
+ **Pattern**
60
+
61
+ ```js
62
+ 'the text {string} should appear after the text {string}'
63
+ ```
64
+
65
+ **Examples**
66
+
67
+ ```gherkin
68
+ Then the text "Sign in" should appear after the text "Welcome"
69
+ Then the text "Total" should appear after the text "Subtotal"
70
+ And the text "Footer" should appear after the text "Header"
71
+ Then the text "Privacy" should appear after the text "Terms"
72
+ Then the text "Step 3" should appear after the text "Step 2"
73
+ ```
74
+
75
+ ## 3. Then the element "a" with the attribute "href" and the value "/about" should exist
76
+
77
+ Assert at least one element matching `<selector>[<attr>="<value>"]` exists.
78
+
79
+ **Keyword**: `Then`
80
+
81
+ **Pattern**
82
+
83
+ ```js
84
+ 'the element {string} with the attribute {string} and the value {string} should exist'
85
+ ```
86
+
87
+ **Examples**
88
+
89
+ ```gherkin
90
+ Then the element "a" with the attribute "href" and the value "/about" should exist
91
+ Then the element "input" with the attribute "name" and the value "email" should exist
92
+ And the element "button" with the attribute "type" and the value "submit" should exist
93
+ Then the element "div" with the attribute "data-testid" and the value "user-list" should exist
94
+ Then the element "img" with the attribute "alt" and the value "Logo" should exist
95
+ ```
96
+
97
+ ## 4. Then the element "a" with the attribute "href" and the value containing "/about" should exist
98
+
99
+ Assert at least one element with attribute value containing a substring exists.
100
+
101
+ **Keyword**: `Then`
102
+
103
+ **Pattern**
104
+
105
+ ```js
106
+ 'the element {string} with the attribute {string} and the value containing {string} should exist'
107
+ ```
108
+
109
+ **Examples**
110
+
111
+ ```gherkin
112
+ Then the element "a" with the attribute "href" and the value containing "/about" should exist
113
+ Then the element "input" with the attribute "class" and the value containing "is-valid" should exist
114
+ And the element "button" with the attribute "data-testid" and the value containing "cta" should exist
115
+ Then the element "img" with the attribute "src" and the value containing ".png" should exist
116
+ Then the element "div" with the attribute "aria-label" and the value containing "card" should exist
117
+ ```
118
+
119
+ ## 5. Then the element "a" with the attribute "href" and the value "/admin" should not exist
120
+
121
+ Assert NO element matches `<selector>[<attr>="<value>"]`.
122
+
123
+ **Keyword**: `Then`
124
+
125
+ **Pattern**
126
+
127
+ ```js
128
+ 'the element {string} with the attribute {string} and the value {string} should not exist'
129
+ ```
130
+
131
+ **Examples**
132
+
133
+ ```gherkin
134
+ Then the element "a" with the attribute "href" and the value "/admin" should not exist
135
+ Then the element "input" with the attribute "type" and the value "hidden" should not exist
136
+ And the element "button" with the attribute "disabled" and the value "true" should not exist
137
+ Then the element "div" with the attribute "data-testid" and the value "error" should not exist
138
+ Then the element "img" with the attribute "alt" and the value "" should not exist
139
+ ```
140
+
141
+ ## 6. Then the element "a" with the attribute "href" and the value containing "/old" should not exist
142
+
143
+ Assert NO element has attribute value containing a substring.
144
+
145
+ **Keyword**: `Then`
146
+
147
+ **Pattern**
148
+
149
+ ```js
150
+ 'the element {string} with the attribute {string} and the value containing {string} should not exist'
151
+ ```
152
+
153
+ **Examples**
154
+
155
+ ```gherkin
156
+ Then the element "a" with the attribute "href" and the value containing "/old" should not exist
157
+ Then the element "div" with the attribute "class" and the value containing "is-error" should not exist
158
+ And the element "button" with the attribute "data-testid" and the value containing "deprecated" should not exist
159
+ Then the element "img" with the attribute "src" and the value containing "tracking" should not exist
160
+ Then the element "input" with the attribute "name" and the value containing "_legacy" should not exist
161
+ ```
162
+
163
+ ## 7. Then the element "#header" should be at the top of the viewport
164
+
165
+ Assert an element is positioned within the top 100 px of the viewport.
166
+
167
+ **Keyword**: `Then`
168
+
169
+ **Pattern**
170
+
171
+ ```js
172
+ 'the element {string} should be at the top of the viewport'
173
+ ```
174
+
175
+ **Examples**
176
+
177
+ ```gherkin
178
+ Then the element "#header" should be at the top of the viewport
179
+ Then the element "h1" should be at the top of the viewport
180
+ And the element ".sticky-nav" should be at the top of the viewport
181
+ When I scroll to the top
182
+ Then the element "#hero" should be at the top of the viewport
183
+ Then the element "[role=banner]" should be at the top of the viewport
184
+ ```
185
+
186
+ ## 8. Then the element ".hero" should be centered in the viewport
187
+
188
+ Assert an element is horizontally centered in the viewport (±10% tolerance).
189
+
190
+ **Keyword**: `Then`
191
+
192
+ **Pattern**
193
+
194
+ ```js
195
+ 'the element {string} should be centered in the viewport'
196
+ ```
197
+
198
+ **Examples**
199
+
200
+ ```gherkin
201
+ Then the element ".hero" should be centered in the viewport
202
+ Then the element "#cta" should be centered in the viewport
203
+ And the element ".modal-dialog" should be centered in the viewport
204
+ Then the element "h1" should be centered in the viewport
205
+ Then the element ".loader" should be centered in the viewport
206
+ ```
207
+
208
+ ## 9. When I click on the element "#sign-in"
209
+
210
+ Click an element addressed by CSS selector.
211
+
212
+ **Keyword**: `When`
213
+
214
+ **Pattern**
215
+
216
+ ```js
217
+ /^(I |we )*click on the element "([^"]*)"$/
218
+ ```
219
+
220
+ **Examples**
221
+
222
+ ```gherkin
223
+ When I click on the element "#sign-in"
224
+ When I click on the element ".btn-primary"
225
+ And we click on the element "[data-testid=cta]"
226
+ When I click on the element "li.nav-item:first-child a"
227
+ When I click on the element "button[aria-label='Close']"
228
+ ```
229
+
230
+ ## 10. When I trigger the JS event "click" on the element "#cta"
231
+
232
+ Dispatch a synthetic JavaScript event on a CSS-addressed element.
233
+
234
+ Useful for components that listen for non-bubbling events or for events
235
+ Playwright cannot synthesize through normal interactions.
236
+
237
+ **Keyword**: `When`
238
+
239
+ **Pattern**
240
+
241
+ ```js
242
+ /^(I |we )*trigger the JS event "([^"]*)" on the element "([^"]*)"$/
243
+ ```
244
+
245
+ **Examples**
246
+
247
+ ```gherkin
248
+ When I trigger the JS event "click" on the element "#cta"
249
+ When I trigger the JS event "change" on the element "#country"
250
+ And I trigger the JS event "input" on the element "#search"
251
+ When I trigger the JS event "focus" on the element "#email"
252
+ When I trigger the JS event "blur" on the element "#name"
253
+ ```
254
+
255
+ ## 11. When I scroll to the element "#footer"
256
+
257
+ Scroll a CSS-addressed element into view (uses Playwright's auto-scroll).
258
+
259
+ **Keyword**: `When`
260
+
261
+ **Pattern**
262
+
263
+ ```js
264
+ /^(I |we )*scroll to the element "([^"]*)"$/
265
+ ```
266
+
267
+ **Examples**
268
+
269
+ ```gherkin
270
+ When I scroll to the element "#footer"
271
+ When I scroll to the element ".pricing-table"
272
+ And we scroll to the element "[data-testid=signup-cta]"
273
+ When I scroll to the element "tbody tr:nth-child(20)"
274
+ When I scroll to the element ".testimonial:last-child"
275
+ ```
276
+
277
+ ## 12. When I hover over the element ".tooltip-trigger"
278
+
279
+ Hover the mouse pointer over a CSS-addressed element.
280
+
281
+ **Keyword**: `When`
282
+
283
+ **Pattern**
284
+
285
+ ```js
286
+ /^(I |we )*hover over the element "([^"]*)"$/
287
+ ```
288
+
289
+ **Examples**
290
+
291
+ ```gherkin
292
+ When I hover over the element ".tooltip-trigger"
293
+ When I hover over the element "#user-menu"
294
+ And we hover over the element "[data-testid=avatar]"
295
+ When I hover over the element "img.preview"
296
+ When I hover over the element "li.menu-item"
297
+ ```
298
+
299
+ ## 13. When I focus on the element "#email"
300
+
301
+ Move keyboard focus to a CSS-addressed element.
302
+
303
+ **Keyword**: `When`
304
+
305
+ **Pattern**
306
+
307
+ ```js
308
+ /^(I |we )*focus on the element "([^"]*)"$/
309
+ ```
310
+
311
+ **Examples**
312
+
313
+ ```gherkin
314
+ When I focus on the element "#email"
315
+ When I focus on the element "input[type=search]"
316
+ And we focus on the element "[data-testid=combobox]"
317
+ When I focus on the element "textarea#message"
318
+ When I focus on the element "button.primary"
319
+ ```
320
+
321
+ ## 14. Then the element "#dashboard" should be displayed
322
+
323
+ Wait for a CSS-addressed element to become visible (display !== none, etc.).
324
+
325
+ **Keyword**: `Then`
326
+
327
+ **Pattern**
328
+
329
+ ```js
330
+ 'the element {string} should be displayed'
331
+ ```
332
+
333
+ **Examples**
334
+
335
+ ```gherkin
336
+ Then the element "#dashboard" should be displayed
337
+ Then the element ".success-banner" should be displayed
338
+ And the element "[data-testid=user-list]" should be displayed
339
+ Then the element ".toast" should be displayed
340
+ When I press "Save"
341
+ Then the element ".toast-success" should be displayed
342
+ ```
343
+
344
+ ## 15. Then the element "#loading-spinner" should not be displayed
345
+
346
+ Assert a CSS-addressed element is hidden or absent.
347
+
348
+ **Keyword**: `Then`
349
+
350
+ **Pattern**
351
+
352
+ ```js
353
+ 'the element {string} should not be displayed'
354
+ ```
355
+
356
+ **Examples**
357
+
358
+ ```gherkin
359
+ Then the element "#loading-spinner" should not be displayed
360
+ Then the element ".error-banner" should not be displayed
361
+ And the element "[data-testid=skeleton]" should not be displayed
362
+ Then the element ".modal" should not be displayed
363
+ When I press "Submit"
364
+ Then the element ".pending-badge" should not be displayed
365
+ ```
366
+
367
+ ## 16. Then the element "#hero" should be displayed within a viewport
368
+
369
+ Assert an element is fully inside the current viewport rectangle.
370
+
371
+ **Keyword**: `Then`
372
+
373
+ **Pattern**
374
+
375
+ ```js
376
+ 'the element {string} should be displayed within a viewport'
377
+ ```
378
+
379
+ **Examples**
380
+
381
+ ```gherkin
382
+ Then the element "#hero" should be displayed within a viewport
383
+ Then the element ".cta" should be displayed within a viewport
384
+ And the element "[data-testid=summary]" should be displayed within a viewport
385
+ Then the element "h1" should be displayed within a viewport
386
+ When I scroll to the element "#footer"
387
+ Then the element "#footer" should be displayed within a viewport
388
+ ```
389
+
390
+ ## 17. Then the element "#hero" should be displayed within a viewport with a top offset of 60 pixels
391
+
392
+ Assert an element is fully inside the viewport, allowing a top offset.
393
+ Useful for sticky headers — pass the header height as the offset.
394
+
395
+ **Keyword**: `Then`
396
+
397
+ **Pattern**
398
+
399
+ ```js
400
+ 'the element {string} should be displayed within a viewport with a top offset of {int} pixels'
401
+ ```
402
+
403
+ **Examples**
404
+
405
+ ```gherkin
406
+ Then the element "#hero" should be displayed within a viewport with a top offset of 60 pixels
407
+ Then the element ".main" should be displayed within a viewport with a top offset of 80 pixels
408
+ And the element ".cta" should be displayed within a viewport with a top offset of 50 pixels
409
+ Then the element "h1" should be displayed within a viewport with a top offset of 100 pixels
410
+ Then the element "#summary" should be displayed within a viewport with a top offset of 64 pixels
411
+ ```
412
+
413
+ ## 18. Then the element "#footer" should not be displayed within a viewport with a top offset of 60 pixels
414
+
415
+ Assert an element is NOT inside the viewport (top-offset variant).
416
+
417
+ **Keyword**: `Then`
418
+
419
+ **Pattern**
420
+
421
+ ```js
422
+ 'the element {string} should not be displayed within a viewport with a top offset of {int} pixels'
423
+ ```
424
+
425
+ **Examples**
426
+
427
+ ```gherkin
428
+ Then the element "#footer" should not be displayed within a viewport with a top offset of 60 pixels
429
+ Then the element ".off-screen" should not be displayed within a viewport with a top offset of 80 pixels
430
+ And the element ".pending" should not be displayed within a viewport with a top offset of 50 pixels
431
+ Then the element "#cookies-banner" should not be displayed within a viewport with a top offset of 100 pixels
432
+ Then the element ".low-priority" should not be displayed within a viewport with a top offset of 64 pixels
433
+ ```
434
+
435
+ ## 19. Then the element "#footer" should not be displayed within a viewport
436
+
437
+ Assert an element is NOT inside the viewport rectangle.
438
+
439
+ **Keyword**: `Then`
440
+
441
+ **Pattern**
442
+
443
+ ```js
444
+ 'the element {string} should not be displayed within a viewport'
445
+ ```
446
+
447
+ **Examples**
448
+
449
+ ```gherkin
450
+ Then the element "#footer" should not be displayed within a viewport
451
+ Then the element ".off-screen" should not be displayed within a viewport
452
+ And the element ".pending" should not be displayed within a viewport
453
+ Then the element "#cookies-banner" should not be displayed within a viewport
454
+ Then the element ".low-priority" should not be displayed within a viewport
455
+ ```