From c885da532eaa64d1072fcfde444c91c99b867886 Mon Sep 17 00:00:00 2001 From: Bart Kalisz Date: Mon, 13 Feb 2023 11:37:17 +0100 Subject: [PATCH 01/14] Init block-deletion.spec.js --- .../editor/various/block-deletion.spec.js | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 test/e2e/specs/editor/various/block-deletion.spec.js diff --git a/test/e2e/specs/editor/various/block-deletion.spec.js b/test/e2e/specs/editor/various/block-deletion.spec.js new file mode 100644 index 0000000000000..d3cc51c67f63b --- /dev/null +++ b/test/e2e/specs/editor/various/block-deletion.spec.js @@ -0,0 +1,24 @@ +/** + * WordPress dependencies + */ +const { test } = require( '@wordpress/e2e-test-utils-playwright' ); + +test.describe( 'Block deletion', () => { + test.beforeEach( async ( { admin } ) => { + await admin.createNewPost(); + } ); + + test( 'deleting last block via the Remove Block menu item', () => {} ); + + test( 'deleting last block via the Remove Block shortcut', () => {} ); + + test( 'deleting last block via backspace from an empty paragraph', () => {} ); + + test( 'deleting last selected block via backspace', () => {} ); + + test( 'deleting last two selected blocks via backspace', () => {} ); + + test( 'deleting all blocks', () => {} ); + + test( 'deleting all blocks when the default block is unavailable', () => {} ); +} ); From 7af78e4daa75789b09ff468bf976c86a8a666d7a Mon Sep 17 00:00:00 2001 From: Bart Kalisz Date: Mon, 13 Feb 2023 12:14:43 +0100 Subject: [PATCH 02/14] Migrate test for removing via the Remove Block menu item --- .../editor/various/block-deletion.spec.js | 59 ++++++++++++++++++- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/test/e2e/specs/editor/various/block-deletion.spec.js b/test/e2e/specs/editor/various/block-deletion.spec.js index d3cc51c67f63b..5d204f39abec4 100644 --- a/test/e2e/specs/editor/various/block-deletion.spec.js +++ b/test/e2e/specs/editor/various/block-deletion.spec.js @@ -1,14 +1,69 @@ /** * WordPress dependencies */ -const { test } = require( '@wordpress/e2e-test-utils-playwright' ); +const { test, expect } = require( '@wordpress/e2e-test-utils-playwright' ); test.describe( 'Block deletion', () => { test.beforeEach( async ( { admin } ) => { await admin.createNewPost(); } ); - test( 'deleting last block via the Remove Block menu item', () => {} ); + test( 'deleting last block via the Block Toolbar options menu', async ( { + editor, + page, + } ) => { + // Add a couple of paragraphs. + await editor.insertBlock( { + name: 'core/paragraph', + attributes: { content: 'First' }, + } ); + await editor.insertBlock( { + name: 'core/paragraph', + attributes: { content: 'Second' }, + } ); + await editor.insertBlock( { + name: 'core/paragraph', + attributes: { content: 'Third' }, + } ); + + // Make sure the last paragraph is focused. + await expect( + editor.canvas + .getByRole( 'document', { + name: 'Paragraph block', + } ) + .last() + ).toBeFocused(); + + // Remove the current paragraph via the Block Toolbar options menu. + await editor.showBlockToolbar(); + await editor.canvas + .getByRole( 'toolbar', { name: 'Block tools' } ) + .getByRole( 'button', { name: 'Options' } ) + .click(); + await page + .getByRole( 'menuitem', { name: /Remove Paragraph/ } ) + .click(); + + // Make sure the last block was removed. + await expect( + editor.canvas + .getByRole( 'document', { + name: 'Paragraph block', + } ) + .last() + ).toContainText( 'Second' ); + + // Make sure the caret is in a correct position. + await page.keyboard.type( '| ← caret was here' ); + await expect( + editor.canvas + .getByRole( 'document', { + name: 'Paragraph block', + } ) + .last() + ).toContainText( 'Second| ← caret was here' ); + } ); test( 'deleting last block via the Remove Block shortcut', () => {} ); From c4cf81b440b492eeaab77ce348bd1b96a0d494ea Mon Sep 17 00:00:00 2001 From: Bart Kalisz Date: Mon, 13 Feb 2023 12:52:10 +0100 Subject: [PATCH 03/14] Migrate test for removing via dedicated keyboard shortcut --- .../editor/various/block-deletion.spec.js | 51 ++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/test/e2e/specs/editor/various/block-deletion.spec.js b/test/e2e/specs/editor/various/block-deletion.spec.js index 5d204f39abec4..832059f952ac0 100644 --- a/test/e2e/specs/editor/various/block-deletion.spec.js +++ b/test/e2e/specs/editor/various/block-deletion.spec.js @@ -65,7 +65,56 @@ test.describe( 'Block deletion', () => { ).toContainText( 'Second| ← caret was here' ); } ); - test( 'deleting last block via the Remove Block shortcut', () => {} ); + test( 'deleting last block via the Remove Block shortcut', async ( { + editor, + page, + pageUtils, + } ) => { + // Add a couple of paragraphs. + await editor.insertBlock( { + name: 'core/paragraph', + attributes: { content: 'First' }, + } ); + await editor.insertBlock( { + name: 'core/paragraph', + attributes: { content: 'Second' }, + } ); + await editor.insertBlock( { + name: 'core/paragraph', + attributes: { content: 'Third' }, + } ); + + // Make sure the last paragraph is focused. + await expect( + editor.canvas + .getByRole( 'document', { + name: 'Paragraph block', + } ) + .last() + ).toBeFocused(); + + // Remove the current paragraph via dedicated keyboard shortcut. + await pageUtils.pressKeyWithModifier( 'access', 'z' ); + + // Make sure the last block was removed. + await expect( + editor.canvas + .getByRole( 'document', { + name: 'Paragraph block', + } ) + .last() + ).toContainText( 'Second' ); + + // Make sure the caret is in a correct position. + await page.keyboard.type( '| ← caret was here' ); + await expect( + editor.canvas + .getByRole( 'document', { + name: 'Paragraph block', + } ) + .last() + ).toContainText( 'Second| ← caret was here' ); + } ); test( 'deleting last block via backspace from an empty paragraph', () => {} ); From 27e5b0a4abef7583e3495eb476c0ef4d8d035acd Mon Sep 17 00:00:00 2001 From: Bart Kalisz Date: Mon, 13 Feb 2023 12:57:37 +0100 Subject: [PATCH 04/14] Migrate test for removing block via backspace --- .../editor/various/block-deletion.spec.js | 45 ++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/test/e2e/specs/editor/various/block-deletion.spec.js b/test/e2e/specs/editor/various/block-deletion.spec.js index 832059f952ac0..478ea8ce826c7 100644 --- a/test/e2e/specs/editor/various/block-deletion.spec.js +++ b/test/e2e/specs/editor/various/block-deletion.spec.js @@ -116,7 +116,50 @@ test.describe( 'Block deletion', () => { ).toContainText( 'Second| ← caret was here' ); } ); - test( 'deleting last block via backspace from an empty paragraph', () => {} ); + test( 'deleting last block via backspace from an empty paragraph', async ( { + editor, + page, + } ) => { + // Add a couple of paragraphs. + await editor.insertBlock( { + name: 'core/paragraph', + attributes: { content: 'First' }, + } ); + await editor.insertBlock( { + name: 'core/paragraph', + attributes: { content: 'Second' }, + } ); + + // Leave last paragraph empty and make sure it's focused. + await editor.insertBlock( { + name: 'core/paragraph', + } ); + await expect( + editor.canvas.getByRole( 'document', { name: /Empty block/ } ) + ).toBeFocused(); + + // Hit backspace to remove the empty paragraph. + await page.keyboard.press( 'Backspace' ); + + // Make sure the last block was removed. + await expect( + editor.canvas + .getByRole( 'document', { + name: 'Paragraph block', + } ) + .last() + ).toContainText( 'Second' ); + + // Make sure the caret is in a correct position. + await page.keyboard.type( '| ← caret was here' ); + await expect( + editor.canvas + .getByRole( 'document', { + name: 'Paragraph block', + } ) + .last() + ).toContainText( 'Second| ← caret was here' ); + } ); test( 'deleting last selected block via backspace', () => {} ); From d5bb8885ffd3d4a65729cb7256862e8c3e7e1543 Mon Sep 17 00:00:00 2001 From: Bart Kalisz Date: Mon, 13 Feb 2023 13:24:14 +0100 Subject: [PATCH 05/14] Migrate test for deleting selected block with backspace --- .../editor/various/block-deletion.spec.js | 48 ++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/test/e2e/specs/editor/various/block-deletion.spec.js b/test/e2e/specs/editor/various/block-deletion.spec.js index 478ea8ce826c7..f4759c76ce4b7 100644 --- a/test/e2e/specs/editor/various/block-deletion.spec.js +++ b/test/e2e/specs/editor/various/block-deletion.spec.js @@ -161,7 +161,53 @@ test.describe( 'Block deletion', () => { ).toContainText( 'Second| ← caret was here' ); } ); - test( 'deleting last selected block via backspace', () => {} ); + test( 'deleting last selected block via backspace', async ( { + editor, + page, + } ) => { + // Add a couple of paragraphs. + await editor.insertBlock( { + name: 'core/paragraph', + attributes: { content: 'First' }, + } ); + await editor.insertBlock( { + name: 'core/paragraph', + attributes: { content: 'Second' }, + } ); + + // Add the Image block and focus it. + await editor.insertBlock( { + name: 'core/image', + } ); + const imageBlock = editor.canvas.getByRole( 'document', { + name: 'Block: Image', + } ); + await expect( + imageBlock.getByRole( 'button', { name: 'Upload' } ) + ).toBeFocused(); + await page.keyboard.press( 'ArrowUp' ); + await expect( imageBlock ).toBeFocused(); + + // Hit backspace and ensure the Image block was removed. + await page.keyboard.press( 'Backspace' ); + await expect( + editor.canvas + .getByRole( 'document', { + name: 'Paragraph block', + } ) + .last() + ).toContainText( 'Second' ); + + // Ensure the caret is in a correct position. + await page.keyboard.type( '| ← caret was here' ); + await expect( + editor.canvas + .getByRole( 'document', { + name: 'Paragraph block', + } ) + .last() + ).toContainText( 'Second| ← caret was here' ); + } ); test( 'deleting last two selected blocks via backspace', () => {} ); From e4e8a28b4ccddc4c71c1a440b0d1d37a1da6ba4b Mon Sep 17 00:00:00 2001 From: Bart Kalisz Date: Mon, 13 Feb 2023 14:19:58 +0100 Subject: [PATCH 06/14] Migrate test for deleting multiple selected blocks --- .../editor/various/block-deletion.spec.js | 54 ++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/test/e2e/specs/editor/various/block-deletion.spec.js b/test/e2e/specs/editor/various/block-deletion.spec.js index f4759c76ce4b7..6a891e769ddca 100644 --- a/test/e2e/specs/editor/various/block-deletion.spec.js +++ b/test/e2e/specs/editor/various/block-deletion.spec.js @@ -209,7 +209,59 @@ test.describe( 'Block deletion', () => { ).toContainText( 'Second| ← caret was here' ); } ); - test( 'deleting last two selected blocks via backspace', () => {} ); + test( 'deleting last two selected blocks via backspace', async ( { + editor, + page, + pageUtils, + } ) => { + // Add a couple of paragraphs. + await editor.insertBlock( { + name: 'core/paragraph', + attributes: { content: 'First' }, + } ); + await editor.insertBlock( { + name: 'core/paragraph', + attributes: { content: 'Second' }, + } ); + await editor.insertBlock( { + name: 'core/paragraph', + attributes: { content: 'Third' }, + } ); + await editor.insertBlock( { + name: 'core/paragraph', + } ); + + // Ensure the empty paragraph is focused. + await expect( + editor.canvas.getByRole( 'document', { + name: /Empty block/i, + } ) + ).toBeFocused(); + + // Select the last two paragraphs. + await pageUtils.pressKeyWithModifier( 'shift', 'ArrowUp' ); + await expect( + editor.canvas.locator( 'p.is-multi-selected' ) + ).toHaveCount( 2 ); + + // Hit backspace and ensure the last two paragraphs were deleted. + await page.keyboard.press( 'Backspace' ); + await expect( + editor.canvas + .getByRole( 'document', { + name: 'Paragraph block', + } ) + .last() + ).toContainText( 'Second' ); + + // Ensure a new empty block was created and focused. + await expect.poll( editor.getBlocks ).toHaveLength( 3 ); + await expect( + editor.canvas.getByRole( 'document', { + name: /Empty block/i, + } ) + ).toBeFocused(); + } ); test( 'deleting all blocks', () => {} ); From 1474796cdc098b890fa78e961e42a81a9e20d1e1 Mon Sep 17 00:00:00 2001 From: Bart Kalisz Date: Mon, 13 Feb 2023 14:23:37 +0100 Subject: [PATCH 07/14] Migrate test for deleting all blocks --- .../editor/various/block-deletion.spec.js | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/test/e2e/specs/editor/various/block-deletion.spec.js b/test/e2e/specs/editor/various/block-deletion.spec.js index 6a891e769ddca..41c1d6b86d06c 100644 --- a/test/e2e/specs/editor/various/block-deletion.spec.js +++ b/test/e2e/specs/editor/various/block-deletion.spec.js @@ -263,7 +263,35 @@ test.describe( 'Block deletion', () => { ).toBeFocused(); } ); - test( 'deleting all blocks', () => {} ); + test( 'deleting all blocks', async ( { editor, page } ) => { + // Add one paragraph with content and ensure it's focused. + await editor.insertBlock( { + name: 'core/paragraph', + attributes: { content: 'Test' }, + } ); + await expect( + editor.canvas.getByRole( 'document', { + name: 'Paragraph block', + } ) + ).toBeFocused(); + + // Remove that paragraph via its options menu. + await editor.showBlockToolbar(); + await editor.canvas + .getByRole( 'toolbar', { name: 'Block tools' } ) + .getByRole( 'button', { name: 'Options' } ) + .click(); + await page + .getByRole( 'menuitem', { name: /Remove Paragraph/ } ) + .click(); + + // Ensure an empty block was created and focused. + await expect( + editor.canvas.getByRole( 'document', { + name: /Empty block/i, + } ) + ).toBeFocused(); + } ); test( 'deleting all blocks when the default block is unavailable', () => {} ); } ); From ad4e8f716935ee6723e0ed16a207c8f0866dbb33 Mon Sep 17 00:00:00 2001 From: Bart Kalisz Date: Mon, 13 Feb 2023 14:48:13 +0100 Subject: [PATCH 08/14] Migrate test for deleting all blocks while the default block is unavailable --- .../editor/various/block-deletion.spec.js | 55 ++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/test/e2e/specs/editor/various/block-deletion.spec.js b/test/e2e/specs/editor/various/block-deletion.spec.js index 41c1d6b86d06c..f7d3e1e1ee9bf 100644 --- a/test/e2e/specs/editor/various/block-deletion.spec.js +++ b/test/e2e/specs/editor/various/block-deletion.spec.js @@ -293,5 +293,58 @@ test.describe( 'Block deletion', () => { ).toBeFocused(); } ); - test( 'deleting all blocks when the default block is unavailable', () => {} ); + /** + * Regression Test: Previously, removing a block would not clear + * selection state when there were no other blocks to select. + * + * See: https://github.com/WordPress/gutenberg/issues/15458 + * See: https://github.com/WordPress/gutenberg/pull/15543 + */ + test( 'deleting all blocks when the default block is unavailable', async ( { + editor, + page, + } ) => { + // Unregister default block type. This may happen if the editor is + // configured to not allow the default (paragraph) block type, either + // by plugin editor settings filtering or user block preferences. + await page.waitForFunction( () => { + try { + // eslint-disable-next-line no-undef + const defaultBlockName = wp.data + .select( 'core/blocks' ) + .getDefaultBlockName(); + // eslint-disable-next-line no-undef + wp.data + .dispatch( 'core/blocks' ) + .removeBlockTypes( defaultBlockName ); + return true; + } catch { + return false; + } + } ); + + // Add the Image block and remove it. + await editor.insertBlock( { name: 'core/image' } ); + const imageBlock = editor.canvas.getByRole( 'document', { + name: 'Block: Image', + } ); + await expect( + imageBlock.getByRole( 'button', { name: 'Upload' } ) + ).toBeFocused(); + await page.keyboard.press( 'ArrowUp' ); + await expect( imageBlock ).toBeFocused(); + await page.keyboard.press( 'Backspace' ); + + // Verify that there's no blocks and only the block appender button is + // visible. + await expect.poll( editor.getBlocks ).toHaveLength( 0 ); + await expect( + editor.canvas.getByRole( 'document', { name: /Empty block/i } ) + ).not.toBeVisible(); + await expect( + editor.canvas.getByRole( 'button', { name: 'Add block' } ) + ).toBeVisible(); + // TODO: There should be expectations around where focus is placed in + // this scenario. Currently, a focus loss occurs, which is unacceptable. + } ); } ); From 7ad7fa8871fdac2dff04a69d09d8939c55cc5afd Mon Sep 17 00:00:00 2001 From: Bart Kalisz Date: Mon, 13 Feb 2023 14:49:37 +0100 Subject: [PATCH 09/14] Remove old test files --- .../__snapshots__/block-deletion.test.js.snap | 111 ---------- .../editor/various/block-deletion.test.js | 209 ------------------ 2 files changed, 320 deletions(-) delete mode 100644 packages/e2e-tests/specs/editor/various/__snapshots__/block-deletion.test.js.snap delete mode 100644 packages/e2e-tests/specs/editor/various/block-deletion.test.js diff --git a/packages/e2e-tests/specs/editor/various/__snapshots__/block-deletion.test.js.snap b/packages/e2e-tests/specs/editor/various/__snapshots__/block-deletion.test.js.snap deleted file mode 100644 index 8b0dcaec4067f..0000000000000 --- a/packages/e2e-tests/specs/editor/various/__snapshots__/block-deletion.test.js.snap +++ /dev/null @@ -1,111 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`block deletion - deleting the third and fourth blocks using backspace with multi-block selection results in two remaining blocks and positions the caret at the end of the second block 1`] = ` -" -

First paragraph

- - - -

Second paragraph

- - - -

-" -`; - -exports[`block deletion - deleting the third and fourth blocks using backspace with multi-block selection results in two remaining blocks and positions the caret at the end of the second block 2`] = ` -" -

First paragraph

- - - -

Second paragraph

- - - -
    -
  • caret was here
  • -
-" -`; - -exports[`block deletion - deleting the third block using backspace in an empty block results in two remaining blocks and positions the caret at the end of the second block 1`] = ` -" -

First paragraph

- - - -

Second paragraph

-" -`; - -exports[`block deletion - deleting the third block using backspace in an empty block results in two remaining blocks and positions the caret at the end of the second block 2`] = ` -" -

First paragraph

- - - -

Second paragraph - caret was here

-" -`; - -exports[`block deletion - deleting the third block using backspace with block wrapper selection results in three remaining blocks and positions the caret at the end of the third block 1`] = ` -" -

First paragraph

- - - -

Second paragraph

-" -`; - -exports[`block deletion - deleting the third block using backspace with block wrapper selection results in three remaining blocks and positions the caret at the end of the third block 2`] = ` -" -

First paragraph

- - - -

Second paragraph - caret was here

-" -`; - -exports[`block deletion - deleting the third block using the Remove Block menu item results in two remaining blocks and positions the caret at the end of the second block 1`] = ` -" -

First paragraph

- - - -

Second paragraph

-" -`; - -exports[`block deletion - deleting the third block using the Remove Block menu item results in two remaining blocks and positions the caret at the end of the second block 2`] = ` -" -

First paragraph

- - - -

Second paragraph - caret was here

-" -`; - -exports[`block deletion - deleting the third block using the Remove Block shortcut results in two remaining blocks and positions the caret at the end of the second block 1`] = ` -" -

First paragraph

- - - -

Second paragraph

-" -`; - -exports[`block deletion - deleting the third block using the Remove Block shortcut results in two remaining blocks and positions the caret at the end of the second block 2`] = ` -" -

First paragraph

- - - -

Second paragraph - caret was here

-" -`; diff --git a/packages/e2e-tests/specs/editor/various/block-deletion.test.js b/packages/e2e-tests/specs/editor/various/block-deletion.test.js deleted file mode 100644 index e4497d45fbfaf..0000000000000 --- a/packages/e2e-tests/specs/editor/various/block-deletion.test.js +++ /dev/null @@ -1,209 +0,0 @@ -/** - * WordPress dependencies - */ -import { - clickBlockAppender, - clickBlockToolbarButton, - getEditedPostContent, - createNewPost, - isInDefaultBlock, - pressKeyWithModifier, - pressKeyTimes, - insertBlock, -} from '@wordpress/e2e-test-utils'; - -const addThreeParagraphsToNewPost = async () => { - await createNewPost(); - - // Add demo content. - await clickBlockAppender(); - await page.keyboard.type( 'First paragraph' ); - await page.keyboard.press( 'Enter' ); - await page.keyboard.type( 'Second paragraph' ); - await page.keyboard.press( 'Enter' ); -}; - -/** - * Due to an issue with the Popover component not being scrollable - * under certain conditions, Pupeteer cannot "see" the "Remove Block" - * button. This is a workaround until that issue is resolved. - * - * see: https://github.com/WordPress/gutenberg/pull/14908#discussion_r284725956 - */ -const clickOnBlockSettingsMenuRemoveBlockButton = async () => { - await clickBlockToolbarButton( 'Options' ); - - let isRemoveButton = false; - - let numButtons = await page.$$eval( - '.block-editor-block-settings-menu__content button', - ( btns ) => btns.length - ); - - // Limit by the number of buttons available. - while ( --numButtons ) { - await page.keyboard.press( 'Tab' ); - - isRemoveButton = await page.evaluate( () => { - return document.activeElement.innerText.includes( - 'Remove Paragraph' - ); - } ); - - // Stop looping once we find the button. - if ( isRemoveButton ) { - await pressKeyTimes( 'Enter', 1 ); - break; - } - } - - // Makes failures more explicit. - await expect( isRemoveButton ).toBe( true ); -}; - -describe( 'block deletion -', () => { - beforeEach( addThreeParagraphsToNewPost ); - - describe( 'deleting the third block using the Remove Block menu item', () => { - it( 'results in two remaining blocks and positions the caret at the end of the second block', async () => { - // The blocks can't be empty to trigger the toolbar. - await page.keyboard.type( 'Paragraph to remove' ); - await clickOnBlockSettingsMenuRemoveBlockButton(); - - expect( await getEditedPostContent() ).toMatchSnapshot(); - - // Type additional text and assert that caret position is correct by comparing to snapshot. - await page.keyboard.type( ' - caret was here' ); - expect( await getEditedPostContent() ).toMatchSnapshot(); - } ); - } ); - - describe( 'deleting the third block using the Remove Block shortcut', () => { - it( 'results in two remaining blocks and positions the caret at the end of the second block', async () => { - // Type some text to assert that the shortcut also deletes block content. - await page.keyboard.type( 'this is block 2' ); - await pressKeyWithModifier( 'access', 'z' ); - expect( await getEditedPostContent() ).toMatchSnapshot(); - - // Type additional text and assert that caret position is correct by comparing to snapshot. - await page.keyboard.type( ' - caret was here' ); - expect( await getEditedPostContent() ).toMatchSnapshot(); - } ); - } ); - - describe( 'deleting the third block using backspace in an empty block', () => { - it( 'results in two remaining blocks and positions the caret at the end of the second block', async () => { - await page.keyboard.press( 'Backspace' ); - expect( await getEditedPostContent() ).toMatchSnapshot(); - - // Type additional text and assert that caret position is correct by comparing to snapshot. - await page.keyboard.type( ' - caret was here' ); - expect( await getEditedPostContent() ).toMatchSnapshot(); - } ); - } ); - - describe( 'deleting the third block using backspace with block wrapper selection', () => { - it( 'results in three remaining blocks and positions the caret at the end of the third block', async () => { - // Add an image block since it's easier to click the wrapper on non-textual blocks. - await page.keyboard.type( '/image' ); - await page.waitForXPath( - `//*[contains(@class, "components-autocomplete__result") and contains(@class, "is-selected") and contains(text(), 'Image')]` - ); - await page.keyboard.press( 'Enter' ); - - // Click on something that's not a block. - await page.click( '.editor-post-title' ); - - // Click on the image block so that its wrapper is selected and backspace to delete it. - await page.click( - '.wp-block[data-type="core/image"] .components-placeholder__label' - ); - await page.keyboard.press( 'Backspace' ); - - expect( await getEditedPostContent() ).toMatchSnapshot(); - - // Type additional text and assert that caret position is correct by comparing to snapshot. - await page.keyboard.type( ' - caret was here' ); - expect( await getEditedPostContent() ).toMatchSnapshot(); - } ); - } ); - - describe( 'deleting the third and fourth blocks using backspace with multi-block selection', () => { - it( 'results in two remaining blocks and positions the caret at the end of the second block', async () => { - // Add a third paragraph for this test. - await page.keyboard.type( 'Third paragraph' ); - await page.keyboard.press( 'Enter' ); - - // Press the up arrow once to select the third and fourth blocks. - await pressKeyWithModifier( 'shift', 'ArrowUp' ); - - // Now that the block wrapper is selected, press backspace to delete it. - await page.keyboard.press( 'Backspace' ); - expect( await getEditedPostContent() ).toMatchSnapshot(); - - // Type additional text and assert that caret position is correct by comparing to snapshot. - await page.keyboard.type( ' - caret was here' ); - expect( await getEditedPostContent() ).toMatchSnapshot(); - } ); - } ); -} ); - -describe( 'deleting all blocks', () => { - beforeEach( async () => { - await createNewPost(); - } ); - - it( 'results in the default block getting selected', async () => { - await clickBlockAppender(); - await page.keyboard.type( 'Paragraph' ); - await clickOnBlockSettingsMenuRemoveBlockButton(); - - // There is a default block and post title: - expect( - await page.$$( '.block-editor-block-list__block' ) - ).toHaveLength( 2 ); - - // But the effective saved content is still empty: - expect( await getEditedPostContent() ).toBe( '' ); - - // And focus is retained: - expect( await isInDefaultBlock() ).toBe( true ); - } ); - - it( 'gracefully removes blocks when the default block is not available', async () => { - // Regression Test: Previously, removing a block would not clear - // selection state when there were no other blocks to select. - // - // See: https://github.com/WordPress/gutenberg/issues/15458 - // See: https://github.com/WordPress/gutenberg/pull/15543 - - // Unregister default block type. This may happen if the editor is - // configured to not allow the default (paragraph) block type, either - // by plugin editor settings filtering or user block preferences. - await page.evaluate( () => { - const defaultBlockName = wp.data - .select( 'core/blocks' ) - .getDefaultBlockName(); - wp.data - .dispatch( 'core/blocks' ) - .removeBlockTypes( defaultBlockName ); - } ); - - // Add and remove a block. - await insertBlock( 'Image' ); - await page.waitForSelector( 'figure[data-type="core/image"]' ); - await page.keyboard.press( 'ArrowUp' ); - await page.keyboard.press( 'Backspace' ); - - // Verify there is no selected block. - // TODO: There should be expectations around where focus is placed in - // this scenario. Currently, a focus loss occurs (not acceptable). - const selectedBlocksCount = await page.evaluate( () => { - return wp.data - .select( 'core/block-editor' ) - .getSelectedBlockClientIds().length; - } ); - - expect( selectedBlocksCount ).toBe( 0 ); - } ); -} ); From 8ad73b188e5a15453344d789e78149ed099e3c72 Mon Sep 17 00:00:00 2001 From: Bart Kalisz Date: Mon, 13 Feb 2023 14:56:27 +0100 Subject: [PATCH 10/14] Reword a few things --- .../editor/various/block-deletion.spec.js | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/test/e2e/specs/editor/various/block-deletion.spec.js b/test/e2e/specs/editor/various/block-deletion.spec.js index f7d3e1e1ee9bf..bdbb8f6cdc4c0 100644 --- a/test/e2e/specs/editor/various/block-deletion.spec.js +++ b/test/e2e/specs/editor/various/block-deletion.spec.js @@ -8,7 +8,7 @@ test.describe( 'Block deletion', () => { await admin.createNewPost(); } ); - test( 'deleting last block via the Block Toolbar options menu', async ( { + test( 'deleting last block via its options menu', async ( { editor, page, } ) => { @@ -26,7 +26,7 @@ test.describe( 'Block deletion', () => { attributes: { content: 'Third' }, } ); - // Make sure the last paragraph is focused. + // Ensure the last paragraph is focused. await expect( editor.canvas .getByRole( 'document', { @@ -45,7 +45,7 @@ test.describe( 'Block deletion', () => { .getByRole( 'menuitem', { name: /Remove Paragraph/ } ) .click(); - // Make sure the last block was removed. + // Ensure the last block was removed. await expect( editor.canvas .getByRole( 'document', { @@ -54,7 +54,7 @@ test.describe( 'Block deletion', () => { .last() ).toContainText( 'Second' ); - // Make sure the caret is in a correct position. + // Ensure the caret is in a correct position. await page.keyboard.type( '| ← caret was here' ); await expect( editor.canvas @@ -65,7 +65,7 @@ test.describe( 'Block deletion', () => { ).toContainText( 'Second| ← caret was here' ); } ); - test( 'deleting last block via the Remove Block shortcut', async ( { + test( 'deleting last block via the keyboard shortcut', async ( { editor, page, pageUtils, @@ -84,7 +84,7 @@ test.describe( 'Block deletion', () => { attributes: { content: 'Third' }, } ); - // Make sure the last paragraph is focused. + // Ensure the last paragraph is focused. await expect( editor.canvas .getByRole( 'document', { @@ -96,7 +96,7 @@ test.describe( 'Block deletion', () => { // Remove the current paragraph via dedicated keyboard shortcut. await pageUtils.pressKeyWithModifier( 'access', 'z' ); - // Make sure the last block was removed. + // Ensure the last block was removed. await expect( editor.canvas .getByRole( 'document', { @@ -105,7 +105,7 @@ test.describe( 'Block deletion', () => { .last() ).toContainText( 'Second' ); - // Make sure the caret is in a correct position. + // Ensure the caret is in a correct position. await page.keyboard.type( '| ← caret was here' ); await expect( editor.canvas @@ -130,7 +130,7 @@ test.describe( 'Block deletion', () => { attributes: { content: 'Second' }, } ); - // Leave last paragraph empty and make sure it's focused. + // Leave last paragraph empty and ensure it's focused. await editor.insertBlock( { name: 'core/paragraph', } ); @@ -141,7 +141,7 @@ test.describe( 'Block deletion', () => { // Hit backspace to remove the empty paragraph. await page.keyboard.press( 'Backspace' ); - // Make sure the last block was removed. + // Ensure the last block was removed. await expect( editor.canvas .getByRole( 'document', { @@ -150,7 +150,7 @@ test.describe( 'Block deletion', () => { .last() ).toContainText( 'Second' ); - // Make sure the caret is in a correct position. + // Ensure the caret is in a correct position. await page.keyboard.type( '| ← caret was here' ); await expect( editor.canvas From 3169fd48229a4c412e6656c21ef076d28d7ca4bf Mon Sep 17 00:00:00 2001 From: Bart Kalisz Date: Tue, 14 Feb 2023 11:44:28 +0100 Subject: [PATCH 11/14] Apply suggestions from code review Co-authored-by: Kai Hao --- .../editor/various/block-deletion.spec.js | 145 +++++++++--------- 1 file changed, 69 insertions(+), 76 deletions(-) diff --git a/test/e2e/specs/editor/various/block-deletion.spec.js b/test/e2e/specs/editor/various/block-deletion.spec.js index bdbb8f6cdc4c0..3c57dbc7a10ef 100644 --- a/test/e2e/specs/editor/various/block-deletion.spec.js +++ b/test/e2e/specs/editor/various/block-deletion.spec.js @@ -42,27 +42,24 @@ test.describe( 'Block deletion', () => { .getByRole( 'button', { name: 'Options' } ) .click(); await page - .getByRole( 'menuitem', { name: /Remove Paragraph/ } ) + .getByRole( 'menuitem', { name: /Remove Paragraph/i } ) .click(); // Ensure the last block was removed. - await expect( - editor.canvas - .getByRole( 'document', { - name: 'Paragraph block', - } ) - .last() - ).toContainText( 'Second' ); + await expect.poll( editor.getBlocks ).toMatchObject( [ + { name: 'core/paragraph', attributes: { content: 'First' } }, + { name: 'core/paragraph', attributes: { content: 'Second' } }, + ] ); // Ensure the caret is in a correct position. await page.keyboard.type( '| ← caret was here' ); - await expect( - editor.canvas - .getByRole( 'document', { - name: 'Paragraph block', - } ) - .last() - ).toContainText( 'Second| ← caret was here' ); + await expect.poll( editor.getBlocks ).toMatchObject( [ + { name: 'core/paragraph', attributes: { content: 'First' } }, + { + name: 'core/paragraph', + attributes: { content: 'Second| ← caret was here' }, + }, + ] ); } ); test( 'deleting last block via the keyboard shortcut', async ( { @@ -97,23 +94,20 @@ test.describe( 'Block deletion', () => { await pageUtils.pressKeyWithModifier( 'access', 'z' ); // Ensure the last block was removed. - await expect( - editor.canvas - .getByRole( 'document', { - name: 'Paragraph block', - } ) - .last() - ).toContainText( 'Second' ); + await expect.poll( editor.getBlocks ).toMatchObject( [ + { name: 'core/paragraph', attributes: { content: 'First' } }, + { name: 'core/paragraph', attributes: { content: 'Second' } }, + ] ); // Ensure the caret is in a correct position. await page.keyboard.type( '| ← caret was here' ); - await expect( - editor.canvas - .getByRole( 'document', { - name: 'Paragraph block', - } ) - .last() - ).toContainText( 'Second| ← caret was here' ); + await expect.poll( editor.getBlocks ).toMatchObject( [ + { name: 'core/paragraph', attributes: { content: 'First' } }, + { + name: 'core/paragraph', + attributes: { content: 'Second| ← caret was here' }, + }, + ] ); } ); test( 'deleting last block via backspace from an empty paragraph', async ( { @@ -135,30 +129,27 @@ test.describe( 'Block deletion', () => { name: 'core/paragraph', } ); await expect( - editor.canvas.getByRole( 'document', { name: /Empty block/ } ) + editor.canvas.getByRole( 'document', { name: /Empty block/i } ) ).toBeFocused(); // Hit backspace to remove the empty paragraph. await page.keyboard.press( 'Backspace' ); // Ensure the last block was removed. - await expect( - editor.canvas - .getByRole( 'document', { - name: 'Paragraph block', - } ) - .last() - ).toContainText( 'Second' ); + await expect.poll( editor.getBlocks ).toMatchObject( [ + { name: 'core/paragraph', attributes: { content: 'First' } }, + { name: 'core/paragraph', attributes: { content: 'Second' } }, + ] ); // Ensure the caret is in a correct position. await page.keyboard.type( '| ← caret was here' ); - await expect( - editor.canvas - .getByRole( 'document', { - name: 'Paragraph block', - } ) - .last() - ).toContainText( 'Second| ← caret was here' ); + await expect.poll( editor.getBlocks ).toMatchObject( [ + { name: 'core/paragraph', attributes: { content: 'First' } }, + { + name: 'core/paragraph', + attributes: { content: 'Second| ← caret was here' }, + }, + ] ); } ); test( 'deleting last selected block via backspace', async ( { @@ -190,23 +181,20 @@ test.describe( 'Block deletion', () => { // Hit backspace and ensure the Image block was removed. await page.keyboard.press( 'Backspace' ); - await expect( - editor.canvas - .getByRole( 'document', { - name: 'Paragraph block', - } ) - .last() - ).toContainText( 'Second' ); + await expect.poll( editor.getBlocks ).toMatchObject( [ + { name: 'core/paragraph', attributes: { content: 'First' } }, + { name: 'core/paragraph', attributes: { content: 'Second' } }, + ] ); // Ensure the caret is in a correct position. await page.keyboard.type( '| ← caret was here' ); - await expect( - editor.canvas - .getByRole( 'document', { - name: 'Paragraph block', - } ) - .last() - ).toContainText( 'Second| ← caret was here' ); + await expect.poll( editor.getBlocks ).toMatchObject( [ + { name: 'core/paragraph', attributes: { content: 'First' } }, + { + name: 'core/paragraph', + attributes: { content: 'Second| ← caret was here' }, + }, + ] ); } ); test( 'deleting last two selected blocks via backspace', async ( { @@ -241,20 +229,19 @@ test.describe( 'Block deletion', () => { // Select the last two paragraphs. await pageUtils.pressKeyWithModifier( 'shift', 'ArrowUp' ); await expect( - editor.canvas.locator( 'p.is-multi-selected' ) + editor.canvas.locator( '.is-multi-selected' ) ).toHaveCount( 2 ); - // Hit backspace and ensure the last two paragraphs were deleted. + // Hit backspace and ensure the last two paragraphs were deleted, and an + // empty block was created. await page.keyboard.press( 'Backspace' ); - await expect( - editor.canvas - .getByRole( 'document', { - name: 'Paragraph block', - } ) - .last() - ).toContainText( 'Second' ); + await expect.poll( editor.getBlocks ).toMatchObject( [ + { name: 'core/paragraph', attributes: { content: 'First' } }, + { name: 'core/paragraph', attributes: { content: 'Second' } }, + { name: 'core/paragraph', attributes: { content: '' } }, + ] ); - // Ensure a new empty block was created and focused. + // Ensure that the newly created empty block is focused. await expect.poll( editor.getBlocks ).toHaveLength( 3 ); await expect( editor.canvas.getByRole( 'document', { @@ -282,7 +269,7 @@ test.describe( 'Block deletion', () => { .getByRole( 'button', { name: 'Options' } ) .click(); await page - .getByRole( 'menuitem', { name: /Remove Paragraph/ } ) + .getByRole( 'menuitem', { name: /Remove Paragraph/i } ) .click(); // Ensure an empty block was created and focused. @@ -291,6 +278,7 @@ test.describe( 'Block deletion', () => { name: /Empty block/i, } ) ).toBeFocused(); + await expect.poll( editor.getBlocks ).toEqual( [] ); } ); /** @@ -309,12 +297,10 @@ test.describe( 'Block deletion', () => { // by plugin editor settings filtering or user block preferences. await page.waitForFunction( () => { try { - // eslint-disable-next-line no-undef - const defaultBlockName = wp.data + const defaultBlockName = window.wp.data .select( 'core/blocks' ) .getDefaultBlockName(); - // eslint-disable-next-line no-undef - wp.data + window.wp.data .dispatch( 'core/blocks' ) .removeBlockTypes( defaultBlockName ); return true; @@ -323,27 +309,34 @@ test.describe( 'Block deletion', () => { } } ); - // Add the Image block and remove it. + // Add the Image block. await editor.insertBlock( { name: 'core/image' } ); const imageBlock = editor.canvas.getByRole( 'document', { name: 'Block: Image', } ); + + // Initially, the "Upload" button is focused, so we need to move focus + // up to the block wrapper. await expect( imageBlock.getByRole( 'button', { name: 'Upload' } ) ).toBeFocused(); await page.keyboard.press( 'ArrowUp' ); await expect( imageBlock ).toBeFocused(); + + // Hit backspace to remove the Image block. await page.keyboard.press( 'Backspace' ); - // Verify that there's no blocks and only the block appender button is - // visible. + // Ensure that there's no blocks. await expect.poll( editor.getBlocks ).toHaveLength( 0 ); await expect( editor.canvas.getByRole( 'document', { name: /Empty block/i } ) ).not.toBeVisible(); + + // Ensure that the block appender button is visible. await expect( editor.canvas.getByRole( 'button', { name: 'Add block' } ) ).toBeVisible(); + // TODO: There should be expectations around where focus is placed in // this scenario. Currently, a focus loss occurs, which is unacceptable. } ); From f45925cbfa86b33264d821ee7491e42adc2376ea Mon Sep 17 00:00:00 2001 From: Bart Kalisz Date: Tue, 14 Feb 2023 12:50:17 +0100 Subject: [PATCH 12/14] Update a few titles --- test/e2e/specs/editor/various/block-deletion.spec.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/e2e/specs/editor/various/block-deletion.spec.js b/test/e2e/specs/editor/various/block-deletion.spec.js index 3c57dbc7a10ef..402d179963210 100644 --- a/test/e2e/specs/editor/various/block-deletion.spec.js +++ b/test/e2e/specs/editor/various/block-deletion.spec.js @@ -8,7 +8,7 @@ test.describe( 'Block deletion', () => { await admin.createNewPost(); } ); - test( 'deleting last block via its options menu', async ( { + test( 'deleting the last block via its options menu', async ( { editor, page, } ) => { @@ -62,7 +62,7 @@ test.describe( 'Block deletion', () => { ] ); } ); - test( 'deleting last block via the keyboard shortcut', async ( { + test( 'deleting the last block via the keyboard shortcut', async ( { editor, page, pageUtils, @@ -110,7 +110,7 @@ test.describe( 'Block deletion', () => { ] ); } ); - test( 'deleting last block via backspace from an empty paragraph', async ( { + test( 'deleting the last block via backspace from an empty paragraph', async ( { editor, page, } ) => { @@ -197,7 +197,7 @@ test.describe( 'Block deletion', () => { ] ); } ); - test( 'deleting last two selected blocks via backspace', async ( { + test( 'deleting the last two selected blocks via backspace', async ( { editor, page, pageUtils, From 4008b6fcf8c7002ae211c97e047dbe552e7bf0af Mon Sep 17 00:00:00 2001 From: Bart Kalisz Date: Fri, 24 Feb 2023 12:03:17 +0100 Subject: [PATCH 13/14] Don't use unnecessary regex matching Not needed since Playwright v1.28 --- .../specs/editor/various/block-deletion.spec.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/e2e/specs/editor/various/block-deletion.spec.js b/test/e2e/specs/editor/various/block-deletion.spec.js index 402d179963210..94bb016e21864 100644 --- a/test/e2e/specs/editor/various/block-deletion.spec.js +++ b/test/e2e/specs/editor/various/block-deletion.spec.js @@ -42,7 +42,7 @@ test.describe( 'Block deletion', () => { .getByRole( 'button', { name: 'Options' } ) .click(); await page - .getByRole( 'menuitem', { name: /Remove Paragraph/i } ) + .getByRole( 'menuitem', { name: 'Remove Paragraph' } ) .click(); // Ensure the last block was removed. @@ -129,7 +129,7 @@ test.describe( 'Block deletion', () => { name: 'core/paragraph', } ); await expect( - editor.canvas.getByRole( 'document', { name: /Empty block/i } ) + editor.canvas.getByRole( 'document', { name: 'Empty block' } ) ).toBeFocused(); // Hit backspace to remove the empty paragraph. @@ -222,7 +222,7 @@ test.describe( 'Block deletion', () => { // Ensure the empty paragraph is focused. await expect( editor.canvas.getByRole( 'document', { - name: /Empty block/i, + name: 'Empty block', } ) ).toBeFocused(); @@ -245,7 +245,7 @@ test.describe( 'Block deletion', () => { await expect.poll( editor.getBlocks ).toHaveLength( 3 ); await expect( editor.canvas.getByRole( 'document', { - name: /Empty block/i, + name: 'Empty block', } ) ).toBeFocused(); } ); @@ -269,13 +269,13 @@ test.describe( 'Block deletion', () => { .getByRole( 'button', { name: 'Options' } ) .click(); await page - .getByRole( 'menuitem', { name: /Remove Paragraph/i } ) + .getByRole( 'menuitem', { name: 'Remove Paragraph' } ) .click(); // Ensure an empty block was created and focused. await expect( editor.canvas.getByRole( 'document', { - name: /Empty block/i, + name: 'Empty block', } ) ).toBeFocused(); await expect.poll( editor.getBlocks ).toEqual( [] ); @@ -329,7 +329,7 @@ test.describe( 'Block deletion', () => { // Ensure that there's no blocks. await expect.poll( editor.getBlocks ).toHaveLength( 0 ); await expect( - editor.canvas.getByRole( 'document', { name: /Empty block/i } ) + editor.canvas.getByRole( 'document', { name: 'Empty block' } ) ).not.toBeVisible(); // Ensure that the block appender button is visible. From 9b27419a1fb7b6cf7b4fa3919e4be06c7fcefd30 Mon Sep 17 00:00:00 2001 From: Bart Kalisz Date: Fri, 24 Feb 2023 12:08:54 +0100 Subject: [PATCH 14/14] Check multi-block selection via data API --- test/e2e/specs/editor/various/block-deletion.spec.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/test/e2e/specs/editor/various/block-deletion.spec.js b/test/e2e/specs/editor/various/block-deletion.spec.js index 94bb016e21864..efcf7b7d5a282 100644 --- a/test/e2e/specs/editor/various/block-deletion.spec.js +++ b/test/e2e/specs/editor/various/block-deletion.spec.js @@ -228,9 +228,15 @@ test.describe( 'Block deletion', () => { // Select the last two paragraphs. await pageUtils.pressKeyWithModifier( 'shift', 'ArrowUp' ); - await expect( - editor.canvas.locator( '.is-multi-selected' ) - ).toHaveCount( 2 ); + await expect + .poll( () => + page.evaluate( () => + window.wp.data + .select( 'core/block-editor' ) + .getMultiSelectedBlocks() + ) + ) + .toHaveLength( 2 ); // Hit backspace and ensure the last two paragraphs were deleted, and an // empty block was created.