diff --git a/packages/e2e-tests/specs/editor/various/__snapshots__/block-hierarchy-navigation.test.js.snap b/packages/e2e-tests/specs/editor/various/__snapshots__/block-hierarchy-navigation.test.js.snap
deleted file mode 100644
index b4d171f170d918..00000000000000
--- a/packages/e2e-tests/specs/editor/various/__snapshots__/block-hierarchy-navigation.test.js.snap
+++ /dev/null
@@ -1,63 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`Navigating the block hierarchy should appear and function even without nested blocks 1`] = `
-"
-
and I say hello
-
-
-
-
-"
-`;
-
-exports[`Navigating the block hierarchy should navigate block hierarchy using only the keyboard 1`] = `
-"
-
-"
-`;
-
-exports[`Navigating the block hierarchy should navigate using the list view sidebar 1`] = `
-"
-
-"
-`;
-
-exports[`Navigating the block hierarchy should select the wrapper div for a group 1`] = `
-"
-
-
just a paragraph
-
-
-
-
-
-"
-`;
diff --git a/packages/e2e-tests/specs/editor/various/block-hierarchy-navigation.test.js b/packages/e2e-tests/specs/editor/various/block-hierarchy-navigation.test.js
deleted file mode 100644
index 9737007ce656e4..00000000000000
--- a/packages/e2e-tests/specs/editor/various/block-hierarchy-navigation.test.js
+++ /dev/null
@@ -1,230 +0,0 @@
-/**
- * WordPress dependencies
- */
-import {
- createNewPost,
- insertBlock,
- getEditedPostContent,
- pressKeyTimes,
- pressKeyWithModifier,
- openDocumentSettingsSidebar,
- getListViewBlocks,
- switchBlockInspectorTab,
- canvas,
-} from '@wordpress/e2e-test-utils';
-
-async function openListViewSidebar() {
- await pressKeyWithModifier( 'access', 'o' );
- await page.waitForSelector( '.block-editor-list-view-leaf.is-selected' );
-}
-
-async function tabToColumnsControl() {
- let isColumnsControl = false;
- do {
- await page.keyboard.press( 'Tab' );
-
- const isBlockInspectorTab = await page.evaluate( () => {
- const activeElement = document.activeElement;
- return (
- activeElement.getAttribute( 'role' ) === 'tab' &&
- activeElement.attributes.getNamedItem( 'aria-label' ).value ===
- 'Styles'
- );
- } );
-
- if ( isBlockInspectorTab ) {
- await page.keyboard.press( 'ArrowRight' );
- }
-
- isColumnsControl = await page.evaluate( () => {
- const activeElement = document.activeElement;
- return (
- activeElement.tagName === 'INPUT' &&
- activeElement.attributes.getNamedItem( 'aria-label' ).value ===
- 'Columns'
- );
- } );
- } while ( ! isColumnsControl );
-}
-
-describe( 'Navigating the block hierarchy', () => {
- beforeEach( async () => {
- await createNewPost();
- } );
-
- it( 'should navigate using the list view sidebar', async () => {
- await insertBlock( 'Columns' );
- await canvas().click( '[aria-label="Two columns; equal split"]' );
-
- // Add a paragraph in the first column.
- await page.keyboard.press( 'ArrowDown' ); // Navigate to inserter.
- await page.keyboard.press( 'Enter' ); // Activate inserter.
- // Wait for inserter results to appear and then insert a paragraph.
- await page.waitForSelector(
- '.block-editor-inserter__quick-inserter-results .editor-block-list-item-paragraph'
- );
- await page.click( '.editor-block-list-item-paragraph' );
- await page.keyboard.type( 'First column' );
-
- // Navigate to the columns blocks.
- await page.click(
- '.edit-post-header-toolbar__document-overview-toggle'
- );
-
- const firstColumnsBlockMenuItem = (
- await getListViewBlocks( 'Columns' )
- )[ 0 ];
- await firstColumnsBlockMenuItem.click();
-
- // Tweak the columns count.
- await openDocumentSettingsSidebar();
- await switchBlockInspectorTab( 'Settings' );
- await page.focus(
- '.block-editor-block-inspector [aria-label="Columns"][type="number"]'
- );
- await page.keyboard.down( 'Shift' );
- await page.keyboard.press( 'ArrowLeft' );
- await page.keyboard.up( 'Shift' );
- await page.keyboard.type( '3' );
-
- // Wait for the new column block to appear in the list view
- // 5 = Columns, Column, Paragraph, Column, *Column*
- await page.waitForSelector(
- 'tr.block-editor-list-view-leaf:nth-of-type(5)'
- );
-
- // Navigate to the last column block.
- const lastColumnBlockMenuItem = (
- await getListViewBlocks( 'Column' )
- )[ 2 ];
- await lastColumnBlockMenuItem.click();
-
- // Insert text in the last column block.
- await page.keyboard.press( 'ArrowDown' ); // Navigate to inserter.
- await page.keyboard.press( 'Enter' ); // Activate inserter.
- // Wait for inserter results to appear and then insert a paragraph.
- await page.waitForSelector(
- '.block-editor-inserter__quick-inserter-results .editor-block-list-item-paragraph'
- );
- await page.click( '.editor-block-list-item-paragraph' );
- await page.keyboard.type( 'Third column' );
-
- expect( await getEditedPostContent() ).toMatchSnapshot();
- } );
-
- it( 'should navigate block hierarchy using only the keyboard', async () => {
- await insertBlock( 'Columns' );
- await openDocumentSettingsSidebar();
- await canvas().click( '[aria-label="Two columns; equal split"]' );
-
- // Add a paragraph in the first column.
- await page.keyboard.press( 'ArrowDown' ); // Navigate to inserter.
- await page.keyboard.press( 'Enter' ); // Activate inserter.
- // Wait for inserter results to appear and then insert a paragraph.
- await page.waitForSelector(
- '.block-editor-inserter__quick-inserter-results .editor-block-list-item-paragraph'
- );
- await page.click( '.editor-block-list-item-paragraph' );
- await page.keyboard.type( 'First column' );
-
- // Navigate to the columns blocks using the keyboard.
- await openListViewSidebar();
- await pressKeyTimes( 'ArrowUp', 2 );
- await page.keyboard.press( 'Enter' );
-
- // Move focus to the sidebar area.
- await pressKeyWithModifier( 'ctrl', '`' );
- await tabToColumnsControl();
-
- // Tweak the columns count by increasing it by one.
- await page.keyboard.press( 'ArrowRight' );
-
- // Navigate to the third column in the columns block.
- await pressKeyWithModifier( 'ctrlShift', '`' );
- await pressKeyWithModifier( 'ctrlShift', '`' );
- await pressKeyTimes( 'Tab', 3 );
- await pressKeyTimes( 'ArrowDown', 4 );
- await canvas().waitForSelector(
- '.is-highlighted[aria-label="Block: Column (3 of 3)"]'
- );
- await page.keyboard.press( 'Enter' );
- await canvas().waitForSelector(
- '.is-selected[data-type="core/column"]'
- );
-
- // Insert text in the last column block.
- await page.keyboard.press( 'ArrowDown' ); // Navigate to inserter.
- await page.keyboard.press( 'Enter' ); // Activate inserter.
- // Wait for inserter results to appear and then insert a paragraph.
- await page.waitForSelector(
- '.block-editor-inserter__quick-inserter-results .editor-block-list-item-paragraph'
- );
- await page.click( '.editor-block-list-item-paragraph' );
- await page.keyboard.type( 'Third column' );
-
- expect( await getEditedPostContent() ).toMatchSnapshot();
- } );
-
- it( 'should appear and function even without nested blocks', async () => {
- const textString = 'You say goodbye';
-
- await insertBlock( 'Paragraph' );
-
- // Add content so there is a block in the hierarchy.
- await page.keyboard.type( textString );
-
- // Create an image block too.
- await page.keyboard.press( 'Enter' );
- await insertBlock( 'Image' );
-
- // Return to first block.
- await openListViewSidebar();
- await page.keyboard.press( 'ArrowUp' );
- await page.keyboard.press( 'Space' );
-
- // Replace its content.
- await pressKeyWithModifier( 'primary', 'a' );
- await page.keyboard.type( 'and I say hello' );
-
- expect( await getEditedPostContent() ).toMatchSnapshot();
- } );
-
- it( 'should select the wrapper div for a group', async () => {
- // Insert a group block.
- await insertBlock( 'Group' );
- // Select the default, selected Group layout from the variation picker.
- await canvas().click(
- 'button[aria-label="Group: Gather blocks in a container."]'
- );
- // Insert some random blocks.
- // The last block shouldn't be a textual block.
- await canvas().click( '.block-list-appender .block-editor-inserter' );
- const paragraphMenuItem = (
- await page.$x( `//button//span[contains(text(), 'Paragraph')]` )
- )[ 0 ];
- await paragraphMenuItem.click();
- await page.keyboard.type( 'just a paragraph' );
- await insertBlock( 'Separator' );
-
- // Check the Group block content.
- expect( await getEditedPostContent() ).toMatchSnapshot();
-
- // Unselect the blocks.
- await canvas().click( '.editor-post-title' );
-
- // Try selecting the group block using the Outline.
- await page.click(
- '.edit-post-header-toolbar__document-overview-toggle'
- );
- const groupMenuItem = ( await getListViewBlocks( 'Group' ) )[ 0 ];
- await groupMenuItem.click();
-
- // The group block's wrapper should be selected.
- const isGroupBlockSelected = await canvas().evaluate(
- () =>
- document.activeElement.getAttribute( 'data-type' ) ===
- 'core/group'
- );
- expect( isGroupBlockSelected ).toBe( true );
- } );
-} );
diff --git a/test/e2e/specs/editor/various/block-hierarchy-navigation.spec.js b/test/e2e/specs/editor/various/block-hierarchy-navigation.spec.js
new file mode 100644
index 00000000000000..4dc49bc0f7510a
--- /dev/null
+++ b/test/e2e/specs/editor/various/block-hierarchy-navigation.spec.js
@@ -0,0 +1,243 @@
+/**
+ * WordPress dependencies
+ */
+const { test, expect } = require( '@wordpress/e2e-test-utils-playwright' );
+
+const COLUMNS_BLOCK = [
+ {
+ name: 'core/columns',
+ innerBlocks: [
+ {
+ name: 'core/column',
+ innerBlocks: [
+ {
+ name: 'core/paragraph',
+ attributes: { content: 'First column' },
+ },
+ ],
+ },
+ {
+ name: 'core/column',
+ },
+ {
+ name: 'core/column',
+ innerBlocks: [
+ {
+ name: 'core/paragraph',
+ attributes: { content: 'Third column' },
+ },
+ ],
+ },
+ ],
+ },
+];
+
+test.describe( 'Navigating the block hierarchy', () => {
+ test.beforeEach( async ( { admin } ) => {
+ await admin.createNewPost();
+ } );
+
+ test( 'should navigate using the list view sidebar', async ( {
+ editor,
+ page,
+ pageUtils,
+ } ) => {
+ await editor.openDocumentSettingsSidebar();
+ await editor.insertBlock( { name: 'core/columns' } );
+ await editor.canvas.click(
+ 'role=button[name="Two columns; equal split"i]'
+ );
+
+ // Open the block inserter.
+ await page.keyboard.press( 'ArrowDown' );
+ await page.keyboard.press( 'Enter' );
+
+ // Add a paragraph in the first column.
+ const paragraph = page.getByRole( 'option', { name: 'Paragraph' } );
+ await expect( paragraph ).toBeVisible();
+ await paragraph.click();
+ await page.keyboard.type( 'First column' );
+
+ await pageUtils.pressKeys( 'access+o' );
+
+ const listView = page.getByRole( 'treegrid', {
+ name: 'Block navigation structure',
+ } );
+
+ await expect( listView ).toBeVisible();
+ await listView
+ .getByRole( 'gridcell', { name: 'Columns', exact: true } )
+ .click();
+
+ // Tweak the columns count.
+ await page.getByRole( 'spinbutton', { name: 'Columns' } ).fill( '3' );
+
+ // Wait for the new column block to appear in the list view
+ const column = listView.getByRole( 'gridcell', {
+ name: 'Column',
+ exact: true,
+ } );
+ await expect( column ).toHaveCount( 3 );
+
+ await column.last().click();
+
+ // Open the block inserter.
+ await page.keyboard.press( 'ArrowDown' );
+ await page.keyboard.press( 'Enter' );
+
+ await expect( paragraph ).toBeVisible();
+ await paragraph.click();
+ await page.keyboard.type( 'Third column' );
+
+ await expect.poll( editor.getBlocks ).toMatchObject( COLUMNS_BLOCK );
+ } );
+
+ test( 'should navigate block hierarchy using only the keyboard', async ( {
+ editor,
+ page,
+ pageUtils,
+ } ) => {
+ await editor.openDocumentSettingsSidebar();
+ await editor.insertBlock( { name: 'core/columns' } );
+ await editor.canvas.click(
+ 'role=button[name="Two columns; equal split"i]'
+ );
+
+ // Open the block inserter.
+ await page.keyboard.press( 'ArrowDown' );
+ await page.keyboard.press( 'Enter' );
+
+ // Add a paragraph in the first column.
+ const paragraph = page.getByRole( 'option', { name: 'Paragraph' } );
+ await expect( paragraph ).toBeVisible();
+ await paragraph.click();
+ await page.keyboard.type( 'First column' );
+
+ await pageUtils.pressKeys( 'access+o' );
+ const listView = page.getByRole( 'treegrid', {
+ name: 'Block navigation structure',
+ } );
+ await expect( listView ).toBeVisible();
+
+ // Navigate to the columns blocks using the keyboard.
+ await pageUtils.pressKeys( 'ArrowUp', { times: 2 } );
+ await page.keyboard.press( 'Enter' );
+
+ // Move focus to the sidebar area.
+ await pageUtils.pressKeys( 'ctrl+`' );
+
+ // Navigate to the block settings sidebar and tweak the column count.
+ await pageUtils.pressKeys( 'Tab', { times: 5 } );
+ await expect(
+ page.getByRole( 'slider', { name: 'Columns' } )
+ ).toBeFocused();
+ await page.keyboard.press( 'ArrowRight' );
+
+ // Navigate to the third column in the columns block via List View.
+ await pageUtils.pressKeys( 'ctrlShift+`', { times: 2 } );
+ await pageUtils.pressKeys( 'Tab', { times: 3 } );
+ await pageUtils.pressKeys( 'ArrowDown', { times: 4 } );
+
+ // Insert text in the last column block.
+ await page.keyboard.press( 'Enter' );
+ await page.keyboard.press( 'ArrowDown' );
+ await page.keyboard.press( 'Enter' );
+
+ await expect( paragraph ).toBeVisible();
+ await paragraph.click();
+ await page.keyboard.type( 'Third column' );
+
+ await expect.poll( editor.getBlocks ).toMatchObject( COLUMNS_BLOCK );
+ } );
+
+ test( 'should appear and function even without nested blocks', async ( {
+ editor,
+ page,
+ pageUtils,
+ } ) => {
+ await editor.canvas.click( 'role=button[name="Add default block"i]' );
+ await page.keyboard.type( 'You say goodbye' );
+ await page.keyboard.press( 'Enter' );
+ await page.keyboard.type( '## Hello, hello' );
+
+ // Open list view and return to the first block.
+ await pageUtils.pressKeys( 'access+o' );
+ await expect(
+ page.getByRole( 'treegrid', {
+ name: 'Block navigation structure',
+ } )
+ ).toBeVisible();
+ await page.keyboard.press( 'ArrowUp' );
+ await page.keyboard.press( 'Space' );
+
+ // Replace its contents.
+ await pageUtils.pressKeys( 'primary+a' );
+ await page.keyboard.type( 'and I say hello' );
+
+ await expect.poll( editor.getBlocks ).toMatchObject( [
+ {
+ name: 'core/paragraph',
+ attributes: { content: 'and I say hello' },
+ },
+ {
+ name: 'core/heading',
+ },
+ ] );
+ } );
+
+ test( 'should select the wrapper div for a group', async ( {
+ editor,
+ page,
+ pageUtils,
+ } ) => {
+ await editor.insertBlock( { name: 'core/group' } );
+ await editor.canvas.click(
+ 'role=button[name="Group: Gather blocks in a container."i]'
+ );
+
+ // Open the block inserter.
+ await page.keyboard.press( 'ArrowDown' );
+ await page.keyboard.press( 'Enter' );
+
+ // Add some random blocks.
+ const paragraph = page.getByRole( 'option', { name: 'Paragraph' } );
+ await expect( paragraph ).toBeVisible();
+ await paragraph.click();
+ await page.keyboard.type( 'just a paragraph' );
+ await page.keyboard.press( 'Enter' );
+ await page.keyboard.type( '/spacer' );
+ await page.keyboard.press( 'Enter' );
+
+ // Verify group block contents.
+ await expect.poll( editor.getBlocks ).toMatchObject( [
+ {
+ name: 'core/group',
+ innerBlocks: [
+ {
+ name: 'core/paragraph',
+ attributes: { content: 'just a paragraph' },
+ },
+ {
+ name: 'core/spacer',
+ },
+ ],
+ },
+ ] );
+
+ // Deselect the blocks.
+ await editor.canvas.click( 'role=textbox[name="Add title"i]' );
+
+ // Open list view and return to the first block.
+ await pageUtils.pressKeys( 'access+o' );
+ await expect(
+ page.getByRole( 'treegrid', {
+ name: 'Block navigation structure',
+ } )
+ ).toBeVisible();
+ await page.keyboard.press( 'Enter' );
+
+ await expect(
+ editor.canvas.getByRole( 'document', { name: 'Block: Group' } )
+ ).toBeFocused();
+ } );
+} );