diff --git a/.eslintrc.js b/.eslintrc.js index bac9e84341434e..5360d8117321fd 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -89,6 +89,11 @@ module.exports = { message: 'Please use `combineReducers` from `@wordpress/data` instead.', }, + { + name: 'puppeteer-testing-library', + message: + '`puppeteer-testing-library` is still experimental.', + }, ], }, ], diff --git a/package-lock.json b/package-lock.json index 93558fe17b5188..49c61026f6cdd1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11838,8 +11838,7 @@ "@types/node": { "version": "14.14.22", "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.22.tgz", - "integrity": "sha512-g+f/qj/cNcqKkc3tFqlXOYjrmZA+jNBiDzbP3kH+B+otKFqAdPgVTGP1IeKRdMml/aE69as5S4FqtxAbl+LaMw==", - "dev": true + "integrity": "sha512-g+f/qj/cNcqKkc3tFqlXOYjrmZA+jNBiDzbP3kH+B+otKFqAdPgVTGP1IeKRdMml/aE69as5S4FqtxAbl+LaMw==" }, "@types/node-fetch": { "version": "2.5.10", @@ -13544,6 +13543,7 @@ "chalk": "^4.0.0", "expect-puppeteer": "^4.4.0", "lodash": "^4.17.19", + "puppeteer-testing-library": "^0.3.1", "uuid": "^8.3.0" } }, @@ -14281,6 +14281,16 @@ "webpack-cli": "^3.3.11", "webpack-livereload-plugin": "^2.3.0", "webpack-sources": "^2.2.0" + }, + "dependencies": { + "puppeteer-testing-library": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/puppeteer-testing-library/-/puppeteer-testing-library-0.3.0.tgz", + "integrity": "sha512-iLD2zaz+d+GYUhZ8DgBL3wyg1KsWUOXUMRQEYgRnjmR6uPJJn6XfZRohQUIqExu2D0rPFNA3PDyqgXHDqeqc6w==", + "requires": { + "jest-diff": "^26.6.2" + } + } } }, "@wordpress/server-side-render": { @@ -25225,7 +25235,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.0.0.tgz", "integrity": "sha512-N9oWFcegS0sFr9oh1oz2d7Npos6vNoWW9HvtCg5N1KRFpUhaAhvTv5Y58g880fZaEYSNm3qDz8SU1UrGvp+n7A==", - "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -25235,7 +25244,6 @@ "version": "4.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", - "dev": true, "requires": { "@types/color-name": "^1.1.1", "color-convert": "^2.0.1" @@ -25245,7 +25253,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "requires": { "color-name": "~1.1.4" } @@ -25253,20 +25260,17 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, "supports-color": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", - "dev": true, "requires": { "has-flag": "^4.0.0" } @@ -28355,8 +28359,7 @@ "diff-sequences": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.6.2.tgz", - "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", - "dev": true + "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==" }, "diffie-hellman": { "version": "5.0.3", @@ -36580,7 +36583,6 @@ "version": "26.6.2", "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-26.6.2.tgz", "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==", - "dev": true, "requires": { "chalk": "^4.0.0", "diff-sequences": "^26.6.2", @@ -36592,7 +36594,6 @@ "version": "26.6.2", "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "dev": true, "requires": { "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", @@ -36605,7 +36606,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz", "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==", - "dev": true, "requires": { "@types/istanbul-lib-report": "*" } @@ -36613,14 +36613,12 @@ "ansi-regex": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "requires": { "color-convert": "^2.0.1" } @@ -36629,7 +36627,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "requires": { "color-name": "~1.1.4" } @@ -36637,20 +36634,17 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "jest-get-type": { "version": "26.3.0", "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.3.0.tgz", - "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", - "dev": true + "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==" }, "pretty-format": { "version": "26.6.2", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", - "dev": true, "requires": { "@jest/types": "^26.6.2", "ansi-regex": "^5.0.0", @@ -36661,8 +36655,7 @@ "react-is": { "version": "17.0.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.1.tgz", - "integrity": "sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA==", - "dev": true + "integrity": "sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA==" } } }, @@ -49340,6 +49333,15 @@ } } }, + "puppeteer-testing-library": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/puppeteer-testing-library/-/puppeteer-testing-library-0.3.1.tgz", + "integrity": "sha512-k2hRLIPEL+BKBHFncEfs1SSICKa9gfEzdxGa5wO3jHofMszJJnIRg9rNEFVx3+K7OOU8gZEqd+zFGICMZNQ9QA==", + "dev": true, + "requires": { + "jest-diff": "^26.6.2" + } + }, "q": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", diff --git a/packages/e2e-tests/jest.config.js b/packages/e2e-tests/jest.config.js index a23def8c2e89d9..defc700dfbbefc 100644 --- a/packages/e2e-tests/jest.config.js +++ b/packages/e2e-tests/jest.config.js @@ -7,6 +7,7 @@ module.exports = { '@wordpress/jest-console', '@wordpress/jest-puppeteer-axe', 'expect-puppeteer', + 'puppeteer-testing-library/extend-expect', ], testPathIgnorePatterns: [ '/node_modules/', diff --git a/packages/e2e-tests/package.json b/packages/e2e-tests/package.json index 7d4a29d587f870..c993424b4274e5 100644 --- a/packages/e2e-tests/package.json +++ b/packages/e2e-tests/package.json @@ -31,6 +31,7 @@ "chalk": "^4.0.0", "expect-puppeteer": "^4.4.0", "lodash": "^4.17.19", + "puppeteer-testing-library": "^0.3.1", "uuid": "^8.3.0" }, "peerDependencies": { diff --git a/packages/e2e-tests/specs/widgets/adding-widgets.test.js b/packages/e2e-tests/specs/widgets/adding-widgets.test.js index 3e7c75c171e0e9..d01a52eddfe9c6 100644 --- a/packages/e2e-tests/specs/widgets/adding-widgets.test.js +++ b/packages/e2e-tests/specs/widgets/adding-widgets.test.js @@ -6,7 +6,6 @@ import { activateTheme, clickBlockToolbarButton, deactivatePlugin, - pressKeyWithModifier, showBlockToolbar, visitAdminPage, } from '@wordpress/e2e-test-utils'; @@ -14,6 +13,8 @@ import { /** * External dependencies */ +// eslint-disable-next-line no-restricted-imports +import { find, findAll } from 'puppeteer-testing-library'; import { groupBy, mapValues } from 'lodash'; /** @typedef {import('puppeteer').ElementHandle} ElementHandle */ @@ -22,9 +23,10 @@ describe( 'Widgets screen', () => { beforeEach( async () => { await visitAdminPage( 'themes.php', 'page=gutenberg-widgets' ); // Wait for the widget areas to load. - await page.waitForSelector( - '[aria-label="Block: Widget Area"][role="group"]' - ); + await findAll( { + role: 'group', + name: 'Block: Widget Area', + } ); } ); afterEach( async () => { @@ -48,20 +50,38 @@ describe( 'Widgets screen', () => { } ); async function getBlockInGlobalInserter( blockName ) { - await page.click( - 'button[aria-pressed="false"][aria-label="Add block"]' - ); + const addBlockButton = await find( { + role: 'button', + name: 'Add block', + pressed: false, + } ); + await addBlockButton.click(); - const blockLibrary = await page.waitForSelector( - '[aria-label="Block Library"][role="region"]' - ); + const blockLibrary = await find( { + role: 'region', + name: 'Block Library', + } ); // Check that there are categorizations in the inserter (#26329). - const categoryHeader = await blockLibrary.$$( 'h2' ); - expect( categoryHeader.length > 0 ).toBe( true ); + const categoryHeaders = await findAll( + { + role: 'heading', + level: 2, + }, + { + root: blockLibrary, + } + ); + expect( categoryHeaders.length > 0 ).toBe( true ); - const [ addBlock ] = await blockLibrary.$x( - `//*[@role="option"][*[text()="${ blockName }"]]` + const addBlock = await find( + { + role: 'option', + name: blockName, + }, + { + root: blockLibrary, + } ); return addBlock; @@ -70,14 +90,17 @@ describe( 'Widgets screen', () => { async function expectInsertionPointIndicatorToBeBelowLastBlock( widgetArea ) { - const childBlocks = await widgetArea.$$( '[data-block]' ); + const childBlocks = await findAll( + { selector: '[data-block]' }, + { root: widgetArea } + ); const lastBlock = childBlocks[ childBlocks.length - 1 ]; const lastBlockBoundingBox = await lastBlock.boundingBox(); // TODO: Probably need a more accessible way to select this, maybe a test ID or data attribute. - const insertionPointIndicator = await page.$( - '.block-editor-block-list__insertion-point-indicator' - ); + const insertionPointIndicator = await find( { + selector: '.block-editor-block-list__insertion-point-indicator', + } ); const insertionPointIndicatorBoundingBox = await insertionPointIndicator.boundingBox(); expect( @@ -86,18 +109,17 @@ describe( 'Widgets screen', () => { } async function getInlineInserterButton() { - return await page.waitForSelector( - 'button[aria-label="Add block"][aria-haspopup="true"]', - { - visible: true, - } - ); + return await find( { + role: 'combobox', + name: 'Add block', + } ); } it( 'Should insert content using the global inserter', async () => { - const widgetAreas = await page.$$( - '[aria-label="Block: Widget Area"][role="group"]' - ); + const widgetAreas = await findAll( { + role: 'group', + name: 'Block: Widget Area', + } ); const [ firstWidgetArea ] = widgetAreas; let addParagraphBlock = await getBlockInGlobalInserter( 'Paragraph' ); @@ -110,9 +132,16 @@ describe( 'Widgets screen', () => { await addParagraphBlock.click(); - let addedParagraphBlockInFirstWidgetArea = await firstWidgetArea.$( - '[data-block][data-type="core/paragraph"][aria-label^="Empty block"]' + let addedParagraphBlockInFirstWidgetArea = await find( + { + name: /^Empty block/, + selector: '[data-block][data-type="core/paragraph"]', + }, + { + root: firstWidgetArea, + } ); + await addedParagraphBlockInFirstWidgetArea.focus(); await page.keyboard.type( 'First Paragraph' ); @@ -189,9 +218,10 @@ describe( 'Widgets screen', () => { } ); it( 'Should insert content using the inline inserter', async () => { - const firstWidgetArea = await page.$( - '[aria-label="Block: Widget Area"][role="group"]' - ); + const [ firstWidgetArea ] = await findAll( { + role: 'group', + name: 'Block: Widget Area', + } ); // Scroll to the end of the first widget area. await firstWidgetArea.evaluate( ( node ) => @@ -211,22 +241,30 @@ describe( 'Widgets screen', () => { let inlineInserterButton = await getInlineInserterButton(); await inlineInserterButton.click(); - const inlineQuickInserter = await page.waitForSelector( - '[aria-label="Blocks"][role="listbox"]' - ); + let inlineQuickInserter = await find( { + role: 'listbox', + name: 'Blocks', + } ); - const [ paragraphBlock ] = await inlineQuickInserter.$x( - '//*[@role="option"][*[text()="Paragraph"]]' + const paragraphBlock = await find( + { + role: 'option', + name: 'Paragraph', + }, + { + root: inlineQuickInserter, + } ); await paragraphBlock.click(); - const firstParagraphBlock = await page.waitForFunction( - ( widgetArea ) => - widgetArea.querySelector( - '[data-block][data-type="core/paragraph"][aria-label^="Empty block"]' - ), - {}, - firstWidgetArea + const firstParagraphBlock = await find( + { + name: /^Empty block/, + selector: '[data-block][data-type="core/paragraph"]', + }, + { + root: firstWidgetArea, + } ); await firstParagraphBlock.focus(); @@ -238,7 +276,9 @@ describe( 'Widgets screen', () => { const secondParagraphBlock = await page.evaluateHandle( () => document.activeElement ); - expect( secondParagraphBlock ).not.toBe( firstParagraphBlock ); + await expect( secondParagraphBlock ).not.toBeElement( + firstParagraphBlock + ); const secondParagraphBlockBoundingBox = await secondParagraphBlock.boundingBox(); @@ -261,23 +301,26 @@ describe( 'Widgets screen', () => { inlineInserterButton = await getInlineInserterButton(); await inlineInserterButton.click(); - // TODO: The query should be rewritten with role and label. - const inserterSearchBox = await page.waitForSelector( - 'input[type="search"][placeholder="Search"]' - ); - expect( - await inserterSearchBox.evaluate( - ( node ) => node === document.activeElement - ) - ).toBe( true ); + const inserterSearchBox = await find( { + role: 'searchbox', + name: 'Search for blocks and patterns', + } ); + await expect( inserterSearchBox ).toHaveFocus(); await page.keyboard.type( 'Heading' ); - const inserterListBox = await page.$( - '[role="listbox"][aria-label="Blocks"]' - ); - const [ headingBlockOption ] = await inserterListBox.$x( - '//*[@role="option"][*[text()="Heading"]]' + inlineQuickInserter = await find( { + role: 'listbox', + name: 'Blocks', + } ); + const headingBlockOption = await find( + { + role: 'option', + name: 'Heading', + }, + { + root: inlineQuickInserter, + } ); await headingBlockOption.click(); @@ -286,20 +329,15 @@ describe( 'Widgets screen', () => { ( node ) => node.previousSibling ); - expect( - await addedHeadingBlock.evaluate( - ( node ) => node === document.activeElement - ) - ).toBe( true ); + await expect( addedHeadingBlock ).toHaveFocus(); await page.keyboard.type( 'My Heading' ); - const addedHeadingBlockSnapshot = await page.accessibility.snapshot( { - root: addedHeadingBlock, + await expect( addedHeadingBlock ).toMatchQuery( { + name: 'Block: Heading', + level: 2, + value: 'My Heading', } ); - expect( addedHeadingBlockSnapshot.name ).toBe( 'Block: Heading' ); - expect( addedHeadingBlockSnapshot.level ).toBe( 2 ); - expect( addedHeadingBlockSnapshot.value ).toBe( 'My Heading' ); await saveWidgets(); const serializedWidgetAreas = await getSerializedWidgetAreas(); @@ -357,8 +395,7 @@ describe( 'Widgets screen', () => { ); await firstParagraphBlock.focus(); - // Trigger the toolbar to appear. - await pressKeyWithModifier( 'shift', 'Tab' ); + await showBlockToolbar(); const blockToolbar = await page.waitForSelector( '[role="toolbar"][aria-label="Block tools"]' @@ -430,14 +467,22 @@ describe( 'Widgets screen', () => { it( 'Should display legacy widgets', async () => { await visitAdminPage( 'widgets.php' ); - const [ searchWidget ] = await page.$x( - '//*[@id="widget-list"]//h3[text()="Search"]' + const searchWidget = await find( + { + role: 'heading', + name: 'Search', + level: 3, + }, + { + root: await page.$( '#widget-list' ), + } ); await searchWidget.click(); - const [ addWidgetButton ] = await page.$x( - '//button[text()="Add Widget"]' - ); + const addWidgetButton = await find( { + role: 'button', + name: 'Add Widget', + } ); await addWidgetButton.click(); // Wait for the changes to be saved. @@ -459,64 +504,91 @@ describe( 'Widgets screen', () => { await visitAdminPage( 'themes.php', 'page=gutenberg-widgets' ); // Wait for the widget areas to load. - await page.waitForSelector( - '[aria-label="Block: Widget Area"][role="group"]' - ); + await findAll( { + role: 'group', + name: 'Block: Widget Area', + } ); // Wait for the widget's form to load. await page.waitForSelector( '[data-block][data-type="core/legacy-widget"] input' ); - const legacyWidget = await page.$( - '[data-block][data-type="core/legacy-widget"]' - ); + const legacyWidget = await find( { + role: 'group', + name: 'Block: Legacy Widget', + } ); - const legacyWidgetName = await legacyWidget.$( 'h3' ); - expect( - await legacyWidgetName.evaluate( ( node ) => node.textContent ) - ).toBe( 'Search' ); + const legacyWidgetName = await find( + { + role: 'heading', + level: 3, + }, + { + root: legacyWidget, + } + ); + expect( legacyWidgetName ).toMatchQuery( { text: 'Search' } ); await legacyWidget.focus(); - // Trigger the toolbar to appear. - await pressKeyWithModifier( 'shift', 'Tab' ); - - let [ previewButton ] = await page.$x( - '//button[*[contains(text(), "Preview")]]' - ); + await showBlockToolbar(); + let previewButton = await find( { + role: 'button', + name: 'Preview', + } ); await previewButton.click(); const iframe = await legacyWidget.$( 'iframe' ); const frame = await iframe.contentFrame(); // Expect to have search input. - await frame.waitForSelector( 'input[type="search"]' ); - - const [ editButton ] = await page.$x( - '//button[*[contains(text(), "Edit")]]' + await find( + { + role: 'searchbox', + }, + { + page: frame, + } ); + + const editButton = await find( { + role: 'button', + name: 'Edit', + } ); await editButton.click(); - const [ titleLabel ] = await legacyWidget.$x( - '//label[contains(text(), "Title")]' - ); - const titleInputId = await titleLabel.evaluate( ( node ) => - node.getAttribute( 'for' ) + const titleInput = await find( + { + role: 'textbox', + name: /^Title/, + }, + { + root: legacyWidget, + } ); - const titleInput = await page.$( `#${ titleInputId }` ); await titleInput.type( 'Search Title' ); - // Trigger the toolbar to appear. - await pressKeyWithModifier( 'shift', 'Tab' ); - - [ previewButton ] = await page.$x( - '//button[*[contains(text(), "Preview")]]' - ); - await previewButton.click(); + await showBlockToolbar(); + previewButton = await find( { + role: 'button', + name: 'Preview', + } ); + await Promise.all( [ + previewButton.click(), + frame.waitForNavigation(), + ] ); // Expect to have search title. - await frame.waitForXPath( '//h2[text()="Search Title"]' ); + await find( + { + role: 'heading', + name: 'Search Title', + }, + { + page: frame, + } + ); await saveWidgets(); const serializedWidgetAreas = await getSerializedWidgetAreas(); @@ -535,10 +607,11 @@ describe( 'Widgets screen', () => { } ); it( 'allows widgets to be moved between widget areas using the dropdown in the block toolbar', async () => { - const widgetAreas = await page.$$( - '[aria-label="Block: Widget Area"][role="group"]' - ); - const [ firstWidgetArea ] = widgetAreas; + const widgetAreas = await findAll( { + role: 'group', + name: 'Block: Widget Area', + } ); + const [ firstWidgetArea, secondWidgetArea ] = widgetAreas; // Insert a paragraph it should be in the first widget area. const inserterParagraphBlock = await getBlockInGlobalInserter( @@ -546,28 +619,47 @@ describe( 'Widgets screen', () => { ); await inserterParagraphBlock.hover(); await inserterParagraphBlock.click(); - const addedParagraphBlockInFirstWidgetArea = await firstWidgetArea.$( - '[data-block][data-type="core/paragraph"][aria-label^="Empty block"]' + const addedParagraphBlockInFirstWidgetArea = await find( + { + role: 'group', + name: /^Empty block/, + }, + { root: firstWidgetArea } ); await addedParagraphBlockInFirstWidgetArea.focus(); await page.keyboard.type( 'First Paragraph' ); // Check that the block exists in the first widget area. - await page.waitForXPath( - '//*[@aria-label="Block: Widget Area"][@role="group"][1]//p[@data-type="core/paragraph"][.="First Paragraph"]' + await find( + { + role: 'group', + name: 'Paragraph block', + value: 'First Paragraph', + }, + { + root: firstWidgetArea, + } ); // Move the block to the second widget area. await showBlockToolbar(); await clickBlockToolbarButton( 'Move to widget area' ); - const widgetAreaButton = await page.waitForXPath( - '//button[@role="menuitemradio"][contains(.,"Footer #2")]' - ); + const widgetAreaButton = await find( { + role: 'menuitemradio', + name: /^Footer #2/, + } ); await widgetAreaButton.click(); // Check that the block exists in the second widget area. - await page.waitForXPath( - '//*[@aria-label="Block: Widget Area"][@role="group"][2]//p[@data-type="core/paragraph"][.="First Paragraph"]' + await find( + { + role: 'group', + name: 'Paragraph block', + value: 'First Paragraph', + }, + { + root: secondWidgetArea, + } ); // Assert that the serialized widget areas shows the block as in the second widget area. @@ -584,10 +676,15 @@ describe( 'Widgets screen', () => { } ); async function saveWidgets() { - const [ updateButton ] = await page.$x( '//button[text()="Update"]' ); + const updateButton = await find( { + role: 'button', + name: 'Update', + } ); await updateButton.click(); - await page.waitForXPath( '//*[text()="Widgets saved."]' ); + await findAll( { + text: 'Widgets saved.', + } ); // FIXME: The snackbar above is enough for the widget areas to get saved, // but not enough for the widgets to get saved. diff --git a/packages/scripts/config/puppeteer.config.js b/packages/scripts/config/puppeteer.config.js index 48941d9e34210f..2ca9621040a64a 100644 --- a/packages/scripts/config/puppeteer.config.js +++ b/packages/scripts/config/puppeteer.config.js @@ -3,5 +3,6 @@ module.exports = { devtools: process.env.PUPPETEER_DEVTOOLS === 'true', headless: process.env.PUPPETEER_HEADLESS !== 'false', slowMo: parseInt( process.env.PUPPETEER_SLOWMO, 10 ) || 0, + args: [ '--enable-blink-features=ComputedAccessibilityInfo' ], }, };