@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,218 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// All navigation step definitions live in this file: anonymous user, going
|
|
4
|
+
// to the homepage / a specific path, browser history (back/forward), reload,
|
|
5
|
+
// and URL/path assertions.
|
|
6
|
+
|
|
7
|
+
const { Given, When, Then } = require('@cucumber/cucumber');
|
|
8
|
+
const assert = require('assert');
|
|
9
|
+
const { gotoUrl, waitForPageLoad, smartSettle } = require('./varbase-e2e');
|
|
10
|
+
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
// Sessions / visits
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Clear cookies and navigate to the launch URL as an anonymous visitor.
|
|
17
|
+
*
|
|
18
|
+
* Example #1: Given I am an anonymous user
|
|
19
|
+
* Example #2: Given we are an anonymous user
|
|
20
|
+
* Example #3: Given an anonymous user
|
|
21
|
+
*
|
|
22
|
+
*/
|
|
23
|
+
Given(/^(I am |we are )?an anonymous user$/, async function (pronounCase) {
|
|
24
|
+
await this.context.clearCookies();
|
|
25
|
+
await gotoUrl(this.page, this.launchUrl);
|
|
26
|
+
await waitForPageLoad(this.page, this.minWaitTime.page || 3000);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Open the homepage.
|
|
31
|
+
*
|
|
32
|
+
* Example #1: Given I am on homepage
|
|
33
|
+
* Example #2: Given I am on the homepage
|
|
34
|
+
* Example #3: Given I am on frontpage
|
|
35
|
+
* Example #4: Given I am on the frontpage
|
|
36
|
+
* Example #5: Given we are on homepage
|
|
37
|
+
* Example #6: Given we are on the frontpage
|
|
38
|
+
* Example #7: Given on homepage
|
|
39
|
+
* Example #8: Given on the homepage
|
|
40
|
+
* Example #9: Given on frontpage
|
|
41
|
+
* Example #10: Given on the frontpage
|
|
42
|
+
*
|
|
43
|
+
*/
|
|
44
|
+
Given(/^(I am |we are )?on( the)* (homepage|frontpage)$/, async function (pronounCase, theCase, pageCase) {
|
|
45
|
+
const defaultTime = this.minWaitTime.page || 3000;
|
|
46
|
+
await gotoUrl(this.page, this.launchUrl);
|
|
47
|
+
await this.page.waitForSelector('body', { state: 'attached', timeout: defaultTime });
|
|
48
|
+
await waitForPageLoad(this.page, defaultTime);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Open a specific page under the launch URL.
|
|
53
|
+
*
|
|
54
|
+
* Example #1: Given I am on "/about-us.html"
|
|
55
|
+
* Example #2: Given I am on the "/about-us.html" page
|
|
56
|
+
* Example #3: Given we are on "/user/login"
|
|
57
|
+
* Example #4: Given we are on the "/contact-us.html" page
|
|
58
|
+
* Example #5: Given on "/about-us.html"
|
|
59
|
+
* Example #6: Given on the "/about-us.html" page
|
|
60
|
+
* Example #7: Given I am on "https://un.org"
|
|
61
|
+
*
|
|
62
|
+
*/
|
|
63
|
+
Given(/^(I am |we are )*on( the)* "([^"]*)?"( page)*$/, async function (pronounCase, theCase, url, pageCase) {
|
|
64
|
+
await gotoUrl(this.page, this.launchUrl + url);
|
|
65
|
+
await this.page.waitForSelector('body', { state: 'attached', timeout: 10000 });
|
|
66
|
+
await waitForPageLoad(this.page);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Navigate to the homepage.
|
|
71
|
+
*
|
|
72
|
+
* Example #1: When I go to homepage
|
|
73
|
+
* Example #2: When I go to the homepage
|
|
74
|
+
* Example #3: When I navigate to the homepage
|
|
75
|
+
* Example #4: When navigating to the homepage
|
|
76
|
+
* Example #5: When navigating to homepage
|
|
77
|
+
* Example #6: When navigating to the frontpage
|
|
78
|
+
* Example #7: When we go to the homepage
|
|
79
|
+
* Example #8: When we navigate to the homepage
|
|
80
|
+
*
|
|
81
|
+
*/
|
|
82
|
+
When(/^(I go |I navigate |we go |we navigate |navigating )?to( the)* (homepage|frontpage)$/, async function (pronounCase, theCase, pageCase) {
|
|
83
|
+
const defaultTime = this.minWaitTime.page || 3000;
|
|
84
|
+
await gotoUrl(this.page, this.launchUrl);
|
|
85
|
+
await this.page.waitForSelector('body', { state: 'attached', timeout: defaultTime });
|
|
86
|
+
await waitForPageLoad(this.page, defaultTime);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Navigate to a specific page.
|
|
91
|
+
*
|
|
92
|
+
* Example #1: When I go to "/contact-us.html"
|
|
93
|
+
* Example #2: When I go to "/user/login"
|
|
94
|
+
* Example #3: When I navigate to "/admin/dashboard"
|
|
95
|
+
* Example #4: When navigating to "/products"
|
|
96
|
+
* Example #5: When we go to "/products"
|
|
97
|
+
* Example #6: When we navigate to "/terms"
|
|
98
|
+
*
|
|
99
|
+
*/
|
|
100
|
+
When(/^(I go |I navigate |we go |we navigate |navigating )?to "([^"]*)?"$/, async function (pronounCase, url) {
|
|
101
|
+
const defaultTime = this.minWaitTime.page || 3000;
|
|
102
|
+
await gotoUrl(this.page, this.launchUrl + url);
|
|
103
|
+
await this.page.waitForSelector('body', { state: 'attached', timeout: defaultTime });
|
|
104
|
+
await waitForPageLoad(this.page, defaultTime);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// ---------------------------------------------------------------------------
|
|
108
|
+
// Browser history + reload
|
|
109
|
+
// ---------------------------------------------------------------------------
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Moves forward one page in browser history.
|
|
113
|
+
*
|
|
114
|
+
* Example #1: When I move forward one page
|
|
115
|
+
* Example #2: When we move forward one page
|
|
116
|
+
* Example #3: And move forward one page
|
|
117
|
+
*
|
|
118
|
+
*/
|
|
119
|
+
When(/^(I |we )*move forward one page$/, async function (pronounCase) {
|
|
120
|
+
await this.page.goForward();
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Moves backward one page in browser history.
|
|
125
|
+
*
|
|
126
|
+
* Example #1: When I move backward one page
|
|
127
|
+
* Example #2: When we move backward one page
|
|
128
|
+
* Example #3: And move backward one page
|
|
129
|
+
*
|
|
130
|
+
*/
|
|
131
|
+
When(/^(I |we )*move backward one page$/, async function (pronounCase) {
|
|
132
|
+
await this.page.goBack();
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Reloads the current page.
|
|
137
|
+
*
|
|
138
|
+
* Example #1: When I reload
|
|
139
|
+
* Example #2: And I reload the page
|
|
140
|
+
* Example #3: And we reload page
|
|
141
|
+
* Example #4: And we reload the page
|
|
142
|
+
*
|
|
143
|
+
*/
|
|
144
|
+
When(/^(I |we )*reload( the)*( page)*$/, async function (pronounCase, theCase, pageCase) {
|
|
145
|
+
await this.page.reload();
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// ---------------------------------------------------------------------------
|
|
149
|
+
// URL / path assertions
|
|
150
|
+
// ---------------------------------------------------------------------------
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Assert that the current page is or is not the homepage.
|
|
154
|
+
*
|
|
155
|
+
* Example #1: Then I should be on homepage
|
|
156
|
+
* Example #2: And I should be on the homepage
|
|
157
|
+
* Example #3: Then I should be on frontpage
|
|
158
|
+
* Example #4: And should be on the homepage
|
|
159
|
+
* Example #5: Then should be on homepage
|
|
160
|
+
* Example #6: And we should be on homepage
|
|
161
|
+
* Example #7: Then should be on frontpage
|
|
162
|
+
* Example #8: And we should be on the homepage
|
|
163
|
+
* Example #9: Then I should not be on homepage
|
|
164
|
+
* Example #10: And I should not be on the homepage
|
|
165
|
+
*
|
|
166
|
+
*/
|
|
167
|
+
Then(/^(I |we )*should( not)* be on( the)* (homepage|frontpage)$/, async function (pronounCase, notCase, theCase, pageCase) {
|
|
168
|
+
const currentUrl = this.page.url();
|
|
169
|
+
if (notCase) {
|
|
170
|
+
assert.ok(currentUrl !== this.launchUrl && !currentUrl.startsWith(this.launchUrl + '/'),
|
|
171
|
+
`Should NOT be on homepage but current URL is: ${currentUrl}`);
|
|
172
|
+
} else {
|
|
173
|
+
assert.ok(currentUrl.startsWith(this.launchUrl),
|
|
174
|
+
`Should be on homepage but current URL is: ${currentUrl}`);
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Assert that the current path is or is not equal to the specified path.
|
|
180
|
+
*
|
|
181
|
+
* Example #1: Then I should be on "/"
|
|
182
|
+
* Example #2: And I should be on "/user/login"
|
|
183
|
+
* Example #3: And I should be on "https://un.org"
|
|
184
|
+
* Example #4: Then we should be on the "/" page
|
|
185
|
+
* Example #5: And we should be on "/user/login"
|
|
186
|
+
* Example #6: Then should be on the "/user/reset" page
|
|
187
|
+
* Example #7: Then I should not be on "/"
|
|
188
|
+
* Example #8: And I should not be on "/user/login"
|
|
189
|
+
* Example #9: And I should not be on "https://un.org"
|
|
190
|
+
* Example #10: And we should not be on the "https://un.org" page
|
|
191
|
+
*
|
|
192
|
+
*/
|
|
193
|
+
Then(/^(I |we )*should( not)* be on( the)* "([^"]*)?"( page)*$/, async function (pronounCase, notCase, theCase, url, pageCase) {
|
|
194
|
+
const currentUrl = this.page.url();
|
|
195
|
+
if (notCase) {
|
|
196
|
+
assert.ok(!currentUrl.includes(url), `URL should NOT contain "${url}" but it is: ${currentUrl}`);
|
|
197
|
+
} else {
|
|
198
|
+
assert.ok(currentUrl.includes(url), `URL should contain "${url}" but it is: ${currentUrl}`);
|
|
199
|
+
}
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Assert that the current URL matches or does not match a regex pattern.
|
|
204
|
+
*
|
|
205
|
+
* Example #1: Then the url should match "/contact-us.html"
|
|
206
|
+
* Example #2: Then the url should not match "/contact-us.html"
|
|
207
|
+
* Example #3: And the url should match "^https://"
|
|
208
|
+
*
|
|
209
|
+
*/
|
|
210
|
+
Then(/^(the )*url should( not)* match "([^"]*)?"$/, async function (theCase, notCase, pattern) {
|
|
211
|
+
const currentUrl = this.page.url();
|
|
212
|
+
const regex = new RegExp(pattern);
|
|
213
|
+
if (notCase) {
|
|
214
|
+
assert.ok(!regex.test(currentUrl), `URL "${currentUrl}" should NOT match "${pattern}" but it does.`);
|
|
215
|
+
} else {
|
|
216
|
+
assert.ok(regex.test(currentUrl), `URL "${currentUrl}" should match "${pattern}" but it does not.`);
|
|
217
|
+
}
|
|
218
|
+
});
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { friendly } = require('./varbase-e2e');
|
|
4
|
+
|
|
5
|
+
// Network interception and mocking via Playwright's `page.route()` API.
|
|
6
|
+
//
|
|
7
|
+
// Lets BDD scenarios stub external dependencies, simulate slow / offline
|
|
8
|
+
// conditions, and assert what the client actually requested — without
|
|
9
|
+
// leaving the test runner. Patterns use Playwright glob matching: `**/path`,
|
|
10
|
+
// `*.gif`, regex inside parentheses, etc.
|
|
11
|
+
//
|
|
12
|
+
// Order matters: register routes BEFORE the action that triggers the request.
|
|
13
|
+
|
|
14
|
+
const { Given, When, Then } = require('@cucumber/cucumber');
|
|
15
|
+
const assert = require('assert');
|
|
16
|
+
|
|
17
|
+
function ensureRequestLog(world) {
|
|
18
|
+
if (world._requestLog) return;
|
|
19
|
+
world._requestLog = [];
|
|
20
|
+
world.page.on('request', (req) => {
|
|
21
|
+
world._requestLog.push({
|
|
22
|
+
url: req.url(),
|
|
23
|
+
method: req.method(),
|
|
24
|
+
resourceType: req.resourceType(),
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
// Stubbing
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Stub a URL pattern with a JSON response body.
|
|
35
|
+
*
|
|
36
|
+
* Body is sent verbatim with `Content-Type: application/json` and HTTP 200.
|
|
37
|
+
*
|
|
38
|
+
* Example #1: Given the URL "**\/api/users" returns the JSON:
|
|
39
|
+
* """
|
|
40
|
+
* {"users": [{"id": 1, "name": "Alice"}]}
|
|
41
|
+
* """
|
|
42
|
+
* Example #2: Given the URL "**\/api/me" returns the JSON:
|
|
43
|
+
* """
|
|
44
|
+
* {"id": 1, "name": "Alice", "role": "admin"}
|
|
45
|
+
* """
|
|
46
|
+
* Example #3: Given the URL "**\/api/products?*" returns the JSON:
|
|
47
|
+
* """
|
|
48
|
+
* {"items": [], "total": 0}
|
|
49
|
+
* """
|
|
50
|
+
* Example #4: Given the URL "https://api.stripe.com/v1/charges" returns the JSON:
|
|
51
|
+
* """
|
|
52
|
+
* {"id": "ch_test", "status": "succeeded"}
|
|
53
|
+
* """
|
|
54
|
+
* Example #5: Given the URL "**\/api/feature-flags" returns the JSON:
|
|
55
|
+
* """
|
|
56
|
+
* {"darkMode": true, "betaUI": false}
|
|
57
|
+
* """
|
|
58
|
+
*
|
|
59
|
+
*/
|
|
60
|
+
Given(/^the URL "([^"]*)" returns the JSON:$/, async function (urlPattern, body) {
|
|
61
|
+
try {
|
|
62
|
+
await this.page.route(urlPattern, async (route) => {
|
|
63
|
+
await route.fulfill({
|
|
64
|
+
status: 200,
|
|
65
|
+
contentType: 'application/json',
|
|
66
|
+
body,
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
} catch (e) {
|
|
70
|
+
throw friendly({
|
|
71
|
+
action: `register a JSON stub for "${urlPattern}"`,
|
|
72
|
+
cause: e,
|
|
73
|
+
hint: `URL pattern uses glob syntax — try "**/api/users" or "*.png".`,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Stub a URL pattern with a status code and plain-text body.
|
|
80
|
+
*
|
|
81
|
+
* Example #1: Given the URL "**\/api/login" returns status 401 with body "Unauthorized"
|
|
82
|
+
* Example #2: Given the URL "**\/api/health" returns status 503
|
|
83
|
+
* Example #3: Given the URL "**\/api/users" returns status 500 with body "Database down"
|
|
84
|
+
* Example #4: Given the URL "**\/api/orders/*" returns status 404
|
|
85
|
+
* Example #5: Given the URL "**\/api/admin/*" returns status 403 with body "Forbidden"
|
|
86
|
+
*
|
|
87
|
+
*/
|
|
88
|
+
Given(/^the URL "([^"]*)" returns status (\d+)(?: with body "([^"]*)")?$/, async function (urlPattern, status, body) {
|
|
89
|
+
try {
|
|
90
|
+
await this.page.route(urlPattern, async (route) => {
|
|
91
|
+
await route.fulfill({ status: parseInt(status, 10), body: body || '' });
|
|
92
|
+
});
|
|
93
|
+
} catch (e) {
|
|
94
|
+
throw friendly({
|
|
95
|
+
action: `register a status-${status} stub for "${urlPattern}"`,
|
|
96
|
+
cause: e,
|
|
97
|
+
hint: `URL pattern uses glob syntax — try "**/api/users" or "*.png".`,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Block a URL pattern entirely (network failure simulation).
|
|
104
|
+
*
|
|
105
|
+
* Example #1: Given the URL "**\/analytics.js" is blocked
|
|
106
|
+
* Example #2: Given the URL "**\/google-analytics.com/**" is blocked
|
|
107
|
+
* Example #3: Given the URL "**\/sentry.io/**" is blocked
|
|
108
|
+
* Example #4: Given the URL "*.gif" is blocked
|
|
109
|
+
* Example #5: Given the URL "**\/api/tracking" is blocked
|
|
110
|
+
*
|
|
111
|
+
*/
|
|
112
|
+
Given(/^the URL "([^"]*)" is blocked$/, async function (urlPattern) {
|
|
113
|
+
try {
|
|
114
|
+
await this.page.route(urlPattern, (route) => route.abort());
|
|
115
|
+
} catch (e) {
|
|
116
|
+
throw friendly({
|
|
117
|
+
action: `block "${urlPattern}"`,
|
|
118
|
+
cause: e,
|
|
119
|
+
hint: `URL pattern uses glob syntax — try "**/analytics.js" or "*.gif".`,
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Delay matching requests by N milliseconds (slow-network simulation).
|
|
126
|
+
*
|
|
127
|
+
* The request still completes against the real upstream — only its arrival
|
|
128
|
+
* time at the page is shifted. Useful for verifying loading-state UI.
|
|
129
|
+
*
|
|
130
|
+
* Example #1: Given the URL "**\/api/**" is delayed by 1500 ms
|
|
131
|
+
* Example #2: Given the URL "**\/api/users" is delayed by 3000 ms
|
|
132
|
+
* Example #3: Given the URL "**\/api/heavy-report" is delayed by 5000 ms
|
|
133
|
+
* Example #4: Given the URL "*.png" is delayed by 500 ms
|
|
134
|
+
* Example #5: Given the URL "**\/api/checkout" is delayed by 2000 ms
|
|
135
|
+
*
|
|
136
|
+
*/
|
|
137
|
+
Given(/^the URL "([^"]*)" is delayed by (\d+) ?ms$/, async function (urlPattern, delay) {
|
|
138
|
+
const ms = parseInt(delay, 10);
|
|
139
|
+
try {
|
|
140
|
+
await this.page.route(urlPattern, async (route) => {
|
|
141
|
+
await new Promise((r) => setTimeout(r, ms));
|
|
142
|
+
await route.continue();
|
|
143
|
+
});
|
|
144
|
+
} catch (e) {
|
|
145
|
+
throw friendly({
|
|
146
|
+
action: `delay "${urlPattern}" by ${ms} ms`,
|
|
147
|
+
cause: e,
|
|
148
|
+
hint: `URL pattern uses glob syntax — try "**/api/**" or "*.png".`,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Simulate offline mode for the rest of the scenario.
|
|
155
|
+
*
|
|
156
|
+
* Example #1: Given the network is offline
|
|
157
|
+
* Example #2: Given I am on the homepage
|
|
158
|
+
* When the network is offline
|
|
159
|
+
* And I follow "Refresh"
|
|
160
|
+
* Then I should see "Offline"
|
|
161
|
+
* Example #3: When the network is offline
|
|
162
|
+
* And I press "Sync"
|
|
163
|
+
* Then I should see "Cannot reach server"
|
|
164
|
+
* Example #4: Given the network is offline
|
|
165
|
+
* And I am on "/dashboard"
|
|
166
|
+
* Example #5: Given the network is offline
|
|
167
|
+
* When I click "Reload"
|
|
168
|
+
* Then "<.error-banner>" should be visible
|
|
169
|
+
*
|
|
170
|
+
*/
|
|
171
|
+
Given(/^the network is offline$/, async function () {
|
|
172
|
+
try { await this.context.setOffline(true); }
|
|
173
|
+
catch (e) { throw friendly({ action: 'switch the network offline', cause: e, hint: 'the browser context may have been closed; try a fresh scenario.' }); }
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Restore network connectivity after `the network is offline`.
|
|
178
|
+
*
|
|
179
|
+
* Example #1: Given the network is online
|
|
180
|
+
* Example #2: When the network is offline
|
|
181
|
+
* And I press "Sync"
|
|
182
|
+
* Then I should see "Cannot reach server"
|
|
183
|
+
* When the network is online
|
|
184
|
+
* And I press "Retry"
|
|
185
|
+
* Then I should see "Synced"
|
|
186
|
+
* Example #3: Given the network is online
|
|
187
|
+
* And I am on the homepage
|
|
188
|
+
* Example #4: When the network is online
|
|
189
|
+
* Example #5: Given the network is online
|
|
190
|
+
* When I follow "Reload"
|
|
191
|
+
* Then I should see "Welcome"
|
|
192
|
+
*
|
|
193
|
+
*/
|
|
194
|
+
Given(/^the network is online$/, async function () {
|
|
195
|
+
try { await this.context.setOffline(false); }
|
|
196
|
+
catch (e) { throw friendly({ action: 'switch the network online', cause: e, hint: 'the browser context may have been closed; try a fresh scenario.' }); }
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
// ---------------------------------------------------------------------------
|
|
200
|
+
// Request logging
|
|
201
|
+
// ---------------------------------------------------------------------------
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Start recording every outgoing request for later assertion.
|
|
205
|
+
*
|
|
206
|
+
* Example #1: Given I start recording network requests
|
|
207
|
+
* Example #2: Given I start recording network requests
|
|
208
|
+
* When I press "Buy now"
|
|
209
|
+
* Then a POST request to "**\/api/checkout" should have been made
|
|
210
|
+
* Example #3: Given we start recording network requests
|
|
211
|
+
* Example #4: Given I start recording network requests
|
|
212
|
+
* When I follow "Pricing"
|
|
213
|
+
* Then no request to "**\/tracking" should have been made
|
|
214
|
+
* Example #5: Given I start recording network requests
|
|
215
|
+
* When I scroll to the bottom
|
|
216
|
+
* Then a GET request to "**\/api/feed/page=2" should have been made
|
|
217
|
+
*
|
|
218
|
+
*/
|
|
219
|
+
Given(/^(I |we )*start recording network requests$/, function () {
|
|
220
|
+
ensureRequestLog(this);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Assert at least one request matching a URL pattern was recorded.
|
|
225
|
+
*
|
|
226
|
+
* Patterns use simple `*` wildcards (regex internally).
|
|
227
|
+
*
|
|
228
|
+
* Example #1: Then a request to "**\/api/users" should have been made
|
|
229
|
+
* Example #2: Then a request to "**\/api/checkout" should have been made
|
|
230
|
+
* Example #3: Then a request to "**\/api/orders/*" should have been made
|
|
231
|
+
* Example #4: Then a request to "*.css" should have been made
|
|
232
|
+
* Example #5: Then a request to "https://api.example.com/**" should have been made
|
|
233
|
+
*
|
|
234
|
+
*/
|
|
235
|
+
Then(/^a request to "([^"]*)" should have been made$/, function (urlPattern) {
|
|
236
|
+
ensureRequestLog(this);
|
|
237
|
+
let re;
|
|
238
|
+
try { re = new RegExp(urlPattern.replace(/\*/g, '.*')); }
|
|
239
|
+
catch (e) { throw friendly({ action: `match URL pattern "${urlPattern}"`, cause: e, hint: "URL pattern must be a valid regex or glob; check for unmatched brackets." }); }
|
|
240
|
+
const found = this._requestLog.some((r) => re.test(r.url));
|
|
241
|
+
assert.ok(found, `Expected at least one request matching "${urlPattern}".`);
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Assert at least one HTTP-method-specific request was recorded.
|
|
246
|
+
*
|
|
247
|
+
* Example #1: Then a GET request to "**\/api/users" should have been made
|
|
248
|
+
* Example #2: Then a POST request to "**\/api/login" should have been made
|
|
249
|
+
* Example #3: Then a PUT request to "**\/api/users/1" should have been made
|
|
250
|
+
* Example #4: Then a PATCH request to "**\/api/orders/*" should have been made
|
|
251
|
+
* Example #5: Then a DELETE request to "**\/api/cart/items/*" should have been made
|
|
252
|
+
*
|
|
253
|
+
*/
|
|
254
|
+
Then(/^a (GET|POST|PUT|PATCH|DELETE) request to "([^"]*)" should have been made$/, function (method, urlPattern) {
|
|
255
|
+
ensureRequestLog(this);
|
|
256
|
+
let re;
|
|
257
|
+
try { re = new RegExp(urlPattern.replace(/\*/g, '.*')); }
|
|
258
|
+
catch (e) { throw friendly({ action: `match URL pattern "${urlPattern}"`, cause: e, hint: "URL pattern must be a valid regex or glob; check for unmatched brackets." }); }
|
|
259
|
+
const found = this._requestLog.some((r) => r.method === method && re.test(r.url));
|
|
260
|
+
assert.ok(found, `Expected at least one ${method} request matching "${urlPattern}".`);
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Assert NO request matching a URL pattern was recorded.
|
|
265
|
+
*
|
|
266
|
+
* Example #1: Then no request to "**\/tracking" should have been made
|
|
267
|
+
* Example #2: Then no request to "**\/google-analytics.com/**" should have been made
|
|
268
|
+
* Example #3: Then no request to "**\/api/admin/**" should have been made
|
|
269
|
+
* Example #4: Then no request to "*.gif" should have been made
|
|
270
|
+
* Example #5: Then no request to "**\/api/v1/legacy/**" should have been made
|
|
271
|
+
*
|
|
272
|
+
*/
|
|
273
|
+
Then(/^no request to "([^"]*)" should have been made$/, function (urlPattern) {
|
|
274
|
+
ensureRequestLog(this);
|
|
275
|
+
let re;
|
|
276
|
+
try { re = new RegExp(urlPattern.replace(/\*/g, '.*')); }
|
|
277
|
+
catch (e) { throw friendly({ action: `match URL pattern "${urlPattern}"`, cause: e, hint: "URL pattern must be a valid regex or glob; check for unmatched brackets." }); }
|
|
278
|
+
const found = this._requestLog.some((r) => re.test(r.url));
|
|
279
|
+
assert.ok(!found, `Did not expect any request matching "${urlPattern}".`);
|
|
280
|
+
});
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// URL path and query parameter assertions, basic auth, history navigation.
|
|
4
|
+
|
|
5
|
+
const { Given, When, Then } = require('@cucumber/cucumber');
|
|
6
|
+
const assert = require('assert');
|
|
7
|
+
|
|
8
|
+
function currentUrl(page) { return new URL(page.url()); }
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Assert the current URL pathname equals an expected string (no query/fragment).
|
|
12
|
+
*
|
|
13
|
+
* Example #1: Then the path should be "/dashboard"
|
|
14
|
+
* Example #2: Then the path should be "/about"
|
|
15
|
+
* Example #3: And the path should be "/checkout/step-2"
|
|
16
|
+
* Example #4: Then the path should be "/admin/users"
|
|
17
|
+
* Example #5: Then the path should be "/"
|
|
18
|
+
*
|
|
19
|
+
*/
|
|
20
|
+
Then('the path should be {string}', async function (path) {
|
|
21
|
+
assert.strictEqual(currentUrl(this.page).pathname, path);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Assert the current URL pathname is NOT equal to an expected string.
|
|
26
|
+
*
|
|
27
|
+
* Example #1: Then the path should not be "/login"
|
|
28
|
+
* Example #2: Then the path should not be "/error"
|
|
29
|
+
* Example #3: And the path should not be "/admin"
|
|
30
|
+
* Example #4: Then the path should not be "/maintenance"
|
|
31
|
+
* Example #5: Then the path should not be "/forbidden"
|
|
32
|
+
*
|
|
33
|
+
*/
|
|
34
|
+
Then('the path should not be {string}', async function (path) {
|
|
35
|
+
assert.notStrictEqual(currentUrl(this.page).pathname, path);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Assert the current URL has the named query parameter (any value).
|
|
40
|
+
*
|
|
41
|
+
* Example #1: Then current url should have the "lang" parameter
|
|
42
|
+
* Example #2: Then current url should have the "page" parameter
|
|
43
|
+
* Example #3: And current url should have the "q" parameter
|
|
44
|
+
* Example #4: Then current url should have the "ref" parameter
|
|
45
|
+
* Example #5: Then current url should have the "sort" parameter
|
|
46
|
+
*
|
|
47
|
+
*/
|
|
48
|
+
Then('current url should have the {string} parameter', async function (param) {
|
|
49
|
+
const u = currentUrl(this.page);
|
|
50
|
+
assert.ok(u.searchParams.has(param), `Query param "${param}" not present in ${u.href}.`);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Assert the current URL has the named query parameter with the exact value.
|
|
55
|
+
*
|
|
56
|
+
* Example #1: Then current url should have the "lang" parameter with the "en" value
|
|
57
|
+
* Example #2: Then current url should have the "page" parameter with the "2" value
|
|
58
|
+
* Example #3: And current url should have the "sort" parameter with the "price" value
|
|
59
|
+
* Example #4: Then current url should have the "ref" parameter with the "newsletter" value
|
|
60
|
+
* Example #5: Then current url should have the "q" parameter with the "laptops" value
|
|
61
|
+
*
|
|
62
|
+
*/
|
|
63
|
+
Then('current url should have the {string} parameter with the {string} value', async function (param, value) {
|
|
64
|
+
const u = currentUrl(this.page);
|
|
65
|
+
assert.strictEqual(u.searchParams.get(param), value);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Assert the current URL does NOT carry the named query parameter.
|
|
70
|
+
*
|
|
71
|
+
* Example #1: Then current url should not have the "missing" parameter
|
|
72
|
+
* Example #2: Then current url should not have the "debug" parameter
|
|
73
|
+
* Example #3: And current url should not have the "preview" parameter
|
|
74
|
+
* Example #4: Then current url should not have the "force" parameter
|
|
75
|
+
* Example #5: Then current url should not have the "test" parameter
|
|
76
|
+
*
|
|
77
|
+
*/
|
|
78
|
+
Then('current url should not have the {string} parameter', async function (param) {
|
|
79
|
+
const u = currentUrl(this.page);
|
|
80
|
+
assert.ok(!u.searchParams.has(param), `Query param "${param}" should not be present.`);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Assert the current URL does NOT carry a parameter+value pair.
|
|
85
|
+
*
|
|
86
|
+
* Example #1: Then current url should not have the "lang" parameter with the "fr" value
|
|
87
|
+
* Example #2: Then current url should not have the "page" parameter with the "100" value
|
|
88
|
+
* Example #3: And current url should not have the "sort" parameter with the "old" value
|
|
89
|
+
* Example #4: Then current url should not have the "preview" parameter with the "1" value
|
|
90
|
+
* Example #5: Then current url should not have the "debug" parameter with the "true" value
|
|
91
|
+
*
|
|
92
|
+
*/
|
|
93
|
+
Then('current url should not have the {string} parameter with the {string} value', async function (param, value) {
|
|
94
|
+
const u = currentUrl(this.page);
|
|
95
|
+
assert.notStrictEqual(u.searchParams.get(param), value);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Re-open the browser context with HTTP basic-auth credentials.
|
|
100
|
+
*
|
|
101
|
+
* Example #1: Given the basic authentication with the username "admin" and the password "secret"
|
|
102
|
+
* Example #2: Given the basic authentication with the username "guest" and the password "guest"
|
|
103
|
+
* Example #3: And the basic authentication with the username "alice" and the password "s3cret"
|
|
104
|
+
* Example #4: Given the basic authentication with the username "ci" and the password "ci-token-123"
|
|
105
|
+
* Example #5: Given the basic authentication with the username "tester" and the password ""
|
|
106
|
+
*
|
|
107
|
+
*/
|
|
108
|
+
Given('the basic authentication with the username {string} and the password {string}', async function (user, pass) {
|
|
109
|
+
// Replace context with one that has HTTP basic auth credentials.
|
|
110
|
+
await this.context.close();
|
|
111
|
+
const playwright = require('playwright');
|
|
112
|
+
const playwrightConfig = require(require('path').join(process.cwd(), 'playwright.config'));
|
|
113
|
+
this.context = await this.playwrightBrowser.newContext({
|
|
114
|
+
...playwrightConfig.contextOptions,
|
|
115
|
+
httpCredentials: { username: user, password: pass },
|
|
116
|
+
});
|
|
117
|
+
this.page = await this.context.newPage();
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Navigate one step back in the browser history.
|
|
122
|
+
*
|
|
123
|
+
* Equivalent to clicking the browser back button. Throws no error if there
|
|
124
|
+
* is no history (returns null from `page.goBack()`).
|
|
125
|
+
*
|
|
126
|
+
* Example #1: When I go back
|
|
127
|
+
* Example #2: When I follow "About"
|
|
128
|
+
* And I go back
|
|
129
|
+
* Then I should be on the homepage
|
|
130
|
+
* Example #3: And I go back
|
|
131
|
+
* Example #4: When I am on "/cart"
|
|
132
|
+
* When I am on "/checkout"
|
|
133
|
+
* And I go back
|
|
134
|
+
* Then I should be on "/cart"
|
|
135
|
+
* Example #5: When I go back
|
|
136
|
+
* And I wait until the URL contains "/products"
|
|
137
|
+
*
|
|
138
|
+
*/
|
|
139
|
+
When(/^(I |we )*go back$/, async function (pronoun) {
|
|
140
|
+
await this.page.goBack();
|
|
141
|
+
});
|