From 6bf43f6138c6b0394b2bc4c67555f7d7d32a41c4 Mon Sep 17 00:00:00 2001 From: Andrea Fercia Date: Mon, 31 Aug 2026 16:09:56 +0200 Subject: [PATCH 01/22] Try adding axe-core. --- package-lock.json | 21 ++++++++++++--- package.json | 1 + tests/e2e/specs/accessibility.spec.js | 38 +++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 tests/e2e/specs/accessibility.spec.js diff --git a/package-lock.json b/package-lock.json index b0cc6e695d85a..5eb5202419ae0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -41,6 +41,7 @@ }, "devDependencies": { "@343dev/gifsicle": "1.2.0", + "@axe-core/playwright": "4.13.0", "@lodder/grunt-postcss": "^3.1.1", "@napi-rs/image": "1.14.0", "@playwright/test": "1.61.1", @@ -134,6 +135,19 @@ "dev": true, "license": "ISC" }, + "node_modules/@axe-core/playwright": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@axe-core/playwright/-/playwright-4.13.0.tgz", + "integrity": "sha512-6YLx+kxXu5GJceG4ozFg+33a2EMTdjYwWGloJ3sb9Kta5pp+ZNS53uxGVog5JetIY8s++P5UrtX+cri+u0VAVg==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "axe-core": "~4.13.0" + }, + "peerDependencies": { + "playwright-core": ">= 1.0.0" + } + }, "node_modules/@babel/code-frame": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", @@ -9406,10 +9420,11 @@ "dev": true }, "node_modules/axe-core": { - "version": "4.10.2", - "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.10.2.tgz", - "integrity": "sha512-RE3mdQ7P3FRSe7eqCWoeQ/Z9QXrtniSjp1wUjt5nRC3WIpz5rSCve6o3fsZ2aCpJtrZjSZgjwXAoTO5k4tEI0w==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.13.0.tgz", + "integrity": "sha512-UzGt8zg7Ny8djbYMhxl2zuEevVa7r2gJjYY5Lwr1xM7+XU2nd6CkIWFTVcCIbAP63vSz71NaVyyuSk9lHKcy0A==", "dev": true, + "license": "MPL-2.0", "engines": { "node": ">=4" } diff --git a/package.json b/package.json index 60f56cc977063..5b8f6e79ce00a 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ ], "devDependencies": { "@343dev/gifsicle": "1.2.0", + "@axe-core/playwright": "4.13.0", "@lodder/grunt-postcss": "^3.1.1", "@napi-rs/image": "1.14.0", "@playwright/test": "1.61.1", diff --git a/tests/e2e/specs/accessibility.spec.js b/tests/e2e/specs/accessibility.spec.js new file mode 100644 index 0000000000000..252cdf20e806e --- /dev/null +++ b/tests/e2e/specs/accessibility.spec.js @@ -0,0 +1,38 @@ +import { test, expect } from '@wordpress/e2e-test-utils-playwright'; +const AxeBuilder = require( '@axe-core/playwright' ).default; + +test.describe( 'PHP Page Accessibility Tests', () => { + test( 'should not have any automatically detectable accessibility violations', async ( { admin, page, requestUtils } ) => { + + // await requestUtils.login(); + // await page.goto( 'http://localhost:8889/wp-admin/edit.php'); + await admin.visitAdminPage( '/edit.php' ); + + // 2. Run the axe scan on the rendered page + const scanResults = await new AxeBuilder({ page }).analyze(); + + // 3. Format and print violations individually if any are found + if (scanResults.violations.length > 0) { + console.log(`\n❌ Found ${scanResults.violations.length} accessibility violation(s):\n`); + + scanResults.violations.forEach((violation, index) => { + console.log(`--- Violation #${index + 1} ---`); + console.log(`Rule ID: ${violation.id}`); + console.log(`Impact: ${violation.impact.toUpperCase()}`); + console.log(`Failure: ${violation.description}`); + console.log(`Help Link: ${violation.helpUrl}`); + + // List every specific HTML element failing this rule + console.log('Failing Elements:'); + violation.nodes.forEach((node) => { + console.log(` - Target Selector: ${node.target.join(', ')}`); + console.log(` HTML Snippet: ${node.html}`); + }); + console.log('\n'); + }); + } + + // 3. Assert that the violations list is empty + expect(scanResults.violations).toEqual([]); + }); +}); From 80ad1bd66bd5d0772e4f093a00034bd3d8e8df4d Mon Sep 17 00:00:00 2001 From: Andrea Fercia Date: Tue, 1 Sep 2026 11:57:52 +0200 Subject: [PATCH 02/22] Clean up. --- src/js/media/views/attachments/browser.js | 3 +- tests/e2e/specs/accessibility.spec.js | 91 +++++++++++++++-------- 2 files changed, 60 insertions(+), 34 deletions(-) diff --git a/src/js/media/views/attachments/browser.js b/src/js/media/views/attachments/browser.js index 8d7d4dca51b76..fc791b1b51d89 100644 --- a/src/js/media/views/attachments/browser.js +++ b/src/js/media/views/attachments/browser.js @@ -254,7 +254,8 @@ AttachmentsBrowser = View.extend(/** @lends wp.media.view.AttachmentsBrowser.pro }).render() ); // DateFilter is a , a label element needs to be rendered before. // Re-introduce the bug fixed in https://core.trac.wordpress.org/changeset/62851 for axe-core testing purposes. - this.toolbar.set( 'dateFilter', new wp.media.view.Label({ + this.toolbar.set( 'dateFilterLabel', new wp.media.view.Label({ value: l10n.filterByDate, attributes: { 'for': 'media-attachment-date-filters' From 6902841da007e919bf55e036bb36f8516757465b Mon Sep 17 00:00:00 2001 From: Andrea Fercia Date: Tue, 8 Sep 2026 16:52:03 +0200 Subject: [PATCH 11/22] Create a few posts to test the Posts page. --- tests/e2e/utils/accessibility-pages.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/tests/e2e/utils/accessibility-pages.js b/tests/e2e/utils/accessibility-pages.js index f8a6f916c5cb9..43ae8cc4049b5 100644 --- a/tests/e2e/utils/accessibility-pages.js +++ b/tests/e2e/utils/accessibility-pages.js @@ -71,6 +71,20 @@ const pages = [ stateVariants: [ { name: 'default', + setup: async ( page, requestUtils ) => { + // Create a published post. + await requestUtils.createPost( { + title: 'Test Published Post', + status: 'publish', + } ); + // Create a pending review post so there's something to filter. + await requestUtils.createPost( { + title: 'Test Pending Review Post', + status: 'pending', + } ); + // Reload the page to show the draft. + await page.reload(); + }, }, { name: 'draft-filter', @@ -82,7 +96,7 @@ const pages = [ } ); // Reload the page to show the draft. await page.reload(); - // Ensure table is visible before filtering. + // Ensure table is visible before filtering. const tableVisible = await page.locator( 'table.wp-list-table' ).isVisible(); if ( tableVisible ) { await filterByStatus( page, 'draft' ); From 89a06b62e83cf74fd5cc4eda24ac23f36f3af6d1 Mon Sep 17 00:00:00 2001 From: Andrea Fercia Date: Wed, 9 Sep 2026 10:54:37 +0200 Subject: [PATCH 12/22] Rename accessibility-pages file. --- tests/e2e/specs/accessibility.spec.js | 4 ++-- .../{accessibility-pages.js => accessibility-pages-matrix.js} | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) rename tests/e2e/utils/{accessibility-pages.js => accessibility-pages-matrix.js} (98%) diff --git a/tests/e2e/specs/accessibility.spec.js b/tests/e2e/specs/accessibility.spec.js index 2ad784c3ed34b..325a31e0314f2 100644 --- a/tests/e2e/specs/accessibility.spec.js +++ b/tests/e2e/specs/accessibility.spec.js @@ -1,11 +1,11 @@ import { test, expect } from '@wordpress/e2e-test-utils-playwright'; const AxeScanner = require( '../utils/accessibility-axe-scanner' ); -const { pages } = require( '../utils/accessibility-pages' ); +const { pages } = require( '../utils/accessibility-pages-matrix' ); const ignoresAndknownFalsePositives = require( '../utils/accessibility-ignores-and-false-positives' ); /** * Global accessibility scan rules. - * Applied to all pages defined in utils/accessibility-pages. + * Applied to all pages defined in utils/accessibility-pages-matrix. * * See the Axe Options parameter documentation. * See: https://github.com/dequelabs/axe-core/blob/master/doc/API.md#options-parameter diff --git a/tests/e2e/utils/accessibility-pages.js b/tests/e2e/utils/accessibility-pages-matrix.js similarity index 98% rename from tests/e2e/utils/accessibility-pages.js rename to tests/e2e/utils/accessibility-pages-matrix.js index 43ae8cc4049b5..cfbcdf0707b0d 100644 --- a/tests/e2e/utils/accessibility-pages.js +++ b/tests/e2e/utils/accessibility-pages-matrix.js @@ -1,5 +1,5 @@ /** - * Accessibility test pages registry. + * Accessibility test pages matrix. * * Defines WordPress admin pages to scan for accessibility violations. * Each page spec can have multiple state variants for testing different UI states. @@ -49,7 +49,7 @@ * - To change rule config per-page, modify the `rules` property. * * IMPORT IN TESTS: - * const { pages } = require( './accessibility-pages' ); + * const { pages } = require( './accessibility-pages-matrix' ); * pages.forEach( (pageSpec) => { ... } ); */ From a50ef4878da6b98fc13c2414603c9480e4f8b263 Mon Sep 17 00:00:00 2001 From: Andrea Fercia Date: Wed, 9 Sep 2026 11:07:10 +0200 Subject: [PATCH 13/22] Exclude post titles with surrounding text in list tables for link-in-text-block rule. --- tests/e2e/utils/accessibility-ignores-and-false-positives.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/e2e/utils/accessibility-ignores-and-false-positives.js b/tests/e2e/utils/accessibility-ignores-and-false-positives.js index 5420388255d1d..e235dd9ffda9a 100644 --- a/tests/e2e/utils/accessibility-ignores-and-false-positives.js +++ b/tests/e2e/utils/accessibility-ignores-and-false-positives.js @@ -43,6 +43,8 @@ module.exports = { // Post title links in list tables may have surrounding text and are only distinguished by color. // We consider this acceptable as these links can be distinguished by the context. '.wp-list-table strong .row-title', + // Em dashes for the pages hierarchy and other text e.g. post status are considered 'surrounding text'. + '.wp-list-table #the-list #post-* th strong a', ], 'aria-allowed-role': [ // The "group" role for the admin bar list items is flagged as invalid by axe-core. From b8ecf4ebda5a603ee17da79d20cab4c7c431afd5 Mon Sep 17 00:00:00 2001 From: Andrea Fercia Date: Sun, 13 Sep 2026 10:05:51 +0200 Subject: [PATCH 14/22] Add more pages to test and two comments. --- tests/e2e/utils/accessibility-pages-matrix.js | 78 ++++++++++++++++--- 1 file changed, 69 insertions(+), 9 deletions(-) diff --git a/tests/e2e/utils/accessibility-pages-matrix.js b/tests/e2e/utils/accessibility-pages-matrix.js index cfbcdf0707b0d..006cd52f0a116 100644 --- a/tests/e2e/utils/accessibility-pages-matrix.js +++ b/tests/e2e/utils/accessibility-pages-matrix.js @@ -62,6 +62,11 @@ const pages = [ path: '/', name: 'Dashboard', }, + { + id: 'updates', + path: '/update-core.php', + name: 'Updates', + }, // Posts & Pages. { @@ -105,11 +110,6 @@ const pages = [ }, ], }, - { - id: 'pages-list', - path: '/edit.php?post_type=page', - name: 'Pages', - }, { id: 'post-categories-list', path: '/edit-tags.php?taxonomy=category', @@ -120,6 +120,11 @@ const pages = [ path: '/edit-tags.php?taxonomy=post_tag', name: 'Tags', }, + { + id: 'pages-list', + path: '/edit.php?post_type=page', + name: 'Pages', + }, // Media. { @@ -153,6 +158,34 @@ const pages = [ id: 'comments', path: '/edit-comments.php', name: 'Comments', + stateVariants: [ + { + name: 'default', + setup: async ( page, requestUtils ) => { + // Create a post to attach comments to. + const { id: postId } = await requestUtils.createPost( { + title: 'Post for comments', + status: 'publish', + } ); + + // Create an approved comment. + await requestUtils.createComment( { + content: 'Test Approved Comment', + status: 'approve', + post: postId, + } ); + // Create a comment awaiting moderation. + await requestUtils.createComment( { + content: 'Test Comment Awaiting Moderation', + status: 'hold', + post: postId, + } ); + + // Reload the page to show the comments. + await page.reload(); + }, + }, + ], }, // Appearance. @@ -196,6 +229,13 @@ const pages = [ name: 'Add User', }, + // Admin profile. + { + id: 'profile', + path: '/profile.php', + name: 'Profile', + }, + // Tools. { id: 'tools', @@ -277,12 +317,32 @@ const pages = [ name: 'Settings - Privacy', }, - // Admin profile. + // About. { - id: 'profile', - path: '/profile.php', - name: 'Profile', + id: 'about', + path: '/about.php', + name: 'About', + }, + { + id: 'credits', + path: '/credits.php', + name: 'Credits', }, + { + id: 'freedoms', + path: '/freedoms.php', + name: 'Freedoms', + }, + { + id: 'privacy', + path: '/privacy.php', + name: 'Privacy', + }, + { + id: 'contribute', + path: '/contribute.php', + name: 'Get involved', + } ]; module.exports = { From 61d0d2367b2d67bc3cb91c5e0f6d13d381f4fa36 Mon Sep 17 00:00:00 2001 From: Andrea Fercia Date: Sun, 13 Sep 2026 10:42:24 +0200 Subject: [PATCH 15/22] Speed up tests by using the wait interval only when necessary. --- tests/e2e/specs/accessibility.spec.js | 4 +++- tests/e2e/utils/accessibility-pages-matrix.js | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/e2e/specs/accessibility.spec.js b/tests/e2e/specs/accessibility.spec.js index 325a31e0314f2..a0663217517de 100644 --- a/tests/e2e/specs/accessibility.spec.js +++ b/tests/e2e/specs/accessibility.spec.js @@ -158,7 +158,9 @@ test.describe( 'Admin Pages Accessibility', () => { // for pages rendered via React components like the Settings > Connectors // page or the Fonts page. Without this wait, the scan may run before all // content is fully rendered. - await page.waitForTimeout( 500 ); + if ( pageSpec.waitInterval ) { + await page.waitForTimeout( 500 ); + } // Run state setup if provided. if ( variant.setup ) { diff --git a/tests/e2e/utils/accessibility-pages-matrix.js b/tests/e2e/utils/accessibility-pages-matrix.js index 006cd52f0a116..a6cc381d2041d 100644 --- a/tests/e2e/utils/accessibility-pages-matrix.js +++ b/tests/e2e/utils/accessibility-pages-matrix.js @@ -203,6 +203,7 @@ const pages = [ id: 'fonts-list', path: '/font-library.php?p=%2Ffont-list', name: 'Fonts', + waitInterval: true, }, // Plugins. @@ -279,6 +280,7 @@ const pages = [ id: 'settings-connectors', path: '/options-connectors.php', name: 'Settings - Connectors', + waitInterval: true, }, { From 9d039b3e615493a9b8a886130b64e3c1e8627801 Mon Sep 17 00:00:00 2001 From: Andrea Fercia Date: Sun, 13 Sep 2026 13:02:45 +0200 Subject: [PATCH 16/22] Explain waitInterval. --- tests/e2e/utils/accessibility-pages-matrix.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/e2e/utils/accessibility-pages-matrix.js b/tests/e2e/utils/accessibility-pages-matrix.js index a6cc381d2041d..14fc6198d282a 100644 --- a/tests/e2e/utils/accessibility-pages-matrix.js +++ b/tests/e2e/utils/accessibility-pages-matrix.js @@ -9,6 +9,11 @@ * - `path`: WordPress admin path relative to /wp-admin/ (e.g., '/upload.php?mode=grid') * - `name`: Human-readable name (shown in test output) * - `rules`: (optional) Per-page axe rules override. Merged with global rules. + * - `waitInterval`: (optional) Boolean indicating if the test should wait for a + * short interval before scanning. This is particularly important + * for pages rendered via React components like the Settings > Connectors + * page or the Fonts page. Without this wait, the scan may run before all + * content is fully rendered. * - `stateVariants`: (optional) Array of UI states to test. Each variant has: * - `name`: State identifier (shown in test name) * - `setup`: (optional) Async function to set up the state. Receives (page, requestUtils) objects. From 932b8006bb3ae2c27a95c5799b724f428a2e737b Mon Sep 17 00:00:00 2001 From: Andrea Fercia Date: Sun, 13 Sep 2026 13:54:54 +0200 Subject: [PATCH 17/22] Use media requestUtils. --- tests/e2e/specs/accessibility.spec.js | 29 +++++++++------------------ 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/tests/e2e/specs/accessibility.spec.js b/tests/e2e/specs/accessibility.spec.js index a0663217517de..549f665472144 100644 --- a/tests/e2e/specs/accessibility.spec.js +++ b/tests/e2e/specs/accessibility.spec.js @@ -1,3 +1,4 @@ +import path from 'path'; import { test, expect } from '@wordpress/e2e-test-utils-playwright'; const AxeScanner = require( '../utils/accessibility-axe-scanner' ); const { pages } = require( '../utils/accessibility-pages-matrix' ); @@ -110,33 +111,21 @@ test.describe( 'Admin Pages Accessibility', () => { test.beforeAll( async ( { requestUtils } ) => { // Upload sample image to media library for testing. - const fs = require( 'fs' ); - const path = require( 'path' ); - - const imagePath = path.join( __dirname, '../assets/sample.png' ); - const imageBuffer = fs.readFileSync( imagePath ); - - const response = await requestUtils.rest( { - method: 'POST', - path: 'wp/v2/media', - data: imageBuffer, - headers: { - 'Content-Disposition': 'attachment; filename="sample.png"', - 'Content-Type': 'image/png', - }, - } ); + const imagePath = path.resolve( __dirname, '../assets/sample.png' ) + const uploadedMedia = await requestUtils.uploadMedia( + imagePath + ); // Store the ID for cleanup later. - mediaAttachmentId = response.id; + mediaAttachmentId = uploadedMedia.id; } ); test.afterAll( async ( { requestUtils } ) => { // Delete the uploaded image to restore initial state if ( mediaAttachmentId ) { - await requestUtils.rest( { - method: 'DELETE', - path: `wp/v2/media/${ mediaAttachmentId }?force=true`, - } ); + await requestUtils.deleteMedia( + mediaAttachmentId + ); } } ); From 425d5d549611e4d5e59be55a07ff9e927f0142ea Mon Sep 17 00:00:00 2001 From: Andrea Fercia Date: Sun, 13 Sep 2026 15:01:50 +0200 Subject: [PATCH 18/22] Simplify beforeAll and afterAll. --- tests/e2e/specs/accessibility.spec.js | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/tests/e2e/specs/accessibility.spec.js b/tests/e2e/specs/accessibility.spec.js index 549f665472144..1fec7b5b73a1e 100644 --- a/tests/e2e/specs/accessibility.spec.js +++ b/tests/e2e/specs/accessibility.spec.js @@ -112,21 +112,16 @@ test.describe( 'Admin Pages Accessibility', () => { test.beforeAll( async ( { requestUtils } ) => { // Upload sample image to media library for testing. const imagePath = path.resolve( __dirname, '../assets/sample.png' ) - const uploadedMedia = await requestUtils.uploadMedia( + await requestUtils.uploadMedia( imagePath ); - - // Store the ID for cleanup later. - mediaAttachmentId = uploadedMedia.id; } ); test.afterAll( async ( { requestUtils } ) => { - // Delete the uploaded image to restore initial state - if ( mediaAttachmentId ) { - await requestUtils.deleteMedia( - mediaAttachmentId - ); - } + // Delete all media. + await requestUtils.deleteAllMedia(); + // Delete all posts of type 'post' and all associated comments. + await requestUtils.deleteAllPosts(); } ); pages.forEach( ( pageSpec ) => { From 91bddac8207765e1ff98e97331a9e9e99cdf4adc Mon Sep 17 00:00:00 2001 From: Andrea Fercia Date: Mon, 14 Sep 2026 11:27:37 +0200 Subject: [PATCH 19/22] Add ignore for the media attachments browser. --- tests/e2e/utils/accessibility-ignores-and-false-positives.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/e2e/utils/accessibility-ignores-and-false-positives.js b/tests/e2e/utils/accessibility-ignores-and-false-positives.js index e235dd9ffda9a..94f24c34e525b 100644 --- a/tests/e2e/utils/accessibility-ignores-and-false-positives.js +++ b/tests/e2e/utils/accessibility-ignores-and-false-positives.js @@ -51,6 +51,8 @@ module.exports = { // This is a known false positive in axe-core and can be ignored. Note // that the 'aria-allowed-role' rule is part of the 'best-practice' rules group. '#wp-toolbar #wp-admin-bar-*', + // Same known false positive in axe-core for the media attachments list browser. + '.attachments-browser .attachments-wrapper #__attachments-view-* .attachment', ], 'region': [ // Visually hidden text that clarifies what the ARIA live regions are about. From 2d6b88d14be7e6d783a057b2364b9ccf52e73e2b Mon Sep 17 00:00:00 2001 From: Andrea Fercia Date: Tue, 15 Sep 2026 23:22:45 +0200 Subject: [PATCH 20/22] Add the fonts Upload and Install Fonts tabs to the pages matrix. --- tests/e2e/utils/accessibility-pages-matrix.js | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/tests/e2e/utils/accessibility-pages-matrix.js b/tests/e2e/utils/accessibility-pages-matrix.js index 14fc6198d282a..13f8ee862fc76 100644 --- a/tests/e2e/utils/accessibility-pages-matrix.js +++ b/tests/e2e/utils/accessibility-pages-matrix.js @@ -209,6 +209,27 @@ const pages = [ path: '/font-library.php?p=%2Ffont-list', name: 'Fonts', waitInterval: true, + stateVariants: [ + { + name: 'default', + }, + { + name: 'fonts-upload-tab', + setup: async ( page ) => { + const uploadTab = page.getByRole( 'tab', { name: 'Upload' } ); + await uploadTab.click(); + await page.getByRole( 'tabpanel', { name: 'Upload' } ).isVisible(); + }, + }, + { + name: 'fonts-install-fonts-tab', + setup: async ( page ) => { + const installFontsTab = page.getByRole( 'tab', { name: 'Install Fonts' } ); + await installFontsTab.click(); + await page.getByRole( 'tabpanel', { name: 'Install Fonts' } ).isVisible(); + }, + }, + ], }, // Plugins. From 1ecb4dbea8fd0b87ac969c5665ca1f7465003a34 Mon Sep 17 00:00:00 2001 From: Andrea Fercia Date: Wed, 23 Sep 2026 13:49:33 +0200 Subject: [PATCH 21/22] Try axe-core checks on the Revisions page. --- tests/e2e/specs/accessibility.spec.js | 4 +- tests/e2e/utils/accessibility-pages-matrix.js | 384 +++++------------- 2 files changed, 99 insertions(+), 289 deletions(-) diff --git a/tests/e2e/specs/accessibility.spec.js b/tests/e2e/specs/accessibility.spec.js index 1fec7b5b73a1e..75d87d647045a 100644 --- a/tests/e2e/specs/accessibility.spec.js +++ b/tests/e2e/specs/accessibility.spec.js @@ -133,7 +133,7 @@ test.describe( 'Admin Pages Accessibility', () => { const variantName = variant.name === 'default' ? '' : ` [${ variant.name }]`; const testName = `${ pageSpec.name }${ variantName } should not have violations`; - test( testName, async ( { admin, page, requestUtils } ) => { + test( testName, async ( { admin, page, editor, requestUtils } ) => { // Navigate to page. await admin.visitAdminPage( pageSpec.path ); @@ -148,7 +148,7 @@ test.describe( 'Admin Pages Accessibility', () => { // Run state setup if provided. if ( variant.setup ) { - await variant.setup( page, requestUtils ); + await variant.setup( page, editor, requestUtils ); } // Scan and assert. diff --git a/tests/e2e/utils/accessibility-pages-matrix.js b/tests/e2e/utils/accessibility-pages-matrix.js index 13f8ee862fc76..105ac587af7e8 100644 --- a/tests/e2e/utils/accessibility-pages-matrix.js +++ b/tests/e2e/utils/accessibility-pages-matrix.js @@ -58,319 +58,129 @@ * pages.forEach( (pageSpec) => { ... } ); */ -const { filterByStatus } = require( './admin-interactions' ); - const pages = [ - // Dashboard. - { - id: 'dashboard', - path: '/', - name: 'Dashboard', - }, - { - id: 'updates', - path: '/update-core.php', - name: 'Updates', - }, - // Posts & Pages. { - id: 'posts-list', - path: '/edit.php?post_type=post', - name: 'Posts', + id: 'posts-revisions', + path: '/post-new.php', + name: 'Posts Revisions', stateVariants: [ { name: 'default', - setup: async ( page, requestUtils ) => { - // Create a published post. - await requestUtils.createPost( { - title: 'Test Published Post', - status: 'publish', - } ); - // Create a pending review post so there's something to filter. - await requestUtils.createPost( { - title: 'Test Pending Review Post', - status: 'pending', - } ); - // Reload the page to show the draft. - await page.reload(); - }, - }, - { - name: 'draft-filter', - setup: async ( page, requestUtils ) => { - // Create a draft post so there's something to filter. - await requestUtils.createPost( { - title: 'Test Draft Post', - status: 'draft', - } ); - // Reload the page to show the draft. - await page.reload(); - // Ensure table is visible before filtering. - const tableVisible = await page.locator( 'table.wp-list-table' ).isVisible(); - if ( tableVisible ) { - await filterByStatus( page, 'draft' ); - } - }, - }, - ], - }, - { - id: 'post-categories-list', - path: '/edit-tags.php?taxonomy=category', - name: 'Categories', - }, - { - id: 'post-tags-list', - path: '/edit-tags.php?taxonomy=post_tag', - name: 'Tags', - }, - { - id: 'pages-list', - path: '/edit.php?post_type=page', - name: 'Pages', - }, + setup: async ( page, editor ) => { - // Media. - { - id: 'media-library-grid', - path: '/upload.php?mode=grid', - name: 'Media Library (Grid View)', - stateVariants: [ - { - name: 'default', - }, - { - name: 'image-modal-open', - setup: async ( page ) => { - // Click the image to open the attachment modal. - const imageLink = page.locator( '.attachment' ).first(); - await imageLink.click(); - // Wait for modal to appear. - await page.waitForSelector( '.media-modal' ); - }, - }, - ], - }, - { - id: 'media-library-list', - path: '/upload.php?mode=list', - name: 'Media Library (List View)', - }, - - // Comments. - { - id: 'comments', - path: '/edit-comments.php', - name: 'Comments', - stateVariants: [ - { - name: 'default', - setup: async ( page, requestUtils ) => { - // Create a post to attach comments to. - const { id: postId } = await requestUtils.createPost( { - title: 'Post for comments', - status: 'publish', + await editor.setPreferences( 'core/edit-post', { + welcomeGuide: false, + fullscreenMode: true, } ); - // Create an approved comment. - await requestUtils.createComment( { - content: 'Test Approved Comment', - status: 'approve', - post: postId, - } ); - // Create a comment awaiting moderation. - await requestUtils.createComment( { - content: 'Test Comment Awaiting Moderation', - status: 'hold', - post: postId, + await editor.insertBlock( { + name: 'core/paragraph', + attributes: { + content: + 'First paragraph', + }, } ); - // Reload the page to show the comments. - await page.reload(); - }, - }, - ], - }, + // Save draft to create first revision. + await editor.saveDraft(); - // Appearance. - { - id: 'themes', - path: '/themes.php', - name: 'Themes', - }, - { - id: 'add-themes', - path: '/theme-install.php?browse=popular', - name: 'Add Themes', - }, - { - id: 'fonts-list', - path: '/font-library.php?p=%2Ffont-list', - name: 'Fonts', - waitInterval: true, - stateVariants: [ - { - name: 'default', - }, - { - name: 'fonts-upload-tab', - setup: async ( page ) => { - const uploadTab = page.getByRole( 'tab', { name: 'Upload' } ); - await uploadTab.click(); - await page.getByRole( 'tabpanel', { name: 'Upload' } ).isVisible(); - }, - }, - { - name: 'fonts-install-fonts-tab', - setup: async ( page ) => { - const installFontsTab = page.getByRole( 'tab', { name: 'Install Fonts' } ); - await installFontsTab.click(); - await page.getByRole( 'tabpanel', { name: 'Install Fonts' } ).isVisible(); - }, - }, - ], - }, + await editor.insertBlock( { + name: 'core/spacer', + attributes: { height: '100px' }, + } ); - // Plugins. - { - id: 'installed-plugins', - path: '/plugins.php', - name: 'Plugins', - }, - { - id: 'add-plugins', - path: '/plugin-install.php', - name: 'Add Plugins', - }, + // Save draft again to create second revision. + await editor.saveDraft(); - // Users. - { - id: 'users-list', - path: '/users.php', - name: 'Users', - }, - { - id: 'add-user', - path: '/user-new.php', - name: 'Add User', - }, + await editor.insertBlock( { + name: 'core/paragraph', + attributes: { + content: 'Second paragraph', + }, + } ); - // Admin profile. - { - id: 'profile', - path: '/profile.php', - name: 'Profile', - }, + // Save draft again to create third revision. + await editor.saveDraft(); - // Tools. - { - id: 'tools', - path: '/tools.php', - name: 'Tools', - }, - { - id: 'tools-import', - path: '/import.php', - name: 'Tools - Import', - }, - { - id: 'tools-export', - path: '/export.php', - name: 'Tools - Export', - }, - { - id: 'site-health', - path: '/site-health.php', - name: 'Tools - Site Health', - }, - { - id: 'export-personal-data', - path: '/export-personal-data.php', - name: 'Tools - Export Personal Data', - }, - { - id: 'erase-personal-data', - path: '/erase-personal-data.php', - name: 'Tools - Erase Personal Data', - }, + // await page.goto( `/?p=${ postId }#target` ); - // Settings. - { - id: 'settings-general', - path: '/options-general.php', - name: 'Settings - General', - }, + // Open revisions. + await editor.openDocumentSettingsSidebar(); + const settingsSidebar = page.getByRole( 'region', { + name: 'Editor settings', + } ); + await settingsSidebar.getByRole( 'tab', { name: 'Post' } ).click(); + await settingsSidebar + .getByRole( 'button', { + name: 'Open revisions screen: 3 revisions', + } ) + .click(); + } + }, + { + name: 'previous-revision', + setup: async ( page, editor ) => { + await editor.setPreferences( 'core/edit-post', { + welcomeGuide: false, + fullscreenMode: true, + } ); - { - id: 'settings-connectors', - path: '/options-connectors.php', - name: 'Settings - Connectors', - waitInterval: true, - }, + await editor.insertBlock( { + name: 'core/paragraph', + attributes: { + content: + 'First paragraph', + }, + } ); - { - id: 'settings-writing', - path: '/options-writing.php', - name: 'Settings - Writing', - }, + // Save draft to create first revision. + await editor.saveDraft(); - { - id: 'settings-reading', - path: '/options-reading.php', - name: 'Settings - Reading', - }, + await editor.insertBlock( { + name: 'core/spacer', + attributes: { height: '100px' }, + } ); - { - id: 'settings-discussion', - path: '/options-discussion.php', - name: 'Settings - Discussion', - }, + // Save draft again to create second revision. + await editor.saveDraft(); - { - id: 'settings-media', - path: '/options-media.php', - name: 'Settings - Media', - }, + await editor.insertBlock( { + name: 'core/paragraph', + attributes: { + content: 'Second paragraph', + }, + } ); - { - id: 'settings-permalinks', - path: '/options-permalink.php', - name: 'Settings - Permalinks', - }, + // Save draft again to create third revision. + await editor.saveDraft(); - { - id: 'settings-privacy', - path: '/options-privacy.php', - name: 'Settings - Privacy', - }, + // await page.goto( `/?p=${ postId }#target` ); - // About. - { - id: 'about', - path: '/about.php', - name: 'About', - }, - { - id: 'credits', - path: '/credits.php', - name: 'Credits', - }, - { - id: 'freedoms', - path: '/freedoms.php', - name: 'Freedoms', - }, - { - id: 'privacy', - path: '/privacy.php', - name: 'Privacy', + // Open revisions. + await editor.openDocumentSettingsSidebar(); + const settingsSidebar = page.getByRole( 'region', { + name: 'Editor settings', + } ); + await settingsSidebar.getByRole( 'tab', { name: 'Post' } ).click(); + await settingsSidebar + .getByRole( 'button', { + name: 'Open revisions screen: 3 revisions', + } ) + .click(); + + const revisonSlider = page.getByRole( 'slider', { + name: 'Revision', + } ); + // Focus the revison slider. + await revisonSlider.focus(); + // Move to previous revision. + await page.keyboard.press( 'ArrowLeft' ); + await page.waitForTimeout( 500 ); + } + }, + ], }, - { - id: 'contribute', - path: '/contribute.php', - name: 'Get involved', - } ]; module.exports = { From 512a760ad7551ace00bf1856a3f56b0414d73b5b Mon Sep 17 00:00:00 2001 From: Andrea Fercia Date: Wed, 23 Sep 2026 14:12:09 +0200 Subject: [PATCH 22/22] Add wait interval. --- tests/e2e/utils/accessibility-pages-matrix.js | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/e2e/utils/accessibility-pages-matrix.js b/tests/e2e/utils/accessibility-pages-matrix.js index 105ac587af7e8..8f13d5d3cebf1 100644 --- a/tests/e2e/utils/accessibility-pages-matrix.js +++ b/tests/e2e/utils/accessibility-pages-matrix.js @@ -64,6 +64,7 @@ const pages = [ id: 'posts-revisions', path: '/post-new.php', name: 'Posts Revisions', + waitInterval: true, stateVariants: [ { name: 'default',