diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index 099f295ff..032b91639 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -1,4 +1,4 @@ -name: End-to-end (e2e) Tests +name: End-to-end Tests on: # Run on all pull requests. @@ -16,8 +16,8 @@ concurrency: jobs: test: - name: e2e against WordPress latest - runs-on: ubuntu-20.04 + name: E2E against WordPress latest + runs-on: ubuntu-24.04 steps: - name: Checkout code @@ -29,22 +29,32 @@ jobs: - name: Use desired version of NodeJS uses: actions/setup-node@v4.0.3 with: - node-version: 16 + node-version: 18 cache: npm - name: Npm install run: | npm ci + - name: Install Playwright dependencies + run: | + npx playwright install chromium --with-deps + - name: Start up WordPress environment run: | npm run dev:start - - name: Running the tests + - name: Running E2E tests run: | npm run test:e2e -- --listTests > ~/.jest-e2e-tests npm run test:e2e + - name: Running Playwright E2E tests + env: + PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 + run: | + npm run test:e2e:playwright + - name: Stop WordPress environment run: | npm run dev:stop diff --git a/jest-e2e.config.js b/jest-e2e.config.js index a429b3fa8..1bf75b508 100644 --- a/jest-e2e.config.js +++ b/jest-e2e.config.js @@ -3,5 +3,6 @@ const baseConfig = require( '@wordpress/scripts/config/jest-e2e.config' ); module.exports = { ...baseConfig, + testMatch: [ '**/tests/e2e/specs/**/*.[jt]s?(x)' ], // Prevent running Playwright tests. testTimeout: 35000, // Increased timeout for E2E tests. }; diff --git a/package-lock.json b/package-lock.json index 5ce12a36e..8c302d45c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "lodash.debounce": "^4.0.8" }, "devDependencies": { + "@playwright/test": "^1.46.1", "@testing-library/jest-dom": "^6.4.8", "@testing-library/react": "^16.0.0", "@types/jest": "^29.5.12", @@ -35,6 +36,7 @@ "@wordpress/core-data": "^7.5.0", "@wordpress/data": "^10.5.0", "@wordpress/e2e-test-utils": "^11.5.0", + "@wordpress/e2e-test-utils-playwright": "^1.5.0", "@wordpress/edit-post": "^8.5.0", "@wordpress/editor": "^14.5.0", "@wordpress/element": "^6.5.0", @@ -4072,20 +4074,19 @@ } }, "node_modules/@playwright/test": { - "version": "1.44.1", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.44.1.tgz", - "integrity": "sha512-1hZ4TNvD5z9VuhNJ/walIjvMVvYkZKf71axoF/uiAqpntQJXpG64dlXhoDXE3OczPuTuvjf/M5KWFg5VAVUS3Q==", + "version": "1.46.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.46.1.tgz", + "integrity": "sha512-Fq6SwLujA/DOIvNC2EL/SojJnkKf/rAwJ//APpJJHRyMi1PdKrY3Az+4XNQ51N4RTbItbIByQ0jgd1tayq1aeA==", "dev": true, "license": "Apache-2.0", - "peer": true, "dependencies": { - "playwright": "1.44.1" + "playwright": "1.46.1" }, "bin": { "playwright": "cli.js" }, "engines": { - "node": ">=16" + "node": ">=18" } }, "node_modules/@pmmmwh/react-refresh-webpack-plugin": { @@ -10554,92 +10555,27 @@ } }, "node_modules/@wordpress/e2e-test-utils-playwright": { - "version": "0.26.0", - "resolved": "https://registry.npmjs.org/@wordpress/e2e-test-utils-playwright/-/e2e-test-utils-playwright-0.26.0.tgz", - "integrity": "sha512-4KFyQ3IsYIJaIvOQ1qhAHhRISs9abNToF/bktfMNxQiEJsmbNn7lq/IbaY+shqwdBWVg8TQtLcL4MpSl0ISaxQ==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@wordpress/e2e-test-utils-playwright/-/e2e-test-utils-playwright-1.5.0.tgz", + "integrity": "sha512-gQuhdDMejum7a4hWW4ejIWSBv1xeeCFda5o7eq766evarU+HwcN+4GPiSYKj2iEHJ4dge1On2VXeg1RFLY3w5Q==", "dev": true, "license": "GPL-2.0-or-later", "dependencies": { - "@wordpress/api-fetch": "^6.55.0", - "@wordpress/keycodes": "^3.58.0", - "@wordpress/url": "^3.59.0", "change-case": "^4.1.2", "form-data": "^4.0.0", "get-port": "^5.1.1", "lighthouse": "^10.4.0", "mime": "^3.0.0", - "web-vitals": "^3.5.0" + "web-vitals": "^4.2.1" }, "engines": { - "node": ">=12" + "node": ">=18.12.0", + "npm": ">=8.19.2" }, "peerDependencies": { "@playwright/test": ">=1" } }, - "node_modules/@wordpress/e2e-test-utils-playwright/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, - "license": "GPL-2.0-or-later", - "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-playwright/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, - "license": "GPL-2.0-or-later", - "dependencies": { - "@babel/runtime": "^7.16.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@wordpress/e2e-test-utils-playwright/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, - "license": "GPL-2.0-or-later", - "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-playwright/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, - "license": "GPL-2.0-or-later", - "dependencies": { - "@babel/runtime": "^7.16.0", - "remove-accents": "^0.5.0" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/@wordpress/e2e-test-utils/node_modules/@wordpress/keycodes": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/@wordpress/keycodes/-/keycodes-4.5.0.tgz", @@ -11984,6 +11920,45 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@wordpress/scripts/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, + "license": "GPL-2.0-or-later", + "dependencies": { + "@babel/runtime": "^7.16.0", + "@wordpress/i18n": "^4.58.0", + "@wordpress/url": "^3.59.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@wordpress/scripts/node_modules/@wordpress/e2e-test-utils-playwright": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/@wordpress/e2e-test-utils-playwright/-/e2e-test-utils-playwright-0.26.0.tgz", + "integrity": "sha512-4KFyQ3IsYIJaIvOQ1qhAHhRISs9abNToF/bktfMNxQiEJsmbNn7lq/IbaY+shqwdBWVg8TQtLcL4MpSl0ISaxQ==", + "dev": true, + "license": "GPL-2.0-or-later", + "dependencies": { + "@wordpress/api-fetch": "^6.55.0", + "@wordpress/keycodes": "^3.58.0", + "@wordpress/url": "^3.59.0", + "change-case": "^4.1.2", + "form-data": "^4.0.0", + "get-port": "^5.1.1", + "lighthouse": "^10.4.0", + "mime": "^3.0.0", + "web-vitals": "^3.5.0" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "@playwright/test": ">=1" + } + }, "node_modules/@wordpress/scripts/node_modules/@wordpress/eslint-plugin": { "version": "18.1.0", "resolved": "https://registry.npmjs.org/@wordpress/eslint-plugin/-/eslint-plugin-18.1.0.tgz", @@ -12028,6 +12003,40 @@ } } }, + "node_modules/@wordpress/scripts/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, + "license": "GPL-2.0-or-later", + "dependencies": { + "@babel/runtime": "^7.16.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@wordpress/scripts/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, + "license": "GPL-2.0-or-later", + "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/scripts/node_modules/@wordpress/prettier-config": { "version": "3.15.0", "resolved": "https://registry.npmjs.org/@wordpress/prettier-config/-/prettier-config-3.15.0.tgz", @@ -12041,6 +12050,20 @@ "prettier": ">=3" } }, + "node_modules/@wordpress/scripts/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, + "license": "GPL-2.0-or-later", + "dependencies": { + "@babel/runtime": "^7.16.0", + "remove-accents": "^0.5.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/@wordpress/scripts/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -12335,6 +12358,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@wordpress/scripts/node_modules/web-vitals": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-3.5.2.tgz", + "integrity": "sha512-c0rhqNcHXRkY/ogGDJQxZ9Im9D19hDihbzSQJrsioex+KnFgmMzBiy57Z1EjkhX/+OjyBpclDCzz2ITtjokFmg==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/@wordpress/scripts/node_modules/ws": { "version": "8.5.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", @@ -26540,37 +26570,35 @@ } }, "node_modules/playwright": { - "version": "1.44.1", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.44.1.tgz", - "integrity": "sha512-qr/0UJ5CFAtloI3avF95Y0L1xQo6r3LQArLIg/z/PoGJ6xa+EwzrwO5lpNr/09STxdHuUoP2mvuELJS+hLdtgg==", + "version": "1.46.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.46.1.tgz", + "integrity": "sha512-oPcr1yqoXLCkgKtD5eNUPLiN40rYEM39odNpIb6VE6S7/15gJmA1NzVv6zJYusV0e7tzvkU/utBFNa/Kpxmwng==", "dev": true, "license": "Apache-2.0", - "peer": true, "dependencies": { - "playwright-core": "1.44.1" + "playwright-core": "1.46.1" }, "bin": { "playwright": "cli.js" }, "engines": { - "node": ">=16" + "node": ">=18" }, "optionalDependencies": { "fsevents": "2.3.2" } }, "node_modules/playwright-core": { - "version": "1.44.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.44.1.tgz", - "integrity": "sha512-wh0JWtYTrhv1+OSsLPgFzGzt67Y7BE/ZS3jEqgGBlp2ppp1ZDj8c+9IARNW4dwf1poq5MgHreEM2KV/GuR4cFA==", + "version": "1.46.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.46.1.tgz", + "integrity": "sha512-h9LqIQaAv+CYvWzsZ+h3RsrqCStkBHlgo6/TJlFst3cOTlLghBQlJwPOZKQJTKNaD3QIB7aAVQ+gfWbN3NXB7A==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "playwright-core": "cli.js" }, "engines": { - "node": ">=16" + "node": ">=18" } }, "node_modules/playwright/node_modules/fsevents": { @@ -26584,7 +26612,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } @@ -31752,9 +31779,9 @@ } }, "node_modules/web-vitals": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-3.5.2.tgz", - "integrity": "sha512-c0rhqNcHXRkY/ogGDJQxZ9Im9D19hDihbzSQJrsioex+KnFgmMzBiy57Z1EjkhX/+OjyBpclDCzz2ITtjokFmg==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-4.2.3.tgz", + "integrity": "sha512-/CFAm1mNxSmOj6i0Co+iGFJ58OS4NRGVP+AWS/l509uIK5a1bSoIVaHz/ZumpHTfHSZBpgrJ+wjfpAOrTHok5Q==", "dev": true, "license": "Apache-2.0" }, diff --git a/package.json b/package.json index 231ce40b1..947648607 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "lodash.debounce": "^4.0.8" }, "devDependencies": { + "@playwright/test": "^1.46.1", "@testing-library/jest-dom": "^6.4.8", "@testing-library/react": "^16.0.0", "@types/jest": "^29.5.12", @@ -63,6 +64,7 @@ "@wordpress/core-data": "^7.5.0", "@wordpress/data": "^10.5.0", "@wordpress/e2e-test-utils": "^11.5.0", + "@wordpress/e2e-test-utils-playwright": "^1.5.0", "@wordpress/edit-post": "^8.5.0", "@wordpress/editor": "^14.5.0", "@wordpress/element": "^6.5.0", @@ -101,7 +103,9 @@ "start": "wp-scripts start", "test": "npm run test:unit", "test:e2e": "wp-scripts test-e2e", + "test:e2e:playwright": "wp-scripts test-playwright --config test/e2e/playwright.config.ts", "test:e2e:debug": "wp-scripts --inspect-brk test-e2e --puppeteer-devtools", + "test:e2e:playwright:debug": "wp-scripts test-playwright --config test/e2e/playwright.config.ts --ui", "test:e2e:help": "wp-scripts test-e2e --help", "test:e2e:interactive": "npm run test:e2e -- --puppeteer-interactive", "test:e2e:watch": "npm run test:e2e -- --watch", diff --git a/test/e2e/playwright.config.ts b/test/e2e/playwright.config.ts new file mode 100644 index 000000000..764839a00 --- /dev/null +++ b/test/e2e/playwright.config.ts @@ -0,0 +1,16 @@ +/** + * External dependencies + */ +import { defineConfig } from '@playwright/test'; + +/** + * WordPress dependencies + */ +// eslint-disable-next-line @typescript-eslint/no-var-requires +const baseConfig = require( '@wordpress/scripts/config/playwright.config' ); + +const config = defineConfig( { + ...baseConfig, +} ); + +export default config; diff --git a/test/e2e/specs/plugin-action-link.spec.ts b/test/e2e/specs/plugin-action-link.spec.ts new file mode 100644 index 000000000..63abf3ccb --- /dev/null +++ b/test/e2e/specs/plugin-action-link.spec.ts @@ -0,0 +1,15 @@ +/** + * WordPress dependencies + */ +import { expect, test } from '@wordpress/e2e-test-utils-playwright'; + +test.describe( 'Plugin action link', () => { + test( 'Should link to the plugin\'s settings page', async ( { admin, page } ) => { + await admin.visitAdminPage( '/plugins.php' ); + await page.locator( '#the-list' ).getByRole( 'link', { name: 'Settings' } ).click(); + + // Check loaded page's URL and heading. + await page.waitForURL( '**/wp-admin/options-general.php?page=parsely' ); + await expect( page.getByText( 'Parse.ly Settings' ) ).toBeVisible(); + } ); +} ); diff --git a/tests/e2e/specs/plugin-action-link.spec.ts b/tests/e2e/specs/plugin-action-link.spec.ts deleted file mode 100644 index 38dcacaa4..000000000 --- a/tests/e2e/specs/plugin-action-link.spec.ts +++ /dev/null @@ -1,23 +0,0 @@ -/** - * WordPress dependencies - */ -import { visitAdminPage } from '@wordpress/e2e-test-utils'; - -/** - * Internal dependencies - */ -import { - waitForWpAdmin, -} from '../utils'; - -describe( 'Plugin action link', () => { - it( 'Should link to plugin settings page', async () => { - await visitAdminPage( '/plugins.php', '' ); - - await page.click( '[data-slug=wp-parsely] .settings>a' ); - await waitForWpAdmin(); - - const versionText = await page.$eval( '#wp-parsely_version', ( el: Element ) => el.textContent ); - expect( versionText ).toMatch( /^Version \d+.\d+/ ); - } ); -} );