@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
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
'use strict';
|
|
4
|
+
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const { run } = require('./init-varbase-e2e');
|
|
8
|
+
|
|
9
|
+
const packagePath = path.join(__dirname, '..');
|
|
10
|
+
const projectPath = process.env.INIT_CWD || process.cwd();
|
|
11
|
+
|
|
12
|
+
// Skip when invoked from varbase-e2e itself (development / CI).
|
|
13
|
+
if (
|
|
14
|
+
projectPath === packagePath ||
|
|
15
|
+
projectPath.startsWith(path.join(packagePath, 'node_modules'))
|
|
16
|
+
) {
|
|
17
|
+
process.exit(0);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Only run on a fresh project — cucumber.js absence marks an uninitialized project.
|
|
21
|
+
// Re-installs (npm install, npm ci) will not overwrite user customizations.
|
|
22
|
+
if (fs.existsSync(path.join(projectPath, 'cucumber.js'))) {
|
|
23
|
+
process.exit(0);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
run(['--cwd', projectPath]);
|
package/cucumber.js
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
default: {
|
|
3
|
+
// Cucumber step timeout must exceed Playwright's default 30s so the
|
|
4
|
+
// try/catch wrappers in step files always see the Playwright error
|
|
5
|
+
// first (and emit a friendly message) rather than cucumber's raw
|
|
6
|
+
// "function timed out" stack.
|
|
7
|
+
timeout: 45000,
|
|
8
|
+
// tsx/cjs registers a require() hook so cucumber-js can load both
|
|
9
|
+
// `.js` and `.ts` step files with zero build step. If you ship only
|
|
10
|
+
// JavaScript, drop `requireModule` and the `.ts` half of the glob.
|
|
11
|
+
requireModule: ['tsx/cjs'],
|
|
12
|
+
require: [
|
|
13
|
+
'tests/step-definitions/**/*.js',
|
|
14
|
+
],
|
|
15
|
+
paths: ['tests/features/**/*.feature'],
|
|
16
|
+
format: [
|
|
17
|
+
'@cucumber/pretty-formatter',
|
|
18
|
+
'json:tests/reports/cucumber_report.json',
|
|
19
|
+
],
|
|
20
|
+
formatOptions: {
|
|
21
|
+
// Color toggle is controlled via the FORCE_COLOR env var (per
|
|
22
|
+
// cucumber-js v10+); the deprecated `colorsEnabled` option is gone.
|
|
23
|
+
theme: {
|
|
24
|
+
'feature keyword': ['bold', 'blue'],
|
|
25
|
+
'feature name': ['blue', 'underline'],
|
|
26
|
+
'feature description': ['blueBright'],
|
|
27
|
+
'scenario keyword': ['bold', 'magenta'],
|
|
28
|
+
'scenario name': ['magenta', 'underline'],
|
|
29
|
+
'step keyword': ['bold', 'green'],
|
|
30
|
+
'step text': ['greenBright', 'italic'],
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
worldParameters: {
|
|
34
|
+
launchUrl: process.env.LAUNCH_URL || 'http://localhost:8080',
|
|
35
|
+
minWaitTime: {
|
|
36
|
+
page: 3000,
|
|
37
|
+
before_scenario: 0,
|
|
38
|
+
after_scenario: 0,
|
|
39
|
+
before_step: 0,
|
|
40
|
+
after_step: 0,
|
|
41
|
+
},
|
|
42
|
+
selectors: {
|
|
43
|
+
// Named CSS selectors — layout components and element locators in one registry.
|
|
44
|
+
// Register inline: When I add "name" selector for "css" css selector
|
|
45
|
+
// Or in bulk: Given I define css selectors:
|
|
46
|
+
// | name | css selector |
|
|
47
|
+
css: {
|
|
48
|
+
// 'header': 'header.page-header',
|
|
49
|
+
// 'main nav': 'nav[role="navigation"]',
|
|
50
|
+
// 'breadcrumb': '.breadcrumb',
|
|
51
|
+
// 'breadcrumb first link': '.breadcrumb li:nth-child(1) a',
|
|
52
|
+
// 'message': '.messages',
|
|
53
|
+
// 'error message': '.messages.error',
|
|
54
|
+
// 'success message': '.messages.status',
|
|
55
|
+
// 'warning message': '.messages.warning',
|
|
56
|
+
},
|
|
57
|
+
// Named XPath selectors — use with: When I add "name" selector for "xpath" xpath selector
|
|
58
|
+
xpath: {
|
|
59
|
+
// 'page title': '//h1[contains(@class,"page-header")]',
|
|
60
|
+
},
|
|
61
|
+
// Load additional selectors from JSON files at scenario start.
|
|
62
|
+
filesPath: './tests/selectors/', // base path for selector files
|
|
63
|
+
files: [], // e.g. ['homepage-selectors.json'] or ['front-end-selectors.json', 'back-end-selectors.json']
|
|
64
|
+
// Relative-position scroll offset (px) — VARBASE_E2E_SELECTORS_OFFSET
|
|
65
|
+
offset: 60,
|
|
66
|
+
// Viewport breakpoints — VARBASE_E2E_SELECTORS_BREAKPOINTS (JSON string)
|
|
67
|
+
breakpoints: {
|
|
68
|
+
xs: { width: 375, height: 667 }, // phone portrait
|
|
69
|
+
sm: { width: 576, height: 800 }, // large phone / phablet
|
|
70
|
+
md: { width: 768, height: 1024 }, // tablet portrait
|
|
71
|
+
lg: { width: 992, height: 768 }, // small laptop / tablet landscape
|
|
72
|
+
xl: { width: 1200, height: 900, default: true }, // desktop
|
|
73
|
+
xxl: { width: 1400, height: 900 }, // wide desktop / HD
|
|
74
|
+
xxxl: { width: 1920, height: 1080 }, // Full HD / large monitor
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
screenshot: {
|
|
78
|
+
dir: './screenshots', // VARBASE_E2E_SCREENSHOT_DIR
|
|
79
|
+
purge: false, // VARBASE_E2E_SCREENSHOT_PURGE
|
|
80
|
+
onFailed: true, // VARBASE_E2E_SCREENSHOT_ON_FAILED
|
|
81
|
+
onEveryStep: false, // VARBASE_E2E_SCREENSHOT_ON_EVERY_STEP
|
|
82
|
+
alwaysFullscreen: false, // VARBASE_E2E_SCREENSHOT_FULLSCREEN
|
|
83
|
+
failedPrefix: 'failed_', // VARBASE_E2E_SCREENSHOT_FAILED_PREFIX
|
|
84
|
+
filenamePattern: '{datetime}.{feature_file}.feature_{step_line}.{ext}', // VARBASE_E2E_SCREENSHOT_PATTERN
|
|
85
|
+
filenamePatternFailed: '{failed_prefix}{datetime}.{feature_file}.feature_{step_line}.{ext}', // VARBASE_E2E_SCREENSHOT_PATTERN_FAIL
|
|
86
|
+
infoTypes: '', // VARBASE_E2E_SCREENSHOT_INFO_TYPES e.g. "url,feature,step,datetime"
|
|
87
|
+
},
|
|
88
|
+
video: {
|
|
89
|
+
// Record the browser as a webm video.
|
|
90
|
+
// 'off' (default) — no recording.
|
|
91
|
+
// 'on' — record every scenario.
|
|
92
|
+
// 'on-failure' — record every scenario, keep only failures.
|
|
93
|
+
// 'tag' — record only scenarios tagged @video.
|
|
94
|
+
// Override per scenario with tags:
|
|
95
|
+
// @video — force recording on (independent of mode).
|
|
96
|
+
// @no-video — suppress recording for this scenario.
|
|
97
|
+
// Override per run with env: VARBASE_E2E_VIDEO.
|
|
98
|
+
mode: 'off', // VARBASE_E2E_VIDEO
|
|
99
|
+
dir: './videos', // VARBASE_E2E_VIDEO_DIR
|
|
100
|
+
size: { width: 1280, height: 720 }, // viewport size of the recording
|
|
101
|
+
// Filename template tokens: {datetime} {feature_file} {feature} {scenario}
|
|
102
|
+
// {status} {ext}. Sanitised to filesystem-safe characters.
|
|
103
|
+
filenamePattern: '{datetime}.{feature_file}.{scenario}.{status}.{ext}',
|
|
104
|
+
},
|
|
105
|
+
javascript: {
|
|
106
|
+
// How to report collected JavaScript errors at scenario end.
|
|
107
|
+
// 'warn' (default) — log a yellow warning, scenario still passes.
|
|
108
|
+
// 'fail' — fail the scenario.
|
|
109
|
+
// 'off' — silent.
|
|
110
|
+
// Override per scenario with tags: @js-fail, @js-warn, @js-off.
|
|
111
|
+
// Override per run with env: VARBASE_E2E_JS_ERROR_MODE.
|
|
112
|
+
mode: 'warn', // VARBASE_E2E_JS_ERROR_MODE
|
|
113
|
+
// Console levels to capture in addition to `pageerror`.
|
|
114
|
+
// Common: ['error'], ['error','warning'], ['error','warning','info'].
|
|
115
|
+
levels: ['error'], // VARBASE_E2E_JS_ERROR_LEVELS (csv)
|
|
116
|
+
// Regex string. Errors whose message matches are ignored.
|
|
117
|
+
ignore: '', // VARBASE_E2E_JS_ERROR_IGNORE
|
|
118
|
+
// Snapshot any pre-existing errors at scenario start.
|
|
119
|
+
beforeScenario: false, // VARBASE_E2E_JS_ERROR_BEFORE
|
|
120
|
+
// Report collected errors at scenario end (default true).
|
|
121
|
+
afterScenario: true, // VARBASE_E2E_JS_ERROR_AFTER
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# Quick Start (5 minutes)
|
|
2
|
+
|
|
3
|
+
Brand new to varbase-e2e? Read this page once. You'll be writing tests in
|
|
4
|
+
five minutes.
|
|
5
|
+
|
|
6
|
+
## What you write
|
|
7
|
+
|
|
8
|
+
Plain English scenarios. No JavaScript required.
|
|
9
|
+
|
|
10
|
+
```gherkin
|
|
11
|
+
Feature: Sign in
|
|
12
|
+
|
|
13
|
+
Scenario: Successful login
|
|
14
|
+
Given I am on "/login"
|
|
15
|
+
When I fill in "Email" with "alice@example.com"
|
|
16
|
+
And I fill in "Password" with "s3cret"
|
|
17
|
+
And I press "Sign in"
|
|
18
|
+
Then I should see "Welcome, Alice"
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
That's a complete test. Every line maps to a built-in step. No setup
|
|
22
|
+
code. No selector jargon.
|
|
23
|
+
|
|
24
|
+
## What you get
|
|
25
|
+
|
|
26
|
+
* **Real browser** — runs in Chromium, Firefox, or WebKit via Playwright.
|
|
27
|
+
* **Automatic smart waits** — every action waits for the page to
|
|
28
|
+
settle. No `sleep` / `wait 5s` needed in the happy path.
|
|
29
|
+
* **HTML report** — runs auto-generate `tests/reports/cucumber_report.html`.
|
|
30
|
+
* **Screenshots on failure** — saved to `screenshots/` for instant
|
|
31
|
+
debugging.
|
|
32
|
+
|
|
33
|
+
## 30-second install
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npm install @vardot/varbase-e2e --save-dev
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The post-install script copies a starter `cucumber.js`,
|
|
40
|
+
`playwright.config.ts`, and `tests/` skeleton.
|
|
41
|
+
|
|
42
|
+
## 60-second first test
|
|
43
|
+
|
|
44
|
+
1. Drop your scenario into `tests/features/smoke.feature`.
|
|
45
|
+
2. Make sure your dev server is running on `http://localhost:8080`
|
|
46
|
+
(or set `LAUNCH_URL` to point elsewhere).
|
|
47
|
+
3. Run:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
npm test
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
If your scenario passes, you're done. If it fails, the Cucumber output
|
|
54
|
+
names the step that failed and the expected vs actual.
|
|
55
|
+
|
|
56
|
+
## Where to go next
|
|
57
|
+
|
|
58
|
+
| Want to… | Read |
|
|
59
|
+
| --- | --- |
|
|
60
|
+
| Understand smart waits (no `sleep`) | [02 BBR smart waits](02-bbr-smart-waits.md) |
|
|
61
|
+
| Use named selectors instead of long CSS | [03 Selector registry](03-selector-registry.md) |
|
|
62
|
+
| See every built-in step | [04 Step reference](04-step-reference.md) |
|
|
63
|
+
| Test forms / clicks / modals | [04 Step reference](04-step-reference.md) |
|
|
64
|
+
| Mock APIs / dialogs | [06 Networking & dialogs](06-network-and-dialogs.md) |
|
|
65
|
+
| Accessibility audits | [10 Accessibility](10-accessibility.md) |
|
|
66
|
+
| Use AI to generate tests | [12 AI agent guide](12-ai-agent-guide.md) |
|
|
67
|
+
| FAQ | [13 FAQ](13-faq.md) |
|
|
68
|
+
| Recipes cookbook | [14 Recipes cookbook](14-recipes-cookbook.md) |
|
|
69
|
+
|
|
70
|
+
## The mental model
|
|
71
|
+
|
|
72
|
+
* `Given` — set up the scene (navigate, restore auth, seed data).
|
|
73
|
+
* `When` — do something (click, fill, submit).
|
|
74
|
+
* `Then` — check what should be true (text visible, URL changed).
|
|
75
|
+
* `And` / `But` — continuation. Pick whichever reads naturally.
|
|
76
|
+
* `Background:` — steps shared across every scenario in a feature.
|
|
77
|
+
* `Scenario Outline:` + `Examples:` — same scenario with different data.
|
|
78
|
+
|
|
79
|
+
## The golden rule
|
|
80
|
+
|
|
81
|
+
**Wait for events, not time.** Varbase E2E does this for you in the
|
|
82
|
+
common case. If you ever feel tempted to add `wait 5 seconds` because
|
|
83
|
+
something flaked, look for an event-based wait first:
|
|
84
|
+
|
|
85
|
+
```gherkin
|
|
86
|
+
# Bad — slow, brittle.
|
|
87
|
+
When I press "Save"
|
|
88
|
+
And I wait 5 seconds
|
|
89
|
+
Then I should see "Saved"
|
|
90
|
+
|
|
91
|
+
# Good — instant when fast, patient when slow.
|
|
92
|
+
When I press "Save"
|
|
93
|
+
Then I should see "Saved"
|
|
94
|
+
|
|
95
|
+
# Best when "Save" navigates.
|
|
96
|
+
When I press "Save"
|
|
97
|
+
And I wait until the URL contains "/saved"
|
|
98
|
+
Then I should see "Saved"
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
That's the entire philosophy. Read [02 BBR smart waits](02-bbr-smart-waits.md)
|
|
102
|
+
when you're ready to internalise the details.
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# Getting Started
|
|
2
|
+
|
|
3
|
+
Varbase E2E is an automated functional testing harness built on Playwright + Cucumber-js. You write feature files in plain Gherkin; varbase-e2e handles the browser, smart waits, screenshots, reports, and CMS-aware selectors out of the box.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @vardot/varbase-e2e --save-dev
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
The post-install script copies a starter `cucumber.js`, `playwright.config.ts`, and `tests/` skeleton into your project on first install.
|
|
12
|
+
|
|
13
|
+
## Project layout
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
your-project/
|
|
17
|
+
├── cucumber.js # Profiles + worldParameters
|
|
18
|
+
├── playwright.config.ts # Browser launch + context options
|
|
19
|
+
└── tests/
|
|
20
|
+
├── features/ # *.feature files (Gherkin)
|
|
21
|
+
├── selectors/ # CMS / framework selector JSON
|
|
22
|
+
└── step-definitions/ # *.js or *.ts (loaded automatically)
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## TypeScript and JavaScript together
|
|
26
|
+
|
|
27
|
+
Step definitions can be plain JavaScript (`.js`) or TypeScript (`.ts`) — mix freely in the same project. The default `cucumber.js` registers the [`tsx`](https://tsx.is) require hook, so `.ts` files run with zero build step:
|
|
28
|
+
|
|
29
|
+
```js
|
|
30
|
+
// cucumber.js (default)
|
|
31
|
+
requireModule: ['tsx/cjs'],
|
|
32
|
+
require: ['tests/step-definitions/**/*.{js,ts}'],
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Add a TypeScript step alongside JS ones:
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
// tests/step-definitions/custom.steps.ts
|
|
39
|
+
import { Then } from '@cucumber/cucumber';
|
|
40
|
+
import assert from 'node:assert';
|
|
41
|
+
|
|
42
|
+
Then(/^(I |we )*see a TypeScript step$/, async function (this: { page: import('playwright').Page }) {
|
|
43
|
+
assert.ok(this.page);
|
|
44
|
+
});
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Pure-JS shops can drop both `requireModule` and the `.ts` half of the glob.
|
|
48
|
+
|
|
49
|
+
## Run the suite
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
# Default — full pretty output, optional auto-screenshots on failure.
|
|
53
|
+
npm test
|
|
54
|
+
|
|
55
|
+
# Fast run — no slow-mo.
|
|
56
|
+
npm run test:fast
|
|
57
|
+
|
|
58
|
+
# Watch the browser interactively.
|
|
59
|
+
npm run test:headed
|
|
60
|
+
|
|
61
|
+
# Pick a single browser.
|
|
62
|
+
BROWSER=firefox npm test
|
|
63
|
+
BROWSER=webkit npm test
|
|
64
|
+
|
|
65
|
+
# Parallel + retry (CLI flags — no separate profile needed).
|
|
66
|
+
npx cucumber-js --parallel 4 --retry 1 --retry-tag-filter @flaky
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Environment variables
|
|
70
|
+
|
|
71
|
+
| Variable | Default | Effect |
|
|
72
|
+
| --- | --- | --- |
|
|
73
|
+
| `LAUNCH_URL` | `http://localhost:8080` | Base URL for `Given I am on "/path"` |
|
|
74
|
+
| `BROWSER` | `chromium` | `chromium` / `firefox` / `webkit` |
|
|
75
|
+
| `HEADLESS` | `true` | Set to `false` for headed mode |
|
|
76
|
+
| `SLOW_MO` | `300` headed: `800` | Per-action delay (ms); set `0` for fast runs |
|
|
77
|
+
| `VARBASE_E2E_AUTO_SETTLE` | on | Set to `off` to disable auto edge-wait after actions |
|
|
78
|
+
|
|
79
|
+
## First feature file
|
|
80
|
+
|
|
81
|
+
```gherkin
|
|
82
|
+
Feature: Smoke
|
|
83
|
+
|
|
84
|
+
Scenario: Homepage loads
|
|
85
|
+
Given I am on the homepage
|
|
86
|
+
Then the page should declare a language
|
|
87
|
+
And the page should have exactly one h1
|
|
88
|
+
And there should be no JavaScript errors
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Next reading
|
|
92
|
+
|
|
93
|
+
- [BBR smart waits](02-bbr-smart-waits.md) — why we never `sleep N seconds`.
|
|
94
|
+
- [Selector registry](03-selector-registry.md) — named selectors + CMS presets.
|
|
95
|
+
- [Step reference](04-step-reference.md) — every built-in step, by topic.
|
|
96
|
+
- [Web-first assertions](05-web-first-assertions.md) — auto-retrying matchers.
|
|
97
|
+
- [Networking & dialogs](06-network-and-dialogs.md) — mocks, routes, alerts.
|
|
98
|
+
- [Auth state](07-auth-state.md) — save / restore login.
|
|
99
|
+
- [Clock mocking](08-clock-mocking.md) — control time.
|
|
100
|
+
- [API testing](09-api-testing.md) — direct HTTP from BDD.
|
|
101
|
+
- [Accessibility](10-accessibility.md) — POUR smoke checks.
|
|
102
|
+
- [Debugging](11-debugging.md) — screenshots, headed mode, traces.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# BBR Smart Waits
|
|
2
|
+
|
|
3
|
+
Varbase E2E follows a **Behavior-Based Robotics** philosophy: **react to the environment, not the clock.** A test never sleeps for a fixed N seconds. Instead, every wait step returns as soon as the page is at the **edge** of activity — DOM ready, no in-flight network, no pending timers, no live mutations.
|
|
4
|
+
|
|
5
|
+
## What gets tracked
|
|
6
|
+
|
|
7
|
+
Varbase E2E installs a small init script in every browser context. It exposes four signals:
|
|
8
|
+
|
|
9
|
+
| Signal | Counter / time | Source |
|
|
10
|
+
| --- | --- | --- |
|
|
11
|
+
| Fetch / XHR in flight | `window.__varbaseE2eAjaxCount` | wraps `window.fetch` and `XMLHttpRequest.send` |
|
|
12
|
+
| Pending `setTimeout` | `window.__varbaseE2ePendingTimers` | wraps `window.setTimeout` / `clearTimeout` |
|
|
13
|
+
| Last DOM mutation | `window.__varbaseE2eLastMutation` | `MutationObserver` on `<html>` |
|
|
14
|
+
| Network idle | (Playwright internal) | `page.waitForLoadState('networkidle')` |
|
|
15
|
+
|
|
16
|
+
`smartSettle(page, budget)` polls all four atomically and returns when:
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
__varbaseE2eAjaxCount === 0
|
|
20
|
+
&& __varbaseE2ePendingTimers === 0
|
|
21
|
+
&& (Date.now() - __varbaseE2eLastMutation) >= 250 ms
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
…or when `budget` elapses, whichever comes first. Each phase is best-effort, so a slow network does not stall the others.
|
|
25
|
+
|
|
26
|
+
## Step phrasings
|
|
27
|
+
|
|
28
|
+
```gherkin
|
|
29
|
+
# Bounded smart wait (returns early on idle).
|
|
30
|
+
When I wait 5 seconds
|
|
31
|
+
When I wait max of 5 seconds
|
|
32
|
+
When I wait for 3 seconds for AJAX to finish
|
|
33
|
+
|
|
34
|
+
# Pure edge waits.
|
|
35
|
+
When I wait until the page is loaded
|
|
36
|
+
When I wait for AJAX to finish
|
|
37
|
+
When I wait until pending timers settle
|
|
38
|
+
When I wait until the network is idle
|
|
39
|
+
|
|
40
|
+
# Targeted edge waits.
|
|
41
|
+
When I wait for "#dashboard" to appear
|
|
42
|
+
When I wait for "#loading" to disappear
|
|
43
|
+
When I wait for the text "Welcome" to appear
|
|
44
|
+
When I wait until the URL contains "/dashboard"
|
|
45
|
+
When I wait until the page title contains "Dashboard"
|
|
46
|
+
When I wait until 5 elements match ".product-card"
|
|
47
|
+
When I wait until at least 3 elements match ".item"
|
|
48
|
+
|
|
49
|
+
# Modal-specific.
|
|
50
|
+
When I wait for the modal to appear
|
|
51
|
+
When I wait for the modal to disappear
|
|
52
|
+
|
|
53
|
+
# Body + DOMContentLoaded only (cheaper than full smart settle).
|
|
54
|
+
When I wait until the page is interactive
|
|
55
|
+
|
|
56
|
+
# Polling text assertion — re-runs the matcher until the deadline.
|
|
57
|
+
Then eventually I should see "Done"
|
|
58
|
+
Then eventually I should see "Done" within 10 seconds
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Auto-settle after actions
|
|
62
|
+
|
|
63
|
+
After every state-changing step (click, press, fill, submit, select, check, uncheck, choose, attach, reload, navigate), varbase-e2e silently runs `smartSettle(page, 1500)`. Tests do not need an explicit wait between an action and its follow-up assertion in the typical case. Disable per-run with `VARBASE_E2E_AUTO_SETTLE=off`.
|
|
64
|
+
|
|
65
|
+
## What this kills
|
|
66
|
+
|
|
67
|
+
- **Sleep-driven testing** — `wait 3s` no longer means "sleep three seconds." It means "wait up to three seconds for the page to become quiet."
|
|
68
|
+
- **`networkidle` blind spots** — animations and `setTimeout`-driven UI changes that did not trigger a network request still register on the DOM-mutation and timer-pending signals.
|
|
69
|
+
- **Race-condition flake** — a click followed by an assertion that runs before the DOM finishes updating is now caught by the auto-settle hook.
|
|
70
|
+
|
|
71
|
+
## When to override
|
|
72
|
+
|
|
73
|
+
You generally don't. A few legitimate cases:
|
|
74
|
+
|
|
75
|
+
- **Real animation** with a known duration (`wait 3 seconds` is fine — smart wait will exit early but the budget is still honored).
|
|
76
|
+
- **Polling backend** that mutates without fetch/XHR (e.g. raw WebSocket pushes). Use a targeted edge wait: `wait for the text "..." to appear`.
|
|
77
|
+
- **Off-by-design UI** that runs an `setInterval` heartbeat. The pending-timer counter only tracks `setTimeout`, so heartbeats do not block `smartSettle`.
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Selector Registry
|
|
2
|
+
|
|
3
|
+
Long, brittle CSS strings poison feature files. Varbase E2E solves this with a **named selector registry**: register a CSS or XPath string once, refer to it by a friendly name in every step.
|
|
4
|
+
|
|
5
|
+
## Three ways to register
|
|
6
|
+
|
|
7
|
+
### 1. Inline (one selector at a time)
|
|
8
|
+
|
|
9
|
+
```gherkin
|
|
10
|
+
Scenario: Add to cart
|
|
11
|
+
Given I am on "/products/101"
|
|
12
|
+
When I add "buy button" selector for ".product__buy button[type=submit]" css selector
|
|
13
|
+
And I click "buy button" by attr
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
### 2. Bulk (Gherkin data table)
|
|
17
|
+
|
|
18
|
+
```gherkin
|
|
19
|
+
Scenario: Layout assertions
|
|
20
|
+
Given I define css selectors:
|
|
21
|
+
| header | header.site |
|
|
22
|
+
| nav | nav[role="navigation"] |
|
|
23
|
+
| main | main |
|
|
24
|
+
| footer | footer |
|
|
25
|
+
Then "main" should be visible
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### 3. JSON file (project-wide preset)
|
|
29
|
+
|
|
30
|
+
```js
|
|
31
|
+
// cucumber.js
|
|
32
|
+
worldParameters: {
|
|
33
|
+
selectors: {
|
|
34
|
+
filesPath: './tests/selectors/',
|
|
35
|
+
files: ['cms-drupal-cms-gin.json'],
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Every scenario starts with a fresh registry. Later entries with the same name override earlier ones (last wins).
|
|
41
|
+
|
|
42
|
+
## Built-in CMS / framework presets
|
|
43
|
+
|
|
44
|
+
Varbase E2E ships ready-made selector packs:
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
tests/selectors/
|
|
48
|
+
├── _canonical-keys.json # Index of canonical keys + naming rules
|
|
49
|
+
├── back-end-selectors.json # Generic admin layout
|
|
50
|
+
├── front-end-selectors.json # Generic public layout
|
|
51
|
+
├── cms-drupal-cms-gin.json # Drupal CMS (Gin admin theme)
|
|
52
|
+
├── cms-drupal-core-claro.json # Drupal Core (Claro admin theme)
|
|
53
|
+
├── cms-generic-admin.json # Pattern-matching generic CMS admin
|
|
54
|
+
├── cms-ghost-admin.json # Ghost
|
|
55
|
+
├── cms-joomla-admin.json # Joomla
|
|
56
|
+
├── cms-magento2-admin.json # Magento 2
|
|
57
|
+
├── cms-prestashop-admin.json # PrestaShop
|
|
58
|
+
├── cms-shopify-admin.json # Shopify Polaris admin
|
|
59
|
+
├── cms-strapi-admin.json # Strapi
|
|
60
|
+
├── cms-typo3-admin.json # TYPO3
|
|
61
|
+
├── cms-contentful-admin.json # Contentful
|
|
62
|
+
├── cms-craft-admin.json # Craft CMS
|
|
63
|
+
├── cms-wordpress-admin.json # WordPress
|
|
64
|
+
├── cms-woocommerce-front.json # WooCommerce storefront
|
|
65
|
+
├── framework-ant-design.json # Ant Design
|
|
66
|
+
├── framework-bootstrap.json # Bootstrap
|
|
67
|
+
├── framework-bulma.json # Bulma
|
|
68
|
+
├── framework-chakra.json # Chakra UI
|
|
69
|
+
├── framework-foundation.json # Foundation
|
|
70
|
+
├── framework-material-ui.json # MUI
|
|
71
|
+
├── framework-shadcn.json # shadcn / Radix
|
|
72
|
+
├── framework-tailwind.json # Tailwind common patterns
|
|
73
|
+
└── framework-vuetify.json # Vuetify
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Canonical key set
|
|
77
|
+
|
|
78
|
+
To keep tests portable, every preset exposes the same core names. See `tests/selectors/_canonical-keys.json` for the full list. Highlights:
|
|
79
|
+
|
|
80
|
+
- **Layout** — `main nav`, `main nav item`, `sidebar`, `header bar`, `main content`, `page title`, `breadcrumb`, `user menu`
|
|
81
|
+
- **Modal** — `modal`, `modal overlay`, `modal title`, `modal body`, `modal footer`, `modal close`
|
|
82
|
+
- **Buttons** — `primary button`, `secondary button`, `danger button`, `save button`, `cancel button`, `delete button`
|
|
83
|
+
- **Notices** — `notice success`, `notice error`, `notice warning`, `notice info`, `toast`
|
|
84
|
+
- **Forms** — `form`, `form item`, `form label`, `form input`, `form select`, `form textarea`, `form actions`
|
|
85
|
+
- **Tables** — `data table`, `table header`, `table row`, `table first row`, `table row cell`
|
|
86
|
+
- **Tabs** — `tabs`, `tab item`, `active tab`, `tab content`
|
|
87
|
+
- **Search** — `search input`
|
|
88
|
+
- **Pagination** — `pagination`
|
|
89
|
+
|
|
90
|
+
## Naming rules
|
|
91
|
+
|
|
92
|
+
- Lowercase words separated by single spaces (`primary button`, not `primary-button`).
|
|
93
|
+
- Modifier first (`active tab`, `danger button`, `first list item`).
|
|
94
|
+
- Synonyms collapse to canonical names (`alert success` / `notification success` / `callout success` → `notice success`).
|
|
95
|
+
- `data table` for HTML tables; `data list` for `ul`/`ol` collections.
|