From a85ce9bb6c4d10133ca2bf7762fec287d1b6aedf Mon Sep 17 00:00:00 2001 From: Delowar Hossain Date: Sat, 7 May 2022 01:16:23 +0600 Subject: [PATCH 01/10] Multiple use block validation logic improvement See: #38502 --- .../various/validate-multiple-use.test.js | 53 +++++++++++++++++++ .../src/hooks/validate-multiple-use/index.js | 31 +++++++++-- 2 files changed, 81 insertions(+), 3 deletions(-) create mode 100644 packages/e2e-tests/specs/editor/various/validate-multiple-use.test.js diff --git a/packages/e2e-tests/specs/editor/various/validate-multiple-use.test.js b/packages/e2e-tests/specs/editor/various/validate-multiple-use.test.js new file mode 100644 index 0000000000000..c8c3bcb099bcb --- /dev/null +++ b/packages/e2e-tests/specs/editor/various/validate-multiple-use.test.js @@ -0,0 +1,53 @@ +/** + * WordPress dependencies + */ +import { createNewPost, insertBlock } from '@wordpress/e2e-test-utils'; + +describe( 'Validate multiple use', () => { + beforeEach( async () => { + await createNewPost(); + } ); + + // Regression of: https://github.com/WordPress/gutenberg/pull/39813 + it( 'should display correct amount of warning message', async () => { + const OPTIONS_SELECTOR = + '//div[contains(@class, "block-editor-block-settings-menu")]//button[contains(@aria-label, "Options")]'; + const DUPLICATE_BUTTON_SELECTOR = + '//button[contains(@class, "components-menu-item__button")][contains(., "Duplicate")]'; + + // Insert a block with `multiple` feature enabled, such as `core/more` + await insertBlock( 'More' ); + + // Block toolbar options dropdown button + let optionButton = await page.waitForXPath( OPTIONS_SELECTOR ); + await optionButton.click(); + + const groupButton = await page.waitForXPath( + '//button[contains(@class, "components-menu-item__button")][contains(., "Group")]' + ); + + await groupButton.click(); + + // Block toolbar options dropdown button + optionButton = await page.waitForXPath( OPTIONS_SELECTOR ); + await optionButton.click(); + + // Duplicate block twice + let duplicateButton = await page.waitForXPath( + DUPLICATE_BUTTON_SELECTOR + ); + await duplicateButton.click(); + + optionButton = await page.waitForXPath( OPTIONS_SELECTOR ); + await optionButton.click(); + duplicateButton = await page.waitForXPath( DUPLICATE_BUTTON_SELECTOR ); + await duplicateButton.click(); + + // Check if there are correct amount of warnings. + expect( + await page.$x( + '//p[contains(@class, "block-editor-warning__message")][contains(., "More: This block can only be used once.")]' + ) + ).toHaveLength( 2 ); + } ); +} ); diff --git a/packages/edit-post/src/hooks/validate-multiple-use/index.js b/packages/edit-post/src/hooks/validate-multiple-use/index.js index 31444a86467c7..bf771f4522036 100644 --- a/packages/edit-post/src/hooks/validate-multiple-use/index.js +++ b/packages/edit-post/src/hooks/validate-multiple-use/index.js @@ -15,6 +15,33 @@ import { addFilter } from '@wordpress/hooks'; import { __ } from '@wordpress/i18n'; import { compose, createHigherOrderComponent } from '@wordpress/compose'; +/** + * Recursively find very first block of an specific block type. + * + * @param {Object[]} blocks List of blocks. + * @param {string} name Block name to search. + * + * @return {Object|undefined} Return block object or undefined. + */ +function findFirstOfSameType( blocks, name ) { + if ( ! Array.isArray( blocks ) || ! blocks.length ) { + return; + } + + for ( const block of blocks ) { + if ( block.name === name ) { + return block; + } + + // Search inside innerBlocks. + const firstBlock = findFirstOfSameType( block.innerBlocks, name ); + + if ( firstBlock ) { + return firstBlock; + } + } +} + const enhance = compose( /** * For blocks whose block type doesn't support `multiple`, provides the @@ -39,9 +66,7 @@ const enhance = compose( // Otherwise, only pass `originalBlockClientId` if it refers to a different // block from the current one. const blocks = select( blockEditorStore ).getBlocks(); - const firstOfSameType = blocks.find( - ( { name } ) => block.name === name - ); + const firstOfSameType = findFirstOfSameType( blocks, block.name ); const isInvalid = firstOfSameType && firstOfSameType.clientId !== block.clientId; return { From b2ccc590d63240eabf862fb622a5029636fb9b09 Mon Sep 17 00:00:00 2001 From: fai-sal Date: Fri, 5 Jan 2024 13:47:01 +0600 Subject: [PATCH 02/10] Added playwright as the testing library --- packages/e2e-tests/package.json | 1 + .../various/validate-multiple-use.test.js | 17 ++++++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/packages/e2e-tests/package.json b/packages/e2e-tests/package.json index f9d8072adb915..a536f5dd747ba 100644 --- a/packages/e2e-tests/package.json +++ b/packages/e2e-tests/package.json @@ -24,6 +24,7 @@ }, "dependencies": { "@wordpress/e2e-test-utils": "file:../e2e-test-utils", + "@wordpress/e2e-test-utils-playwright": "^0.16.0", "@wordpress/interactivity": "file:../interactivity", "@wordpress/jest-console": "file:../jest-console", "@wordpress/jest-puppeteer-axe": "file:../jest-puppeteer-axe", diff --git a/packages/e2e-tests/specs/editor/various/validate-multiple-use.test.js b/packages/e2e-tests/specs/editor/various/validate-multiple-use.test.js index c8c3bcb099bcb..6c3da5da468b6 100644 --- a/packages/e2e-tests/specs/editor/various/validate-multiple-use.test.js +++ b/packages/e2e-tests/specs/editor/various/validate-multiple-use.test.js @@ -1,22 +1,25 @@ /** * WordPress dependencies */ -import { createNewPost, insertBlock } from '@wordpress/e2e-test-utils'; -describe( 'Validate multiple use', () => { - beforeEach( async () => { - await createNewPost(); +const { test, expect } = require( '@wordpress/e2e-test-utils-playwright' ); + +test.describe( 'Validate multiple use', () => { + test.beforeEach( async ( { admin } ) => { + await admin.createNewPost(); } ); - // Regression of: https://github.com/WordPress/gutenberg/pull/39813 - it( 'should display correct amount of warning message', async () => { + test( 'should display correct amount of warning message', async ( { + editor, + page, + } ) => { const OPTIONS_SELECTOR = '//div[contains(@class, "block-editor-block-settings-menu")]//button[contains(@aria-label, "Options")]'; const DUPLICATE_BUTTON_SELECTOR = '//button[contains(@class, "components-menu-item__button")][contains(., "Duplicate")]'; // Insert a block with `multiple` feature enabled, such as `core/more` - await insertBlock( 'More' ); + await editor.insertBlock( 'More' ); // Block toolbar options dropdown button let optionButton = await page.waitForXPath( OPTIONS_SELECTOR ); From 847b7cea8d0c740878c0305a60245802fa399b9f Mon Sep 17 00:00:00 2001 From: fai-sal Date: Fri, 5 Jan 2024 14:21:58 +0600 Subject: [PATCH 03/10] Moved 'validate-multiple-use' test to 'test/e2e/specs/editor/variou' dir --- packages/e2e-tests/package.json | 1 - .../e2e/specs/editor/various/validate-multiple-use.js | 0 2 files changed, 1 deletion(-) rename packages/e2e-tests/specs/editor/various/validate-multiple-use.test.js => test/e2e/specs/editor/various/validate-multiple-use.js (100%) diff --git a/packages/e2e-tests/package.json b/packages/e2e-tests/package.json index a536f5dd747ba..f9d8072adb915 100644 --- a/packages/e2e-tests/package.json +++ b/packages/e2e-tests/package.json @@ -24,7 +24,6 @@ }, "dependencies": { "@wordpress/e2e-test-utils": "file:../e2e-test-utils", - "@wordpress/e2e-test-utils-playwright": "^0.16.0", "@wordpress/interactivity": "file:../interactivity", "@wordpress/jest-console": "file:../jest-console", "@wordpress/jest-puppeteer-axe": "file:../jest-puppeteer-axe", diff --git a/packages/e2e-tests/specs/editor/various/validate-multiple-use.test.js b/test/e2e/specs/editor/various/validate-multiple-use.js similarity index 100% rename from packages/e2e-tests/specs/editor/various/validate-multiple-use.test.js rename to test/e2e/specs/editor/various/validate-multiple-use.js From b5b25eea87abeb161cb797c718fafb54475ba61b Mon Sep 17 00:00:00 2001 From: fai-sal Date: Fri, 5 Jan 2024 15:57:54 +0600 Subject: [PATCH 04/10] renamed test file --- .../{validate-multiple-use.js => validate-multiple-use.spec.js} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename test/e2e/specs/editor/various/{validate-multiple-use.js => validate-multiple-use.spec.js} (100%) diff --git a/test/e2e/specs/editor/various/validate-multiple-use.js b/test/e2e/specs/editor/various/validate-multiple-use.spec.js similarity index 100% rename from test/e2e/specs/editor/various/validate-multiple-use.js rename to test/e2e/specs/editor/various/validate-multiple-use.spec.js From 7858b030d81b38193103b4a37b15fa9359e19378 Mon Sep 17 00:00:00 2001 From: fai-sal Date: Fri, 5 Jan 2024 16:28:54 +0600 Subject: [PATCH 05/10] Fix: issues with block insertion for testing --- test/e2e/specs/editor/various/validate-multiple-use.spec.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/e2e/specs/editor/various/validate-multiple-use.spec.js b/test/e2e/specs/editor/various/validate-multiple-use.spec.js index 6c3da5da468b6..ac3eb2e74c33f 100644 --- a/test/e2e/specs/editor/various/validate-multiple-use.spec.js +++ b/test/e2e/specs/editor/various/validate-multiple-use.spec.js @@ -19,7 +19,9 @@ test.describe( 'Validate multiple use', () => { '//button[contains(@class, "components-menu-item__button")][contains(., "Duplicate")]'; // Insert a block with `multiple` feature enabled, such as `core/more` - await editor.insertBlock( 'More' ); + await editor.insertBlock( { + name: 'core/more', + } ); // Block toolbar options dropdown button let optionButton = await page.waitForXPath( OPTIONS_SELECTOR ); From 7d8985544dadddf47065897173ea60bc699884e7 Mon Sep 17 00:00:00 2001 From: fai-sal Date: Wed, 10 Jan 2024 21:21:09 +0600 Subject: [PATCH 06/10] Rewrite test cases by playwright role api --- .../various/validate-multiple-use.spec.js | 38 ++++--------------- 1 file changed, 8 insertions(+), 30 deletions(-) diff --git a/test/e2e/specs/editor/various/validate-multiple-use.spec.js b/test/e2e/specs/editor/various/validate-multiple-use.spec.js index ac3eb2e74c33f..08e0d6b40e094 100644 --- a/test/e2e/specs/editor/various/validate-multiple-use.spec.js +++ b/test/e2e/specs/editor/various/validate-multiple-use.spec.js @@ -13,46 +13,24 @@ test.describe( 'Validate multiple use', () => { editor, page, } ) => { - const OPTIONS_SELECTOR = - '//div[contains(@class, "block-editor-block-settings-menu")]//button[contains(@aria-label, "Options")]'; - const DUPLICATE_BUTTON_SELECTOR = - '//button[contains(@class, "components-menu-item__button")][contains(., "Duplicate")]'; - // Insert a block with `multiple` feature enabled, such as `core/more` await editor.insertBlock( { name: 'core/more', } ); - // Block toolbar options dropdown button - let optionButton = await page.waitForXPath( OPTIONS_SELECTOR ); - await optionButton.click(); - - const groupButton = await page.waitForXPath( - '//button[contains(@class, "components-menu-item__button")][contains(., "Group")]' + const optionButton = page.locator( + ".components-dropdown-menu__toggle[data-toolbar-item='true'][aria-label='Options']" ); - await groupButton.click(); - - // Block toolbar options dropdown button - optionButton = await page.waitForXPath( OPTIONS_SELECTOR ); + // Group the block await optionButton.click(); + await page.getByText( 'Group' ).click(); - // Duplicate block twice - let duplicateButton = await page.waitForXPath( - DUPLICATE_BUTTON_SELECTOR - ); - await duplicateButton.click(); - - optionButton = await page.waitForXPath( OPTIONS_SELECTOR ); + // Duplicate the block await optionButton.click(); - duplicateButton = await page.waitForXPath( DUPLICATE_BUTTON_SELECTOR ); - await duplicateButton.click(); + await page.getByText( 'Duplicate' ).click(); - // Check if there are correct amount of warnings. - expect( - await page.$x( - '//p[contains(@class, "block-editor-warning__message")][contains(., "More: This block can only be used once.")]' - ) - ).toHaveLength( 2 ); + // Check if warnings is visible + await expect( page.locator( '.block-editor-warning' ) ).toBeVisible(); } ); } ); From 12138731a110ee4cb97f2f075ace61311b946680 Mon Sep 17 00:00:00 2001 From: fai-sal Date: Wed, 10 Jan 2024 23:10:23 +0600 Subject: [PATCH 07/10] Fix iframe locator issue --- test/e2e/specs/editor/various/validate-multiple-use.spec.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/e2e/specs/editor/various/validate-multiple-use.spec.js b/test/e2e/specs/editor/various/validate-multiple-use.spec.js index 08e0d6b40e094..de7f6cf6cdc56 100644 --- a/test/e2e/specs/editor/various/validate-multiple-use.spec.js +++ b/test/e2e/specs/editor/various/validate-multiple-use.spec.js @@ -31,6 +31,8 @@ test.describe( 'Validate multiple use', () => { await page.getByText( 'Duplicate' ).click(); // Check if warnings is visible - await expect( page.locator( '.block-editor-warning' ) ).toBeVisible(); + await expect( + page.frameLocator( 'iFrame' ).locator( '.block-editor-warning' ) + ).toBeVisible(); } ); } ); From d8fa31f93783f4be62c75b0bbae1a2a6497acbae Mon Sep 17 00:00:00 2001 From: fai-sal Date: Sat, 13 Jan 2024 13:50:04 +0600 Subject: [PATCH 08/10] Update playwright locators by 'getByRole' --- .../various/validate-multiple-use.spec.js | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/test/e2e/specs/editor/various/validate-multiple-use.spec.js b/test/e2e/specs/editor/various/validate-multiple-use.spec.js index de7f6cf6cdc56..b351a3d6ebfde 100644 --- a/test/e2e/specs/editor/various/validate-multiple-use.spec.js +++ b/test/e2e/specs/editor/various/validate-multiple-use.spec.js @@ -4,6 +4,14 @@ const { test, expect } = require( '@wordpress/e2e-test-utils-playwright' ); +async function showBlockMenuItems( { editor, page } ) { + await editor.showBlockToolbar(); + await page + .getByRole( 'toolbar', { name: 'Block tools' } ) + .getByRole( 'button', { name: 'Options' } ) + .click(); +} + test.describe( 'Validate multiple use', () => { test.beforeEach( async ( { admin } ) => { await admin.createNewPost(); @@ -18,21 +26,19 @@ test.describe( 'Validate multiple use', () => { name: 'core/more', } ); - const optionButton = page.locator( - ".components-dropdown-menu__toggle[data-toolbar-item='true'][aria-label='Options']" - ); - // Group the block - await optionButton.click(); - await page.getByText( 'Group' ).click(); + await showBlockMenuItems( { editor, page } ); + await page.getByRole( 'menuitem', { name: 'Group' } ).click(); // Duplicate the block - await optionButton.click(); - await page.getByText( 'Duplicate' ).click(); + await showBlockMenuItems( { editor, page } ); + await page.getByRole( 'menuitem', { name: 'Duplicate' } ).click(); // Check if warnings is visible await expect( - page.frameLocator( 'iFrame' ).locator( '.block-editor-warning' ) + editor.canvas.getByRole( 'button', { + name: 'Find original', + } ) ).toBeVisible(); } ); } ); From 64cfa4cdbfcd8e4de251512aaed40c63a0a180a8 Mon Sep 17 00:00:00 2001 From: fai-sal Date: Thu, 25 Jan 2024 19:11:57 +0600 Subject: [PATCH 09/10] Using 'clickBlockOptionsMenuItem' function --- .../various/validate-multiple-use.spec.js | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/test/e2e/specs/editor/various/validate-multiple-use.spec.js b/test/e2e/specs/editor/various/validate-multiple-use.spec.js index b351a3d6ebfde..fa1201c36533b 100644 --- a/test/e2e/specs/editor/various/validate-multiple-use.spec.js +++ b/test/e2e/specs/editor/various/validate-multiple-use.spec.js @@ -4,14 +4,6 @@ const { test, expect } = require( '@wordpress/e2e-test-utils-playwright' ); -async function showBlockMenuItems( { editor, page } ) { - await editor.showBlockToolbar(); - await page - .getByRole( 'toolbar', { name: 'Block tools' } ) - .getByRole( 'button', { name: 'Options' } ) - .click(); -} - test.describe( 'Validate multiple use', () => { test.beforeEach( async ( { admin } ) => { await admin.createNewPost(); @@ -19,7 +11,7 @@ test.describe( 'Validate multiple use', () => { test( 'should display correct amount of warning message', async ( { editor, - page, + pageUtils, } ) => { // Insert a block with `multiple` feature enabled, such as `core/more` await editor.insertBlock( { @@ -27,12 +19,12 @@ test.describe( 'Validate multiple use', () => { } ); // Group the block - await showBlockMenuItems( { editor, page } ); - await page.getByRole( 'menuitem', { name: 'Group' } ).click(); + await pageUtils.pressKeys( 'primary+a' ); + await editor.clickBlockOptionsMenuItem( 'Group' ); // Duplicate the block - await showBlockMenuItems( { editor, page } ); - await page.getByRole( 'menuitem', { name: 'Duplicate' } ).click(); + await pageUtils.pressKeys( 'primary+a' ); + await editor.clickBlockOptionsMenuItem( 'Duplicate' ); // Check if warnings is visible await expect( From 8a3a1b6dbcfa19c2a53703918cfe47fd4d74d232 Mon Sep 17 00:00:00 2001 From: Dave Smith Date: Fri, 9 Feb 2024 13:39:09 +0000 Subject: [PATCH 10/10] Apply comment wording improvements Co-authored-by: Ben Dwyer --- test/e2e/specs/editor/various/validate-multiple-use.spec.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/e2e/specs/editor/various/validate-multiple-use.spec.js b/test/e2e/specs/editor/various/validate-multiple-use.spec.js index fa1201c36533b..4ab455d22cf29 100644 --- a/test/e2e/specs/editor/various/validate-multiple-use.spec.js +++ b/test/e2e/specs/editor/various/validate-multiple-use.spec.js @@ -9,11 +9,11 @@ test.describe( 'Validate multiple use', () => { await admin.createNewPost(); } ); - test( 'should display correct amount of warning message', async ( { + test( 'should display correct number of warning messages', async ( { editor, pageUtils, } ) => { - // Insert a block with `multiple` feature enabled, such as `core/more` + // Insert a block with the `multiple` feature enabled, such as `core/more` await editor.insertBlock( { name: 'core/more', } ); @@ -26,7 +26,7 @@ test.describe( 'Validate multiple use', () => { await pageUtils.pressKeys( 'primary+a' ); await editor.clickBlockOptionsMenuItem( 'Duplicate' ); - // Check if warnings is visible + // Check if warning is visible await expect( editor.canvas.getByRole( 'button', { name: 'Find original',