From 56ab77cc31a25d426a390e304d73e5cd13e0e6d6 Mon Sep 17 00:00:00 2001 From: Eduardo Umpierre Date: Wed, 12 Feb 2025 12:21:37 -0300 Subject: [PATCH] Remove Puppeteer references (#10352) --- .eslintrc | 3 +- .github/actions/e2e/run-log-tests/action.yml | 2 +- .github/workflows/e2e-pull-request.yml | 2 +- .github/workflows/e2e-pw-pull-request.yml | 2 +- .github/workflows/e2e-test.yml | 2 +- .github/workflows/e2e-tests-atomic.yml | 2 +- .gitignore | 13 +- .puppeteerrc.cjs | 9 - .../dev-10241-remove-puppeteer-references | 4 + .../blocks/test/payment-method-logos.test.tsx | 16 +- package-lock.json | 481 --------- package.json | 13 +- tests/e2e-pw/README.md | 116 -- tests/e2e-pw/test-e2e-pw-ui.sh | 8 - tests/e2e-pw/test-e2e-pw.sh | 6 - tests/e2e/config/atomic.json | 3 - tests/{e2e-pw => e2e}/config/default.ts | 0 tests/e2e/config/env.setup.js | 6 - tests/e2e/config/jest-custom-environment.js | 20 - tests/e2e/config/jest-custom-sequencer.js | 15 - .../config/jest-puppeteer-headless.config.js | 19 - tests/e2e/config/jest-puppeteer.config.js | 34 - tests/e2e/config/jest.config.js | 62 -- tests/e2e/config/jest.performance.config.js | 15 - tests/e2e/config/jest.setup.js | 152 --- tests/e2e/config/test.json | 3 - tests/{e2e-pw => e2e}/docker-compose.yml | 0 tests/e2e/env/down.sh | 2 +- tests/{e2e-pw => e2e}/playwright.config.ts | 3 +- tests/e2e/playwright.performance.config.ts | 82 ++ ...ytics-should-load-without-any-errors-1.png | Bin ...elect-deposits-list-advanced-filters-1.png | Bin ...ions-page-should-load-without-errors-1.png | Bin ...disputed-order-notice-button-clicked-1.png | Bin ...tton-when-no-currencies-are-selected-1.png | Bin ...olocation-correctly-with-USD-and-GBP-1.png | Bin ...olocation-correctly-with-USD-and-GBP-2.png | Bin ...urrency-page-load-without-any-errors-1.png | Bin tests/{e2e-pw => e2e}/specs/auth.setup.ts | 0 tests/{e2e-pw => e2e}/specs/basic.spec.ts | 0 .../specs/performance/payment-methods.spec.js | 105 -- .../specs/performance/payment-methods.spec.ts | 82 ++ ...bscriptions-renew-action-scheduler.spec.ts | 0 .../merchant-subscriptions-renew.spec.ts | 0 .../merchant-subscriptions-settings.spec.ts | 0 ...pper-subscriptions-manage-payments.spec.ts | 0 ...-subscriptions-purchase-free-trial.spec.ts | 0 ...ns-purchase-multiple-subscriptions.spec.ts | 0 ...bscriptions-purchase-no-signup-fee.spec.ts | 0 ...subscriptions-purchase-sign-up-fee.spec.ts | 0 .../merchant-admin-account-balance.spec.ts | 0 .../merchant/merchant-admin-analytics.spec.ts | 0 .../merchant/merchant-admin-deposits.spec.js | 23 - .../merchant/merchant-admin-deposits.spec.ts | 0 .../merchant/merchant-admin-disputes.spec.ts | 0 .../merchant-admin-transactions.spec.ts | 0 .../merchant-disputes-respond.spec.ts | 0 ...utes-view-details-via-order-notice.spec.ts | 0 .../merchant-multi-currency-widget.spec.ts | 0 .../merchant-orders-full-refund.spec.ts | 0 .../merchant-orders-manual-capture.spec.ts | 0 .../merchant-orders-partial-refund.spec.ts | 0 .../merchant-orders-refund-failures.spec.ts | 0 .../merchant-orders-status-change.spec.ts | 0 ...hant-payment-gateways-confirmation.spec.ts | 0 ...nt-payment-settings-manual-capture.spec.ts | 0 .../merchant-progressive-onboarding.spec.ts | 0 .../multi-currency-on-boarding.spec.ts | 0 .../merchant/multi-currency-setup.spec.ts | 0 .../wcpay/merchant/multi-currency.spec.ts | 0 .../specs/wcpay/merchant/woopay-setup.spec.ts | 0 .../shopper/klarna-checkout-purchase.spec.ts | 0 .../shopper/multi-currency-checkout.spec.ts | 0 .../shopper/shopper-bnpls-checkout.spec.ts | 0 .../shopper-checkout-cart-coupon.spec.ts | 0 .../shopper/shopper-checkout-failures.spec.ts | 0 ...pper-checkout-purchase-site-editor.spec.ts | 0 ...checkout-purchase-with-upe-methods.spec.ts | 0 .../shopper/shopper-checkout-purchase.spec.ts | 0 ...er-checkout-save-card-and-purchase.spec.ts | 0 .../shopper-multi-currency-widget.spec.ts | 0 ...myaccount-payment-methods-add-fail.spec.ts | 0 ...opper-myaccount-renew-subscription.spec.ts | 0 .../shopper-myaccount-saved-cards.spec.ts | 0 .../shopper/shopper-pay-for-order.spec.ts | 0 ...hopper-wc-blocks-checkout-failures.spec.ts | 0 ...hopper-wc-blocks-checkout-purchase.spec.ts | 0 ...ocks-saved-card-checkout-and-usage.spec.ts | 0 tests/e2e/test-e2e-performance.sh | 6 + tests/e2e/test-e2e-ui.sh | 8 + tests/e2e/test-e2e.sh | 6 + tests/e2e/utils/constants.js | 9 - tests/{e2e-pw => e2e}/utils/constants.ts | 7 + tests/e2e/utils/debug.js | 7 - tests/{e2e-pw => e2e}/utils/devtools.ts | 0 tests/e2e/utils/flows.js | 998 ------------------ tests/e2e/utils/helpers.js | 100 -- tests/{e2e-pw => e2e}/utils/helpers.ts | 0 tests/e2e/utils/index.js | 2 - .../utils/merchant-navigation.ts | 0 tests/{e2e-pw => e2e}/utils/merchant.ts | 0 tests/e2e/utils/payments.js | 364 ------- .../utils/{performance.js => performance.ts} | 64 +- tests/{e2e-pw => e2e}/utils/rest-api.ts | 0 .../utils/shopper-navigation.ts | 0 tests/{e2e-pw => e2e}/utils/shopper.ts | 0 tests/js/jest.config.js | 1 - 107 files changed, 257 insertions(+), 2620 deletions(-) delete mode 100644 .puppeteerrc.cjs create mode 100644 changelog/dev-10241-remove-puppeteer-references delete mode 100644 tests/e2e-pw/README.md delete mode 100755 tests/e2e-pw/test-e2e-pw-ui.sh delete mode 100755 tests/e2e-pw/test-e2e-pw.sh delete mode 100644 tests/e2e/config/atomic.json rename tests/{e2e-pw => e2e}/config/default.ts (100%) delete mode 100644 tests/e2e/config/env.setup.js delete mode 100644 tests/e2e/config/jest-custom-environment.js delete mode 100644 tests/e2e/config/jest-custom-sequencer.js delete mode 100644 tests/e2e/config/jest-puppeteer-headless.config.js delete mode 100644 tests/e2e/config/jest-puppeteer.config.js delete mode 100644 tests/e2e/config/jest.config.js delete mode 100644 tests/e2e/config/jest.performance.config.js delete mode 100644 tests/e2e/config/jest.setup.js delete mode 100644 tests/e2e/config/test.json rename tests/{e2e-pw => e2e}/docker-compose.yml (100%) rename tests/{e2e-pw => e2e}/playwright.config.ts (96%) create mode 100644 tests/e2e/playwright.performance.config.ts rename tests/{e2e-pw => e2e}/specs/__snapshots__/wcpay/merchant/merchant-admin-analytics.spec.ts/Admin-order-analytics-should-load-without-any-errors-1.png (100%) rename tests/{e2e-pw => e2e}/specs/__snapshots__/wcpay/merchant/merchant-admin-deposits.spec.ts/Merchant-deposits-Select-deposits-list-advanced-filters-1.png (100%) rename tests/{e2e-pw => e2e}/specs/__snapshots__/wcpay/merchant/merchant-admin-transactions.spec.ts/Admin-transactions-page-should-load-without-errors-1.png (100%) rename tests/{e2e-pw => e2e}/specs/__snapshots__/wcpay/merchant/merchant-disputes-view-details-via-order-notice.spec.ts/Disputes-View-dispute-details-via-disputed-o-f9e9d-ils-when-disputed-order-notice-button-clicked-1.png (100%) rename tests/{e2e-pw => e2e}/specs/__snapshots__/wcpay/merchant/multi-currency-on-boarding.spec.ts/Multi-currency-on-boarding-Currency-selection--7b0d9-submit-button-when-no-currencies-are-selected-1.png (100%) rename tests/{e2e-pw => e2e}/specs/__snapshots__/wcpay/merchant/multi-currency-on-boarding.spec.ts/Multi-currency-on-boarding-Geolocation-feature-83665-tch-by-geolocation-correctly-with-USD-and-GBP-1.png (100%) rename tests/{e2e-pw => e2e}/specs/__snapshots__/wcpay/merchant/multi-currency-on-boarding.spec.ts/Multi-currency-on-boarding-Geolocation-feature-d8568-tch-by-geolocation-correctly-with-USD-and-GBP-2.png (100%) rename tests/{e2e-pw => e2e}/specs/__snapshots__/wcpay/merchant/multi-currency.spec.ts/Multi-currency-page-load-without-any-errors-1.png (100%) rename tests/{e2e-pw => e2e}/specs/auth.setup.ts (100%) rename tests/{e2e-pw => e2e}/specs/basic.spec.ts (100%) delete mode 100644 tests/e2e/specs/performance/payment-methods.spec.js create mode 100644 tests/e2e/specs/performance/payment-methods.spec.ts rename tests/{e2e-pw => e2e}/specs/subscriptions/merchant/merchant-subscriptions-renew-action-scheduler.spec.ts (100%) rename tests/{e2e-pw => e2e}/specs/subscriptions/merchant/merchant-subscriptions-renew.spec.ts (100%) rename tests/{e2e-pw => e2e}/specs/subscriptions/merchant/merchant-subscriptions-settings.spec.ts (100%) rename tests/{e2e-pw => e2e}/specs/subscriptions/shopper/shopper-subscriptions-manage-payments.spec.ts (100%) rename tests/{e2e-pw => e2e}/specs/subscriptions/shopper/shopper-subscriptions-purchase-free-trial.spec.ts (100%) rename tests/{e2e-pw => e2e}/specs/subscriptions/shopper/shopper-subscriptions-purchase-multiple-subscriptions.spec.ts (100%) rename tests/{e2e-pw => e2e}/specs/subscriptions/shopper/shopper-subscriptions-purchase-no-signup-fee.spec.ts (100%) rename tests/{e2e-pw => e2e}/specs/subscriptions/shopper/shopper-subscriptions-purchase-sign-up-fee.spec.ts (100%) rename tests/{e2e-pw => e2e}/specs/wcpay/merchant/merchant-admin-account-balance.spec.ts (100%) rename tests/{e2e-pw => e2e}/specs/wcpay/merchant/merchant-admin-analytics.spec.ts (100%) delete mode 100644 tests/e2e/specs/wcpay/merchant/merchant-admin-deposits.spec.js rename tests/{e2e-pw => e2e}/specs/wcpay/merchant/merchant-admin-deposits.spec.ts (100%) rename tests/{e2e-pw => e2e}/specs/wcpay/merchant/merchant-admin-disputes.spec.ts (100%) rename tests/{e2e-pw => e2e}/specs/wcpay/merchant/merchant-admin-transactions.spec.ts (100%) rename tests/{e2e-pw => e2e}/specs/wcpay/merchant/merchant-disputes-respond.spec.ts (100%) rename tests/{e2e-pw => e2e}/specs/wcpay/merchant/merchant-disputes-view-details-via-order-notice.spec.ts (100%) rename tests/{e2e-pw => e2e}/specs/wcpay/merchant/merchant-multi-currency-widget.spec.ts (100%) rename tests/{e2e-pw => e2e}/specs/wcpay/merchant/merchant-orders-full-refund.spec.ts (100%) rename tests/{e2e-pw => e2e}/specs/wcpay/merchant/merchant-orders-manual-capture.spec.ts (100%) rename tests/{e2e-pw => e2e}/specs/wcpay/merchant/merchant-orders-partial-refund.spec.ts (100%) rename tests/{e2e-pw => e2e}/specs/wcpay/merchant/merchant-orders-refund-failures.spec.ts (100%) rename tests/{e2e-pw => e2e}/specs/wcpay/merchant/merchant-orders-status-change.spec.ts (100%) rename tests/{e2e-pw => e2e}/specs/wcpay/merchant/merchant-payment-gateways-confirmation.spec.ts (100%) rename tests/{e2e-pw => e2e}/specs/wcpay/merchant/merchant-payment-settings-manual-capture.spec.ts (100%) rename tests/{e2e-pw => e2e}/specs/wcpay/merchant/merchant-progressive-onboarding.spec.ts (100%) rename tests/{e2e-pw => e2e}/specs/wcpay/merchant/multi-currency-on-boarding.spec.ts (100%) rename tests/{e2e-pw => e2e}/specs/wcpay/merchant/multi-currency-setup.spec.ts (100%) rename tests/{e2e-pw => e2e}/specs/wcpay/merchant/multi-currency.spec.ts (100%) rename tests/{e2e-pw => e2e}/specs/wcpay/merchant/woopay-setup.spec.ts (100%) rename tests/{e2e-pw => e2e}/specs/wcpay/shopper/klarna-checkout-purchase.spec.ts (100%) rename tests/{e2e-pw => e2e}/specs/wcpay/shopper/multi-currency-checkout.spec.ts (100%) rename tests/{e2e-pw => e2e}/specs/wcpay/shopper/shopper-bnpls-checkout.spec.ts (100%) rename tests/{e2e-pw => e2e}/specs/wcpay/shopper/shopper-checkout-cart-coupon.spec.ts (100%) rename tests/{e2e-pw => e2e}/specs/wcpay/shopper/shopper-checkout-failures.spec.ts (100%) rename tests/{e2e-pw => e2e}/specs/wcpay/shopper/shopper-checkout-purchase-site-editor.spec.ts (100%) rename tests/{e2e-pw => e2e}/specs/wcpay/shopper/shopper-checkout-purchase-with-upe-methods.spec.ts (100%) rename tests/{e2e-pw => e2e}/specs/wcpay/shopper/shopper-checkout-purchase.spec.ts (100%) rename tests/{e2e-pw => e2e}/specs/wcpay/shopper/shopper-checkout-save-card-and-purchase.spec.ts (100%) rename tests/{e2e-pw => e2e}/specs/wcpay/shopper/shopper-multi-currency-widget.spec.ts (100%) rename tests/{e2e-pw => e2e}/specs/wcpay/shopper/shopper-myaccount-payment-methods-add-fail.spec.ts (100%) rename tests/{e2e-pw => e2e}/specs/wcpay/shopper/shopper-myaccount-renew-subscription.spec.ts (100%) rename tests/{e2e-pw => e2e}/specs/wcpay/shopper/shopper-myaccount-saved-cards.spec.ts (100%) rename tests/{e2e-pw => e2e}/specs/wcpay/shopper/shopper-pay-for-order.spec.ts (100%) rename tests/{e2e-pw => e2e}/specs/wcpay/shopper/shopper-wc-blocks-checkout-failures.spec.ts (100%) rename tests/{e2e-pw => e2e}/specs/wcpay/shopper/shopper-wc-blocks-checkout-purchase.spec.ts (100%) rename tests/{e2e-pw => e2e}/specs/wcpay/shopper/shopper-wc-blocks-saved-card-checkout-and-usage.spec.ts (100%) create mode 100755 tests/e2e/test-e2e-performance.sh create mode 100755 tests/e2e/test-e2e-ui.sh create mode 100755 tests/e2e/test-e2e.sh delete mode 100644 tests/e2e/utils/constants.js rename tests/{e2e-pw => e2e}/utils/constants.ts (66%) delete mode 100644 tests/e2e/utils/debug.js rename tests/{e2e-pw => e2e}/utils/devtools.ts (100%) delete mode 100644 tests/e2e/utils/flows.js delete mode 100644 tests/e2e/utils/helpers.js rename tests/{e2e-pw => e2e}/utils/helpers.ts (100%) delete mode 100644 tests/e2e/utils/index.js rename tests/{e2e-pw => e2e}/utils/merchant-navigation.ts (100%) rename tests/{e2e-pw => e2e}/utils/merchant.ts (100%) delete mode 100644 tests/e2e/utils/payments.js rename tests/e2e/utils/{performance.js => performance.ts} (67%) rename tests/{e2e-pw => e2e}/utils/rest-api.ts (100%) rename tests/{e2e-pw => e2e}/utils/shopper-navigation.ts (100%) rename tests/{e2e-pw => e2e}/utils/shopper.ts (100%) diff --git a/.eslintrc b/.eslintrc index 8e00567ca43..98c80c96018 100644 --- a/.eslintrc +++ b/.eslintrc @@ -21,8 +21,7 @@ "wcpaySettings": true, "page": true, "browser": true, - "context": true, - "jestPuppeteer": true + "context": true }, "settings": { "react": { diff --git a/.github/actions/e2e/run-log-tests/action.yml b/.github/actions/e2e/run-log-tests/action.yml index 53f0f78652c..f2f9a4b236e 100644 --- a/.github/actions/e2e/run-log-tests/action.yml +++ b/.github/actions/e2e/run-log-tests/action.yml @@ -39,7 +39,7 @@ runs: name: wp(${{ env.E2E_WP_VERSION }})-wc(${{ env.E2E_WC_VERSION }})-${{ env.E2E_GROUP }}-${{ env.E2E_BRANCH }} path: | playwright-report/ - tests/e2e-pw/test-results + tests/e2e/test-results ${{ env.E2E_RESULT_FILEPATH }} if-no-files-found: ignore retention-days: 14 diff --git a/.github/workflows/e2e-pull-request.yml b/.github/workflows/e2e-pull-request.yml index afb5dfecdfb..e8f5e526bef 100644 --- a/.github/workflows/e2e-pull-request.yml +++ b/.github/workflows/e2e-pull-request.yml @@ -30,7 +30,7 @@ env: E2E_SLACK_CHANNEL: ${{ secrets.E2E_SLACK_CHANNEL }} E2E_SLACK_TOKEN: ${{ secrets.E2E_SLACK_TOKEN }} E2E_USE_LOCAL_SERVER: false - E2E_RESULT_FILEPATH: 'tests/e2e-pw/results.json' + E2E_RESULT_FILEPATH: 'tests/e2e/results.json' WCPAY_USE_BUILD_ARTIFACT: ${{ inputs.wcpay-use-build-artifact }} WCPAY_ARTIFACT_DIRECTORY: 'zipfile' NODE_ENV: 'test' diff --git a/.github/workflows/e2e-pw-pull-request.yml b/.github/workflows/e2e-pw-pull-request.yml index da6765fb51b..c5a8f20201a 100644 --- a/.github/workflows/e2e-pw-pull-request.yml +++ b/.github/workflows/e2e-pw-pull-request.yml @@ -71,4 +71,4 @@ jobs: run: npx playwright install chromium - name: Run tests, upload screenshots & logs - uses: ./.github/actions/e2e-pw/run-log-tests + uses: ./.github/actions/e2e/run-log-tests diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.yml index c68a4d61a81..16c0736beb3 100644 --- a/.github/workflows/e2e-test.yml +++ b/.github/workflows/e2e-test.yml @@ -22,7 +22,7 @@ env: E2E_SLACK_CHANNEL: ${{ secrets.E2E_SLACK_CHANNEL }} E2E_SLACK_TOKEN: ${{ secrets.E2E_SLACK_TOKEN }} E2E_USE_LOCAL_SERVER: false - E2E_RESULT_FILEPATH: 'tests/e2e-pw/results.json' + E2E_RESULT_FILEPATH: 'tests/e2e/results.json' WC_MIN_SUPPORTED_VERSION: '7.6.0' NODE_ENV: 'test' FORCE_E2E_DEPS_SETUP: true diff --git a/.github/workflows/e2e-tests-atomic.yml b/.github/workflows/e2e-tests-atomic.yml index 30cb1b55d61..be25eddd88a 100644 --- a/.github/workflows/e2e-tests-atomic.yml +++ b/.github/workflows/e2e-tests-atomic.yml @@ -10,7 +10,7 @@ env: E2E_SLACK_TOKEN: ${{ secrets.E2E_SLACK_TOKEN }} E2E_WP_VERSION: 'nightly' E2E_WC_VERSION: 'latest' - E2E_RESULT_FILEPATH: 'tests/e2e-pw/results.json' + E2E_RESULT_FILEPATH: 'tests/e2e/results.json' NODE_ENV: 'atomic' concurrency: diff --git a/.gitignore b/.gitignore index 8a1b9da0119..0248c9744e8 100644 --- a/.gitignore +++ b/.gitignore @@ -85,16 +85,15 @@ local.env # Screenshots created locally when running e2e tests tests/e2e/screenshots -# E2E Performance test results +# E2E test results tests/e2e/reports - -# E2E Playwright /playwright-report/ /blob-report/ -tests/e2e-pw/.auth/ -tests/e2e-pw/test-results/ -tests/e2e-pw/playwright/.cache/ -tests/e2e-pw/tests/e2e-pw/.auth/* +tests/e2e/.auth/ +tests/e2e/test-results/ +tests/e2e/playwright/.cache/ +tests/e2e/tests/e2e/.auth/* + # Slate docs docs/rest-api/build/* diff --git a/.puppeteerrc.cjs b/.puppeteerrc.cjs deleted file mode 100644 index 8c0e0bd08b6..00000000000 --- a/.puppeteerrc.cjs +++ /dev/null @@ -1,9 +0,0 @@ -const {join} = require('path'); - -/** - * @type {import("puppeteer").Configuration} - */ -module.exports = { - // Changes the cache location for Puppeteer. - cacheDirectory: join(__dirname, 'node_modules', '.cache', 'puppeteer'), -}; \ No newline at end of file diff --git a/changelog/dev-10241-remove-puppeteer-references b/changelog/dev-10241-remove-puppeteer-references new file mode 100644 index 00000000000..632ad49d6f1 --- /dev/null +++ b/changelog/dev-10241-remove-puppeteer-references @@ -0,0 +1,4 @@ +Significance: patch +Type: dev + +Remove Puppeteer references. diff --git a/client/checkout/blocks/test/payment-method-logos.test.tsx b/client/checkout/blocks/test/payment-method-logos.test.tsx index 2e946884312..b9dc227b5c4 100644 --- a/client/checkout/blocks/test/payment-method-logos.test.tsx +++ b/client/checkout/blocks/test/payment-method-logos.test.tsx @@ -3,7 +3,7 @@ */ import React from 'react'; import { render, screen, fireEvent } from '@testing-library/react'; -import { describe, test, expect } from '@jest/globals'; + /** * Internal dependencies */ @@ -18,7 +18,7 @@ const mockPaymentMethods = [ ]; describe( 'PaymentMethodsLogos', () => { - test( 'renders without crashing', () => { + it( 'renders without crashing', () => { render( { expect( logoContainer ).toBeTruthy(); } ); - test( 'displays correct number of logos based on maxElements', () => { + it( 'displays correct number of logos based on maxElements', () => { render( { expect( logos ).toHaveLength( 3 ); } ); - test( 'shows popover indicator when there are more payment methods than maxElements', () => { + it( 'shows popover indicator when there are more payment methods than maxElements', () => { render( { expect( popoverIndicator ).toBeTruthy(); } ); - test( 'opens popover on button click', async () => { + it( 'opens popover on button click', async () => { render( { expect( popover ).toBeTruthy(); } ); - test( 'handles keyboard navigation', async () => { + it( 'handles keyboard navigation', async () => { render( { expect( popover ).toBeTruthy(); } ); - test( 'does not show popover indicator when there are fewer payment methods than maxElements', () => { + it( 'does not show popover indicator when there are fewer payment methods than maxElements', () => { render( { expect( logos ).toHaveLength( mockPaymentMethods.length ); } ); - test( 'does not show popover when there are fewer payment methods than maxElements', async () => { + it( 'does not show popover when there are fewer payment methods than maxElements', async () => { render( =12" } }, - "node_modules/@wordpress/e2e-test-utils": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/@wordpress/e2e-test-utils/-/e2e-test-utils-8.6.0.tgz", - "integrity": "sha512-ojauttVboG2jc8OftFoG09SLPqhGGPGQY22Gzzn270jdB+ZJFP3mRv2E79/nd0F8b9qvYbiyhE57Dv+Tby9W+g==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.16.0", - "@wordpress/api-fetch": "^6.19.0", - "@wordpress/keycodes": "^3.22.0", - "@wordpress/url": "^3.23.0", - "change-case": "^4.1.2", - "form-data": "^4.0.0", - "node-fetch": "^2.6.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "jest": ">=27", - "puppeteer-core": ">=11" - } - }, "node_modules/@wordpress/e2e-test-utils-playwright": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@wordpress/e2e-test-utils-playwright/-/e2e-test-utils-playwright-1.3.0.tgz", @@ -17036,91 +17009,6 @@ "node": ">= 6" } }, - "node_modules/@wordpress/e2e-test-utils/node_modules/@wordpress/api-fetch": { - "version": "6.55.0", - "resolved": "https://registry.npmjs.org/@wordpress/api-fetch/-/api-fetch-6.55.0.tgz", - "integrity": "sha512-1HrCUsJdeRY5Y0IjplotINwqMRO81e7O7VhBScuKk7iOuDm/E1ioKv2uLGnPNWziYu+Zf025byxOqVzXDyM2gw==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.16.0", - "@wordpress/i18n": "^4.58.0", - "@wordpress/url": "^3.59.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@wordpress/e2e-test-utils/node_modules/@wordpress/hooks": { - "version": "3.58.0", - "resolved": "https://registry.npmjs.org/@wordpress/hooks/-/hooks-3.58.0.tgz", - "integrity": "sha512-9LB0ZHnZRQlORttux9t/xbAskF+dk2ujqzPGsVzc92mSKpQP3K2a5Wy74fUnInguB1vLUNHT6nrNdkVom5qX1Q==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.16.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@wordpress/e2e-test-utils/node_modules/@wordpress/i18n": { - "version": "4.58.0", - "resolved": "https://registry.npmjs.org/@wordpress/i18n/-/i18n-4.58.0.tgz", - "integrity": "sha512-VfvS3BWv/RDjRKD6PscIcvYfWKnGJcI/DEqyDgUMhxCM6NRwoL478CsUKTiGJIymeyRodNRfprdcF086DpGKYw==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.16.0", - "@wordpress/hooks": "^3.58.0", - "gettext-parser": "^1.3.1", - "memize": "^2.1.0", - "sprintf-js": "^1.1.1", - "tannin": "^1.2.0" - }, - "bin": { - "pot-to-php": "tools/pot-to-php.js" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@wordpress/e2e-test-utils/node_modules/@wordpress/url": { - "version": "3.59.0", - "resolved": "https://registry.npmjs.org/@wordpress/url/-/url-3.59.0.tgz", - "integrity": "sha512-GxvoMjYCav0w4CiX0i0h3qflrE/9rhLIZg5aPCQjbrBdwTxYR3Exfw0IJYcmVaTKXQOUU8fOxlDxULsbLmKe9w==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.16.0", - "remove-accents": "^0.5.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@wordpress/e2e-test-utils/node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/@wordpress/e2e-test-utils/node_modules/memize": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/memize/-/memize-2.1.0.tgz", - "integrity": "sha512-yywVJy8ctVlN5lNPxsep5urnZ6TTclwPEyigM9M3Bi8vseJBOfqNrGWN/r8NzuIt3PovM323W04blJfGQfQSVg==", - "dev": true - }, - "node_modules/@wordpress/e2e-test-utils/node_modules/remove-accents": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/remove-accents/-/remove-accents-0.5.0.tgz", - "integrity": "sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A==", - "dev": true - }, "node_modules/@wordpress/element": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/@wordpress/element/-/element-4.4.1.tgz", @@ -28117,15 +28005,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/expect-puppeteer": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/expect-puppeteer/-/expect-puppeteer-10.0.0.tgz", - "integrity": "sha512-E7sE6nVdEbrnpDOBMmcLgyqLJKt876AlBg1A+gsu5R8cWx+SLafreOgJAgzXg5Qko7Tk0cW5oZdRbHQLU738dg==", - "dev": true, - "engines": { - "node": ">=16" - } - }, "node_modules/expect/node_modules/ansi-styles": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", @@ -33533,109 +33412,6 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-environment-puppeteer": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/jest-environment-puppeteer/-/jest-environment-puppeteer-10.0.1.tgz", - "integrity": "sha512-FxMzVRyqieQqSy5CPWiwdK5t9dkRHid5eoRTVa8RtYeXLlpW6lU0dAmxEfPkdnDVCiPUhC2APeKOXq0J72bgag==", - "dev": true, - "dependencies": { - "chalk": "^4.1.2", - "cosmiconfig": "^8.3.6", - "deepmerge": "^4.3.1", - "jest-dev-server": "^10.0.0", - "jest-environment-node": "^29.7.0" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/jest-environment-puppeteer/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/jest-environment-puppeteer/node_modules/cosmiconfig": { - "version": "8.3.6", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", - "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", - "dev": true, - "dependencies": { - "import-fresh": "^3.3.0", - "js-yaml": "^4.1.0", - "parse-json": "^5.2.0", - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/d-fischer" - }, - "peerDependencies": { - "typescript": ">=4.9.5" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/jest-environment-puppeteer/node_modules/jest-dev-server": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/jest-dev-server/-/jest-dev-server-10.0.0.tgz", - "integrity": "sha512-FtyBBDxrAIfTX3hyKSOwj5KU6Z7fFLew5pQYOFpwyf+qpPpULL8aYxtsFkbkAwcs+Mb7qhcNbVLeiWsLOd7CKw==", - "dev": true, - "dependencies": { - "chalk": "^4.1.2", - "cwd": "^0.10.0", - "find-process": "^1.4.7", - "prompts": "^2.4.2", - "spawnd": "^10.0.0", - "tree-kill": "^1.2.2", - "wait-on": "^7.2.0" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/jest-environment-puppeteer/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jest-environment-puppeteer/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/jest-environment-puppeteer/node_modules/spawnd": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/spawnd/-/spawnd-10.0.0.tgz", - "integrity": "sha512-6GKcakMTryb5b1SWCvdubCDHEsR2k+5VZUD5G19umZRarkvj1RyCGyizcqhjewI7cqZo8fTVD8HpnDZbVOLMtg==", - "dev": true, - "dependencies": { - "signal-exit": "^4.1.0", - "tree-kill": "^1.2.2" - }, - "engines": { - "node": ">=16" - } - }, "node_modules/jest-get-type": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", @@ -34279,22 +34055,6 @@ } } }, - "node_modules/jest-puppeteer": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/jest-puppeteer/-/jest-puppeteer-10.0.1.tgz", - "integrity": "sha512-FzC35XbqeuQEt1smXh1EOqhJaRkWqJkyWDMfGkcZ8C59QHXeJ7F/iOmiNqYi6l/OsycUuOPCk+IkjfGfS9YbrQ==", - "dev": true, - "dependencies": { - "expect-puppeteer": "^10.0.0", - "jest-environment-puppeteer": "^10.0.1" - }, - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "puppeteer": ">=19" - } - }, "node_modules/jest-regex-util": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", @@ -41067,22 +40827,6 @@ "node": ">=6" } }, - "node_modules/puppeteer": { - "version": "19.11.1", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-19.11.1.tgz", - "integrity": "sha512-39olGaX2djYUdhaQQHDZ0T0GwEp+5f9UB9HmEP0qHfdQHIq0xGQZuAZ5TLnJIc/88SrPLpEflPC+xUqOTv3c5g==", - "deprecated": "< 22.6.4 is no longer supported", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "@puppeteer/browsers": "0.5.0", - "cosmiconfig": "8.1.3", - "https-proxy-agent": "5.0.1", - "progress": "2.0.3", - "proxy-from-env": "1.1.0", - "puppeteer-core": "19.11.1" - } - }, "node_modules/puppeteer-core": { "version": "13.7.0", "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-13.7.0.tgz", @@ -41186,231 +40930,6 @@ } } }, - "node_modules/puppeteer/node_modules/@puppeteer/browsers": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-0.5.0.tgz", - "integrity": "sha512-Uw6oB7VvmPRLE4iKsjuOh8zgDabhNX67dzo8U/BB0f9527qx+4eeUs+korU98OhG5C4ubg7ufBgVi63XYwS6TQ==", - "dev": true, - "dependencies": { - "debug": "4.3.4", - "extract-zip": "2.0.1", - "https-proxy-agent": "5.0.1", - "progress": "2.0.3", - "proxy-from-env": "1.1.0", - "tar-fs": "2.1.1", - "unbzip2-stream": "1.4.3", - "yargs": "17.7.1" - }, - "bin": { - "browsers": "lib/cjs/main-cli.js" - }, - "engines": { - "node": ">=14.1.0" - }, - "peerDependencies": { - "typescript": ">= 4.7.4" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/puppeteer/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/puppeteer/node_modules/chromium-bidi": { - "version": "0.4.7", - "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.7.tgz", - "integrity": "sha512-6+mJuFXwTMU6I3vYLs6IL8A1DyQTPjCfIL971X0aMPVGRbGnNfl6i6Cl0NMbxi2bRYLGESt9T2ZIMRM5PAEcIQ==", - "dev": true, - "dependencies": { - "mitt": "3.0.0" - }, - "peerDependencies": { - "devtools-protocol": "*" - } - }, - "node_modules/puppeteer/node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/puppeteer/node_modules/cosmiconfig": { - "version": "8.1.3", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.1.3.tgz", - "integrity": "sha512-/UkO2JKI18b5jVMJUp0lvKFMpa/Gye+ZgZjKD+DGEN9y7NRcf/nK1A0sp67ONmKtnDCNMS44E6jrk0Yc3bDuUw==", - "dev": true, - "dependencies": { - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/d-fischer" - } - }, - "node_modules/puppeteer/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/puppeteer/node_modules/devtools-protocol": { - "version": "0.0.1107588", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1107588.tgz", - "integrity": "sha512-yIR+pG9x65Xko7bErCUSQaDLrO/P1p3JUzEk7JCU4DowPcGHkTGUGQapcfcLc4qj0UaALwZ+cr0riFgiqpixcg==", - "dev": true - }, - "node_modules/puppeteer/node_modules/extract-zip": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", - "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", - "dev": true, - "dependencies": { - "debug": "^4.1.1", - "get-stream": "^5.1.0", - "yauzl": "^2.10.0" - }, - "bin": { - "extract-zip": "cli.js" - }, - "engines": { - "node": ">= 10.17.0" - }, - "optionalDependencies": { - "@types/yauzl": "^2.9.1" - } - }, - "node_modules/puppeteer/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/puppeteer/node_modules/puppeteer-core": { - "version": "19.11.1", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-19.11.1.tgz", - "integrity": "sha512-qcuC2Uf0Fwdj9wNtaTZ2OvYRraXpAK+puwwVW8ofOhOgLPZyz1c68tsorfIZyCUOpyBisjr+xByu7BMbEYMepA==", - "dev": true, - "dependencies": { - "@puppeteer/browsers": "0.5.0", - "chromium-bidi": "0.4.7", - "cross-fetch": "3.1.5", - "debug": "4.3.4", - "devtools-protocol": "0.0.1107588", - "extract-zip": "2.0.1", - "https-proxy-agent": "5.0.1", - "proxy-from-env": "1.1.0", - "tar-fs": "2.1.1", - "unbzip2-stream": "1.4.3", - "ws": "8.13.0" - }, - "engines": { - "node": ">=14.14.0" - }, - "peerDependencies": { - "typescript": ">= 4.7.4" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/puppeteer/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/puppeteer/node_modules/ws": { - "version": "8.13.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", - "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", - "dev": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/puppeteer/node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/puppeteer/node_modules/yargs": { - "version": "17.7.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", - "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", - "dev": true, - "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/pure-rand": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", diff --git a/package.json b/package.json index c0be9d14c13..2ce86f7b741 100644 --- a/package.json +++ b/package.json @@ -34,10 +34,10 @@ "test:e2e-up": "./tests/e2e/env/up.sh", "test:e2e-cleanup": "./tests/e2e/env/cleanup.sh", "test:e2e-reset": "npm run test:e2e-down && npm run test:e2e-cleanup", - "test:e2e": "./tests/e2e-pw/test-e2e-pw.sh", - "test:e2e-ci": "npx playwright test --config=tests/e2e-pw/playwright.config.ts --grep-invert @todo", - "test:e2e-ui": "./tests/e2e-pw/test-e2e-pw-ui.sh", - "test:e2e-performance": "NODE_CONFIG_DIR='tests/e2e/config' wp-scripts test-e2e --config tests/e2e/config/jest.performance.config.js", + "test:e2e": "./tests/e2e/test-e2e.sh", + "test:e2e-ci": "npx playwright test --config=tests/e2e/playwright.config.ts --grep-invert @todo", + "test:e2e-ui": "./tests/e2e/test-e2e-ui.sh", + "test:e2e-performance": "./tests/e2e/test-e2e-performance.sh", "test:e2e-update-snapshots": "npm run test:e2e -- --update-snapshots", "test:update-snapshots": "npm run test:js -- --updateSnapshot", "test:php": "./bin/run-tests.sh", @@ -135,7 +135,6 @@ "@wordpress/data-controls": "2.6.1", "@wordpress/date": "4.5.0", "@wordpress/dom-ready": "3.6.1", - "@wordpress/e2e-test-utils": "8.6.0", "@wordpress/element": "4.4.1", "@wordpress/hooks": "3.6.1", "@wordpress/html-entities": "3.6.1", @@ -167,15 +166,12 @@ "eslint-plugin-react": "7.22.0", "eslint-plugin-react-hooks": "4.2.0", "eslint-plugin-wpcalypso": "5.0.0", - "expect-puppeteer": "10.0.0", "gridicons": "3.4.2", "husky": "8.0.1", "is-ci": "3.0.0", "iti": "0.6.0", "jest": "29.7.0", "jest-environment-jsdom": "29.7.0", - "jest-environment-puppeteer": "10.0.1", - "jest-puppeteer": "10.0.1", "lint-staged": "10.5.4", "mini-css-extract-plugin": "2.3.0", "moment": "2.29.4", @@ -183,7 +179,6 @@ "postcss": "8.3.5", "prettier": "npm:wp-prettier@2.0.5", "process": "0.11.10", - "puppeteer": "19.11.1", "qrcode.react": "3.1.0", "react": "17.0.2", "react-dom": "17.0.2", diff --git a/tests/e2e-pw/README.md b/tests/e2e-pw/README.md deleted file mode 100644 index e7f7f50e671..00000000000 --- a/tests/e2e-pw/README.md +++ /dev/null @@ -1,116 +0,0 @@ -# Playwright end-to-end tests 🎭 - -Playwright e2e tests can be found in the `./tests/e2e-pw/specs` directory. These will run in parallel with the existing Puppeteer e2e tests and are intended to replace them as they are migrated. - -## Setup local e2e environment - -See [tests/e2e/README.md](/tests/e2e/README.md) for detailed e2e environment setup instructions. - -1. `npm run test:e2e-setup` -1. `npm run test:e2e-up` - -> [!TIP] -> In case some tests fail due to the lack of `data-test-id` attributes, you'll need to run `npm start` or `NODE_ENV=test npm run build:client` to re-build the assets. - -## Running Playwright e2e tests - -- `npm run test:e2e-pw` headless run from within a linux docker container. -- `npm run test:e2e-pw-ui` runs tests in interactive UI mode from within a linux docker container – recommended for authoring tests and re-running failed tests. -- `npm run test:e2e-pw keyword` runs tests only with a specific keyword in the file name, e.g. `dispute` or `checkout`. -- `npm run test:e2e-pw -- --update-snapshots` updates snapshots. This can be combined with a keyword to update a specific set of snapshots, e.g. `npm run test:e2e-pw -- --update-snapshots deposits`. - -## FAQs - -**I'm getting errors that host.docker.internal is not found.** - -This is because the `host.docker.internal` alias is not available on Linux. You can use the `localhost` alias instead. To apply it, create a file called `docker-compose.override.yml` in the `tests/e2e-pw` directory and add the following content: - -```yaml -services: - playwright: - environment: - - BASE_URL=http://localhost:8084 -``` - -**How do I wait for a page or element to load?** - -Since [Playwright automatically waits](https://playwright.dev/docs/actionability) for elements to be present in the page before interacting with them, you probably don't need to explicitly wait for elements to load. For example, all of the following locators will automatically wait for the element to be present and stable before asserting or interacting with it: - -```ts -await expect( page.getByRole( 'heading', { name: 'Sign up' } ) ).toBeVisible(); -await page.getByRole( 'checkbox', { name: 'Subscribe' } ).check(); -await page.getByRole( 'button', { name: /submit/i } ).click(); -``` - -In some cases, you may need to wait for the page to reach a certain load state before interacting with it. You can use `await page.waitForLoadState( 'domcontentloaded' );` to wait for the page to finish loading. - -**What is the best way to target elements in the page?** - -Prefer the use of [user-facing attribute or test-id locators](https://playwright.dev/docs/locators#locating-elements) to target elements in the page. This will make the tests more resilient to changes to implementation details, such as class names. - -```ts -// Prefer locating by role, label, text, or test id when possible. See https://playwright.dev/docs/locators -await page.getByRole( 'button', { name: 'All payouts' } ).click(); -await page.getByLabel( 'Select a deposit status' ).selectOption( 'Pending' ); -await expect( page.getByText( 'Order received' ) ).toBeVisible(); -await page.getByTestId( 'accept-dispute-button' ).click(); - -// Use CSS selectors as a last resort -await page.locator( 'button.components-button.is-secondary' ); -``` - -**How do I create a visual regression test?** - -Visual regression tests are captured by the [`toHaveScreenshot()` function](https://playwright.dev/docs/api/class-pageassertions#page-assertions-to-have-screenshot-2). This function takes a screenshot of a page or element and compares it to a reference image. If the images are different, the test will fail. - -```ts -await expect( page ).toHaveScreenshot(); - -await expect( - page.getByRole( 'button', { name: 'All payouts' } ) -).toHaveScreenshot(); -``` - -**How can I act as shopper or merchant in a test?** - -1. To switch between `shopper` and `merchant` role in a test, use the `getShopper` and `getMerchant` function: - -```ts -import { getShopper, getMerchant } from './utils/helpers'; - -test( 'should do things as shopper and merchant', async ( { browser } ) => { - const { shopperPage } = await getShopper( browser ); - const { merchantPage } = await getMerchant( browser ); - - // do things as shopper - await shopperPage.goto( '/cart/' ); - - // do things as merchant - await merchantPage.goto( '/wp-admin/admin.php?page=wc-settings' ); -} ); -``` - -2. To act as `shopper` or `merchant` for an entire test suite (`describe`), use the helper function `useShopper` or `useMerchant` from `tests/e2e-pw/utils/helpers.ts`: - -```ts -import { useShopper } from '../utils/helpers'; - -test.describe( 'Sign in as customer', () => { - useShopper(); - test( 'Load customer my account page', async ( { page } ) => { - // do things as shopper - await page.goto( '/my-account' ); - } ); -} ); -``` - -**How can I investigate and interact with a test failures?** - -- **Github Action test runs** - - View GitHub checks in the "Checks" tab of a PR - - Click on the "E2E Playwright Tests" job to see the job summary - - Download the `playwright-report.zip` artifact, extract and copy the `playwright-report` directory to the root of the WooPayments repository - - Run `npx playwright show-report` to open the report in a browser -- **Local test runs**: - - Local test reports will output in the `playwright-report` directory - - Run `npx playwright show-report` to open the report in a browser diff --git a/tests/e2e-pw/test-e2e-pw-ui.sh b/tests/e2e-pw/test-e2e-pw-ui.sh deleted file mode 100755 index d035bb07cd7..00000000000 --- a/tests/e2e-pw/test-e2e-pw-ui.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash - -echo "🎭 Running Playwright e2e tests in interactive UI mode."; -echo ""; -echo "Open http://localhost:8077 in your browser to see the UI."; - -docker compose -f ./tests/e2e-pw/docker-compose.yml run --rm -it --service-ports playwright \ - npx playwright test --config=tests/e2e-pw/playwright.config.ts --ui --ui-host=0.0.0.0 --ui-port=8077 "$@" diff --git a/tests/e2e-pw/test-e2e-pw.sh b/tests/e2e-pw/test-e2e-pw.sh deleted file mode 100755 index 25f0cc85d75..00000000000 --- a/tests/e2e-pw/test-e2e-pw.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env bash - -echo "🎭 Running Playwright e2e tests in default headless mode, skipping @todo."; - -docker compose -f ./tests/e2e-pw/docker-compose.yml run --rm -it --service-ports playwright \ - npx playwright test --config=tests/e2e-pw/playwright.config.ts --grep-invert @todo "$@" diff --git a/tests/e2e/config/atomic.json b/tests/e2e/config/atomic.json deleted file mode 100644 index e82ea948d7d..00000000000 --- a/tests/e2e/config/atomic.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "url": "https://wcpaytestecomm.wpcomstaging.com/" -} diff --git a/tests/e2e-pw/config/default.ts b/tests/e2e/config/default.ts similarity index 100% rename from tests/e2e-pw/config/default.ts rename to tests/e2e/config/default.ts diff --git a/tests/e2e/config/env.setup.js b/tests/e2e/config/env.setup.js deleted file mode 100644 index 2087b3cbc67..00000000000 --- a/tests/e2e/config/env.setup.js +++ /dev/null @@ -1,6 +0,0 @@ -const config = require( 'config' ); - -global.process.env = { - ...global.process.env, - WP_BASE_URL: config.get( 'url' ), -}; diff --git a/tests/e2e/config/jest-custom-environment.js b/tests/e2e/config/jest-custom-environment.js deleted file mode 100644 index e6505a5735a..00000000000 --- a/tests/e2e/config/jest-custom-environment.js +++ /dev/null @@ -1,20 +0,0 @@ -const { TestEnvironment } = require( 'jest-environment-puppeteer' ); -require( 'jest-circus' ); - -class JestCustomEnvironment extends TestEnvironment { - async handleTestEvent( event, state ) { - if ( event.name === 'test_fn_failure' && this.global.page ) { - const testDescription = state.currentlyRunningTest.name.replace( - /[":<>\|*?]/g, - '' - ); - - await this.global.page.screenshot( { - path: `./screenshots/${ testDescription }.png`, - fullPage: true, - } ); - } - } -} - -module.exports = JestCustomEnvironment; diff --git a/tests/e2e/config/jest-custom-sequencer.js b/tests/e2e/config/jest-custom-sequencer.js deleted file mode 100644 index 41ef487cc4d..00000000000 --- a/tests/e2e/config/jest-custom-sequencer.js +++ /dev/null @@ -1,15 +0,0 @@ -// testSequencer.js -const Sequencer = require( '@jest/test-sequencer' ).default; - -class CustomSequencer extends Sequencer { - sort( tests ) { - // Test structure information - // https://github.com/facebook/jest/blob/6b8b1404a1d9254e7d5d90a8934087a9c9899dab/packages/jest-runner/src/types.ts#L17-L21 - const copyTests = Array.from( tests ); - return copyTests.sort( ( testA, testB ) => - testA.path > testB.path ? 1 : -1 - ); - } -} - -module.exports = CustomSequencer; diff --git a/tests/e2e/config/jest-puppeteer-headless.config.js b/tests/e2e/config/jest-puppeteer-headless.config.js deleted file mode 100644 index 5649e519798..00000000000 --- a/tests/e2e/config/jest-puppeteer-headless.config.js +++ /dev/null @@ -1,19 +0,0 @@ -const { jestPuppeteerConfig } = require( '@woocommerce/e2e-environment' ); - -// Add arg to allow accessing the payments iframes in interactive mode ({ headles: false }). -// https://github.com/puppeteer/puppeteer/issues/4960#issuecomment-535729011 -jestPuppeteerConfig.launch.args.push( '--disable-features=site-per-process' ); -jestPuppeteerConfig.launch.args.push( '--disable-web-security' ); -jestPuppeteerConfig.launch.args.push( '--disable-features=IsolateOrigins' ); -jestPuppeteerConfig.launch.args.push( '--disable-site-isolation-trials' ); - -// Set a real User Agent so the "Add block" button isn't disabled in Gutenberg during -dev tests. -// Also keeping the "puppeteer-debug" value coming from @automattic.puppeteer -jestPuppeteerConfig.launch.args.push( - // eslint-disable-next-line max-len - '--user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.55 Safari/537.36 puppeteer-debug' -); - -jestPuppeteerConfig.launch.headless = 'new'; - -module.exports = jestPuppeteerConfig; diff --git a/tests/e2e/config/jest-puppeteer.config.js b/tests/e2e/config/jest-puppeteer.config.js deleted file mode 100644 index 124987386e5..00000000000 --- a/tests/e2e/config/jest-puppeteer.config.js +++ /dev/null @@ -1,34 +0,0 @@ -const { jestPuppeteerConfig } = require( '@woocommerce/e2e-environment' ); - -// Add arg to allow accessing the payments iframes in interactive mode ({ headles: false }). -// https://github.com/puppeteer/puppeteer/issues/4960#issuecomment-535729011 -jestPuppeteerConfig.launch.args.push( '--disable-features=site-per-process' ); -jestPuppeteerConfig.launch.args.push( '--disable-web-security' ); -jestPuppeteerConfig.launch.args.push( '--disable-features=IsolateOrigins' ); -jestPuppeteerConfig.launch.args.push( '--disable-site-isolation-trials' ); - -// Set a real User Agent so the "Add block" button isn't disabled in Gutenberg during -dev tests. -// Also keeping the "puppeteer-debug" value coming from @automattic.puppeteer -jestPuppeteerConfig.launch.args.push( - // eslint-disable-next-line max-len - '--user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.55 Safari/537.36 puppeteer-debug' -); - -// Use this config to run puppeteer in interactive mode ({ headless: false }). -const config = { - ...jestPuppeteerConfig, - launch: { - ...jestPuppeteerConfig.launch, - // Devtools must be false to avoid crashing Chromium with `--disable-features=site-per-process` - devtools: false, - headless: false, - // Used for slowing down Puppeteer operations by specified amount of ms, set locally for debugging if needed. - slowMo: 0, - defaultViewport: { - width: 1280, - height: 720, - }, - }, -}; - -module.exports = config; diff --git a/tests/e2e/config/jest.config.js b/tests/e2e/config/jest.config.js deleted file mode 100644 index 158849bace8..00000000000 --- a/tests/e2e/config/jest.config.js +++ /dev/null @@ -1,62 +0,0 @@ -const path = require( 'path' ); -const { config } = require( 'dotenv' ); -const { useE2EJestConfig } = require( '@woocommerce/e2e-environment' ); -const fs = require( 'fs' ); - -config( { path: path.resolve( __dirname, '.env' ) } ); -config( { path: path.resolve( __dirname, 'local.env' ) } ); - -// Define paths to look for E2E tests. -const e2ePaths = { - wcpay: path.resolve( __dirname, '../specs/wcpay' ), - blocks: path.resolve( __dirname, '../specs/blocks' ), -}; - -// Allow E2E tests to run specific tests - wcpay, subscriptions, blocks, all (default). -const allowedPaths = []; - -if ( process.env.E2E_GROUP ) { - // Throw error if E2E_GROUP is not found in defined paths. - if ( ! ( process.env.E2E_GROUP in e2ePaths ) ) { - throw new Error( - `Invalid test group specified: ${ process.env.E2E_GROUP }` - ); - } - - if ( process.env.E2E_BRANCH ) { - const combinedPath = path.join( - e2ePaths[ process.env.E2E_GROUP ], - process.env.E2E_BRANCH - ); - - // Throw error if path doesn't exist. - if ( ! fs.existsSync( combinedPath ) ) { - throw new Error( - `Invalid test branch specified: ${ process.env.E2E_BRANCH }` - ); - } - - allowedPaths.push( combinedPath ); - } else { - allowedPaths.push( e2ePaths[ process.env.E2E_GROUP ] ); - } -} else { - Object.values( e2ePaths ).forEach( ( testPath ) => { - allowedPaths.push( testPath ); - } ); -} - -// eslint-disable-next-line react-hooks/rules-of-hooks -const testConfig = useE2EJestConfig( { - setupFiles: [ '/tests/e2e/config/env.setup.js' ], - rootDir: path.resolve( __dirname, '../../../' ), - roots: allowedPaths, - testEnvironment: '/tests/e2e/config/jest-custom-environment.js', - testSequencer: path.resolve( - __dirname, - '../config/jest-custom-sequencer.js' - ), - testTimeout: 100000, -} ); - -module.exports = testConfig; diff --git a/tests/e2e/config/jest.performance.config.js b/tests/e2e/config/jest.performance.config.js deleted file mode 100644 index 5d3c11ab1cc..00000000000 --- a/tests/e2e/config/jest.performance.config.js +++ /dev/null @@ -1,15 +0,0 @@ -const path = require( 'path' ); -const { useE2EJestConfig } = require( '@woocommerce/e2e-environment' ); - -// eslint-disable-next-line react-hooks/rules-of-hooks -const testConfig = useE2EJestConfig( { - setupFiles: [], - rootDir: path.resolve( __dirname, '../../../' ), - roots: [ path.resolve( __dirname, '../specs/performance' ) ], - testSequencer: path.resolve( - __dirname, - '../config/jest-custom-sequencer.js' - ), -} ); - -module.exports = testConfig; diff --git a/tests/e2e/config/jest.setup.js b/tests/e2e/config/jest.setup.js deleted file mode 100644 index 0c6624ea610..00000000000 --- a/tests/e2e/config/jest.setup.js +++ /dev/null @@ -1,152 +0,0 @@ -/** - * External dependencies - */ -import { setDefaultOptions } from 'expect-puppeteer'; -import { setBrowserViewport } from '@wordpress/e2e-test-utils'; - -import { addConsoleSuppression } from '@woocommerce/e2e-environment'; - -setDefaultOptions( { timeout: 3000 } ); - -const ERROR_MESSAGES_TO_IGNORE = [ - 'violates the following Content Security Policy directive', - 'You may test your Stripe.js integration over HTTP.', - // eslint-disable-next-line max-len - "The page requested an origin-keyed agent cluster using the Origin-Agent-Cluster header, but could not be origin-keyed since the origin 'https://js.stripe.com' had previously been placed in a site-keyed agent cluster. Update your headers to uniformly request origin-keying for all pages on the origin.", - 'is deprecated', - 'Unrecognized feature:', - 'This Element will be mounted to a DOM element that contains child nodes', - 'Each dictionary in the list', - 'Missing data from PHP (wpNotesArgs).', - 'We were rate-limited from checking if your requested Payment Request options are allowed. Please test again before going live.', - "Unrecognized Content-Security-Policy directive 'require-trusted-types-for'.", - 'Failed to load resource: the server responded with a status of 400 ()', - "WebSocket connection to 'wss://public-api.wordpress.com/pinghub/wpcom/me/newest-note-data' failed", - 'Failed to load resource: the server responded with a status of 500 ()', - 'Scripts that have a dependency on', - 'was preloaded using link preload but not used within a few seconds', - 'No UI will be shown. CanMakePayment and hasEnrolledInstrument', - 'Failed to load resource: the server responded with a status of 404 (Not Found)', - 'is already registered.', - 'Preflight request for request with keepalive specified is currently not supported', - 'ReactDOM.render is no longer supported in React 18', - '[Stripe.js] Unrecognized', - '[Stripe.js] For more information', - '[Stripe.js] The following payment method types are not activated', - 'Failed to load resource: the server responded with a status of 400 (Bad Request)', - 'No Amplitude API key provided', - 'is registered with an invalid category', -]; - -ERROR_MESSAGES_TO_IGNORE.forEach( ( errorMessage ) => { - addConsoleSuppression( errorMessage, false ); -} ); - -/** - * Array of page event tuples of [ eventName, handler ]. - * - * @type {Array} - */ -const pageEvents = []; - -async function setupBrowser() { - await setBrowserViewport( 'large' ); -} - -/** - * Adds a few event listeners to the page for debugging purposes. - */ -function addPageDebugEvents() { - page.on( 'pageerror', ( error ) => { - // eslint-disable-next-line no-console - console.log( 'pageerror: ' + error.message ); - } ); - - page.on( 'response', ( response ) => { - if ( response.status() !== 200 && response.status() !== 204 ) { - // eslint-disable-next-line no-console - console.log( 'response: ' + response.status(), response.url() ); - } - } ); - - page.on( 'requestfailed', ( request ) => { - // eslint-disable-next-line no-console - console.log( - 'requestfailed: ' + request.failure().errorText, - request.url() - ); - } ); -} - -/** - * Adds a special cookie during the session to avoid the support session detection page. - * This is temporarily displayed when navigating to the login page while Jetpack SSO and protect modules are disabled. - * Relevant for Atomic sites only. - */ -async function addSupportSessionDetectedCookie() { - const domain = new URL( process.env.WP_BASE_URL ).hostname; - await page.setCookie( { - value: 'true', - name: '_wpcomsh_support_session_detected', - domain: domain, - } ); -} - -/** - * Adds an event listener to the page to handle additions of page event - * handlers, to assure that they are removed at test teardown. - */ -function capturePageEventsForTearDown() { - page.on( 'newListener', ( eventName, listener ) => { - pageEvents.push( [ eventName, listener ] ); - } ); -} - -/** - * Removes all bound page event handlers. - */ -function removePageEvents() { - pageEvents.forEach( ( [ eventName, handler ] ) => { - page.off( eventName, handler ); - } ); -} - -function setTestTimeouts() { - const TIMEOUT = 100000; - // Increase default value to avoid test failing due to timeouts. - // But we want the matchers timeout to be smaller than the test timeout to have meaningful error messages. - page.setDefaultTimeout( TIMEOUT / 4 ); - // running the login flow takes more than the default timeout of 5 seconds, - // so we need to increase it to run the login in the beforeAll hook - jest.setTimeout( TIMEOUT ); -} - -// Before every test suite run, delete all content created by the test. This ensures -// other posts/comments/etc. aren't dirtying tests and tests don't depend on -// each other's side-effects. -beforeAll( async () => { - if ( process.env.E2E_MORE_DEBUG ) { - addPageDebugEvents(); - } - - if ( ! process.env.WP_BASE_URL.includes( 'localhost' ) ) { - await addSupportSessionDetectedCookie(); - } - - capturePageEventsForTearDown(); - page.on( 'dialog', async function ( dialog ) { - try { - await dialog.accept(); - } catch ( err ) {} - } ); - setTestTimeouts(); - await setupBrowser(); -} ); - -afterEach( async () => { - await setupBrowser(); -} ); - -afterAll( () => { - removePageEvents(); -} ); diff --git a/tests/e2e/config/test.json b/tests/e2e/config/test.json deleted file mode 100644 index d6f822b624b..00000000000 --- a/tests/e2e/config/test.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "url": "http://localhost:8084/" -} diff --git a/tests/e2e-pw/docker-compose.yml b/tests/e2e/docker-compose.yml similarity index 100% rename from tests/e2e-pw/docker-compose.yml rename to tests/e2e/docker-compose.yml diff --git a/tests/e2e/env/down.sh b/tests/e2e/env/down.sh index 9d48ed157da..4a161cec501 100755 --- a/tests/e2e/env/down.sh +++ b/tests/e2e/env/down.sh @@ -19,4 +19,4 @@ fi # Remove auth credentials from the Playwright config. # This must be kept when we fully migrate. step "Removing Playwright auth credentials" -rm -rf "$E2E_ROOT/../e2e-pw/.auth" +rm -rf "$E2E_ROOT/../e2e/.auth" diff --git a/tests/e2e-pw/playwright.config.ts b/tests/e2e/playwright.config.ts similarity index 96% rename from tests/e2e-pw/playwright.config.ts rename to tests/e2e/playwright.config.ts index 14350953f40..b5c01f4746e 100644 --- a/tests/e2e-pw/playwright.config.ts +++ b/tests/e2e/playwright.config.ts @@ -73,7 +73,7 @@ export default defineConfig( { video: 'on-first-retry', viewport: { width: 1280, height: 720 }, }, - timeout: 120 * 1000, // Default is 30s, somteimes it is not enough for local tests due to long setup. + timeout: 120 * 1000, // Default is 30s, sometimes it is not enough for local tests due to long setup. expect: { toHaveScreenshot: { maxDiffPixelRatio: @@ -85,6 +85,7 @@ export default defineConfig( { snapshotPathTemplate: '{testDir}/__snapshots__/{testFilePath}/{arg}{ext}', testMatch: getTestMatch( E2E_GROUP, E2E_BRANCH ), + testIgnore: /specs\/performance/, /* Configure projects for major browsers */ projects: [ diff --git a/tests/e2e/playwright.performance.config.ts b/tests/e2e/playwright.performance.config.ts new file mode 100644 index 00000000000..56e733b72b5 --- /dev/null +++ b/tests/e2e/playwright.performance.config.ts @@ -0,0 +1,82 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +/** + * External dependencies + */ +import { defineConfig, devices } from '@playwright/test'; +import { config } from 'dotenv'; +import path from 'path'; + +config( { path: path.resolve( __dirname, '../e2e/config', '.env' ) } ); +config( { path: path.resolve( __dirname, '../e2e/config', 'local.env' ) } ); + +const { BASE_URL, NODE_ENV } = process.env; + +const getBaseUrl = () => { + if ( NODE_ENV === 'atomic' ) { + return 'https://wcpaytestecomm.wpcomstaging.com/'; + } + + return BASE_URL ?? 'http://localhost:8084'; +}; + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig( { + testDir: './specs/', + /* Run tests in files in parallel */ + fullyParallel: false, + /* Fail the build on CI if you accidentally left test.only in the source code. */ + forbidOnly: !! process.env.CI, + /* Retry on CI only */ + retries: process.env.CI ? 2 : 0, + /* Opt out of parallel tests. */ + workers: 1, + /* Reporters to use. See https://playwright.dev/docs/test-reporters */ + reporter: process.env.CI + ? [ + /* If running on CI, include the dot reporter and JSON reporter. */ + [ 'dot' ], + [ 'json', { outputFile: 'results.json' } ], + [ 'html' ], + ] + : [ [ 'html', { open: 'never' } ] ], + outputDir: './test-results', + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + baseURL: getBaseUrl(), + screenshot: 'only-on-failure', + trace: 'retain-on-failure', + video: 'on-first-retry', + viewport: { width: 1280, height: 720 }, + }, + timeout: 120 * 1000, // Default is 30s, sometimes it is not enough for local tests due to long setup. + expect: { + toHaveScreenshot: { + maxDiffPixelRatio: + process.env.E2E_WC_VERSION === '7.7.0' ? 0.035 : 0.025, + }, + //=* Increase expect timeout to 10 seconds. See https://playwright.dev/docs/test-timeouts#set-expect-timeout-in-the-config.*/ + timeout: 20 * 1000, + }, + snapshotPathTemplate: '{testDir}/__snapshots__/{testFilePath}/{arg}{ext}', + + testMatch: /specs\/performance/, + + /* Configure projects for major browsers */ + projects: [ + { + name: 'basic', + use: { ...devices[ 'Desktop Chrome' ] }, + testMatch: /basic.spec.ts/, + dependencies: [ 'setup' ], + }, + { + name: 'chromium', + use: { ...devices[ 'Desktop Chrome' ] }, + dependencies: [ 'setup' ], + }, + // Setup project + { name: 'setup', testMatch: /.*\.setup\.ts/ }, + ], +} ); diff --git a/tests/e2e-pw/specs/__snapshots__/wcpay/merchant/merchant-admin-analytics.spec.ts/Admin-order-analytics-should-load-without-any-errors-1.png b/tests/e2e/specs/__snapshots__/wcpay/merchant/merchant-admin-analytics.spec.ts/Admin-order-analytics-should-load-without-any-errors-1.png similarity index 100% rename from tests/e2e-pw/specs/__snapshots__/wcpay/merchant/merchant-admin-analytics.spec.ts/Admin-order-analytics-should-load-without-any-errors-1.png rename to tests/e2e/specs/__snapshots__/wcpay/merchant/merchant-admin-analytics.spec.ts/Admin-order-analytics-should-load-without-any-errors-1.png diff --git a/tests/e2e-pw/specs/__snapshots__/wcpay/merchant/merchant-admin-deposits.spec.ts/Merchant-deposits-Select-deposits-list-advanced-filters-1.png b/tests/e2e/specs/__snapshots__/wcpay/merchant/merchant-admin-deposits.spec.ts/Merchant-deposits-Select-deposits-list-advanced-filters-1.png similarity index 100% rename from tests/e2e-pw/specs/__snapshots__/wcpay/merchant/merchant-admin-deposits.spec.ts/Merchant-deposits-Select-deposits-list-advanced-filters-1.png rename to tests/e2e/specs/__snapshots__/wcpay/merchant/merchant-admin-deposits.spec.ts/Merchant-deposits-Select-deposits-list-advanced-filters-1.png diff --git a/tests/e2e-pw/specs/__snapshots__/wcpay/merchant/merchant-admin-transactions.spec.ts/Admin-transactions-page-should-load-without-errors-1.png b/tests/e2e/specs/__snapshots__/wcpay/merchant/merchant-admin-transactions.spec.ts/Admin-transactions-page-should-load-without-errors-1.png similarity index 100% rename from tests/e2e-pw/specs/__snapshots__/wcpay/merchant/merchant-admin-transactions.spec.ts/Admin-transactions-page-should-load-without-errors-1.png rename to tests/e2e/specs/__snapshots__/wcpay/merchant/merchant-admin-transactions.spec.ts/Admin-transactions-page-should-load-without-errors-1.png diff --git a/tests/e2e-pw/specs/__snapshots__/wcpay/merchant/merchant-disputes-view-details-via-order-notice.spec.ts/Disputes-View-dispute-details-via-disputed-o-f9e9d-ils-when-disputed-order-notice-button-clicked-1.png b/tests/e2e/specs/__snapshots__/wcpay/merchant/merchant-disputes-view-details-via-order-notice.spec.ts/Disputes-View-dispute-details-via-disputed-o-f9e9d-ils-when-disputed-order-notice-button-clicked-1.png similarity index 100% rename from tests/e2e-pw/specs/__snapshots__/wcpay/merchant/merchant-disputes-view-details-via-order-notice.spec.ts/Disputes-View-dispute-details-via-disputed-o-f9e9d-ils-when-disputed-order-notice-button-clicked-1.png rename to tests/e2e/specs/__snapshots__/wcpay/merchant/merchant-disputes-view-details-via-order-notice.spec.ts/Disputes-View-dispute-details-via-disputed-o-f9e9d-ils-when-disputed-order-notice-button-clicked-1.png diff --git a/tests/e2e-pw/specs/__snapshots__/wcpay/merchant/multi-currency-on-boarding.spec.ts/Multi-currency-on-boarding-Currency-selection--7b0d9-submit-button-when-no-currencies-are-selected-1.png b/tests/e2e/specs/__snapshots__/wcpay/merchant/multi-currency-on-boarding.spec.ts/Multi-currency-on-boarding-Currency-selection--7b0d9-submit-button-when-no-currencies-are-selected-1.png similarity index 100% rename from tests/e2e-pw/specs/__snapshots__/wcpay/merchant/multi-currency-on-boarding.spec.ts/Multi-currency-on-boarding-Currency-selection--7b0d9-submit-button-when-no-currencies-are-selected-1.png rename to tests/e2e/specs/__snapshots__/wcpay/merchant/multi-currency-on-boarding.spec.ts/Multi-currency-on-boarding-Currency-selection--7b0d9-submit-button-when-no-currencies-are-selected-1.png diff --git a/tests/e2e-pw/specs/__snapshots__/wcpay/merchant/multi-currency-on-boarding.spec.ts/Multi-currency-on-boarding-Geolocation-feature-83665-tch-by-geolocation-correctly-with-USD-and-GBP-1.png b/tests/e2e/specs/__snapshots__/wcpay/merchant/multi-currency-on-boarding.spec.ts/Multi-currency-on-boarding-Geolocation-feature-83665-tch-by-geolocation-correctly-with-USD-and-GBP-1.png similarity index 100% rename from tests/e2e-pw/specs/__snapshots__/wcpay/merchant/multi-currency-on-boarding.spec.ts/Multi-currency-on-boarding-Geolocation-feature-83665-tch-by-geolocation-correctly-with-USD-and-GBP-1.png rename to tests/e2e/specs/__snapshots__/wcpay/merchant/multi-currency-on-boarding.spec.ts/Multi-currency-on-boarding-Geolocation-feature-83665-tch-by-geolocation-correctly-with-USD-and-GBP-1.png diff --git a/tests/e2e-pw/specs/__snapshots__/wcpay/merchant/multi-currency-on-boarding.spec.ts/Multi-currency-on-boarding-Geolocation-feature-d8568-tch-by-geolocation-correctly-with-USD-and-GBP-2.png b/tests/e2e/specs/__snapshots__/wcpay/merchant/multi-currency-on-boarding.spec.ts/Multi-currency-on-boarding-Geolocation-feature-d8568-tch-by-geolocation-correctly-with-USD-and-GBP-2.png similarity index 100% rename from tests/e2e-pw/specs/__snapshots__/wcpay/merchant/multi-currency-on-boarding.spec.ts/Multi-currency-on-boarding-Geolocation-feature-d8568-tch-by-geolocation-correctly-with-USD-and-GBP-2.png rename to tests/e2e/specs/__snapshots__/wcpay/merchant/multi-currency-on-boarding.spec.ts/Multi-currency-on-boarding-Geolocation-feature-d8568-tch-by-geolocation-correctly-with-USD-and-GBP-2.png diff --git a/tests/e2e-pw/specs/__snapshots__/wcpay/merchant/multi-currency.spec.ts/Multi-currency-page-load-without-any-errors-1.png b/tests/e2e/specs/__snapshots__/wcpay/merchant/multi-currency.spec.ts/Multi-currency-page-load-without-any-errors-1.png similarity index 100% rename from tests/e2e-pw/specs/__snapshots__/wcpay/merchant/multi-currency.spec.ts/Multi-currency-page-load-without-any-errors-1.png rename to tests/e2e/specs/__snapshots__/wcpay/merchant/multi-currency.spec.ts/Multi-currency-page-load-without-any-errors-1.png diff --git a/tests/e2e-pw/specs/auth.setup.ts b/tests/e2e/specs/auth.setup.ts similarity index 100% rename from tests/e2e-pw/specs/auth.setup.ts rename to tests/e2e/specs/auth.setup.ts diff --git a/tests/e2e-pw/specs/basic.spec.ts b/tests/e2e/specs/basic.spec.ts similarity index 100% rename from tests/e2e-pw/specs/basic.spec.ts rename to tests/e2e/specs/basic.spec.ts diff --git a/tests/e2e/specs/performance/payment-methods.spec.js b/tests/e2e/specs/performance/payment-methods.spec.js deleted file mode 100644 index 470fff34f5c..00000000000 --- a/tests/e2e/specs/performance/payment-methods.spec.js +++ /dev/null @@ -1,105 +0,0 @@ -/** - * External dependencies - */ -import config from 'config'; -const { merchant } = require( '@woocommerce/e2e-utils' ); - -/** - * Internal dependencies - */ -import { setupProductCheckout } from '../../utils/payments'; -import { shopperWCP, merchantWCP } from '../../utils'; -import { - recreatePerformanceFile, - logPerformanceResult, - measureCheckoutMetrics, - averageMetrics, -} from '../../utils/performance'; - -describe( 'Checkout page performance', () => { - beforeAll( async () => { - // Start a new file for every run. - recreatePerformanceFile(); - } ); - - describe( 'Stripe element', () => { - beforeEach( async () => { - await setupProductCheckout( - config.get( 'addresses.customer.billing' ) - ); - } ); - - afterEach( async () => { - // Clear the cart at the end so it's ready for another test - await shopperWCP.emptyCart(); - } ); - - it( 'measures averaged page load metrics', async () => { - const results = await measureCheckoutMetrics( - '#wcpay-card-element iframe' - ); - logPerformanceResult( - 'Stripe element: Average', - averageMetrics( results ) - ); - } ); - } ); - - describe( 'UPE', () => { - beforeEach( async () => { - // Setup cart - await setupProductCheckout( - config.get( 'addresses.customer.billing' ) - ); - } ); - - afterEach( async () => { - // Clear the cart at the end so it's ready for another test - await shopperWCP.emptyCart(); - } ); - - it( 'measures averaged page load metrics', async () => { - const results = await measureCheckoutMetrics( - '#wcpay-upe-element iframe' - ); - logPerformanceResult( - 'Stripe UPE: Average', - averageMetrics( results ) - ); - } ); - } ); - - describe( 'WooPay without UPE', () => { - beforeEach( async () => { - // Activate UPE - await merchant.login(); - await merchantWCP.activateWooPay(); - await merchant.logout(); - - // Setup cart - await setupProductCheckout( - config.get( 'addresses.customer.billing' ) - ); - } ); - - afterEach( async () => { - // Clear the cart at the end so it's ready for another test - await shopperWCP.emptyCart(); - - // Deactivate UPE - await merchant.login(); - await merchantWCP.deactivateWooPay(); - await merchant.logout(); - } ); - - it( 'measures averaged page load metrics', async () => { - const results = await measureCheckoutMetrics( - '#wcpay-card-element iframe' - ); - logPerformanceResult( - 'WooPay: Average', - averageMetrics( results ) - ); - } ); - } ); -} ); diff --git a/tests/e2e/specs/performance/payment-methods.spec.ts b/tests/e2e/specs/performance/payment-methods.spec.ts new file mode 100644 index 00000000000..84a0e48d53e --- /dev/null +++ b/tests/e2e/specs/performance/payment-methods.spec.ts @@ -0,0 +1,82 @@ +/** + * External dependencies + */ +import test, { Page } from '@playwright/test'; + +/** + * Internal dependencies + */ +import { + recreatePerformanceFile, + logPerformanceResult, + measureCheckoutMetrics, + averageMetrics, +} from '../../utils/performance'; +import { getMerchant, getShopper } from '../../utils/helpers'; +import { emptyCart, setupProductCheckout } from '../../utils/shopper'; +import { activateWooPay, deactivateWooPay } from '../../utils/merchant'; + +test.describe( 'Checkout page performance', () => { + let shopperPage: Page; + let merchantPage: Page; + + test.beforeAll( async ( { browser }, { project } ) => { + shopperPage = ( await getShopper( browser, true, project.use.baseURL ) ) + .shopperPage; + merchantPage = ( await getMerchant( browser ) ).merchantPage; + + // Start a new file for every run. + recreatePerformanceFile(); + } ); + + test.describe( 'Stripe', () => { + test.beforeEach( async () => { + await setupProductCheckout( shopperPage ); + } ); + + test.afterEach( async () => { + // Clear the cart at the end so it's ready for another test + await emptyCart( shopperPage ); + } ); + + test( 'measures averaged page load metrics', async () => { + const results = await measureCheckoutMetrics( + shopperPage, + '#payment .payment_method_woocommerce_payments .wcpay-upe-element iframe' + ); + logPerformanceResult( + 'Stripe: Average', + averageMetrics( results ) + ); + } ); + } ); + + test.describe( 'WooPay', () => { + test.beforeEach( async () => { + // Activate WooPay + await activateWooPay( merchantPage ); + + // Setup cart + await setupProductCheckout( shopperPage ); + } ); + + test.afterEach( async () => { + // Clear the cart at the end so it's ready for another test + await emptyCart( shopperPage ); + + // Deactivate WooPay + await deactivateWooPay( merchantPage ); + } ); + + test( 'measures averaged page load metrics', async () => { + const results = await measureCheckoutMetrics( + shopperPage, + '#payment .payment_method_woocommerce_payments .wcpay-upe-element iframe' + ); + logPerformanceResult( + 'WooPay: Average', + averageMetrics( results ) + ); + } ); + } ); +} ); diff --git a/tests/e2e-pw/specs/subscriptions/merchant/merchant-subscriptions-renew-action-scheduler.spec.ts b/tests/e2e/specs/subscriptions/merchant/merchant-subscriptions-renew-action-scheduler.spec.ts similarity index 100% rename from tests/e2e-pw/specs/subscriptions/merchant/merchant-subscriptions-renew-action-scheduler.spec.ts rename to tests/e2e/specs/subscriptions/merchant/merchant-subscriptions-renew-action-scheduler.spec.ts diff --git a/tests/e2e-pw/specs/subscriptions/merchant/merchant-subscriptions-renew.spec.ts b/tests/e2e/specs/subscriptions/merchant/merchant-subscriptions-renew.spec.ts similarity index 100% rename from tests/e2e-pw/specs/subscriptions/merchant/merchant-subscriptions-renew.spec.ts rename to tests/e2e/specs/subscriptions/merchant/merchant-subscriptions-renew.spec.ts diff --git a/tests/e2e-pw/specs/subscriptions/merchant/merchant-subscriptions-settings.spec.ts b/tests/e2e/specs/subscriptions/merchant/merchant-subscriptions-settings.spec.ts similarity index 100% rename from tests/e2e-pw/specs/subscriptions/merchant/merchant-subscriptions-settings.spec.ts rename to tests/e2e/specs/subscriptions/merchant/merchant-subscriptions-settings.spec.ts diff --git a/tests/e2e-pw/specs/subscriptions/shopper/shopper-subscriptions-manage-payments.spec.ts b/tests/e2e/specs/subscriptions/shopper/shopper-subscriptions-manage-payments.spec.ts similarity index 100% rename from tests/e2e-pw/specs/subscriptions/shopper/shopper-subscriptions-manage-payments.spec.ts rename to tests/e2e/specs/subscriptions/shopper/shopper-subscriptions-manage-payments.spec.ts diff --git a/tests/e2e-pw/specs/subscriptions/shopper/shopper-subscriptions-purchase-free-trial.spec.ts b/tests/e2e/specs/subscriptions/shopper/shopper-subscriptions-purchase-free-trial.spec.ts similarity index 100% rename from tests/e2e-pw/specs/subscriptions/shopper/shopper-subscriptions-purchase-free-trial.spec.ts rename to tests/e2e/specs/subscriptions/shopper/shopper-subscriptions-purchase-free-trial.spec.ts diff --git a/tests/e2e-pw/specs/subscriptions/shopper/shopper-subscriptions-purchase-multiple-subscriptions.spec.ts b/tests/e2e/specs/subscriptions/shopper/shopper-subscriptions-purchase-multiple-subscriptions.spec.ts similarity index 100% rename from tests/e2e-pw/specs/subscriptions/shopper/shopper-subscriptions-purchase-multiple-subscriptions.spec.ts rename to tests/e2e/specs/subscriptions/shopper/shopper-subscriptions-purchase-multiple-subscriptions.spec.ts diff --git a/tests/e2e-pw/specs/subscriptions/shopper/shopper-subscriptions-purchase-no-signup-fee.spec.ts b/tests/e2e/specs/subscriptions/shopper/shopper-subscriptions-purchase-no-signup-fee.spec.ts similarity index 100% rename from tests/e2e-pw/specs/subscriptions/shopper/shopper-subscriptions-purchase-no-signup-fee.spec.ts rename to tests/e2e/specs/subscriptions/shopper/shopper-subscriptions-purchase-no-signup-fee.spec.ts diff --git a/tests/e2e-pw/specs/subscriptions/shopper/shopper-subscriptions-purchase-sign-up-fee.spec.ts b/tests/e2e/specs/subscriptions/shopper/shopper-subscriptions-purchase-sign-up-fee.spec.ts similarity index 100% rename from tests/e2e-pw/specs/subscriptions/shopper/shopper-subscriptions-purchase-sign-up-fee.spec.ts rename to tests/e2e/specs/subscriptions/shopper/shopper-subscriptions-purchase-sign-up-fee.spec.ts diff --git a/tests/e2e-pw/specs/wcpay/merchant/merchant-admin-account-balance.spec.ts b/tests/e2e/specs/wcpay/merchant/merchant-admin-account-balance.spec.ts similarity index 100% rename from tests/e2e-pw/specs/wcpay/merchant/merchant-admin-account-balance.spec.ts rename to tests/e2e/specs/wcpay/merchant/merchant-admin-account-balance.spec.ts diff --git a/tests/e2e-pw/specs/wcpay/merchant/merchant-admin-analytics.spec.ts b/tests/e2e/specs/wcpay/merchant/merchant-admin-analytics.spec.ts similarity index 100% rename from tests/e2e-pw/specs/wcpay/merchant/merchant-admin-analytics.spec.ts rename to tests/e2e/specs/wcpay/merchant/merchant-admin-analytics.spec.ts diff --git a/tests/e2e/specs/wcpay/merchant/merchant-admin-deposits.spec.js b/tests/e2e/specs/wcpay/merchant/merchant-admin-deposits.spec.js deleted file mode 100644 index 9363910e44b..00000000000 --- a/tests/e2e/specs/wcpay/merchant/merchant-admin-deposits.spec.js +++ /dev/null @@ -1,23 +0,0 @@ -/** - * External dependencies - */ -const { merchant } = require( '@woocommerce/e2e-utils' ); - -/** - * Internal dependencies - */ -import { merchantWCP, takeScreenshot } from '../../../utils'; - -describe( 'Admin deposits', () => { - beforeAll( async () => { - await merchant.login(); - } ); - - it( 'page should load without any errors', async () => { - await merchantWCP.openDeposits(); - await expect( page ).toMatchElement( 'h2', { - text: 'Payout history', - } ); - await takeScreenshot( 'merchant-admin-deposits' ); - } ); -} ); diff --git a/tests/e2e-pw/specs/wcpay/merchant/merchant-admin-deposits.spec.ts b/tests/e2e/specs/wcpay/merchant/merchant-admin-deposits.spec.ts similarity index 100% rename from tests/e2e-pw/specs/wcpay/merchant/merchant-admin-deposits.spec.ts rename to tests/e2e/specs/wcpay/merchant/merchant-admin-deposits.spec.ts diff --git a/tests/e2e-pw/specs/wcpay/merchant/merchant-admin-disputes.spec.ts b/tests/e2e/specs/wcpay/merchant/merchant-admin-disputes.spec.ts similarity index 100% rename from tests/e2e-pw/specs/wcpay/merchant/merchant-admin-disputes.spec.ts rename to tests/e2e/specs/wcpay/merchant/merchant-admin-disputes.spec.ts diff --git a/tests/e2e-pw/specs/wcpay/merchant/merchant-admin-transactions.spec.ts b/tests/e2e/specs/wcpay/merchant/merchant-admin-transactions.spec.ts similarity index 100% rename from tests/e2e-pw/specs/wcpay/merchant/merchant-admin-transactions.spec.ts rename to tests/e2e/specs/wcpay/merchant/merchant-admin-transactions.spec.ts diff --git a/tests/e2e-pw/specs/wcpay/merchant/merchant-disputes-respond.spec.ts b/tests/e2e/specs/wcpay/merchant/merchant-disputes-respond.spec.ts similarity index 100% rename from tests/e2e-pw/specs/wcpay/merchant/merchant-disputes-respond.spec.ts rename to tests/e2e/specs/wcpay/merchant/merchant-disputes-respond.spec.ts diff --git a/tests/e2e-pw/specs/wcpay/merchant/merchant-disputes-view-details-via-order-notice.spec.ts b/tests/e2e/specs/wcpay/merchant/merchant-disputes-view-details-via-order-notice.spec.ts similarity index 100% rename from tests/e2e-pw/specs/wcpay/merchant/merchant-disputes-view-details-via-order-notice.spec.ts rename to tests/e2e/specs/wcpay/merchant/merchant-disputes-view-details-via-order-notice.spec.ts diff --git a/tests/e2e-pw/specs/wcpay/merchant/merchant-multi-currency-widget.spec.ts b/tests/e2e/specs/wcpay/merchant/merchant-multi-currency-widget.spec.ts similarity index 100% rename from tests/e2e-pw/specs/wcpay/merchant/merchant-multi-currency-widget.spec.ts rename to tests/e2e/specs/wcpay/merchant/merchant-multi-currency-widget.spec.ts diff --git a/tests/e2e-pw/specs/wcpay/merchant/merchant-orders-full-refund.spec.ts b/tests/e2e/specs/wcpay/merchant/merchant-orders-full-refund.spec.ts similarity index 100% rename from tests/e2e-pw/specs/wcpay/merchant/merchant-orders-full-refund.spec.ts rename to tests/e2e/specs/wcpay/merchant/merchant-orders-full-refund.spec.ts diff --git a/tests/e2e-pw/specs/wcpay/merchant/merchant-orders-manual-capture.spec.ts b/tests/e2e/specs/wcpay/merchant/merchant-orders-manual-capture.spec.ts similarity index 100% rename from tests/e2e-pw/specs/wcpay/merchant/merchant-orders-manual-capture.spec.ts rename to tests/e2e/specs/wcpay/merchant/merchant-orders-manual-capture.spec.ts diff --git a/tests/e2e-pw/specs/wcpay/merchant/merchant-orders-partial-refund.spec.ts b/tests/e2e/specs/wcpay/merchant/merchant-orders-partial-refund.spec.ts similarity index 100% rename from tests/e2e-pw/specs/wcpay/merchant/merchant-orders-partial-refund.spec.ts rename to tests/e2e/specs/wcpay/merchant/merchant-orders-partial-refund.spec.ts diff --git a/tests/e2e-pw/specs/wcpay/merchant/merchant-orders-refund-failures.spec.ts b/tests/e2e/specs/wcpay/merchant/merchant-orders-refund-failures.spec.ts similarity index 100% rename from tests/e2e-pw/specs/wcpay/merchant/merchant-orders-refund-failures.spec.ts rename to tests/e2e/specs/wcpay/merchant/merchant-orders-refund-failures.spec.ts diff --git a/tests/e2e-pw/specs/wcpay/merchant/merchant-orders-status-change.spec.ts b/tests/e2e/specs/wcpay/merchant/merchant-orders-status-change.spec.ts similarity index 100% rename from tests/e2e-pw/specs/wcpay/merchant/merchant-orders-status-change.spec.ts rename to tests/e2e/specs/wcpay/merchant/merchant-orders-status-change.spec.ts diff --git a/tests/e2e-pw/specs/wcpay/merchant/merchant-payment-gateways-confirmation.spec.ts b/tests/e2e/specs/wcpay/merchant/merchant-payment-gateways-confirmation.spec.ts similarity index 100% rename from tests/e2e-pw/specs/wcpay/merchant/merchant-payment-gateways-confirmation.spec.ts rename to tests/e2e/specs/wcpay/merchant/merchant-payment-gateways-confirmation.spec.ts diff --git a/tests/e2e-pw/specs/wcpay/merchant/merchant-payment-settings-manual-capture.spec.ts b/tests/e2e/specs/wcpay/merchant/merchant-payment-settings-manual-capture.spec.ts similarity index 100% rename from tests/e2e-pw/specs/wcpay/merchant/merchant-payment-settings-manual-capture.spec.ts rename to tests/e2e/specs/wcpay/merchant/merchant-payment-settings-manual-capture.spec.ts diff --git a/tests/e2e-pw/specs/wcpay/merchant/merchant-progressive-onboarding.spec.ts b/tests/e2e/specs/wcpay/merchant/merchant-progressive-onboarding.spec.ts similarity index 100% rename from tests/e2e-pw/specs/wcpay/merchant/merchant-progressive-onboarding.spec.ts rename to tests/e2e/specs/wcpay/merchant/merchant-progressive-onboarding.spec.ts diff --git a/tests/e2e-pw/specs/wcpay/merchant/multi-currency-on-boarding.spec.ts b/tests/e2e/specs/wcpay/merchant/multi-currency-on-boarding.spec.ts similarity index 100% rename from tests/e2e-pw/specs/wcpay/merchant/multi-currency-on-boarding.spec.ts rename to tests/e2e/specs/wcpay/merchant/multi-currency-on-boarding.spec.ts diff --git a/tests/e2e-pw/specs/wcpay/merchant/multi-currency-setup.spec.ts b/tests/e2e/specs/wcpay/merchant/multi-currency-setup.spec.ts similarity index 100% rename from tests/e2e-pw/specs/wcpay/merchant/multi-currency-setup.spec.ts rename to tests/e2e/specs/wcpay/merchant/multi-currency-setup.spec.ts diff --git a/tests/e2e-pw/specs/wcpay/merchant/multi-currency.spec.ts b/tests/e2e/specs/wcpay/merchant/multi-currency.spec.ts similarity index 100% rename from tests/e2e-pw/specs/wcpay/merchant/multi-currency.spec.ts rename to tests/e2e/specs/wcpay/merchant/multi-currency.spec.ts diff --git a/tests/e2e-pw/specs/wcpay/merchant/woopay-setup.spec.ts b/tests/e2e/specs/wcpay/merchant/woopay-setup.spec.ts similarity index 100% rename from tests/e2e-pw/specs/wcpay/merchant/woopay-setup.spec.ts rename to tests/e2e/specs/wcpay/merchant/woopay-setup.spec.ts diff --git a/tests/e2e-pw/specs/wcpay/shopper/klarna-checkout-purchase.spec.ts b/tests/e2e/specs/wcpay/shopper/klarna-checkout-purchase.spec.ts similarity index 100% rename from tests/e2e-pw/specs/wcpay/shopper/klarna-checkout-purchase.spec.ts rename to tests/e2e/specs/wcpay/shopper/klarna-checkout-purchase.spec.ts diff --git a/tests/e2e-pw/specs/wcpay/shopper/multi-currency-checkout.spec.ts b/tests/e2e/specs/wcpay/shopper/multi-currency-checkout.spec.ts similarity index 100% rename from tests/e2e-pw/specs/wcpay/shopper/multi-currency-checkout.spec.ts rename to tests/e2e/specs/wcpay/shopper/multi-currency-checkout.spec.ts diff --git a/tests/e2e-pw/specs/wcpay/shopper/shopper-bnpls-checkout.spec.ts b/tests/e2e/specs/wcpay/shopper/shopper-bnpls-checkout.spec.ts similarity index 100% rename from tests/e2e-pw/specs/wcpay/shopper/shopper-bnpls-checkout.spec.ts rename to tests/e2e/specs/wcpay/shopper/shopper-bnpls-checkout.spec.ts diff --git a/tests/e2e-pw/specs/wcpay/shopper/shopper-checkout-cart-coupon.spec.ts b/tests/e2e/specs/wcpay/shopper/shopper-checkout-cart-coupon.spec.ts similarity index 100% rename from tests/e2e-pw/specs/wcpay/shopper/shopper-checkout-cart-coupon.spec.ts rename to tests/e2e/specs/wcpay/shopper/shopper-checkout-cart-coupon.spec.ts diff --git a/tests/e2e-pw/specs/wcpay/shopper/shopper-checkout-failures.spec.ts b/tests/e2e/specs/wcpay/shopper/shopper-checkout-failures.spec.ts similarity index 100% rename from tests/e2e-pw/specs/wcpay/shopper/shopper-checkout-failures.spec.ts rename to tests/e2e/specs/wcpay/shopper/shopper-checkout-failures.spec.ts diff --git a/tests/e2e-pw/specs/wcpay/shopper/shopper-checkout-purchase-site-editor.spec.ts b/tests/e2e/specs/wcpay/shopper/shopper-checkout-purchase-site-editor.spec.ts similarity index 100% rename from tests/e2e-pw/specs/wcpay/shopper/shopper-checkout-purchase-site-editor.spec.ts rename to tests/e2e/specs/wcpay/shopper/shopper-checkout-purchase-site-editor.spec.ts diff --git a/tests/e2e-pw/specs/wcpay/shopper/shopper-checkout-purchase-with-upe-methods.spec.ts b/tests/e2e/specs/wcpay/shopper/shopper-checkout-purchase-with-upe-methods.spec.ts similarity index 100% rename from tests/e2e-pw/specs/wcpay/shopper/shopper-checkout-purchase-with-upe-methods.spec.ts rename to tests/e2e/specs/wcpay/shopper/shopper-checkout-purchase-with-upe-methods.spec.ts diff --git a/tests/e2e-pw/specs/wcpay/shopper/shopper-checkout-purchase.spec.ts b/tests/e2e/specs/wcpay/shopper/shopper-checkout-purchase.spec.ts similarity index 100% rename from tests/e2e-pw/specs/wcpay/shopper/shopper-checkout-purchase.spec.ts rename to tests/e2e/specs/wcpay/shopper/shopper-checkout-purchase.spec.ts diff --git a/tests/e2e-pw/specs/wcpay/shopper/shopper-checkout-save-card-and-purchase.spec.ts b/tests/e2e/specs/wcpay/shopper/shopper-checkout-save-card-and-purchase.spec.ts similarity index 100% rename from tests/e2e-pw/specs/wcpay/shopper/shopper-checkout-save-card-and-purchase.spec.ts rename to tests/e2e/specs/wcpay/shopper/shopper-checkout-save-card-and-purchase.spec.ts diff --git a/tests/e2e-pw/specs/wcpay/shopper/shopper-multi-currency-widget.spec.ts b/tests/e2e/specs/wcpay/shopper/shopper-multi-currency-widget.spec.ts similarity index 100% rename from tests/e2e-pw/specs/wcpay/shopper/shopper-multi-currency-widget.spec.ts rename to tests/e2e/specs/wcpay/shopper/shopper-multi-currency-widget.spec.ts diff --git a/tests/e2e-pw/specs/wcpay/shopper/shopper-myaccount-payment-methods-add-fail.spec.ts b/tests/e2e/specs/wcpay/shopper/shopper-myaccount-payment-methods-add-fail.spec.ts similarity index 100% rename from tests/e2e-pw/specs/wcpay/shopper/shopper-myaccount-payment-methods-add-fail.spec.ts rename to tests/e2e/specs/wcpay/shopper/shopper-myaccount-payment-methods-add-fail.spec.ts diff --git a/tests/e2e-pw/specs/wcpay/shopper/shopper-myaccount-renew-subscription.spec.ts b/tests/e2e/specs/wcpay/shopper/shopper-myaccount-renew-subscription.spec.ts similarity index 100% rename from tests/e2e-pw/specs/wcpay/shopper/shopper-myaccount-renew-subscription.spec.ts rename to tests/e2e/specs/wcpay/shopper/shopper-myaccount-renew-subscription.spec.ts diff --git a/tests/e2e-pw/specs/wcpay/shopper/shopper-myaccount-saved-cards.spec.ts b/tests/e2e/specs/wcpay/shopper/shopper-myaccount-saved-cards.spec.ts similarity index 100% rename from tests/e2e-pw/specs/wcpay/shopper/shopper-myaccount-saved-cards.spec.ts rename to tests/e2e/specs/wcpay/shopper/shopper-myaccount-saved-cards.spec.ts diff --git a/tests/e2e-pw/specs/wcpay/shopper/shopper-pay-for-order.spec.ts b/tests/e2e/specs/wcpay/shopper/shopper-pay-for-order.spec.ts similarity index 100% rename from tests/e2e-pw/specs/wcpay/shopper/shopper-pay-for-order.spec.ts rename to tests/e2e/specs/wcpay/shopper/shopper-pay-for-order.spec.ts diff --git a/tests/e2e-pw/specs/wcpay/shopper/shopper-wc-blocks-checkout-failures.spec.ts b/tests/e2e/specs/wcpay/shopper/shopper-wc-blocks-checkout-failures.spec.ts similarity index 100% rename from tests/e2e-pw/specs/wcpay/shopper/shopper-wc-blocks-checkout-failures.spec.ts rename to tests/e2e/specs/wcpay/shopper/shopper-wc-blocks-checkout-failures.spec.ts diff --git a/tests/e2e-pw/specs/wcpay/shopper/shopper-wc-blocks-checkout-purchase.spec.ts b/tests/e2e/specs/wcpay/shopper/shopper-wc-blocks-checkout-purchase.spec.ts similarity index 100% rename from tests/e2e-pw/specs/wcpay/shopper/shopper-wc-blocks-checkout-purchase.spec.ts rename to tests/e2e/specs/wcpay/shopper/shopper-wc-blocks-checkout-purchase.spec.ts diff --git a/tests/e2e-pw/specs/wcpay/shopper/shopper-wc-blocks-saved-card-checkout-and-usage.spec.ts b/tests/e2e/specs/wcpay/shopper/shopper-wc-blocks-saved-card-checkout-and-usage.spec.ts similarity index 100% rename from tests/e2e-pw/specs/wcpay/shopper/shopper-wc-blocks-saved-card-checkout-and-usage.spec.ts rename to tests/e2e/specs/wcpay/shopper/shopper-wc-blocks-saved-card-checkout-and-usage.spec.ts diff --git a/tests/e2e/test-e2e-performance.sh b/tests/e2e/test-e2e-performance.sh new file mode 100755 index 00000000000..6b55c8c664e --- /dev/null +++ b/tests/e2e/test-e2e-performance.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +echo "🎭 Running Playwright e2e performance tests in default headless mode, skipping @todo."; + +docker compose -f ./tests/e2e/docker-compose.yml run --rm -it --service-ports playwright \ + npx playwright test --config=tests/e2e/playwright.performance.config.ts --grep-invert @todo "$@" diff --git a/tests/e2e/test-e2e-ui.sh b/tests/e2e/test-e2e-ui.sh new file mode 100755 index 00000000000..7a579341c9e --- /dev/null +++ b/tests/e2e/test-e2e-ui.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +echo "🎭 Running Playwright e2e tests in interactive UI mode."; +echo ""; +echo "Open http://localhost:8077 in your browser to see the UI."; + +docker compose -f ./tests/e2e/docker-compose.yml run --rm -it --service-ports playwright \ + npx playwright test --config=tests/e2e/playwright.config.ts --ui --ui-host=0.0.0.0 --ui-port=8077 "$@" diff --git a/tests/e2e/test-e2e.sh b/tests/e2e/test-e2e.sh new file mode 100755 index 00000000000..3d19725dec2 --- /dev/null +++ b/tests/e2e/test-e2e.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +echo "🎭 Running Playwright e2e tests in default headless mode, skipping @todo."; + +docker compose -f ./tests/e2e/docker-compose.yml run --rm -it --service-ports playwright \ + npx playwright test --config=tests/e2e/playwright.config.ts --grep-invert @todo "$@" diff --git a/tests/e2e/utils/constants.js b/tests/e2e/utils/constants.js deleted file mode 100644 index 90d328360c4..00000000000 --- a/tests/e2e/utils/constants.js +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Constants used for E2E tests. - * - * @type {string} - */ -export const PERFORMANCE_REPORT_DIR = __dirname + '/../reports/'; -export const PERFORMANCE_REPORT_FILENAME = - PERFORMANCE_REPORT_DIR + 'checkout-performance.txt'; -export const NUMBER_OF_TRIALS = 3; diff --git a/tests/e2e-pw/utils/constants.ts b/tests/e2e/utils/constants.ts similarity index 66% rename from tests/e2e-pw/utils/constants.ts rename to tests/e2e/utils/constants.ts index c9c3ae7d8c8..00e4c78f5ee 100644 --- a/tests/e2e-pw/utils/constants.ts +++ b/tests/e2e/utils/constants.ts @@ -9,3 +9,10 @@ export const shouldRunWCBlocksTests = process.env.SKIP_WC_BLOCKS_TESTS !== '1'; export const wooCoreVersion = process.env.E2E_WC_VERSION; export const isAtomicSite = process.env.NODE_ENV === 'atomic'; + +export const performanceReportDir = __dirname + '/../reports/'; + +export const performanceReportfilename = + performanceReportDir + 'checkout-performance.txt'; + +export const performanceNumberOfTrials = 3; diff --git a/tests/e2e/utils/debug.js b/tests/e2e/utils/debug.js deleted file mode 100644 index cdc65f64e0a..00000000000 --- a/tests/e2e/utils/debug.js +++ /dev/null @@ -1,7 +0,0 @@ -export function dumpFrameTree( frame, indent ) { - // eslint-disable-next-line no-console - console.log( indent + frame.url() ); - for ( const child of frame.childFrames() ) { - dumpFrameTree( child, indent + ' ' ); - } -} diff --git a/tests/e2e-pw/utils/devtools.ts b/tests/e2e/utils/devtools.ts similarity index 100% rename from tests/e2e-pw/utils/devtools.ts rename to tests/e2e/utils/devtools.ts diff --git a/tests/e2e/utils/flows.js b/tests/e2e/utils/flows.js deleted file mode 100644 index c3cb7c570b3..00000000000 --- a/tests/e2e/utils/flows.js +++ /dev/null @@ -1,998 +0,0 @@ -/** - * @format - */ - -/** - * External dependencies - */ - -const { - merchant, - shopper, - uiUnblocked, - clearAndFillInput, - setCheckbox, - SHOP_PAGE, - WP_ADMIN_DASHBOARD, -} = require( '@woocommerce/e2e-utils' ); -const { - fillCardDetails, - confirmCardAuthentication, -} = require( '../utils/payments' ); - -const config = require( 'config' ); -const baseUrl = config.get( 'url' ); - -import { uiLoaded } from './helpers'; - -const SHOP_MY_ACCOUNT_PAGE = baseUrl + 'my-account/'; -const MY_ACCOUNT_PAYMENT_METHODS = baseUrl + 'my-account/payment-methods'; -const MY_ACCOUNT_SUBSCRIPTIONS = baseUrl + 'my-account/subscriptions'; -const MY_ACCOUNT_EDIT = baseUrl + 'my-account/edit-account'; -const MY_ACCOUNT_ORDERS = SHOP_MY_ACCOUNT_PAGE + 'orders/'; -const WCPAY_CONNECT = - baseUrl + 'wp-admin/admin.php?page=wc-admin&path=/payments/connect'; -const WCPAY_DISPUTES = - baseUrl + 'wp-admin/admin.php?page=wc-admin&path=/payments/disputes'; -const WCPAY_DEPOSITS = - baseUrl + 'wp-admin/admin.php?page=wc-admin&path=/payments/payouts'; -const WCPAY_TRANSACTIONS = - baseUrl + 'wp-admin/admin.php?page=wc-admin&path=/payments/transactions'; -const WCPAY_MULTI_CURRENCY = - baseUrl + 'wp-admin/admin.php?page=wc-settings&tab=wcpay_multi_currency'; -const WCPAY_PAYMENT_SETTINGS = - baseUrl + - 'wp-admin/admin.php?page=wc-settings&tab=checkout§ion=woocommerce_payments'; -const WC_SUBSCRIPTIONS_PAGE = - baseUrl + 'wp-admin/edit.php?post_type=shop_subscription'; -const ACTION_SCHEDULER = baseUrl + 'wp-admin/tools.php?page=action-scheduler'; -const WP_ADMIN_PAGES = baseUrl + 'wp-admin/edit.php?post_type=page'; -const WCB_CHECKOUT = baseUrl + 'checkout-wcb/'; -const WCPAY_DEV_TOOLS = baseUrl + 'wp-admin/admin.php?page=wcpaydev'; -const SHOP_CART_PAGE = baseUrl + 'cart/'; - -export const RUN_SUBSCRIPTIONS_TESTS = - process.env.SKIP_WC_SUBSCRIPTIONS_TESTS !== '1'; - -export const RUN_ACTION_SCHEDULER_TESTS = - process.env.SKIP_WC_ACTION_SCHEDULER_TESTS !== '1'; - -export const RUN_WC_BLOCKS_TESTS = process.env.SKIP_WC_BLOCKS_TESTS !== '1'; - -// The generic flows will be moved to their own package soon (more details in p7bje6-2gV-p2), so we're -// keeping our customizations grouped here so it's easier to extend the flows once the move happens. -export const shopperWCP = { - goToPaymentMethods: async () => { - await page.goto( MY_ACCOUNT_PAYMENT_METHODS, { - waitUntil: 'networkidle0', - } ); - }, - - goToShopWithCurrency: async ( currency ) => { - await page.goto( SHOP_PAGE + `/?currency=${ currency }`, { - waitUntil: 'networkidle0', - } ); - }, - - goToOrders: async () => { - await page.goto( MY_ACCOUNT_ORDERS, { - waitUntil: 'networkidle0', - } ); - }, - - goToOrder: async ( orderId ) => { - await page.goto( SHOP_MY_ACCOUNT_PAGE + `view-order/${ orderId }`, { - waitUntil: 'networkidle0', - } ); - }, - - logout: async ( skipIfAlreadyLoggedOut = false ) => { - await page.goto( SHOP_MY_ACCOUNT_PAGE, { - waitUntil: 'networkidle0', - } ); - - await expect( page.title() ).resolves.toMatch( 'My account' ); - - const hasLoginButton = await page.$( 'button[name="login"]' ); - - if ( hasLoginButton ) { - if ( skipIfAlreadyLoggedOut ) { - return; - } - throw new Error( - 'Cannot log out since the user is already logged out' - ); - } - - await Promise.all( [ - page.waitForNavigation( { waitUntil: 'networkidle0' } ), - page.click( - '.woocommerce-MyAccount-navigation-link--customer-logout a' - ), - ] ); - }, - - deleteSavedPaymentMethod: async ( label ) => { - const [ paymentMethodRow ] = await page.$x( - `//tr[contains(., '${ label }')]` - ); - await expect( paymentMethodRow ).toClick( '.button.delete' ); - await page.waitForNavigation( { waitUntil: 'networkidle0' } ); - }, - - selectNewPaymentMethod: async () => { - if ( - ( await page.$( '#wc-woocommerce_payments-payment-token-new' ) ) !== - null - ) { - await expect( page ).toClick( - '#wc-woocommerce_payments-payment-token-new' - ); - } - }, - - toggleSavePaymentMethod: async () => { - await expect( page ).toClick( - '#wc-woocommerce_payments-new-payment-method' - ); - }, - - selectSavedPaymentMethod: async ( label ) => { - await expect( page ).toClick( 'label', { text: label } ); - }, - - setDefaultPaymentMethod: async ( label ) => { - const [ paymentMethodRow ] = await page.$x( - `//tr[contains(., '${ label }')]` - ); - await expect( paymentMethodRow ).toClick( '.button.default' ); - await page.waitForNavigation( { waitUntil: 'networkidle0' } ); - }, - - toggleCreateAccount: async () => { - await expect( page ).toClick( '#createaccount' ); - }, - - goToSubscriptions: async () => { - await page.goto( MY_ACCOUNT_SUBSCRIPTIONS, { - waitUntil: 'networkidle0', - } ); - }, - - changeAccountCurrencyTo: async ( customerDetails, currencyToSet ) => { - await page.goto( MY_ACCOUNT_EDIT, { - waitUntil: 'networkidle0', - } ); - - // In some cases (when running tests independently), when these fields are empty, the saving - // fails. So ensuring these fields are filled before setting the currency. - await clearAndFillInput( - '#account_first_name', - customerDetails.firstname - ); - - await clearAndFillInput( - '#account_last_name', - customerDetails.lastname - ); - - await page.select( '#wcpay_selected_currency', currencyToSet ); - await expect( page ).toClick( 'button', { - text: 'Save changes', - } ); - await page.waitForNavigation( { - waitUntil: 'networkidle0', - } ); - }, - - /** - * Happy path for adding a new payment method in 'My Account > Payment methods' page. - * It can handle 3DS and 3DS2 flows. - * - * @param {*} cardType Card type as defined in the `test.json` file. Examples: `basic`, `3ds2`, `declined`. - * @param {*} card Card object that you want to add as the new payment method. - */ - addNewPaymentMethod: async ( cardType, card ) => { - await expect( page ).toClick( 'a', { - text: 'Add payment method', - } ); - await page.waitForNavigation( { - waitUntil: 'networkidle0', - } ); - - if ( - ( await page.$( '#wc-woocommerce_payments-payment-token-new' ) ) !== - null - ) { - await setCheckbox( '#wc-woocommerce_payments-payment-token-new' ); - } - - await fillCardDetails( page, card ); - - await expect( page ).toClick( 'button', { - text: 'Add payment method', - } ); - - const cardIs3DS = - cardType.toUpperCase().includes( '3DS' ) && - ! cardType.toLowerCase().includes( 'declined' ); - - if ( cardIs3DS ) { - await confirmCardAuthentication( page ); - } - - await page.waitForNavigation( { - waitUntil: 'networkidle0', - } ); - }, - - openCheckoutWCB: async () => { - await page.goto( WCB_CHECKOUT, { - waitUntil: 'networkidle0', - } ); - }, - - fillShippingDetailsWCB: async ( customerShippingDetails ) => { - await clearAndFillInput( '#email', customerShippingDetails.email ); - await clearAndFillInput( - '#shipping-first_name', - customerShippingDetails.firstname - ); - await clearAndFillInput( - '#shipping-last_name', - customerShippingDetails.lastname - ); - await clearAndFillInput( - '#shipping-address_1', - customerShippingDetails.addressfirstline - ); - await clearAndFillInput( - '#shipping-city', - customerShippingDetails.city - ); - await clearAndFillInput( - '#shipping-postcode', - customerShippingDetails.postcode - ); - }, - - fillBillingDetailsWCB: async ( customerBillingDetails ) => { - await clearAndFillInput( '#email', customerBillingDetails.email ); - await clearAndFillInput( - '#billing-first_name', - customerBillingDetails.firstname - ); - await clearAndFillInput( - '#billing-last_name', - customerBillingDetails.lastname - ); - await clearAndFillInput( - '#billing-address_1', - customerBillingDetails.addressfirstline - ); - await clearAndFillInput( - '#billing-country .components-form-token-field__input', - customerBillingDetails.country - ); - await clearAndFillInput( '#billing-city', customerBillingDetails.city ); - await clearAndFillInput( - '#billing-state .components-form-token-field__input', - customerBillingDetails.state - ); - await clearAndFillInput( - '#billing-postcode', - customerBillingDetails.postcode - ); - }, - - emptyCart: async () => { - await page.goto( SHOP_CART_PAGE, { - waitUntil: 'networkidle0', - } ); - - // Remove products if they exist - if ( ( await page.$$( '.remove' ) ) !== null ) { - let products = await page.$$( '.remove' ); - while ( products && products.length > 0 ) { - for ( const product of products ) { - await product.click(); - await uiUnblocked(); - } - products = await page.$$( '.remove' ); - } - } - - // Remove coupons if they exist - if ( ( await page.$( '.woocommerce-remove-coupon' ) ) !== null ) { - await page.click( '.woocommerce-remove-coupon' ); - await uiUnblocked(); - } - - await shopperWCP.waitForErrorBanner( - 'Your cart is currently empty.', - 'div.wc-block-components-notice-banner', - '.cart-empty.woocommerce-info' - ); - }, - - goToProductPageBySlug: async ( productSlug ) => { - await page.goto( config.get( 'url' ) + `product/${ productSlug }`, { - waitUntil: 'networkidle0', - } ); - }, - - addToCartBySlug: async ( productSlug ) => { - await shopperWCP.goToProductPageBySlug( productSlug ); - await shopper.addToCart(); - }, - - waitForErrorBanner: async ( - errorText, - noticeSelector, - oldNoticeSelector - ) => { - const errorBannerToCheck = ( async () => { - await expect( page ).toMatchElement( noticeSelector, { - text: errorText, - } ); - } )(); - - const oldErrorBannerToCheck = ( async () => { - await expect( page ).toMatchElement( oldNoticeSelector, { - text: errorText, - } ); - } )(); - - await Promise.race( [ errorBannerToCheck, oldErrorBannerToCheck ] ); - }, - - waitForSubscriptionsErrorBanner: async ( - errorText, - errorSelector, - oldErrorSelector - ) => { - const errorBannerToCheck = ( async () => { - return page.waitForSelector( errorSelector, { - text: errorText, - } ); - } )(); - - const oldErrorBannerToCheck = ( async () => { - return page.waitForSelector( oldErrorSelector, { - text: errorText, - } ); - } )(); - - await Promise.race( [ errorBannerToCheck, oldErrorBannerToCheck ] ); - }, - - // Copy of shopper.addToCartFromShopPage from `@woocommerce/e2e-utils` until it removes the deprecated `waitFor` function. - addToCartFromShopPage: async ( productIdOrTitle ) => { - if ( Number.isInteger( productIdOrTitle ) ) { - const addToCart = `a[data-product_id="${ productIdOrTitle }"]`; - await page.click( addToCart ); - await expect( page ).toMatchElement( addToCart + '.added' ); - } else { - const addToCartXPath = - `//li[contains(@class, "type-product") and a/h2[contains(text(), "${ productIdOrTitle }")]]` + - '//a[contains(@class, "add_to_cart_button") and contains(@class, "ajax_add_to_cart")'; - const [ addToCartButton ] = await page.$x( addToCartXPath + ']' ); - await addToCartButton.click(); - - await page.waitForXPath( - addToCartXPath + ' and contains(@class, "added")]' - ); - } - }, -}; - -// The generic flows will be moved to their own package soon (more details in p7bje6-2gV-p2), so we're -// keeping our customizations grouped here so it's easier to extend the flows once the move happens. -export const merchantWCP = { - enableActAsDisconnectedFromWCPay: async () => { - await page.goto( WCPAY_DEV_TOOLS, { - waitUntil: 'networkidle0', - } ); - - if ( ! ( await page.$( '#wcpaydev_force_disconnected:checked' ) ) ) { - await expect( page ).toClick( - 'label[for="wcpaydev_force_disconnected"]' - ); - } - - await expect( page ).toClick( 'input#submit' ); - await page.waitForNavigation( { - waitUntil: 'networkidle0', - } ); - }, - - disableActAsDisconnectedFromWCPay: async () => { - await page.goto( WCPAY_DEV_TOOLS, { - waitUntil: 'networkidle0', - } ); - - if ( await page.$( '#wcpaydev_force_disconnected:checked' ) ) { - await expect( page ).toClick( - 'label[for="wcpaydev_force_disconnected"]' - ); - } - await expect( page ).toClick( 'input#submit' ); - await page.waitForNavigation( { - waitUntil: 'networkidle0', - } ); - }, - - enableCardTestingProtection: async () => { - await page.goto( WCPAY_DEV_TOOLS, { - waitUntil: 'networkidle0', - } ); - - if ( - ! ( await page.$( - '#wcpaydev_force_card_testing_protection_on:checked' - ) ) - ) { - await expect( page ).toClick( - 'label[for="wcpaydev_force_card_testing_protection_on"]' - ); - } - - await expect( page ).toClick( 'input#submit' ); - await page.waitForNavigation( { - waitUntil: 'networkidle0', - } ); - }, - - disableCardTestingProtection: async () => { - await page.goto( WCPAY_DEV_TOOLS, { - waitUntil: 'networkidle0', - } ); - - if ( - await page.$( '#wcpaydev_force_card_testing_protection_on:checked' ) - ) { - await expect( page ).toClick( - 'label[for="wcpaydev_force_card_testing_protection_on"]' - ); - } - await expect( page ).toClick( 'input#submit' ); - await page.waitForNavigation( { - waitUntil: 'networkidle0', - } ); - }, - - enablePaymentMethod: async ( paymentMethods ) => { - await page.goto( WCPAY_PAYMENT_SETTINGS, { - waitUntil: 'networkidle0', - } ); - - for ( const paymentMethod of paymentMethods ) { - // Skip fraud protection tools tour. - const tourKitDismissButton = await page.$( - `button.woocommerce-tour-kit-step-controls__close-btn` - ); - if ( tourKitDismissButton ) { - await tourKitDismissButton.evaluate( ( button ) => - button.click() - ); - } - - // Check if paymentMethod is an XPath - if ( paymentMethod.startsWith( '//' ) ) { - // Find the element using XPath and click it - const elements = await page.$x( paymentMethod ); - if ( elements.length > 0 ) { - await elements[ 0 ].click(); - } - } else { - // If it's a CSS selector, use $eval - await page.$eval( paymentMethod, ( method ) => method.click() ); - } - await new Promise( ( resolve ) => setTimeout( resolve, 2000 ) ); - } - - await expect( page ).toClick( 'button', { - text: 'Save changes', - } ); - }, - - disablePaymentMethod: async ( paymentMethods ) => { - await page.goto( WCPAY_PAYMENT_SETTINGS, { - waitUntil: 'networkidle0', - } ); - - for ( const paymentMethod of paymentMethods ) { - // Skip fraud protection tools tour. - const tourKitDismissButton = await page.$( - `button.woocommerce-tour-kit-step-controls__close-btn` - ); - if ( tourKitDismissButton ) { - await tourKitDismissButton.evaluate( ( button ) => - button.click() - ); - } - // Check if paymentMethod is an XPath - if ( paymentMethod.startsWith( '//' ) ) { - // Find the element using XPath and click it - const elements = await page.$x( paymentMethod ); - if ( elements.length > 0 ) { - await elements[ 0 ].click(); - } - } else { - // If it's a CSS selector, use $eval - await page.$eval( paymentMethod, ( method ) => method.click() ); - } - await expect( page ).toClick( 'button', { - text: 'Remove', - } ); - await new Promise( ( resolve ) => setTimeout( resolve, 2000 ) ); - } - - await expect( page ).toClick( 'button', { - text: 'Save changes', - } ); - }, - - openPaymentDetails: async ( paymentDetailsLink ) => { - await Promise.all( [ - page.goto( paymentDetailsLink, { - waitUntil: 'networkidle0', - } ), - uiLoaded(), - ] ); - await uiLoaded(); - }, - - openSubscriptions: async () => { - await page.goto( WC_SUBSCRIPTIONS_PAGE, { - waitUntil: 'networkidle0', - } ); - await expect( page ).toMatchElement( 'h1', { text: 'Subscriptions' } ); - }, - - /** - * Create a subscription product with an optional signup fee - * - * @param productName - * @param periodTime can be `day`, `week`, `month` or `year` - * @param includeSignupFee defaults to `false` - * @param includeFreeTrial defaults to `false` - * @return id of the created subscription product - * - */ - - openDisputes: async () => { - await page.goto( WCPAY_DISPUTES, { - waitUntil: 'networkidle0', - } ); - await uiLoaded(); - }, - - openDeposits: async () => { - await page.goto( WCPAY_DEPOSITS, { - waitUntil: 'networkidle0', - } ); - await uiLoaded(); - }, - - openTransactions: async () => { - await page.goto( WCPAY_TRANSACTIONS, { - waitUntil: 'networkidle0', - } ); - await uiLoaded(); - }, - - openMultiCurrency: async () => { - await page.goto( WCPAY_MULTI_CURRENCY, { - waitUntil: 'networkidle0', - } ); - await uiLoaded(); - }, - - addCurrency: async ( currencyCode ) => { - if ( currencyCode === 'USD' ) { - return; - } - await merchantWCP.openMultiCurrency(); - await page.click( '[data-testid="enabled-currencies-add-button"]' ); - - await page.evaluate( ( code ) => { - const inputs = Array.from( - document.querySelectorAll( 'input[type="checkbox"]' ) - ); - const targetInput = inputs.find( - ( input ) => input.getAttribute( 'code' ) === code - ); - if ( targetInput && ! targetInput.checked ) { - targetInput.click(); - } - }, currencyCode ); - - await page.waitForSelector( - 'div.wcpay-confirmation-modal__footer button.components-button.is-primary', - { timeout: 3000 } - ); - - await page.click( - 'div.wcpay-confirmation-modal__footer button.components-button.is-primary', - { text: 'Update selected' } - ); - - const snackbar = '.components-snackbar'; - await expect( page ).toMatchElement( snackbar, { - text: 'Enabled currencies updated.', - timeout: 60000, - } ); - - const selector = `li.enabled-currency.${ currencyCode.toLowerCase() }`; - await page.waitForSelector( selector ); - const element = await page.$( selector ); - - expect( element ).not.toBeNull(); - }, - - removeCurrency: async ( currencyCode ) => { - await merchantWCP.openMultiCurrency(); - const currencyItemSelector = `li.enabled-currency.${ currencyCode.toLowerCase() }`; - await page.waitForSelector( currencyItemSelector, { timeout: 10000 } ); - await page.click( - `${ currencyItemSelector } .enabled-currency__action.delete` - ); - - const snackbar = '.components-snackbar'; - await expect( page ).toMatchElement( snackbar, { - text: 'Enabled currencies updated.', - timeout: 60000, - } ); - - await page.waitForSelector( currencyItemSelector, { - hidden: true, - timeout: 15000, - } ); - }, - - openConnectPage: async () => { - await page.goto( WCPAY_CONNECT, { - waitUntil: 'networkidle0', - } ); - await uiLoaded(); - }, - - openOrderAnalytics: async () => { - await merchant.openAnalyticsPage( 'orders' ); - await uiLoaded(); - }, - - openActionScheduler: async ( status, search ) => { - let pageUrl = ACTION_SCHEDULER; - - if ( typeof status !== 'undefined' ) { - pageUrl += '&status=' + status; - } - - if ( typeof search !== 'undefined' ) { - pageUrl += '&s=' + search; - } - - await page.goto( pageUrl, { - waitUntil: 'networkidle0', - } ); - }, - - openWCPSettings: async () => { - await merchant.openSettings( 'checkout', 'woocommerce_payments' ); - }, - - skipFraudProtectionTour: async () => { - const tourKitDismissButton = await page.$( - `button.woocommerce-tour-kit-step-controls__close-btn` - ); - if ( tourKitDismissButton ) { - await tourKitDismissButton.evaluate( ( button ) => button.click() ); - } - }, - - wcpSettingsSaveChanges: async () => { - const saveSettingsButtonSelector = '.save-settings-section button'; - const saveSettingsButton = await page.$( saveSettingsButtonSelector ); - const buttonStatus = await ( - await saveSettingsButton.getProperty( 'disabled' ) - ).jsonValue(); - if ( buttonStatus === true ) { - return; - } - - const snackbarSettingsSaved = '.components-snackbar'; - - await expect( page ).toClick( saveSettingsButtonSelector ); - await expect( page ).toMatchElement( snackbarSettingsSaved, { - text: 'Settings saved.', - timeout: 60000, - } ); - await expect( page ).toClick( snackbarSettingsSaved ); - }, - - addNewPageCheckoutWCB: async () => { - await page.goto( WP_ADMIN_PAGES, { - waitUntil: 'networkidle0', - } ); - - // Add a new page called "Checkout WCB" - await page.keyboard.press( 'Escape' ); // to dismiss a dialog if present - await expect( page ).toClick( '.page-title-action', { - waitUntil: 'networkidle0', - } ); - await page.waitForSelector( 'h1.editor-post-title__input' ); - await page.type( 'h1.editor-post-title__input', 'Checkout WCB' ); - - // Insert new checkout by WCB (searching for Checkout block and pressing Enter) - await expect( page ).toClick( 'button.block-editor-inserter__toggle' ); - const searchInput = await page.waitForSelector( - 'div.components-search-control input.components-input-control__input' - ); - await searchInput.type( 'Checkout', { delay: 20 } ); - - await page.waitForSelector( 'button.components-button[role="option"]', { - visible: true, - } ); - await page.click( 'button.components-button[role="option"]' ); - await page.waitForTimeout( 500 ); - - // Dismiss dialog about potentially compatibility issues - await page.keyboard.press( 'Escape' ); // to dismiss a dialog if present - - // Publish the page - await expect( page ).toClick( - 'button.editor-post-publish-panel__toggle' - ); - await page.waitForTimeout( 500 ); - await expect( page ).toClick( 'button.editor-post-publish-button' ); - await page.waitForSelector( - '.components-snackbar__content', - 'Page updated.' - ); - }, - - setCheckboxByTestId: async ( testId ) => { - await page.waitForSelector( `[data-testid="${ testId }"]`, { - timeout: 5000, - } ); - const checkbox = await page.$( `[data-testid="${ testId }"]` ); - const checkboxStatus = await ( - await checkbox.getProperty( 'checked' ) - ).jsonValue(); - if ( checkboxStatus !== true ) { - await checkbox.click(); - } - }, - - unsetCheckboxByTestId: async ( testId ) => { - await page.waitForSelector( `[data-testid="${ testId }"]`, { - timeout: 5000, - } ); - const checkbox = await page.$( `[data-testid="${ testId }"]` ); - const checkboxStatus = await ( - await checkbox.getProperty( 'checked' ) - ).jsonValue(); - if ( checkboxStatus === true ) { - await checkbox.click(); - } - }, - - activateWooPay: async () => { - await page.goto( WCPAY_DEV_TOOLS, { - waitUntil: 'networkidle0', - } ); - - if ( ! ( await page.$( '#override_woopay_eligible:checked' ) ) ) { - await expect( page ).toClick( - 'label[for="override_woopay_eligible"]' - ); - - await expect( page ).toSelect( - 'select[name="override_woopay_eligible_value"]', - 'true' - ); - } - - await expect( page ).toClick( 'input#submit' ); - await page.waitForNavigation( { - waitUntil: 'networkidle0', - } ); - }, - - deactivateWooPay: async () => { - await page.goto( WCPAY_DEV_TOOLS, { - waitUntil: 'networkidle0', - } ); - - if ( await page.$( '#override_woopay_eligible:checked' ) ) { - await expect( page ).toClick( - 'label[for="override_woopay_eligible"]' - ); - await expect( page ).toSelect( - 'select[name="override_woopay_eligible_value"]', - 'false' - ); - } - - await expect( page ).toClick( 'input#submit' ); - await page.waitForNavigation( { - waitUntil: 'networkidle0', - } ); - }, - - deactivateMulticurrency: async () => { - await merchantWCP.openWCPSettings(); - await merchantWCP.unsetCheckboxByTestId( 'multi-currency-toggle' ); - await merchantWCP.wcpSettingsSaveChanges(); - }, - - activateMulticurrency: async () => { - await merchantWCP.openWCPSettings(); - const wasInitiallyEnabled = await page.evaluate( () => { - const checkbox = document.querySelector( - "[data-testid='multi-currency-toggle']" - ); - return checkbox ? checkbox.checked : false; - } ); - if ( ! wasInitiallyEnabled ) { - await merchantWCP.setCheckboxByTestId( 'multi-currency-toggle' ); - await merchantWCP.wcpSettingsSaveChanges(); - } - return wasInitiallyEnabled; - }, - - disableAllEnabledCurrencies: async () => { - await page.goto( WCPAY_MULTI_CURRENCY, { waitUntil: 'networkidle0' } ); - - await page.waitForSelector( '.enabled-currencies-list li', { - timeout: 10000, - } ); - - // Select all delete buttons for enabled currencies. - const deleteButtons = await page.$$( - '.enabled-currency .enabled-currency__action.delete' - ); - - // Loop through each delete button and click it. - for ( const button of deleteButtons ) { - await button.click(); - - await page.waitForSelector( '.components-snackbar', { - text: 'Enabled currencies updated.', - timeout: 10000, - } ); - - await page.waitForTimeout( 1000 ); - } - }, - - editCurrency: async ( currencyCode ) => { - await merchantWCP.openMultiCurrency(); - - const currencyItemSelector = `li.enabled-currency.${ currencyCode.toLowerCase() }`; - await page.waitForSelector( currencyItemSelector, { timeout: 10000 } ); - await page.click( - `${ currencyItemSelector } .enabled-currency__action.edit` - ); - }, - - saveCurrencySettings: async () => { - await page.click( - '.single-currency-settings-save-settings-section button' - ); - await page.waitForSelector( '.components-snackbar', { - text: 'Currency settings updated.', - timeout: 15000, - } ); - }, - - setCurrencyRate: async ( currencyCode, rate ) => { - await merchantWCP.editCurrency( currencyCode ); - - await page.waitForSelector( - '#single-currency-settings__manual_rate_radio' - ); - await page.click( '#single-currency-settings__manual_rate_radio' ); - - await page.waitForSelector( '[data-testid="manual_rate_input"]', { - timeout: 5000, - } ); - await clearAndFillInput( - '[data-testid="manual_rate_input"]', - rate.toString() - ); - - await merchantWCP.saveCurrencySettings(); - }, - - setCurrencyPriceRounding: async ( currencyCode, rounding ) => { - await merchantWCP.editCurrency( currencyCode ); - - await page.waitForSelector( '[data-testid="price_rounding"]', { - timeout: 5000, - } ); - await page.select( '[data-testid="price_rounding"]', rounding ); - - await merchantWCP.saveCurrencySettings(); - }, - - setCurrencyCharmPricing: async ( currencyCode, charmPricing ) => { - await merchantWCP.editCurrency( currencyCode ); - - await page.waitForSelector( '[data-testid="price_charm"]', { - timeout: 5000, - } ); - await page.select( '[data-testid="price_charm"]', charmPricing ); - - await merchantWCP.saveCurrencySettings(); - }, - - addMulticurrencyWidget: async () => { - await page.goto( `${ WP_ADMIN_DASHBOARD }widgets.php`, { - waitUntil: 'load', - } ); - - await page.waitForTimeout( 2000 ); - - const closeWelcomeModal = await page.$( 'button[aria-label="Close"]' ); - if ( closeWelcomeModal ) { - await closeWelcomeModal.click(); - } - - const isWidgetAdded = await page.$( - '.wp-block iframe[srcdoc*=\'name="currency"\']' - ); - if ( ! isWidgetAdded ) { - await page.click( 'button[aria-label="Add block"]' ); - - const searchInput = await page.waitForSelector( - 'input[placeholder="Search"]' - ); - await searchInput.type( 'switcher', { delay: 20 } ); - - await page.waitForSelector( - 'button.components-button[role="option"]', - { - visible: true, - timeout: 5000, - } - ); - await page.click( 'button.components-button[role="option"]' ); - await page.waitForTimeout( 2000 ); - await page.waitForSelector( - '.edit-widgets-header .edit-widgets-header__actions button.is-primary' - ); - await page.click( - '.edit-widgets-header .edit-widgets-header__actions button.is-primary' - ); - await expect( page ).toMatchElement( '.components-snackbar', { - text: 'Widgets saved.', - timeout: 15000, - } ); - } - }, - createPayForOrder: async () => { - await merchant.openNewOrder(); - await page.click( 'button.add-line-item' ); - await page.waitForTimeout( 500 ); - await page.click( 'button.add-order-item' ); - const selectItem = await page.waitForSelector( - 'select[name="item_id"]' - ); - await selectItem.click(); - const dropdownInput = await page.waitForSelector( - '.select2-search--dropdown > input' - ); - await dropdownInput.type( config.get( 'products.simple.name' ), { - delay: 20, - } ); - await page.waitForTimeout( 2000 ); - await page.click( '.select2-results .select2-results__option' ); - await page.click( '#btn-ok' ); - await page.waitForTimeout( 2000 ); - await page.click( 'button.save_order' ); - await page.waitForNavigation( { waitUntil: 'networkidle0' } ); - }, -}; diff --git a/tests/e2e/utils/helpers.js b/tests/e2e/utils/helpers.js deleted file mode 100644 index 2d9b0e0932b..00000000000 --- a/tests/e2e/utils/helpers.js +++ /dev/null @@ -1,100 +0,0 @@ -/** - * Wait for UI placeholders to finish and UI content is loaded. - * - */ -const config = require( 'config' ); - -export const uiLoaded = async () => { - await page.waitForFunction( - () => ! Boolean( document.querySelector( '.is-loadable-placeholder' ) ) - ); -}; - -// Conditionally determine whether or not to skip a test suite -export const describeif = ( condition ) => - condition ? describe : describe.skip; - -// Save full page screenshot to file. -export const takeScreenshot = ( name ) => { - return page.screenshot( { - path: `./screenshots/${ name }.png`, - fullPage: true, - } ); -}; - -// Check whether specified page exists -export const checkPageExists = async ( slug ) => { - const wcbPage = await page.goto( config.get( 'url' ) + slug, { - waitUntil: 'load', - } ); - - if ( wcbPage.status() === 404 ) { - return Promise.reject(); - } -}; - -/** - * Retrieves the product price from the current product page. - * - * This function assumes that the Puppeteer page object is already navigated to a product page. - * It extracts the textual content of the element with the class '.woocommerce-Price-amount.amount', - * which is expected to contain the product's price. The function then removes any non-numeric characters - * from this text, typically to exclude the currency symbol, and returns just the numeric price. - * - * @return {Promise} A promise that resolves to the product price as a string. If the price element - * is not found on the page, the promise is rejected with an error message. - * @throws {Promise} If the price element is not found on the page, the function rejects the promise - * with an error message indicating that the price element was not found. - */ -export const getProductPriceFromProductPage = async () => { - await page.waitForSelector( '.woocommerce-Price-amount.amount', { - timeout: 5000, - } ); - const price = await page.evaluate( () => { - let priceElement = document.querySelector( - 'ins .woocommerce-Price-amount.amount' - ); - if ( ! priceElement ) { - // If no discounted price is found, look for the regular price - priceElement = document.querySelector( - '.woocommerce-Price-amount.amount' - ); - } - - if ( priceElement ) { - let priceText = priceElement.textContent || ''; - - // Remove non-numeric characters (excluding the decimal point) - priceText = priceText.replace( /[^0-9.]/g, '' ); - - return priceText; - } - return null; - } ); - - if ( price === null ) { - return Promise.reject( - new Error( 'Price element not found on the page' ) - ); - } - - return price; -}; - -/** - * Sets the state of all checkboxes matching the specified selector. - * - * @param {string} selector The selector to use to find checkboxes. - * @param {boolean} desiredState The desired state of the checkboxes. - */ -export const setCheckboxState = async ( selector, desiredState ) => { - const checkboxes = await page.$$( selector ); - for ( const checkbox of checkboxes ) { - const isChecked = await ( - await checkbox.getProperty( 'checked' ) - ).jsonValue(); - if ( isChecked !== desiredState ) { - await checkbox.click(); - } - } -}; diff --git a/tests/e2e-pw/utils/helpers.ts b/tests/e2e/utils/helpers.ts similarity index 100% rename from tests/e2e-pw/utils/helpers.ts rename to tests/e2e/utils/helpers.ts diff --git a/tests/e2e/utils/index.js b/tests/e2e/utils/index.js deleted file mode 100644 index f31accc3e0a..00000000000 --- a/tests/e2e/utils/index.js +++ /dev/null @@ -1,2 +0,0 @@ -export * from './flows'; -export * from './helpers'; diff --git a/tests/e2e-pw/utils/merchant-navigation.ts b/tests/e2e/utils/merchant-navigation.ts similarity index 100% rename from tests/e2e-pw/utils/merchant-navigation.ts rename to tests/e2e/utils/merchant-navigation.ts diff --git a/tests/e2e-pw/utils/merchant.ts b/tests/e2e/utils/merchant.ts similarity index 100% rename from tests/e2e-pw/utils/merchant.ts rename to tests/e2e/utils/merchant.ts diff --git a/tests/e2e/utils/payments.js b/tests/e2e/utils/payments.js deleted file mode 100644 index 9754bc85418..00000000000 --- a/tests/e2e/utils/payments.js +++ /dev/null @@ -1,364 +0,0 @@ -/** - * External dependencies - */ -import config from 'config'; -import { shopperWCP } from './flows'; - -const { shopper, uiUnblocked } = require( '@woocommerce/e2e-utils' ); - -// WooCommerce Checkout -export async function fillCardDetails( page, card ) { - if ( - await page.$( - '#payment .payment_method_woocommerce_payments .wcpay-upe-element' - ) - ) { - const frameHandle = await page.waitForSelector( - '#payment .payment_method_woocommerce_payments .wcpay-upe-element iframe' - ); - - const stripeFrame = await frameHandle.contentFrame(); - - const cardNumberInput = await stripeFrame.waitForSelector( - '[name="number"]', - { timeout: 30000 } - ); - - await cardNumberInput.type( card.number, { delay: 20 } ); - - const cardDateInput = await stripeFrame.waitForSelector( - '[name="expiry"]' - ); - - await cardDateInput.type( card.expires.month + card.expires.year, { - delay: 20, - } ); - await page.waitForTimeout( 1000 ); - - const cardCvcInput = await stripeFrame.waitForSelector( - '[name="cvc"]' - ); - await cardCvcInput.type( card.cvc, { delay: 20 } ); - await page.waitForTimeout( 1000 ); - - const zip = await stripeFrame.$( '[name="postalCode"]' ); - if ( zip !== null ) { - await zip.type( '90210', { delay: 20 } ); - } - } -} - -// Clear WC Checkout Card Details -export async function clearCardDetails() { - if ( await page.$( '#payment #wcpay-card-element' ) ) { - const frameHandle = await page.waitForSelector( - '#payment #wcpay-card-element iframe[name^="__privateStripeFrame"]' - ); - const stripeFrame = await frameHandle.contentFrame(); - - const cardNumberInput = await stripeFrame.waitForSelector( - '[name="cardnumber"]' - ); - await cardNumberInput.click( { clickCount: 3, delay: 100 } ); - await page.keyboard.press( 'Backspace' ); - - const cardDateInput = await stripeFrame.waitForSelector( - '[name="exp-date"]' - ); - await page.waitForTimeout( 1000 ); - await cardDateInput.click( { clickCount: 3, delay: 100 } ); - await page.keyboard.press( 'Backspace' ); - - const cardCvcInput = await stripeFrame.waitForSelector( - '[name="cvc"]' - ); - await page.waitForTimeout( 1000 ); - await cardCvcInput.click( { clickCount: 3, delay: 100 } ); - await page.keyboard.press( 'Backspace' ); - - await page.waitForTimeout( 1000 ); - } else { - // Handling Stripe UPE element - const frameHandle = await page.waitForSelector( - '#payment .payment_method_woocommerce_payments .wcpay-upe-element iframe[name^="__privateStripeFrame"]' - ); - - await page.waitForTimeout( 1000 ); - - await page.evaluate( ( selector ) => { - document.querySelector( selector ).scrollIntoView(); - }, '#payment .payment_method_woocommerce_payments .wcpay-upe-element iframe[name^="__privateStripeFrame"]' ); - - await page.waitForTimeout( 500 ); - - const stripeFrame = await frameHandle.contentFrame(); - const cardNumberInput = await stripeFrame.waitForSelector( - '[name="number"]', - { timeout: 30000 } - ); - await cardNumberInput.click( { clickCount: 3, delay: 50 } ); - await page.keyboard.press( 'Backspace' ); - - const cardDateInput = await stripeFrame.waitForSelector( - '[name="expiry"]', - { timeout: 30000 } - ); - await cardDateInput.click( { clickCount: 3, delay: 50 } ); - await page.keyboard.press( 'Backspace' ); - - const cardCvcInput = await stripeFrame.waitForSelector( - '[name="cvc"]', - { timeout: 30000 } - ); - await cardCvcInput.click( { clickCount: 3, delay: 50 } ); - await page.keyboard.press( 'Backspace' ); - await page.waitForTimeout( 1000 ); - } -} -export async function fillCardDetailsPayForOrder( page, card ) { - await page.waitForSelector( '.__PrivateStripeElement' ); - const frameHandle = await page.waitForSelector( - '#payment .payment_method_woocommerce_payments .wcpay-upe-element iframe' - ); - const stripeFrame = await frameHandle.contentFrame(); - - const cardNumberInput = await stripeFrame.waitForSelector( - '[name="number"]', - { timeout: 30000 } - ); - await cardNumberInput.type( card.number, { delay: 20 } ); - - const cardDateInput = await stripeFrame.waitForSelector( - '[name="expiry"]' - ); - - await cardDateInput.type( card.expires.month + card.expires.year, { - delay: 20, - } ); - - const cardCvcInput = await stripeFrame.waitForSelector( '[name="cvc"]' ); - await cardCvcInput.type( card.cvc, { delay: 20 } ); - await page.waitForTimeout( 1000 ); - - const zip = await stripeFrame.$( '[name="postalCode"]' ); - if ( zip !== null ) { - await zip.type( '90210', { delay: 20 } ); - } -} - -// WooCommerce Blocks Checkout -export async function fillCardDetailsWCB( page, card ) { - await page.waitForSelector( '.__PrivateStripeElement' ); - const frameHandle = await page.waitForSelector( - '#payment-method .wcpay-payment-element iframe[name^="__privateStripeFrame"]' - ); - const stripeFrame = await frameHandle.contentFrame(); - const inputs = await stripeFrame.$$( '.p-CardForm .p-Input-input' ); - - const [ cardNumberInput, cardDateInput, cardCvcInput ] = inputs; - await cardNumberInput.type( card.number, { delay: 20 } ); - await cardDateInput.type( card.expires.month + card.expires.year, { - delay: 20, - } ); - await cardCvcInput.type( card.cvc, { delay: 20 } ); -} - -// Clear WC Checkout Card Details -export async function clearWCBCardDetails() { - const frameHandle = await page.waitForSelector( - '#payment-method .wcpay-card-mounted iframe[name^="__privateStripeFrame"]' - ); - const stripeFrame = await frameHandle.contentFrame(); - const inputs = await stripeFrame.$$( '.InputElement.Input' ); - const [ cardNumberInput, cardDateInput, cardCvcInput ] = inputs; - - await page.waitForTimeout( 1000 ); - await cardNumberInput.click( { clickCount: 3, delay: 50 } ); - await page.keyboard.press( 'Backspace' ); - - await page.waitForTimeout( 1000 ); - await cardDateInput.click( { clickCount: 3, delay: 50 } ); - await page.keyboard.press( 'Backspace' ); - - await page.waitForTimeout( 1000 ); - await cardCvcInput.click( { clickCount: 3, delay: 50 } ); - await page.keyboard.press( 'Backspace' ); -} - -export async function confirmCardAuthentication( page, authorize = true ) { - const target = authorize - ? '#test-source-authorize-3ds' - : '#test-source-fail-3ds'; - - // Stripe card input also uses __privateStripeFrame as a prefix, so need to make sure we wait for an iframe that - // appears at the top of the DOM. - const frameHandle = await page.waitForSelector( - 'body>div>iframe[name^="__privateStripeFrame"]' - ); - const stripeFrame = await frameHandle.contentFrame(); - const challengeFrameHandle = await stripeFrame.waitForSelector( - 'iframe#challengeFrame' - ); - const challengeFrame = await challengeFrameHandle.contentFrame(); - // Need to wait for the CSS animations to complete. - await page.waitForTimeout( 500 ); - const button = await challengeFrame.waitForSelector( target ); - await button.click(); -} - -/** - * Set up checkout with any number of products. - * - * @param {any} billingDetails Values to be entered into the 'Billing details' form in the Checkout page - * @param {any} lineItems A 2D array of line items where each line item is an array - * that contains the product title as the first element, and the quantity as the second. - * For example, if you want to checkout the products x2 "Hoodie" and x3 "Belt" then you can set this `lineItems` parameter like this: - * - * `[ [ "Hoodie", 2 ], [ "Belt", 3 ] ]`. - * - * Default value is 1 piece of `config.get( 'products.simple.name' )`. - */ -export async function setupProductCheckout( - billingDetails, - lineItems = [ [ config.get( 'products.simple.name' ), 1 ] ] -) { - const cartItemsCounter = '.cart-contents .count'; - - await shopper.goToShop(); - - // Get the current number of items in the cart - let cartSize = await page.$eval( cartItemsCounter, ( e ) => - Number( e.innerText.replace( /\D/g, '' ) ) - ); - - // Add items to the cart - for ( const line of lineItems ) { - let [ productTitle, qty ] = line; - - while ( qty-- ) { - await shopperWCP.addToCartFromShopPage( productTitle ); - - // Make sure that the number of items in the cart is incremented first before adding another item. - await expect( page ).toMatchElement( cartItemsCounter, { - text: new RegExp( `${ ++cartSize } items?` ), - timeout: 30000, - } ); - } - } - - await setupCheckout( billingDetails ); -} - -export async function setupProductCheckoutNoMiniCart( - billingDetails, - lineItems = [ [ config.get( 'products.simple.name' ), 1 ] ] -) { - // Add items to the cart - for ( const line of lineItems ) { - const [ productTitle ] = line; - await shopper.goToShop(); - await shopperWCP.addToCartBySlug( productTitle ); - } - await shopper.goToCart(); - for ( const line of lineItems ) { - const [ productTitle, qty ] = line; - await shopper.setCartQuantity( productTitle, qty ); - } - await setupCheckout( billingDetails ); -} - -// Set up checkout -export async function setupCheckout( billingDetails ) { - await shopper.goToCheckout(); - await uiUnblocked(); - await fillBillingDetails( billingDetails ); - - // Woo core blocks and refreshes the UI after 1s after each key press in a text field or immediately after a select - // field changes. Need to wait to make sure that all key presses were processed by that mechanism. - await page.waitForTimeout( 1000 ); - await uiUnblocked(); - await page.click( 'label[for="payment_method_woocommerce_payments"]' ); -} - -// Copy of the fillBillingDetails function from woocommerce/e2e-utils/src/flows/shopper.js -// Supporting countries that do not have a state select input. -// Remove after https://github.com/woocommerce/woocommerce/pull/44090 is merged. -async function fillBillingDetails( customerBillingDetails ) { - await expect( page ).toFill( - '#billing_first_name', - customerBillingDetails.firstname - ); - await expect( page ).toFill( - '#billing_last_name', - customerBillingDetails.lastname - ); - await expect( page ).toFill( - '#billing_company', - customerBillingDetails.company - ); - await expect( page ).toSelect( - '#billing_country', - customerBillingDetails.country - ); - await expect( page ).toFill( - '#billing_address_1', - customerBillingDetails.addressfirstline - ); - await expect( page ).toFill( - '#billing_address_2', - customerBillingDetails.addresssecondline - ); - await expect( page ).toFill( '#billing_city', customerBillingDetails.city ); - if ( customerBillingDetails.state ) { - await expect( page ).toSelect( - '#billing_state', - customerBillingDetails.state - ); - } - await expect( page ).toFill( - '#billing_postcode', - customerBillingDetails.postcode - ); - await expect( page ).toFill( - '#billing_phone', - customerBillingDetails.phone - ); - await expect( page ).toFill( - '#billing_email', - customerBillingDetails.email - ); -} - -/** - * Selects the payment method on the checkout page. - * - * @param {*} paymentMethod The payment method to select. - * @param {*} page The page reference object. - */ -export async function selectOnCheckout( paymentMethod, page ) { - await page.$( - '#payment .payment_method_woocommerce_payments_' + paymentMethod - ); - const radioLabel = await page.waitForSelector( - '#payment .payment_method_woocommerce_payments_' + - paymentMethod + - ' label' - ); - radioLabel.click(); - await page.waitForTimeout( 1000 ); -} - -/** - * Authorizes or fails a redirected payment. - * - * @param {*} page The page reference object. - * @param {string} action Either of 'success' or 'failure'. - */ -export async function completeRedirectedPayment( page, action ) { - await page.$( '.actions .common-ButtonGroup' ); - const actionButton = await page.waitForSelector( - `.actions .common-ButtonGroup a[name=${ action }]` - ); - actionButton.click(); - await page.waitForTimeout( 1000 ); -} diff --git a/tests/e2e/utils/performance.js b/tests/e2e/utils/performance.ts similarity index 67% rename from tests/e2e/utils/performance.js rename to tests/e2e/utils/performance.ts index c381475fb45..5bbd482a964 100644 --- a/tests/e2e/utils/performance.js +++ b/tests/e2e/utils/performance.ts @@ -2,28 +2,37 @@ * External dependencies */ import { appendFileSync, existsSync, mkdirSync, truncateSync } from 'fs'; +import { expect, Page } from '@playwright/test'; /** * Internal dependencies */ import { - PERFORMANCE_REPORT_DIR, - PERFORMANCE_REPORT_FILENAME, - NUMBER_OF_TRIALS, + performanceReportDir, + performanceReportfilename, + performanceNumberOfTrials, } from './constants'; -async function getLoadingDurations() { +type Metrics = Record< string, number[] >; +type AverageMetrics = Record< string, number >; + +async function getLoadingDurations( page: Page ) { return await page.evaluate( () => { + const navigation = performance.getEntriesByType( + 'navigation' + )[ 0 ] as PerformanceNavigationTiming; + const { requestStart, responseStart, responseEnd, domContentLoadedEventEnd, loadEventEnd, - } = performance.getEntriesByType( 'navigation' )[ 0 ]; + } = navigation; const paintTimings = performance.getEntriesByType( 'paint' ); - let firstPaintTimings, firstContentfulPaintTimings; + let firstPaintTimings: PerformanceEntry, + firstContentfulPaintTimings: PerformanceEntry; paintTimings.forEach( ( item ) => { if ( item.name === 'first-paint' ) { @@ -45,7 +54,7 @@ async function getLoadingDurations() { loaded: loadEventEnd - responseEnd, firstContentfulPaint: firstContentfulPaintTimings.startTime - responseEnd, - // This is evaluated right after Puppeteer found the block selector. + // This is evaluated right after we find the block selector. firstBlock: performance.now() - responseEnd, }; } ); @@ -53,13 +62,13 @@ async function getLoadingDurations() { /** * Writes a line to the e2e performance result. - * - * @param {string} description A title that describe this metric - * @param {Object} metrics array of metrics to record. */ -export const logPerformanceResult = ( description, metrics ) => { +export const logPerformanceResult = ( + description: string, + metrics: AverageMetrics +) => { appendFileSync( - PERFORMANCE_REPORT_FILENAME, + performanceReportfilename, JSON.stringify( { description, ...metrics } ) + '\n' ); }; @@ -68,26 +77,24 @@ export const logPerformanceResult = ( description, metrics ) => { * Wipe the existing performance file. Also make sure the "report" folder exists. */ export const recreatePerformanceFile = () => { - if ( ! existsSync( PERFORMANCE_REPORT_DIR ) ) { - mkdirSync( PERFORMANCE_REPORT_DIR ); + if ( ! existsSync( performanceReportDir ) ) { + mkdirSync( performanceReportDir ); } - if ( existsSync( PERFORMANCE_REPORT_FILENAME ) ) { - truncateSync( PERFORMANCE_REPORT_FILENAME ); + if ( existsSync( performanceReportfilename ) ) { + truncateSync( performanceReportfilename ); } }; /** * Takes the metric object and for each of the property, reduce to the average. - * - * @param {Object} metrics An object containing multiple trials' data. - * @return {Object} The averaged results. */ -export const averageMetrics = ( metrics ) => { +export const averageMetrics = ( metrics: Metrics ): AverageMetrics => { const results = {}; for ( const [ key, value ] of Object.entries( metrics ) ) { results[ key ] = - value.reduce( ( prev, curr ) => prev + curr ) / NUMBER_OF_TRIALS; + value.reduce( ( prev, curr ) => prev + curr ) / + performanceNumberOfTrials; } return results; }; @@ -96,13 +103,12 @@ export const averageMetrics = ( metrics ) => { * This helper function goes to checkout page *i* times. Wait * for the given card selector to load, retrieve all the metrics * and find the average. - * - * @param {string} selector CSS selector. - * @param {number} numberOfTrials The number of trials we would like to do. - * @return {Object} The averaged results. */ -export const measureCheckoutMetrics = async ( selector ) => { - await expect( page ).toMatchTextContent( 'Checkout' ); +export const measureCheckoutMetrics = async ( + page: Page, + selector: string +): Promise< Metrics > => { + await expect( page.getByText( 'Checkout' ).first() ).toBeVisible(); // Run performance tests a few times, then take the average. const results = { @@ -114,7 +120,7 @@ export const measureCheckoutMetrics = async ( selector ) => { firstBlock: [], }; - let i = NUMBER_OF_TRIALS; + let i = performanceNumberOfTrials; while ( i-- ) { await page.reload(); await page.waitForSelector( selector ); @@ -125,7 +131,7 @@ export const measureCheckoutMetrics = async ( selector ) => { loaded, firstContentfulPaint, firstBlock, - } = await getLoadingDurations(); + } = await getLoadingDurations( page ); results.serverResponse.push( serverResponse ); results.firstPaint.push( firstPaint ); diff --git a/tests/e2e-pw/utils/rest-api.ts b/tests/e2e/utils/rest-api.ts similarity index 100% rename from tests/e2e-pw/utils/rest-api.ts rename to tests/e2e/utils/rest-api.ts diff --git a/tests/e2e-pw/utils/shopper-navigation.ts b/tests/e2e/utils/shopper-navigation.ts similarity index 100% rename from tests/e2e-pw/utils/shopper-navigation.ts rename to tests/e2e/utils/shopper-navigation.ts diff --git a/tests/e2e-pw/utils/shopper.ts b/tests/e2e/utils/shopper.ts similarity index 100% rename from tests/e2e-pw/utils/shopper.ts rename to tests/e2e/utils/shopper.ts diff --git a/tests/js/jest.config.js b/tests/js/jest.config.js index 7a918a8d63c..7665524e08d 100644 --- a/tests/js/jest.config.js +++ b/tests/js/jest.config.js @@ -30,7 +30,6 @@ module.exports = { setupFilesAfterEnv: [ '/node_modules/@wordpress/jest-preset-default/scripts/setup-test-framework.js', '/tests/js/jest-extensions-setup.js', - 'expect-puppeteer', ], preset: '@wordpress/jest-preset-default', testMatch: [