@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.
- package/AGENTS.md +148 -0
- package/CLAUDE.md +544 -0
- package/README.md +22 -0
- package/bin/generate-reports.js +363 -0
- package/bin/init-varbase-e2e.js +330 -0
- package/bin/postinstall.js +26 -0
- package/cucumber.js +125 -0
- package/docs/00-quick-start.md +102 -0
- package/docs/01-getting-started.md +102 -0
- package/docs/02-bbr-smart-waits.md +77 -0
- package/docs/03-selector-registry.md +95 -0
- package/docs/04-step-reference.md +801 -0
- package/docs/05-web-first-assertions.md +91 -0
- package/docs/06-network-and-dialogs.md +83 -0
- package/docs/07-auth-state.md +75 -0
- package/docs/08-clock-mocking.md +59 -0
- package/docs/09-api-testing.md +114 -0
- package/docs/10-accessibility.md +167 -0
- package/docs/11-debugging.md +129 -0
- package/docs/12-ai-agent-guide.md +338 -0
- package/docs/13-faq.md +236 -0
- package/docs/14-recipes-cookbook.md +255 -0
- package/docs/15-tag-conventions.md +76 -0
- package/docs/16-ci-cd.md +90 -0
- package/docs/README.md +125 -0
- package/docs/advanced-screenshots/then-i-save-fullscreen-screenshot.md +36 -0
- package/docs/advanced-screenshots/then-i-save-width-x-height-screenshot.md +34 -0
- package/docs/advanced-screenshots/when-i-save-screenshot-name-filename.md +45 -0
- package/docs/advanced-screenshots.md +52 -0
- package/docs/advanced-selectors.md +18 -0
- package/docs/api-step-definitions.md +45 -0
- package/docs/global-settings.md +267 -0
- package/docs/install-varbase-e2e/ddev-varbase-e2e.md +52 -0
- package/docs/install-varbase-e2e.md +34 -0
- package/docs/overview.md +40 -0
- package/docs/step-definitions/given-i-am-anonymous-user.md +67 -0
- package/docs/step-definitions/given-i-am-homepage.md +68 -0
- package/docs/step-definitions/given-i-am-specific-page.md +72 -0
- package/docs/step-definitions/then-i-should-be.md +56 -0
- package/docs/step-definitions/then-i-should-see.md +62 -0
- package/docs/step-definitions/then-item-checkbox.md +54 -0
- package/docs/step-definitions/then-item-link-should-contain-url.md +84 -0
- package/docs/step-definitions/then-item-should-contain.md +67 -0
- package/docs/step-definitions/then-radio-button-value-should-be-selected.md +68 -0
- package/docs/step-definitions/then-response-status-code-should-be-number.md +69 -0
- package/docs/step-definitions/then-value-radio-button-selected.md +62 -0
- package/docs/step-definitions/when-i-attach-file-file-name-element.md +71 -0
- package/docs/step-definitions/when-i-check-checkbox.md +60 -0
- package/docs/step-definitions/when-i-click-link.md +51 -0
- package/docs/step-definitions/when-i-click-operation-text-row.md +71 -0
- package/docs/step-definitions/when-i-fill.md +59 -0
- package/docs/step-definitions/when-i-go-homepage.md +60 -0
- package/docs/step-definitions/when-i-go-specific-page.md +67 -0
- package/docs/step-definitions/when-i-move-backward-one-page.md +49 -0
- package/docs/step-definitions/when-i-move-forward-one-page.md +58 -0
- package/docs/step-definitions/when-i-press-button.md +58 -0
- package/docs/step-definitions/when-i-reload-page.md +51 -0
- package/docs/step-definitions/when-i-scroll.md +73 -0
- package/docs/step-definitions/when-i-select-option-select-list.md +53 -0
- package/docs/step-definitions/when-i-select-radio-button-value.md +62 -0
- package/docs/step-definitions/when-i-uncheck-checkbox.md +57 -0
- package/docs/step-definitions/when-i-wait-ajax-finish.md +64 -0
- package/docs/step-definitions/when-i-wait.md +62 -0
- package/docs/step-definitions.md +82 -0
- package/docs/steps/README.md +137 -0
- package/docs/steps/a11y.md +731 -0
- package/docs/steps/action.md +181 -0
- package/docs/steps/api.md +679 -0
- package/docs/steps/assertion.md +328 -0
- package/docs/steps/auth.md +108 -0
- package/docs/steps/clock.md +171 -0
- package/docs/steps/cookie.md +293 -0
- package/docs/steps/debug.md +52 -0
- package/docs/steps/dialog.md +226 -0
- package/docs/steps/drupal-canvas.md +414 -0
- package/docs/steps/drupal-ckeditor.md +118 -0
- package/docs/steps/drupal-core.md +688 -0
- package/docs/steps/drupal-layout-builder.md +437 -0
- package/docs/steps/drupal-media.md +107 -0
- package/docs/steps/drupal-moderation.md +81 -0
- package/docs/steps/drupal-paragraphs.md +36 -0
- package/docs/steps/element.md +455 -0
- package/docs/steps/field.md +648 -0
- package/docs/steps/file-download.md +235 -0
- package/docs/steps/form.md +344 -0
- package/docs/steps/iframe.md +248 -0
- package/docs/steps/input.md +220 -0
- package/docs/steps/javascript.md +111 -0
- package/docs/steps/keyboard.md +107 -0
- package/docs/steps/link.md +217 -0
- package/docs/steps/metatag.md +99 -0
- package/docs/steps/modal.md +232 -0
- package/docs/steps/navigation.md +275 -0
- package/docs/steps/network.md +284 -0
- package/docs/steps/path.md +203 -0
- package/docs/steps/response.md +102 -0
- package/docs/steps/responsive.md +139 -0
- package/docs/steps/rest.md +140 -0
- package/docs/steps/screenshot.md +211 -0
- package/docs/steps/scroll.md +266 -0
- package/docs/steps/selectors.md +848 -0
- package/docs/steps/storage.md +254 -0
- package/docs/steps/table.md +216 -0
- package/docs/steps/varbase.md +391 -0
- package/docs/steps/video.md +111 -0
- package/docs/steps/wait.md +553 -0
- package/docs/steps/web-first.md +289 -0
- package/docs/steps/xml.md +505 -0
- package/docs/steps/yaml.md +951 -0
- package/examples/a11y.html +31 -0
- package/examples/about-us.html +11 -0
- package/examples/account.html +32 -0
- package/examples/ajax-wait-examples.html +147 -0
- package/examples/contact-us.html +10 -0
- package/examples/cookies.html +10 -0
- package/examples/date.html +12 -0
- package/examples/dynamic-examples.html +498 -0
- package/examples/element.html +11 -0
- package/examples/example-api.json +28 -0
- package/examples/existing-page.html +11 -0
- package/examples/field.html +24 -0
- package/examples/index.html +37 -0
- package/examples/keyboard.html +11 -0
- package/examples/links.html +9 -0
- package/examples/modal.html +14 -0
- package/examples/path.html +3 -0
- package/examples/table.html +13 -0
- package/examples/test--modal-dialogs.html +252 -0
- package/examples/test--then--i-should--not--see-text-in-element.html +48 -0
- package/examples/test--then--i-should--see-text-in-element.html +48 -0
- package/examples/test--then--i-should--see-text-matching-pattern.html +31 -0
- package/examples/test--then--i-should-see-text-in-table-row.html +232 -0
- package/examples/test--then--the-checkbox-checked.html +68 -0
- package/examples/test--then--the-element-should_not-contain-cssproperty.html +47 -0
- package/examples/test--then--the-link-should-contain.html +21 -0
- package/examples/test--when--i-additionally-select.html +27 -0
- package/examples/test--when--i-attach-file-to-feild.html +50 -0
- package/examples/test--when--i-check-uncheck-checkbox.html +47 -0
- package/examples/test--when--i-click-link.html +18 -0
- package/examples/test--when--i-click-text-in-table-row.html +178 -0
- package/examples/test--when--i-fill-in.html +48 -0
- package/examples/test--when--i-press-button.html +31 -0
- package/examples/test--when--i-reload-page.html +27 -0
- package/examples/test--when--i-scroll-functionality.html +177 -0
- package/examples/test--when--i-scroll-left-right-functionality.html +149 -0
- package/examples/test--when--i-select-option-from-dropdownlist.html +35 -0
- package/examples/test--when--i-select-radio-button.html +95 -0
- package/examples/test--when-i-wait-max-of-time.html +39 -0
- package/examples/test--when-i-wait-page-until-is-loaded.html +47 -0
- package/examples/test--when-i-wait-specific-time.html +39 -0
- package/examples/test-acceptable-url-path.html +11 -0
- package/examples/video-demo.html +43 -0
- package/package.json +56 -0
- package/playwright.config.ts +39 -0
- package/tests/assets/test-document.pdf +14 -0
- package/tests/assets/vardot.png +0 -0
- package/tests/features/a11y.feature +39 -0
- package/tests/features/ajax-wait-examples.feature +24 -0
- package/tests/features/api-step-definitions-individual.feature +185 -0
- package/tests/features/complete-api-testing-examples.feature +205 -0
- package/tests/features/cookie.feature +13 -0
- package/tests/features/date.feature +11 -0
- package/tests/features/dynamic-content-examples.feature +156 -0
- package/tests/features/element.feature +16 -0
- package/tests/features/field.feature +25 -0
- package/tests/features/keyboard.feature +10 -0
- package/tests/features/link.feature +11 -0
- package/tests/features/modal-advanced-example.feature +54 -0
- package/tests/features/modal-basic-example.feature +42 -0
- package/tests/features/modal-error-handling-example.feature +37 -0
- package/tests/features/modal.feature +11 -0
- package/tests/features/path.feature +16 -0
- package/tests/features/response.feature +8 -0
- package/tests/features/responsive.feature +10 -0
- package/tests/features/table.feature +18 -0
- package/tests/features/test--given--i-am-an-anonymous-user.feature +10 -0
- package/tests/features/test--given--i-am-on-homepage.feature +16 -0
- package/tests/features/test--then--i-save-screenshot.feature +33 -0
- package/tests/features/test--then--i-see-locator.feature +320 -0
- package/tests/features/test--then--i-should--not--see-text-in-element.feature +13 -0
- package/tests/features/test--then--i-should--see-text-in-element-by-attr.feature +10 -0
- package/tests/features/test--then--i-should--see-text-in-element.feature +10 -0
- package/tests/features/test--then--i-should--see-text-matching-pattern-in-element.feature +13 -0
- package/tests/features/test--then--i-should--see-text-matching-pattern.feature +18 -0
- package/tests/features/test--then--i-should-be-on-page.feature +10 -0
- package/tests/features/test--then--i-should-be-on-the-homepage.feature +10 -0
- package/tests/features/test--then--i-should-not-see-an-element-by-attr.feature +8 -0
- package/tests/features/test--then--i-should-not-see-an-element.feature +8 -0
- package/tests/features/test--then--i-should-see-an-element-by-attr.feature +8 -0
- package/tests/features/test--then--i-should-see-an-element.feature +8 -0
- package/tests/features/test--then--i-should-see-n-elements.feature +24 -0
- package/tests/features/test--then--i-should-see-text-in-table-row.feature +96 -0
- package/tests/features/test--then--print-current-url-and-response.feature +21 -0
- package/tests/features/test--then--the-checkbox-is-checked.feature +18 -0
- package/tests/features/test--then--the-checkbox-should-be-checked.feature +16 -0
- package/tests/features/test--then--the-element-should-contain-cssproperty.feature +9 -0
- package/tests/features/test--then--the-element-should-not-contain-cssproperty.feature +10 -0
- package/tests/features/test--then--the-field-should-contain-value.feature +11 -0
- package/tests/features/test--then--the-response-should-contain.feature +11 -0
- package/tests/features/test--then--the-response-status-code-should-be.feature +31 -0
- package/tests/features/test--then--the-url-should-match.feature +7 -0
- package/tests/features/test--then-the-link-should-contain-by-attribute.feature +18 -0
- package/tests/features/test--then-the-link-should-contain.feature +7 -0
- package/tests/features/test--when--i-additionally-select.feature +30 -0
- package/tests/features/test--when--i-attach-file-to-feild.feature +9 -0
- package/tests/features/test--when--i-check-checkbox.feature +21 -0
- package/tests/features/test--when--i-click-link-by-attribute.feature +21 -0
- package/tests/features/test--when--i-click-link.feature +9 -0
- package/tests/features/test--when--i-click-text-in-table-row.feature +37 -0
- package/tests/features/test--when--i-fill-in-by-attr.feature +31 -0
- package/tests/features/test--when--i-fill-in-table-by-attr.feature +19 -0
- package/tests/features/test--when--i-fill-in.feature +32 -0
- package/tests/features/test--when--i-follow.feature +22 -0
- package/tests/features/test--when--i-go-to-homepage.feature +9 -0
- package/tests/features/test--when--i-move-forward-backward-one-page.feature +14 -0
- package/tests/features/test--when--i-press-button-by-attribute.feature +18 -0
- package/tests/features/test--when--i-press-button.feature +13 -0
- package/tests/features/test--when--i-reload-page.feature +11 -0
- package/tests/features/test--when--i-scroll-left-right.feature +48 -0
- package/tests/features/test--when--i-scroll.feature +48 -0
- package/tests/features/test--when--i-select-option-from-dropdownlist.feature +21 -0
- package/tests/features/test--when--i-select-radio-button.feature +37 -0
- package/tests/features/test--when--i-wait-page-is-loaded.feature +8 -0
- package/tests/features/test--when--i-wait-time.feature +21 -0
- package/tests/features/video.feature +18 -0
- package/tests/features/wait.feature +7 -0
- package/tests/features/yaml.feature +102 -0
- package/tests/selectors/_canonical-keys.json +113 -0
- package/tests/selectors/back-end-selectors.json +19 -0
- package/tests/selectors/cms-contentful-admin.json +35 -0
- package/tests/selectors/cms-craft-admin.json +39 -0
- package/tests/selectors/cms-drupal-cms-gin.json +56 -0
- package/tests/selectors/cms-drupal-core-claro.json +50 -0
- package/tests/selectors/cms-generic-admin.json +34 -0
- package/tests/selectors/cms-ghost-admin.json +34 -0
- package/tests/selectors/cms-joomla-admin.json +41 -0
- package/tests/selectors/cms-magento2-admin.json +32 -0
- package/tests/selectors/cms-prestashop-admin.json +38 -0
- package/tests/selectors/cms-shopify-admin.json +25 -0
- package/tests/selectors/cms-strapi-admin.json +42 -0
- package/tests/selectors/cms-typo3-admin.json +41 -0
- package/tests/selectors/cms-woocommerce-front.json +50 -0
- package/tests/selectors/cms-wordpress-admin.json +31 -0
- package/tests/selectors/framework-ant-design.json +80 -0
- package/tests/selectors/framework-bootstrap.json +86 -0
- package/tests/selectors/framework-bulma.json +74 -0
- package/tests/selectors/framework-chakra.json +58 -0
- package/tests/selectors/framework-foundation.json +51 -0
- package/tests/selectors/framework-material-ui.json +72 -0
- package/tests/selectors/framework-shadcn.json +51 -0
- package/tests/selectors/framework-tailwind.json +40 -0
- package/tests/selectors/framework-vuetify.json +61 -0
- package/tests/selectors/front-end-selectors.json +16 -0
- package/tests/selectors/homepage-selectors.json +13 -0
- package/tests/step-definitions/a11y.steps.js +800 -0
- package/tests/step-definitions/action.steps.js +167 -0
- package/tests/step-definitions/api.steps.js +732 -0
- package/tests/step-definitions/assertion.steps.js +352 -0
- package/tests/step-definitions/auth.steps.js +126 -0
- package/tests/step-definitions/clock.steps.js +128 -0
- package/tests/step-definitions/cookie.steps.js +216 -0
- package/tests/step-definitions/debug.steps.js +39 -0
- package/tests/step-definitions/dialog.steps.js +193 -0
- package/tests/step-definitions/drupal-canvas.steps.js +764 -0
- package/tests/step-definitions/drupal-ckeditor.steps.js +108 -0
- package/tests/step-definitions/drupal-core.steps.js +665 -0
- package/tests/step-definitions/drupal-helpers.js +371 -0
- package/tests/step-definitions/drupal-layout-builder.steps.js +466 -0
- package/tests/step-definitions/drupal-media.steps.js +99 -0
- package/tests/step-definitions/drupal-moderation.steps.js +71 -0
- package/tests/step-definitions/drupal-paragraphs.steps.js +50 -0
- package/tests/step-definitions/element.steps.js +356 -0
- package/tests/step-definitions/field.steps.js +653 -0
- package/tests/step-definitions/file-download.steps.js +211 -0
- package/tests/step-definitions/form.steps.js +333 -0
- package/tests/step-definitions/iframe.steps.js +228 -0
- package/tests/step-definitions/input.steps.js +202 -0
- package/tests/step-definitions/javascript.steps.js +232 -0
- package/tests/step-definitions/keyboard.steps.js +112 -0
- package/tests/step-definitions/link.steps.js +142 -0
- package/tests/step-definitions/metatag.steps.js +91 -0
- package/tests/step-definitions/modal.steps.js +244 -0
- package/tests/step-definitions/navigation.steps.js +218 -0
- package/tests/step-definitions/network.steps.js +280 -0
- package/tests/step-definitions/path.steps.js +141 -0
- package/tests/step-definitions/response.steps.js +98 -0
- package/tests/step-definitions/responsive.steps.js +125 -0
- package/tests/step-definitions/rest.steps.js +111 -0
- package/tests/step-definitions/screenshot.steps.js +423 -0
- package/tests/step-definitions/scroll.steps.js +189 -0
- package/tests/step-definitions/selectors.steps.js +1003 -0
- package/tests/step-definitions/storage.steps.js +194 -0
- package/tests/step-definitions/table.steps.js +181 -0
- package/tests/step-definitions/varbase-e2e.js +897 -0
- package/tests/step-definitions/varbase.steps.js +458 -0
- package/tests/step-definitions/video.steps.js +178 -0
- package/tests/step-definitions/wait.steps.js +400 -0
- package/tests/step-definitions/web-first.steps.js +298 -0
- package/tests/step-definitions/xml.steps.js +411 -0
- package/tests/step-definitions/yaml.steps.js +913 -0
- package/tsconfig.json +26 -0
package/CLAUDE.md
ADDED
|
@@ -0,0 +1,544 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
It is also the durable contract between human maintainers of varbase-e2e and
|
|
6
|
+
any AI coding assistant working on the repository. Read it in full before
|
|
7
|
+
making changes. Follow it to the letter — these rules emerged from real
|
|
8
|
+
sessions and reflect strong preferences. `AGENTS.md` is the short,
|
|
9
|
+
machine-readable extract of the same rules; keep the two in sync.
|
|
10
|
+
|
|
11
|
+
## 0. Identity
|
|
12
|
+
|
|
13
|
+
varbase-e2e is a BDD-first browser automation harness built on
|
|
14
|
+
**Playwright + Cucumber-js**. It is its own product. It is **NOT** Behat,
|
|
15
|
+
DrevOps, Drupal, or PHP. Code, file names, comments, and step phrasings
|
|
16
|
+
must never reference those tools or imply that varbase-e2e was ported from
|
|
17
|
+
them. Treat varbase-e2e as the source of truth.
|
|
18
|
+
|
|
19
|
+
Current line: **2.0.x** (branch `2.0.x`; `1.0.x` is the older main branch).
|
|
20
|
+
Node **≥ 20**.
|
|
21
|
+
|
|
22
|
+
## 1. Commands
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install # required first — node_modules is not committed
|
|
26
|
+
npx playwright install --with-deps chromium # browser binaries (CI does this too)
|
|
27
|
+
npm start # http-server over examples/ on :8080 (the fixture site)
|
|
28
|
+
npm test # full suite, pretty output, slowMo 300ms
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
`npm start` must be running (or `LAUNCH_URL` pointed elsewhere) before the
|
|
32
|
+
suite — nearly every bundled feature loads a static fixture from `examples/`.
|
|
33
|
+
|
|
34
|
+
| Command | Effect |
|
|
35
|
+
| --- | --- |
|
|
36
|
+
| `npm test` | Default — pretty output, slow-mo 300 ms, headless chromium. |
|
|
37
|
+
| `npm run test:headed` | `HEADLESS=false`, slow-mo auto-bumps to 800 ms. |
|
|
38
|
+
| `npm run test:fast` | `SLOW_MO=0`. |
|
|
39
|
+
| `npm run test:chromium` / `:firefox` / `:webkit` | Pick the browser (same as `BROWSER=…`). |
|
|
40
|
+
| `npx cucumber-js --dry-run` | Ambiguity / undefined-step check. Run this before declaring done. |
|
|
41
|
+
| `npm run generate-reports` | HTML (+ optional PDF) report from `tests/reports/cucumber_report.json`. |
|
|
42
|
+
|
|
43
|
+
Targeting a subset:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
npx cucumber-js tests/features/modal.feature # one feature file
|
|
47
|
+
npx cucumber-js tests/features/modal.feature:12 # one scenario, by line
|
|
48
|
+
npx cucumber-js --name "Dashboard renders" # by scenario name
|
|
49
|
+
npx cucumber-js --tags "@critical and not @wip" # by tag
|
|
50
|
+
npx cucumber-js --parallel 4 --retry 1 --retry-tag-filter @flaky
|
|
51
|
+
LAUNCH_URL=http://localhost:8080 npx cucumber-js # point at another target
|
|
52
|
+
HEADLESS=false SLOW_MO=800 npx cucumber-js tests/features/x.feature # watch a flake
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Env vars: `LAUNCH_URL`, `BROWSER`, `HEADLESS`, `SLOW_MO`, `FORCE_COLOR`,
|
|
56
|
+
`VARBASE_E2E_AUTO_SETTLE`, `VARBASE_E2E_REPORT_DISABLE`, `VARBASE_E2E_REPORT_ARGS`,
|
|
57
|
+
`VARBASE_E2E_FILTER_HOOK_LINES`, `VARBASE_E2E_SCREENSHOT_*`, `VARBASE_E2E_VIDEO*`,
|
|
58
|
+
`VARBASE_E2E_JS_ERROR_*`, `VARBASE_E2E_SELECTORS_OFFSET`,
|
|
59
|
+
`VARBASE_E2E_SELECTORS_BREAKPOINTS`, `DIFFY_*`. Every one of them mirrors a
|
|
60
|
+
`worldParameters` key in `cucumber.js` — that file is the annotated
|
|
61
|
+
reference; read it before inventing a new knob.
|
|
62
|
+
|
|
63
|
+
## 2. Architecture
|
|
64
|
+
|
|
65
|
+
### 2.1 This repo is a library **and** its own test suite
|
|
66
|
+
|
|
67
|
+
`tests/` serves double duty: it is the step-definition library shipped to
|
|
68
|
+
consumers on npm *and* the self-test suite proving those steps work
|
|
69
|
+
against the static fixtures in `examples/`. A change to a step must keep
|
|
70
|
+
both roles green.
|
|
71
|
+
|
|
72
|
+
Consumer projects install the package and get scaffolded by
|
|
73
|
+
`bin/postinstall.js` → `bin/init-varbase-e2e.js`, which writes a `cucumber.js`
|
|
74
|
+
whose `require` array points at
|
|
75
|
+
`node_modules/@vardot/varbase-e2e/tests/step-definitions/**/*.js` plus the
|
|
76
|
+
project's own `tests/step-definitions/`. Postinstall is a no-op when a
|
|
77
|
+
`cucumber.js` already exists, so re-installs never clobber user config.
|
|
78
|
+
**If you change the shape of `cucumber.js` `worldParameters`, update the
|
|
79
|
+
`CUCUMBER_JS` template inside `bin/init-varbase-e2e.js` in the same change** —
|
|
80
|
+
otherwise new projects get scaffolded with a stale config.
|
|
81
|
+
|
|
82
|
+
### 2.2 `tests/step-definitions/varbase-e2e.js` — the single canonical entry point
|
|
83
|
+
|
|
84
|
+
Everything shared lives here; every `*.steps.js` does
|
|
85
|
+
`require('./varbase-e2e')`. It owns, in one file:
|
|
86
|
+
|
|
87
|
+
* **The World** (`PlaywrightWorld extends World`) — `page`, `context`,
|
|
88
|
+
`playwrightBrowser`, `frame` (iframe scope), `launchUrl`, `minWaitTime`,
|
|
89
|
+
`assetsFolder`, and the named-selector registries `__selectorsCss` /
|
|
90
|
+
`__selectorsXpath`. `setDefaultTimeout(45s)` — deliberately above
|
|
91
|
+
Playwright's 30 s default so locator timeouts reach our try/catch
|
|
92
|
+
wrappers and testers see a friendly message, not "function timed out".
|
|
93
|
+
The 45 s in `cucumber.js` exists for the same reason; keep them aligned.
|
|
94
|
+
* **The init script** installed via `context.addInitScript()` in
|
|
95
|
+
`openBrowser()` — monkey-patches `fetch`, `XMLHttpRequest.send`,
|
|
96
|
+
`setTimeout`/`clearTimeout` and attaches a `MutationObserver` to
|
|
97
|
+
maintain `window.__varbaseE2eAjaxCount`, `__varbaseE2ePendingTimers`,
|
|
98
|
+
`__varbaseE2eLastMutation`. This is the substrate the whole wait policy
|
|
99
|
+
stands on. **Never strip it.**
|
|
100
|
+
* **Hooks** — `Before({order:5})` opens the browser (merging
|
|
101
|
+
`recordVideo` context options when video is on); `After({order:5})`
|
|
102
|
+
captures the video path *before* closing the context, saves/deletes per
|
|
103
|
+
mode, then closes the browser; `BeforeStep` resolves `[relative:…]` date
|
|
104
|
+
tokens in step text, doc strings, and data-table cells; `AfterStep`
|
|
105
|
+
runs the auto-settle.
|
|
106
|
+
* **Shared helpers** (exported): `smartSettle`, `waitForPageLoad`,
|
|
107
|
+
`buildSelector`, `gotoUrl`, `fillField`, `getLocatorText`, `pad`,
|
|
108
|
+
the modal probes (`getModalSelector`, `getModalLocator`,
|
|
109
|
+
`waitForModalState`, `findVisibleModal`, `isAnyModalVisible`), the date
|
|
110
|
+
helpers (`resolveRelativeDate`, `parseRelativeOffset`,
|
|
111
|
+
`formatRelativeDate`), and the error builders (`friendly`, `humanize`).
|
|
112
|
+
* **Two process-level side effects**: a stdout/stderr filter that strips
|
|
113
|
+
noisy `✔ Before # …` hook lines from cucumber's failure dump
|
|
114
|
+
(`VARBASE_E2E_FILTER_HOOK_LINES=off` to disable), and a `process.on('exit')`
|
|
115
|
+
hook that auto-generates the HTML report via `bin/generate-reports`
|
|
116
|
+
(`VARBASE_E2E_REPORT_DISABLE=1` to disable, `VARBASE_E2E_REPORT_ARGS` to pass
|
|
117
|
+
flags).
|
|
118
|
+
|
|
119
|
+
### 2.3 Config layering
|
|
120
|
+
|
|
121
|
+
`playwright.config.ts` (browser choice, launch args, context options) is
|
|
122
|
+
loaded by `varbase-e2e.js` from `process.cwd()` — so a consumer project's own
|
|
123
|
+
copy wins. `cucumber.js` supplies `worldParameters` (launch URL, wait
|
|
124
|
+
padding, selector registry + files + breakpoints, screenshot, video,
|
|
125
|
+
and javascript-error settings). Resolution order everywhere is
|
|
126
|
+
**env var → `worldParameters` → built-in default**; follow that order in
|
|
127
|
+
any new option.
|
|
128
|
+
|
|
129
|
+
### 2.4 Error contract — tester-facing, not developer-facing
|
|
130
|
+
|
|
131
|
+
Risky locator work is wrapped and re-thrown through `friendly()`, which
|
|
132
|
+
renders `Could not <action> "<target>". / Why: <humanize(cause)> /
|
|
133
|
+
Hint: …` and sets `err.stack` to that body so cucumber prints no JS stack.
|
|
134
|
+
`humanize()` maps ~20 Playwright/Node/HTTP patterns to plain English.
|
|
135
|
+
`action.steps.js`'s `actOrExplain(label, target, fn)` is the reference
|
|
136
|
+
wrapper — copy that shape for new interaction steps. Never let a raw
|
|
137
|
+
Playwright error reach the tester.
|
|
138
|
+
|
|
139
|
+
### 2.5 Named selector registry
|
|
140
|
+
|
|
141
|
+
`selectors.steps.js` owns the registry. Selectors resolve **css first,
|
|
142
|
+
then xpath** (auto-prefixed `xpath=`). Three registration paths: inline
|
|
143
|
+
step, bulk data table, or JSON files listed in
|
|
144
|
+
`worldParameters.selectors.files` (loaded from `filesPath`). 26 presets
|
|
145
|
+
ship in `tests/selectors/` (14 CMS admin skins, 9 CSS frameworks, generic
|
|
146
|
+
front/back-end/homepage), normalised against `_canonical-keys.json`. Registry keys
|
|
147
|
+
are also what the human-language steps read — `Then I see main nav above
|
|
148
|
+
breadcrumb`, `When I click primary button` — which is why canonical key
|
|
149
|
+
names matter more than they look.
|
|
150
|
+
|
|
151
|
+
### 2.6 Visual regression lives outside this repo
|
|
152
|
+
|
|
153
|
+
The Diffy step-pack was extracted to its own plugin,
|
|
154
|
+
[`diffy-steps`](https://github.com/webship/diffy-steps). varbase-e2e no
|
|
155
|
+
longer ships `tests/step-definitions-diffy/`, the `diffy`
|
|
156
|
+
`worldParameters` block, or the mock Diffy API. Consumers install the
|
|
157
|
+
plugin and add `node_modules/@webship-js/diffy-steps/tests/step-definitions/**/*.js`
|
|
158
|
+
to their own `require:` list. Nothing in this repo depends on it — the
|
|
159
|
+
steps only ever used `@cucumber/cucumber`, `axios`, and Node built-ins.
|
|
160
|
+
Treat any `diffy` question as a `diffy-steps` question.
|
|
161
|
+
|
|
162
|
+
### 2.7 CI
|
|
163
|
+
|
|
164
|
+
One provider: **GitHub Actions**, `.github/workflows/github-actions.yml`.
|
|
165
|
+
It runs install → `npx playwright install --with-deps chromium` →
|
|
166
|
+
`npm start &` → `npm test`. Change it and update `docs/16-ci-cd.md`.
|
|
167
|
+
|
|
168
|
+
## 3. Communication & change rules
|
|
169
|
+
|
|
170
|
+
1. **Never commit on the user's behalf.** The user always invokes git
|
|
171
|
+
commits manually. AI work stays uncommitted unless asked.
|
|
172
|
+
2. **Pause for irreversible operations.** Never `rm -rf`, `git push --force`,
|
|
173
|
+
`npm publish`, or anything that affects shared state without explicit
|
|
174
|
+
confirmation in the same turn.
|
|
175
|
+
3. **Caveman mode.** When the user has caveman mode active, drop articles,
|
|
176
|
+
filler, and pleasantries in chat replies. Code, commits, security notes,
|
|
177
|
+
and documentation always stay normal English.
|
|
178
|
+
4. **Update docs with every change.** When you add, rename, remove, or
|
|
179
|
+
restructure a step / selector / configuration option, update the matching
|
|
180
|
+
page under `docs/` in the same turn. Specifically:
|
|
181
|
+
* New / removed step → update `docs/04-step-reference.md`.
|
|
182
|
+
* New step file → add it to the source layout block in `docs/README.md`
|
|
183
|
+
(which carries per-file step counts — keep them accurate).
|
|
184
|
+
* Topic-level addition (auth, network, clock, …) → add or refresh the
|
|
185
|
+
dedicated page (`docs/07-auth-state.md`, `docs/06-network-and-dialogs.md`,
|
|
186
|
+
etc.).
|
|
187
|
+
* Selector preset added under `tests/selectors/` → add to the table in
|
|
188
|
+
`docs/03-selector-registry.md`.
|
|
189
|
+
* New config key → `cucumber.js` comment, `bin/init-varbase-e2e.js`
|
|
190
|
+
template, and `docs/global-settings.md`.
|
|
191
|
+
5. **Backups.** When the user says "backup" or asks for a versioned zip,
|
|
192
|
+
bump the patch version in `package.json` and produce
|
|
193
|
+
`~/workspace/products/varbase-e2e-<version>.zip`. Excludes:
|
|
194
|
+
`node_modules/`, `tests/reports/`, `screenshots/`, `.git/`.
|
|
195
|
+
|
|
196
|
+
## 4. Step definition rules
|
|
197
|
+
|
|
198
|
+
### 4.1 Phrasing
|
|
199
|
+
|
|
200
|
+
* Every step MUST support the pronoun prefix `(I |we )*`. Use a regex
|
|
201
|
+
pattern, not a Cucumber Expression with `'I ...'`, for any step where the
|
|
202
|
+
user could plausibly say "I" or "we".
|
|
203
|
+
* Use plain English in the user-visible step text. Avoid camelCase. Examples:
|
|
204
|
+
* `local storage` — NOT `localStorage`
|
|
205
|
+
* `session storage` — NOT `sessionStorage`
|
|
206
|
+
* Keep technical identifiers (CSS selectors, JSON Pointer paths, header
|
|
207
|
+
names) verbatim — they are domain language, not prose.
|
|
208
|
+
* Never reference Behat, DrevOps, Drupal, PHP, or Vardot versioned
|
|
209
|
+
product names in step phrasings or examples. Use neutral placeholders
|
|
210
|
+
(`example`, `Sample title`, `test-runner`).
|
|
211
|
+
|
|
212
|
+
### 4.2 JSDoc block — required for every step
|
|
213
|
+
|
|
214
|
+
Every step definition MUST be preceded by a JSDoc block with:
|
|
215
|
+
|
|
216
|
+
* A short description of what the step asserts or does.
|
|
217
|
+
* Implementation notes only when the WHY is non-obvious (e.g. "uses
|
|
218
|
+
Playwright's networkidle plus a custom AJAX counter so late-firing
|
|
219
|
+
setTimeout callbacks re-arm the wait").
|
|
220
|
+
* **At least 5 `Example #N:` lines** of valid Gherkin that match the step
|
|
221
|
+
pattern. Multi-line examples are permitted (continuation lines are
|
|
222
|
+
context — only the example header line needs to match the pattern).
|
|
223
|
+
* Examples MUST use real, plausible data — no escaped JSON inside `"..."`
|
|
224
|
+
strings unless the step accepts a doc string. Avoid quotes-within-quotes
|
|
225
|
+
Gherkin in examples.
|
|
226
|
+
|
|
227
|
+
Audit the examples by walking every JSDoc `Example #N:` line, stripping the
|
|
228
|
+
Gherkin keyword, and confirming the remainder matches the step regex. Keep
|
|
229
|
+
mismatches at zero. (Past sessions used a throwaway `audit-examples.js`
|
|
230
|
+
for this; write it into the scratchpad, not the repo.)
|
|
231
|
+
|
|
232
|
+
### 4.3 No duplicate logic
|
|
233
|
+
|
|
234
|
+
Before adding a step, search existing files. Identical Playwright calls
|
|
235
|
+
under different phrasings ARE allowed when the phrasings target different
|
|
236
|
+
audiences (e.g. `I hover over "X"` versus `I hover over the element "X"`).
|
|
237
|
+
True duplicate logic — same code, same conceptual scope — must be merged
|
|
238
|
+
or deleted.
|
|
239
|
+
|
|
240
|
+
### 4.4 Do NOT merge
|
|
241
|
+
|
|
242
|
+
Some pairs look similar but cover different domains. NEVER merge:
|
|
243
|
+
|
|
244
|
+
| Pair | Domain boundary |
|
|
245
|
+
| --- | --- |
|
|
246
|
+
| `modal.steps.js` vs `dialog.steps.js` | HTML modal overlay (`role="dialog"`, `.modal`) vs native browser alert / confirm / prompt. |
|
|
247
|
+
| `field.steps.js` vs `form.steps.js` | CSS-selector field control vs label / placeholder / name form fills. |
|
|
248
|
+
| `assertion.steps.js` vs `web-first.steps.js` | Single-snapshot page assertions vs auto-retrying matchers (`within N seconds`). |
|
|
249
|
+
| `xml.steps.js` vs `yaml.steps.js` | Different parsers, different path conventions. |
|
|
250
|
+
| `api.steps.js` vs `rest.steps.js` | Long form (header + body table) vs short-form REST. |
|
|
251
|
+
| `element.steps.js` vs `input.steps.js` | Element-scoped (`the element "X"`) vs short pointer (`"X"`). |
|
|
252
|
+
|
|
253
|
+
## 5. File organisation
|
|
254
|
+
|
|
255
|
+
495 built-in steps across 44 step files. Cucumber auto-loads every
|
|
256
|
+
`*.steps.js` in `tests/step-definitions/`.
|
|
257
|
+
|
|
258
|
+
```
|
|
259
|
+
tests/step-definitions/
|
|
260
|
+
├── varbase-e2e.js # World, hooks, init script, shared helpers — see §2.2. Not a steps file.
|
|
261
|
+
├── drupal-helpers.js # Shared helpers + Before hooks for the drupal-*/varbase step packs. Not a steps file.
|
|
262
|
+
├── a11y.steps.js (26) # axe-core WCAG audits + POUR hygiene probes (axe loaded lazily)
|
|
263
|
+
├── action.steps.js (7) # press / click / follow / attach file (actOrExplain lives here)
|
|
264
|
+
├── api.steps.js (22) # REST long form — base URL, headers, query, body, JSON Pointer
|
|
265
|
+
├── assertion.steps.js (14) # see / not see, in row, in element, response, count
|
|
266
|
+
├── auth.steps.js (3) # storageState save / restore / clear
|
|
267
|
+
├── clock.steps.js (7) # page.clock — install / advance / pause / set
|
|
268
|
+
├── cookie.steps.js (12) # cookie exists / equals / contains
|
|
269
|
+
├── debug.steps.js (2) # print URL / last response
|
|
270
|
+
├── dialog.steps.js (8) # native alert / confirm / prompt handlers
|
|
271
|
+
├── element.steps.js (19) # focus / scroll-to / dispatch / count / position
|
|
272
|
+
├── field.steps.js (27) # field, checkbox, radio, select-list state assertions
|
|
273
|
+
├── file-download.steps.js (8) # download capture + filename / mime / path assertions
|
|
274
|
+
├── form.steps.js (13) # fill / select / additionally select / check / uncheck / radio
|
|
275
|
+
├── iframe.steps.js (10) # frameLocator switch + frame-scoped interactions
|
|
276
|
+
├── input.steps.js (9) # hover / drag / dbl-click / right-click / tap / viewport size
|
|
277
|
+
├── javascript.steps.js (4) # JS error tracking + assertion (warn / fail / off)
|
|
278
|
+
├── keyboard.steps.js (4) # single key + combos with alias normalisation
|
|
279
|
+
├── link.steps.js (9) # href / title / target / rel assertions
|
|
280
|
+
├── metatag.steps.js (3) # <meta> description / keywords / OG / Twitter
|
|
281
|
+
├── modal.steps.js (9) # HTML modal visibility / content / interactions
|
|
282
|
+
├── navigation.steps.js (11) # anonymous user, homepage, paths, history, URL assertions
|
|
283
|
+
├── network.steps.js (10) # route stubs / blocks / delays / offline
|
|
284
|
+
├── path.steps.js (8) # URL path / query parameter / fragment
|
|
285
|
+
├── response.steps.js (4) # response header inspection
|
|
286
|
+
├── responsive.steps.js (5) # named breakpoints + explicit viewport
|
|
287
|
+
├── rest.steps.js (5) # REST short form
|
|
288
|
+
├── screenshot.steps.js (6) # manual + auto-on-failure + per-step capture
|
|
289
|
+
├── scroll.steps.js (12) # ALL scroll phrasings (page + scoped element)
|
|
290
|
+
├── selectors.steps.js (24) # named CSS / XPath registry + position + human-language steps
|
|
291
|
+
├── storage.steps.js (9) # local storage + session storage
|
|
292
|
+
├── table.steps.js (8) # data-table row / column assertions
|
|
293
|
+
├── video.steps.js (4) # start / stop / save webm recording
|
|
294
|
+
├── wait.steps.js (21) # ALL wait phrasings (BBR — see §6)
|
|
295
|
+
├── web-first.steps.js (12) # auto-retrying state matchers
|
|
296
|
+
├── xml.steps.js (20) # XPath equals / contains / count / attr
|
|
297
|
+
├── drupal-canvas.steps.js (12) # Drupal Canvas editor + authoring API (pages, library, patterns, publish)
|
|
298
|
+
├── drupal-ckeditor.steps.js (4) # CKEditor 5 body writing, toolbar commands, Linkit dialog
|
|
299
|
+
├── drupal-core.steps.js (27) # Drupal core: session, rows, operations, breadcrumbs, toolbar, waits
|
|
300
|
+
├── drupal-layout-builder.steps.js (17) # Layout Builder sections + the form controls that configure them
|
|
301
|
+
├── drupal-media.steps.js (4) # media library open / select / insert / submit dialog
|
|
302
|
+
├── drupal-moderation.steps.js (3)# moderation sidebar open + shows / does not show
|
|
303
|
+
├── drupal-paragraphs.steps.js (1)# choose a paragraph component in the add-widget dialog
|
|
304
|
+
├── varbase.steps.js (14) # Varbase: users, tour, theme settings, sticky header, a11y checker, warm-up
|
|
305
|
+
└── yaml.steps.js (38) # multi-doc, types, numerics, JSON Schema, diff
|
|
306
|
+
|
|
307
|
+
tests/features/ # 71 .feature files
|
|
308
|
+
tests/selectors/ # 26 JSON presets + _canonical-keys.json
|
|
309
|
+
tests/assets/ # upload fixtures (pdf, png)
|
|
310
|
+
examples/ # static HTML fixtures served by `npm start`
|
|
311
|
+
bin/ # init-varbase-e2e / postinstall / generate-reports
|
|
312
|
+
docs/ # 17 numbered guides + mirrored reference pages
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
When you add a new step, place it in the file whose topic matches. Do NOT
|
|
316
|
+
spawn a new file unless the topic is genuinely orthogonal to every
|
|
317
|
+
existing file. New file → mention it in `docs/README.md` AND update the
|
|
318
|
+
table above.
|
|
319
|
+
|
|
320
|
+
## 6. Behavior-Based Robotics (BBR) wait policy
|
|
321
|
+
|
|
322
|
+
Static `sleep` is forbidden in step bodies. Every wait step uses
|
|
323
|
+
`smartSettle(page, budget)` from `varbase-e2e.js`, which composites:
|
|
324
|
+
|
|
325
|
+
1. `<body>` attached
|
|
326
|
+
2. `DOMContentLoaded` fired
|
|
327
|
+
3. Playwright `networkidle`
|
|
328
|
+
4. `window.__varbaseE2eAjaxCount === 0` (custom fetch / XHR counter)
|
|
329
|
+
5. `window.__varbaseE2ePendingTimers === 0` (custom `setTimeout` counter)
|
|
330
|
+
6. `Date.now() - window.__varbaseE2eLastMutation >= 250 ms` (DOM-quiet)
|
|
331
|
+
|
|
332
|
+
Conditions 4/5/6 are evaluated atomically in one `waitForFunction`, so a
|
|
333
|
+
late-firing `setTimeout` that mutates the DOM re-arms the wait.
|
|
334
|
+
|
|
335
|
+
Auto-settle hook: `AfterStep` runs `smartSettle(page, 1500)` after every
|
|
336
|
+
step whose text matches `STATE_MUTATING_STEP` (click / press / fill /
|
|
337
|
+
select / check / attach / reload / navigate / …). This is what makes
|
|
338
|
+
`When I click "X" Then I should see "Y"` work without an explicit wait.
|
|
339
|
+
Disable per-run with `VARBASE_E2E_AUTO_SETTLE=off`. If a wait is flaky only in
|
|
340
|
+
CI, raise the budget — never add a static sleep.
|
|
341
|
+
|
|
342
|
+
## 7. Selector registry
|
|
343
|
+
|
|
344
|
+
* Selectors live in `tests/selectors/*.json`, two top-level keys: `css`,
|
|
345
|
+
`xpath`.
|
|
346
|
+
* Built-in presets are normalised against `_canonical-keys.json`. New
|
|
347
|
+
presets MUST use canonical key names where possible — `notice success`
|
|
348
|
+
not `alert-success`, `main nav` not `admin menu`, `data table` not
|
|
349
|
+
`entries table`.
|
|
350
|
+
* Named selector resolution priority: `css` registry first, then `xpath`
|
|
351
|
+
(auto-prefixed with `xpath=`). Register in three ways: inline (`When I
|
|
352
|
+
add "X" selector for "Y" css selector`), bulk via data table, or JSON
|
|
353
|
+
files listed in `worldParameters.selectors.files`.
|
|
354
|
+
* Custom modal selector: every preset SHOULD expose a `modal` key. The
|
|
355
|
+
modal helpers in `varbase-e2e.js` use it before falling back to
|
|
356
|
+
`[role="dialog"], dialog`.
|
|
357
|
+
* When a UI change breaks tests, fix the selector in the JSON preset —
|
|
358
|
+
not the feature files.
|
|
359
|
+
|
|
360
|
+
## 8. Tests must stay green
|
|
361
|
+
|
|
362
|
+
Before declaring a task done:
|
|
363
|
+
|
|
364
|
+
1. `npm install` if `node_modules/` is absent (it is not committed).
|
|
365
|
+
2. Run `npx cucumber-js --dry-run` — no ambiguity, no undefined steps.
|
|
366
|
+
3. Run the full suite with the fixture server up:
|
|
367
|
+
`npm start &` then `LAUNCH_URL=http://localhost:8080 npx cucumber-js`.
|
|
368
|
+
All scenarios must pass.
|
|
369
|
+
4. Fix any mismatch between JSDoc examples and step patterns (§4.2).
|
|
370
|
+
5. Report honestly: if you could not run the suite, say so rather than
|
|
371
|
+
implying green.
|
|
372
|
+
|
|
373
|
+
## 9. AI agent wisdom — see [docs/12-ai-agent-guide.md](docs/12-ai-agent-guide.md)
|
|
374
|
+
|
|
375
|
+
That page distils the canonical guidance from *Varbase-E2E-Recipes v1.0.30*
|
|
376
|
+
into one reference. Internalise these:
|
|
377
|
+
|
|
378
|
+
* **AI generates. Humans validate. Tests verify.** AI does not know what
|
|
379
|
+
"correct" means for the business. The test suite is the executable
|
|
380
|
+
contract.
|
|
381
|
+
* **Test-Drive-Develop loop.** Human writes feature file → human
|
|
382
|
+
prompts AI → AI implements → tests verify. Pass = ship. Fail =
|
|
383
|
+
iterate.
|
|
384
|
+
* **SPDD REASONS canvas.** Every prompt covers Requirements, Entities,
|
|
385
|
+
Approach, Structure, Operations, Norms, Safeguards. Varbase E2E
|
|
386
|
+
feature files map cleanly to it.
|
|
387
|
+
* **Cardinal SPDD rule.** When reality diverges from the prompt,
|
|
388
|
+
**fix the prompt first**, then update the code.
|
|
389
|
+
* **Three Amigos before scenarios.** Product / QA / Dev questions get
|
|
390
|
+
answered in `Feature:` description before any `Scenario:` lines.
|
|
391
|
+
* **DAMP / KISS / YAGNI / MMF.** Self-contained scenarios, simplest
|
|
392
|
+
test that fails, no speculative features, smallest piece of value.
|
|
393
|
+
* **Golden rules** — top three: test behaviour not implementation, wait
|
|
394
|
+
for events not time, one behaviour per scenario.
|
|
395
|
+
* **AI pitfalls.** Over-trusting output, implementation tests, missing
|
|
396
|
+
edge cases, false confidence. Mitigation: AI generates, humans
|
|
397
|
+
validate against business requirements.
|
|
398
|
+
|
|
399
|
+
Tag conventions live in `docs/15-tag-conventions.md` — `@critical`,
|
|
400
|
+
`@smoke`, `@auth`, `@security`, `@a11y`, `@i18n`, `@perf`, `@flaky`,
|
|
401
|
+
`@wip`, `@desktop`/`@mobile`, `@external`, `@auth-setup`, plus the
|
|
402
|
+
recording tags `@video` / `@no-video` and the JS-error tags `@js-fail` /
|
|
403
|
+
`@js-warn` / `@js-off`.
|
|
404
|
+
|
|
405
|
+
## 10. AI prompts — concrete templates
|
|
406
|
+
|
|
407
|
+
When asked to do common tasks, use these templates. They are battle-tested.
|
|
408
|
+
|
|
409
|
+
### Generate a feature file from a user story
|
|
410
|
+
|
|
411
|
+
```
|
|
412
|
+
Read templates/spdd-feature.md (REASONS canvas).
|
|
413
|
+
Fill every section before writing any Gherkin.
|
|
414
|
+
Place the filled-in canvas as # comments at the top of tests/features/<name>.feature.
|
|
415
|
+
Generate one Scenario per Operations item.
|
|
416
|
+
Tag each scenario with the relevant Norm / Safeguard category
|
|
417
|
+
(@critical, @auth, @a11y, @security, @i18n).
|
|
418
|
+
Use built-in steps. Only write a custom step when no preset matches —
|
|
419
|
+
and place it in the file whose topic matches (see CLAUDE.md §5).
|
|
420
|
+
Run npx cucumber-js tests/features/<name>.feature when done.
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
### Add a custom step
|
|
424
|
+
|
|
425
|
+
```
|
|
426
|
+
Search tests/step-definitions/*.steps.js for an existing matching step.
|
|
427
|
+
If one exists, point me at it instead of duplicating.
|
|
428
|
+
Pick the file whose topic matches.
|
|
429
|
+
Use a regex with (I |we )* — never plain 'I ...' Cucumber Expressions.
|
|
430
|
+
Plain English only — no camelCase identifiers in step text.
|
|
431
|
+
Add a JSDoc block with at least 5 Example #N: Gherkin lines.
|
|
432
|
+
Wrap risky locator actions with a friendly try/catch that explains
|
|
433
|
+
the failure (see action.steps.js actOrExplain helper).
|
|
434
|
+
Run npx cucumber-js --dry-run to confirm no ambiguity.
|
|
435
|
+
Run the affected feature(s) to confirm green.
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
### Maintain tests after a UI change
|
|
439
|
+
|
|
440
|
+
```
|
|
441
|
+
Run the suite. Capture every failure: scenario name + step + expected/actual.
|
|
442
|
+
Group failures by root cause (usually 2-3 causes drive 90% of red).
|
|
443
|
+
For text-only changes, find/replace the step text in feature files.
|
|
444
|
+
For structural changes, update the named selector in tests/selectors/<preset>.json.
|
|
445
|
+
Re-run. Iterate until green. Commit prompt + code + selector changes together.
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
### Debug a flaky test
|
|
449
|
+
|
|
450
|
+
```
|
|
451
|
+
Re-run with HEADLESS=false SLOW_MO=800 to watch what really happens.
|
|
452
|
+
Look at screenshots/failed_*.png for the moment of failure.
|
|
453
|
+
Record it: VARBASE_E2E_VIDEO=on npx cucumber-js <path> (or tag the scenario @video).
|
|
454
|
+
Replace any wait Ns with an edge wait:
|
|
455
|
+
wait until the URL contains "..."
|
|
456
|
+
wait for "selector" to appear
|
|
457
|
+
web-first matcher with within N seconds.
|
|
458
|
+
Verify each scenario creates its own data — no cross-scenario state.
|
|
459
|
+
If the bug is timing only in CI, bump the budget on the smart wait,
|
|
460
|
+
do NOT add static sleeps.
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
### Rules of engagement (for the prompt itself)
|
|
464
|
+
|
|
465
|
+
When the user gives an ambiguous task, ASK before guessing. Specifically:
|
|
466
|
+
|
|
467
|
+
- "Where should this step live?" — pick the file whose topic matches §5.
|
|
468
|
+
- "Should this be a custom step or compose existing ones?" — prefer
|
|
469
|
+
composing existing steps inside a feature scenario.
|
|
470
|
+
- "Should I commit?" — never. The user always commits manually.
|
|
471
|
+
- "Should I update docs?" — yes, in the same change. See §3.4.
|
|
472
|
+
- "Should I bump the version + zip?" — only when the user says "backup".
|
|
473
|
+
|
|
474
|
+
## 11. Local AI agents & skills that drive varbase-e2e
|
|
475
|
+
|
|
476
|
+
Seven local Claude Code definitions target varbase-e2e. They are **not**
|
|
477
|
+
part of this repo (`.gitignore` excludes `.claude`) — they are authored in
|
|
478
|
+
the workspace repos and installed into `~/.claude/`:
|
|
479
|
+
|
|
480
|
+
| Source of truth | Installed to | Sync |
|
|
481
|
+
| --- | --- | --- |
|
|
482
|
+
| `~/workspace/agents/*.md` | `~/.claude/agents/` | `agents/cmd-tool-sync-agents.sh --install` (also mirrors the shared `Vardot/ai-agents` repo) |
|
|
483
|
+
| `~/workspace/skills/<name>/SKILL.md` | `~/.claude/skills/` | `skills/cmd-tool-sync-skills.sh` |
|
|
484
|
+
|
|
485
|
+
### Agents
|
|
486
|
+
|
|
487
|
+
| Agent | Model | Scope |
|
|
488
|
+
| --- | --- | --- |
|
|
489
|
+
| `agent-varbase-e2e` | opus | The full specialist. Scaffold (Node.js or DDEV) → author `.feature` files → write custom steps → run → debug → HTML/PDF report. Carries a distilled copy of the whole step catalog, the BBR/selector/tag sections, the 20-recipe cookbook, Varbase learnings, and recipes AI-1…AI-5. Use for anything non-trivial. |
|
|
490
|
+
| `varbase-e2e-ai-agent` | sonnet | The loop-until-green worker for a consumer project: read available steps → write/fix scenarios → run → fix root cause → iterate to zero failures. Lighter, autonomous, Drupal/DDEV-flavoured (`NN-NN-NN-name.feature`, `https://<project>.ddev.site`). |
|
|
491
|
+
|
|
492
|
+
### Skills (slash commands)
|
|
493
|
+
|
|
494
|
+
| Skill | Does |
|
|
495
|
+
| --- | --- |
|
|
496
|
+
| `/varbase-e2e-init` | Scaffold a test project for a URL, or `--ddev` for the `ddev-varbase-e2e` add-on. Idempotent; never clobbers `cucumber.js` without `--force`. |
|
|
497
|
+
| `/varbase-e2e-create` | Author `tests/features/<page>--<category>.feature` for a page or flow — desktop + mobile, web-first assertions, named selectors, tags. |
|
|
498
|
+
| `/varbase-e2e-run` | Run the suite (tag expression or feature path), generate HTML/PDF, and return a root-cause summary per failure. |
|
|
499
|
+
| `/varbase-e2e-audit` | Lint features + custom steps against the documented anti-patterns — sleep-driven waits, god scenarios, brittle selectors, implementation testing, premature custom steps, leaked module state. Output is `file:line — severity — pattern — fix`. |
|
|
500
|
+
| `/varbase-e2e-steps` | Step catalog reference, filterable by category. |
|
|
501
|
+
|
|
502
|
+
`barmoog-varbase-e2e-{init,create,run,audit,steps}` are the same five skills
|
|
503
|
+
hard-targeted at a Barmoog Odoo 18.0 instance. Don't edit them for
|
|
504
|
+
varbase-e2e changes — fix the `varbase-e2e-*` originals and let the Barmoog
|
|
505
|
+
copies be re-derived.
|
|
506
|
+
|
|
507
|
+
### What this means when working *inside* this repo
|
|
508
|
+
|
|
509
|
+
1. **Every one of them reads `node_modules/@vardot/varbase-e2e/…` as the source of
|
|
510
|
+
truth.** That path does not exist here — this *is* the package. Translate:
|
|
511
|
+
`node_modules/@vardot/varbase-e2e/tests/step-definitions/` → `tests/step-definitions/`,
|
|
512
|
+
`node_modules/@vardot/varbase-e2e/docs/` → `docs/`,
|
|
513
|
+
`node_modules/@vardot/varbase-e2e/bin/` → `bin/`.
|
|
514
|
+
Running one of these skills unmodified in this repo will find nothing and
|
|
515
|
+
fall back to fetching from GitHub — i.e. it will read the *published*
|
|
516
|
+
step regex, not your uncommitted change. Read the local files directly
|
|
517
|
+
instead.
|
|
518
|
+
2. **Step regex, JSDoc examples, and `docs/` are their API.** The agents are
|
|
519
|
+
explicitly instructed to verify phrasing against the installed
|
|
520
|
+
`<category>.steps.js` and its JSDoc before recommending a step. A
|
|
521
|
+
rename here silently changes what every agent tells every user — which
|
|
522
|
+
is the real reason for the docs rule in §3.4 and the ≥5-examples rule
|
|
523
|
+
in §4.2.
|
|
524
|
+
3. **Known drift to be aware of, not to "fix" here:** the agents and the
|
|
525
|
+
`/varbase-e2e-run` skill reference a `worldParameters.users` registry and
|
|
526
|
+
an auth helper built on it. There is no `users` key in this repo's
|
|
527
|
+
`cucumber.js` or in `bin/init-varbase-e2e.js` — it is a Varbase-project
|
|
528
|
+
convention layered on top. If a user asks about `users`, say so rather
|
|
529
|
+
than adding the key on the agents' say-so.
|
|
530
|
+
4. **Guardrails they already carry** (so don't re-litigate them): never
|
|
531
|
+
commit; never overwrite a user's `.feature` or `cucumber.js` without
|
|
532
|
+
explicit consent; verify a step exists before recommending it; when
|
|
533
|
+
reality diverges from the prompt, fix the prompt first.
|
|
534
|
+
|
|
535
|
+
## 12. Avoid
|
|
536
|
+
|
|
537
|
+
* Comments that describe WHAT the code does — names already do that.
|
|
538
|
+
* Backwards-compatibility shims for unused code paths — delete unused code.
|
|
539
|
+
* Renaming `_unused` for variables — delete them.
|
|
540
|
+
* Adding feature flags for hypothetical future requirements.
|
|
541
|
+
* `// removed` comments — git history is the record, not the file.
|
|
542
|
+
* Replacing existing selectors with synonyms when canonical keys exist.
|
|
543
|
+
* Raw Playwright errors surfacing to testers — always go through
|
|
544
|
+
`friendly()` / `humanize()`.
|
package/README.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Varbase E2E
|
|
2
|
+
|
|
3
|
+
[](https://github.com/Vardot/varbase-e2e/actions)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
Varbase E2E is an Automated Functional Acceptance Testing tool. Helps to ease and speed the work with the End-to-end testing features in web apps or projects. Utilizing [Playwright](https://playwright.dev) and [Cucumber-js](https://github.com/cucumber/cucumber-js). Having custom and advanced general step definitions.
|
|
7
|
+
|
|
8
|
+
### Varbase E2E Documentation
|
|
9
|
+
All you need to know is in [`docs/`](docs/README.md).
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
## Install varbase-e2e using npm
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
npm install @vardot/varbase-e2e
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Automated Functional Acceptance Testing
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
npm test
|
|
22
|
+
```
|