From fd087a665c81ba66ddab3e077da16923caf231b8 Mon Sep 17 00:00:00 2001 From: Jerry Jones Date: Tue, 16 May 2023 15:54:42 -0500 Subject: [PATCH 1/5] Combine frontend navigation tests into one test to speed up e2e tests There is quite a bit of setup needed for each of the frontend navigation tests, and by combining them into one we can speed it up and follow the best practices of write fewer but longer tests: https://playwright.dev/docs/best-practices#write-fewer-tests-but-longer-tests --- .../specs/editor/blocks/navigation.spec.js | 47 ++++--------------- 1 file changed, 8 insertions(+), 39 deletions(-) diff --git a/test/e2e/specs/editor/blocks/navigation.spec.js b/test/e2e/specs/editor/blocks/navigation.spec.js index e35346efca56b..eba3b64ad65e6 100644 --- a/test/e2e/specs/editor/blocks/navigation.spec.js +++ b/test/e2e/specs/editor/blocks/navigation.spec.js @@ -1278,7 +1278,7 @@ test.describe( 'Navigation block - Frontend interactivity', () => { await editor.saveSiteEditorEntities(); } ); - test( 'page-list submenu opens on click', async ( { page } ) => { + test( 'page-list submenu user interactions', async ( { page } ) => { await page.goto( '/' ); const submenuButton = page.getByRole( 'button', { name: 'Parent Page', @@ -1287,58 +1287,27 @@ test.describe( 'Navigation block - Frontend interactivity', () => { name: 'Subpage', } ); await expect( innerElement ).toBeHidden(); - await submenuButton.click(); - await expect( innerElement ).toBeVisible(); - } ); - test( 'page-list submenu closes on click outside', async ( { - page, - } ) => { - await page.goto( '/' ); - const submenuButton = page.getByRole( 'button', { - name: 'Parent Page', - } ); - const innerElement = page.getByRole( 'link', { - name: 'Subpage', - } ); - await expect( innerElement ).toBeHidden(); + // page-list submenu opens on click await submenuButton.click(); await expect( innerElement ).toBeVisible(); + + // page-list submenu closes on click outside await page.click( 'body' ); await expect( innerElement ).toBeHidden(); - } ); - test( 'page-list submenu closes on ESC key', async ( { page } ) => { - await page.goto( '/' ); - const submenuButton = page.getByRole( 'button', { - name: 'Parent Page', - } ); - const innerElement = page.getByRole( 'link', { - name: 'Subpage', - } ); - await expect( innerElement ).toBeHidden(); + // page-list submenu opens on enter keypress await submenuButton.focus(); await page.keyboard.press( 'Enter' ); await expect( innerElement ).toBeVisible(); + + // page-list submenu closes on ESC key and focuses submenu button await page.keyboard.press( 'Escape' ); await expect( innerElement ).toBeHidden(); await expect( submenuButton ).toBeFocused(); - } ); - test( 'page-list submenu closes on tab outside submenu', async ( { - page, - } ) => { - await page.goto( '/' ); - const submenuButton = page.getByRole( 'button', { - name: 'Parent Page', - } ); - const innerElement = page.getByRole( 'link', { - name: 'Subpage', - } ); - await expect( innerElement ).toBeHidden(); - await submenuButton.focus(); + // page-list submenu closes on tab outside submenu await page.keyboard.press( 'Enter' ); - await expect( innerElement ).toBeVisible(); // Tab to first element. await page.keyboard.press( 'Tab' ); // Tab outside the submenu. From 30977ea4abe9240dd02fef474a3385f14de23954 Mon Sep 17 00:00:00 2001 From: Jerry Jones Date: Tue, 16 May 2023 16:40:07 -0500 Subject: [PATCH 2/5] Simplify setup logic for creating navigation menu for frontend interaction tests --- .../specs/editor/blocks/navigation.spec.js | 32 ++++--------------- 1 file changed, 7 insertions(+), 25 deletions(-) diff --git a/test/e2e/specs/editor/blocks/navigation.spec.js b/test/e2e/specs/editor/blocks/navigation.spec.js index eba3b64ad65e6..f8eb24adc394a 100644 --- a/test/e2e/specs/editor/blocks/navigation.spec.js +++ b/test/e2e/specs/editor/blocks/navigation.spec.js @@ -1229,35 +1229,17 @@ test.describe( 'Navigation block - Frontend interactivity', () => { } ); test.describe( 'Page list block', () => { - test.beforeEach( async ( { admin, editor, page, requestUtils } ) => { - // Create parent page. - await admin.createNewPost( { - postType: 'page', + test.beforeEach( async ( { admin, editor, requestUtils } ) => { + const parentPage = await requestUtils.createPage( { title: 'Parent Page', + status: 'publish', } ); - await editor.publishPost(); - // Create subpage. - await admin.createNewPost( { - postType: 'page', + await requestUtils.createPage( { title: 'Subpage', + status: 'publish', + parent: parentPage.id, } ); - await editor.openDocumentSettingsSidebar(); - const parentPageList = page.getByLabel( 'Parent page:' ); - if ( await parentPageList.isHidden() ) { - await page - .getByRole( 'button', { - name: 'Page Attributes', - } ) - .click(); - } - await parentPageList.click(); - await page - .getByRole( 'option', { - name: 'Parent Page', - } ) - .click(); - await editor.publishPost(); await admin.visitSiteEditor( { postId: 'emptytheme//header', @@ -1265,7 +1247,7 @@ test.describe( 'Navigation block - Frontend interactivity', () => { } ); await editor.canvas.click( 'body' ); await requestUtils.createNavigationMenu( { - title: 'Hidden menu', + title: 'Page list menu', content: ` From 1080f040a4eceea33044a8f00a8517234dd1d78e Mon Sep 17 00:00:00 2001 From: Jerry Jones Date: Tue, 16 May 2023 16:53:58 -0500 Subject: [PATCH 3/5] Combine submenu interaction tests into one test --- test/e2e/artifacts/storage-states/admin.json | 1 + .../specs/editor/blocks/navigation.spec.js | 140 +++--------------- 2 files changed, 22 insertions(+), 119 deletions(-) create mode 100644 test/e2e/artifacts/storage-states/admin.json diff --git a/test/e2e/artifacts/storage-states/admin.json b/test/e2e/artifacts/storage-states/admin.json new file mode 100644 index 0000000000000..cd90306028e8a --- /dev/null +++ b/test/e2e/artifacts/storage-states/admin.json @@ -0,0 +1 @@ +{"cookies":[{"name":"wordpress_test_cookie","value":"WP%20Cookie%20check","domain":"localhost","path":"/","expires":-1,"httpOnly":false,"secure":false,"sameSite":"Lax"},{"name":"wordpress_23778236db82f19306f247e20a353a99","value":"admin%7C1684446357%7Cdx01QADx42SHH9s4ikPkhkS07FzxnWES5FY2SsnwL7v%7C45404d74460259bc9148f2357f2180af488d65921b10ed5981fff860afa5c8ca","domain":"localhost","path":"/wp-content/plugins","expires":-1,"httpOnly":true,"secure":false,"sameSite":"Lax"},{"name":"wordpress_23778236db82f19306f247e20a353a99","value":"admin%7C1684446357%7Cdx01QADx42SHH9s4ikPkhkS07FzxnWES5FY2SsnwL7v%7C45404d74460259bc9148f2357f2180af488d65921b10ed5981fff860afa5c8ca","domain":"localhost","path":"/wp-admin","expires":-1,"httpOnly":true,"secure":false,"sameSite":"Lax"},{"name":"wordpress_logged_in_23778236db82f19306f247e20a353a99","value":"admin%7C1684446357%7Cdx01QADx42SHH9s4ikPkhkS07FzxnWES5FY2SsnwL7v%7C8ace4a8f867bc4e587d5264662296f90fcd133710cd0dd3386a92801816bd5d1","domain":"localhost","path":"/","expires":-1,"httpOnly":true,"secure":false,"sameSite":"Lax"},{"name":"wp-settings-1","value":"editor%3Dtinymce","domain":"localhost","path":"/","expires":1715809558.14,"httpOnly":false,"secure":false,"sameSite":"Lax"},{"name":"wp-settings-time-1","value":"1684273558","domain":"localhost","path":"/","expires":1715809558.14,"httpOnly":false,"secure":false,"sameSite":"Lax"}],"nonce":"fe590a7aae","rootURL":"http://localhost:8889/index.php?rest_route=/"} \ No newline at end of file diff --git a/test/e2e/specs/editor/blocks/navigation.spec.js b/test/e2e/specs/editor/blocks/navigation.spec.js index f8eb24adc394a..5dfbf0dff2214 100644 --- a/test/e2e/specs/editor/blocks/navigation.spec.js +++ b/test/e2e/specs/editor/blocks/navigation.spec.js @@ -958,7 +958,7 @@ test.describe( 'Navigation block - Frontend interactivity', () => { } ); } ); - test.describe( 'Submenus (Open on click)', () => { + test.describe( 'Submenu interactions', () => { test.beforeEach( async ( { admin, editor, requestUtils } ) => { await admin.visitSiteEditor( { postId: 'emptytheme//header', @@ -989,7 +989,7 @@ test.describe( 'Navigation block - Frontend interactivity', () => { await editor.saveSiteEditorEntities(); } ); - test( 'submenu opens on click', async ( { page } ) => { + test( 'Submenus interactions', async ( { page } ) => { await page.goto( '/' ); const simpleSubmenuButton = page.getByRole( 'button', { name: 'Simple Submenu', @@ -997,13 +997,6 @@ test.describe( 'Navigation block - Frontend interactivity', () => { const innerElement = page.getByRole( 'link', { name: 'Simple Submenu Link 1', } ); - await expect( innerElement ).toBeHidden(); - await simpleSubmenuButton.click(); - await expect( innerElement ).toBeVisible(); - } ); - - test( 'nested submenu opens on click', async ( { page } ) => { - await page.goto( '/' ); const complexSubmenuButton = page.getByRole( 'button', { name: 'Complex Submenu', } ); @@ -1016,6 +1009,17 @@ test.describe( 'Navigation block - Frontend interactivity', () => { const secondLevelElement = page.getByRole( 'link', { name: 'Nested Submenu Link 1', } ); + + // Test: submenu opens on click + await expect( innerElement ).toBeHidden(); + await simpleSubmenuButton.click(); + await expect( innerElement ).toBeVisible(); + + // Test: submenu closes on click outside submenu + await page.click( 'body' ); + await expect( innerElement ).toBeHidden(); + + // Test: nested submenu opens on click await complexSubmenuButton.click(); await expect( firstLevelElement ).toBeVisible(); await expect( secondLevelElement ).toBeHidden(); @@ -1023,53 +1027,23 @@ test.describe( 'Navigation block - Frontend interactivity', () => { await nestedSubmenuButton.click(); await expect( firstLevelElement ).toBeVisible(); await expect( secondLevelElement ).toBeVisible(); - } ); - test( 'submenu closes on click outside', async ( { page } ) => { - await page.goto( '/' ); - const simpleSubmenuButton = page.getByRole( 'button', { - name: 'Simple Submenu', - } ); - const innerElement = page.getByRole( 'link', { - name: 'Simple Submenu Link 1', - includeHidden: true, - } ); - await expect( innerElement ).toBeHidden(); - await simpleSubmenuButton.click(); - await expect( innerElement ).toBeVisible(); + // Test: nested submenus close on click outside submenu await page.click( 'body' ); - await expect( innerElement ).toBeHidden(); - } ); + await expect( firstLevelElement ).toBeHidden(); + await expect( secondLevelElement ).toBeHidden(); - test( 'submenu closes on ESC key', async ( { page } ) => { - await page.goto( '/' ); - const simpleSubmenuButton = page.getByRole( 'button', { - name: 'Simple Submenu', - } ); - const innerElement = page.getByRole( 'link', { - name: 'Simple Submenu Link 1', - } ); - await expect( innerElement ).toBeHidden(); + // Test: submenu opens on Enter keypress await simpleSubmenuButton.focus(); await page.keyboard.press( 'Enter' ); await expect( innerElement ).toBeVisible(); + + // Test: submenu closes on ESC key and focuses parent link await page.keyboard.press( 'Escape' ); await expect( innerElement ).toBeHidden(); await expect( simpleSubmenuButton ).toBeFocused(); - } ); - test( 'submenu closes on tab outside submenu', async ( { page } ) => { - await page.goto( '/' ); - const simpleSubmenuButton = page.getByRole( 'button', { - name: 'Simple Submenu', - } ); - const complexSubmenuButton = page.getByRole( 'button', { - name: 'Complex Submenu', - } ); - const innerElement = page.getByRole( 'link', { - name: 'Simple Submenu Link 1', - } ); - await expect( innerElement ).toBeHidden(); + // Test: submenu closes on tab outside submenu await simpleSubmenuButton.focus(); await page.keyboard.press( 'Enter' ); await expect( innerElement ).toBeVisible(); @@ -1079,80 +1053,8 @@ test.describe( 'Navigation block - Frontend interactivity', () => { await page.keyboard.press( 'Tab' ); await expect( innerElement ).toBeHidden(); await expect( complexSubmenuButton ).toBeFocused(); - } ); - - test( 'nested submenu closes on click outside', async ( { page } ) => { - await page.goto( '/' ); - const complexSubmenuButton = page.getByRole( 'button', { - name: 'Complex Submenu', - } ); - const nestedSubmenuButton = page.getByRole( 'button', { - name: 'Nested Submenu', - } ); - const firstLevelElement = page.getByRole( 'link', { - name: 'Complex Submenu Link 1', - } ); - const secondLevelElement = page.getByRole( 'link', { - name: 'Nested Submenu Link 1', - } ); - await complexSubmenuButton.click(); - await expect( firstLevelElement ).toBeVisible(); - await expect( secondLevelElement ).toBeHidden(); - - await nestedSubmenuButton.click(); - await expect( firstLevelElement ).toBeVisible(); - await expect( secondLevelElement ).toBeVisible(); - - await page.click( 'body' ); - await expect( firstLevelElement ).toBeHidden(); - await expect( secondLevelElement ).toBeHidden(); - } ); - - test( 'nested submenu closes on ESC key', async ( { page } ) => { - await page.goto( '/' ); - const complexSubmenuButton = page.getByRole( 'button', { - name: 'Complex Submenu', - } ); - const nestedSubmenuButton = page.getByRole( 'button', { - name: 'Nested Submenu', - } ); - const firstLevelElement = page.getByRole( 'link', { - name: 'Complex Submenu Link 1', - } ); - const secondLevelElement = page.getByRole( 'link', { - name: 'Nested Submenu Link 1', - } ); - await complexSubmenuButton.focus(); - await page.keyboard.press( 'Enter' ); - await expect( firstLevelElement ).toBeVisible(); - await expect( secondLevelElement ).toBeHidden(); - - await nestedSubmenuButton.click(); - await expect( firstLevelElement ).toBeVisible(); - await expect( secondLevelElement ).toBeVisible(); - - await page.keyboard.press( 'Escape' ); - await expect( firstLevelElement ).toBeHidden(); - await expect( secondLevelElement ).toBeHidden(); - await expect( complexSubmenuButton ).toBeFocused(); - } ); - test( 'only nested submenu closes on tab outside', async ( { - page, - } ) => { - await page.goto( '/' ); - const complexSubmenuButton = page.getByRole( 'button', { - name: 'Complex Submenu', - } ); - const nestedSubmenuButton = page.getByRole( 'button', { - name: 'Nested Submenu', - } ); - const firstLevelElement = page.getByRole( 'link', { - name: 'Complex Submenu Link 1', - } ); - const secondLevelElement = page.getByRole( 'link', { - name: 'Nested Submenu Link 1', - } ); + // Test: only nested submenu closes on tab outside await complexSubmenuButton.focus(); await page.keyboard.press( 'Enter' ); await expect( firstLevelElement ).toBeVisible(); From 4556669c3d0f869d5282162308ef1b1c31e4bd9b Mon Sep 17 00:00:00 2001 From: Jerry Jones Date: Tue, 16 May 2023 16:58:11 -0500 Subject: [PATCH 4/5] Rename parent test to make it more clearly different from child test --- test/e2e/specs/editor/blocks/navigation.spec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/e2e/specs/editor/blocks/navigation.spec.js b/test/e2e/specs/editor/blocks/navigation.spec.js index 5dfbf0dff2214..0f44482109df6 100644 --- a/test/e2e/specs/editor/blocks/navigation.spec.js +++ b/test/e2e/specs/editor/blocks/navigation.spec.js @@ -958,7 +958,7 @@ test.describe( 'Navigation block - Frontend interactivity', () => { } ); } ); - test.describe( 'Submenu interactions', () => { + test.describe( 'Submenu mouse and keyboard interactions', () => { test.beforeEach( async ( { admin, editor, requestUtils } ) => { await admin.visitSiteEditor( { postId: 'emptytheme//header', @@ -989,7 +989,7 @@ test.describe( 'Navigation block - Frontend interactivity', () => { await editor.saveSiteEditorEntities(); } ); - test( 'Submenus interactions', async ( { page } ) => { + test( 'Submenu interactions', async ( { page } ) => { await page.goto( '/' ); const simpleSubmenuButton = page.getByRole( 'button', { name: 'Simple Submenu', From ca8a21dc7e0c24ea416f166fb55d7428ee8042ee Mon Sep 17 00:00:00 2001 From: Jerry Jones Date: Tue, 16 May 2023 17:03:05 -0500 Subject: [PATCH 5/5] Combine overlay menu interactions into one test --- .../specs/editor/blocks/navigation.spec.js | 85 ++++--------------- 1 file changed, 16 insertions(+), 69 deletions(-) diff --git a/test/e2e/specs/editor/blocks/navigation.spec.js b/test/e2e/specs/editor/blocks/navigation.spec.js index 0f44482109df6..103e4bc9d5715 100644 --- a/test/e2e/specs/editor/blocks/navigation.spec.js +++ b/test/e2e/specs/editor/blocks/navigation.spec.js @@ -863,9 +863,7 @@ test.describe( 'Navigation block - Frontend interactivity', () => { await editor.saveSiteEditorEntities(); } ); - test( 'overlay menu opens on click on open menu button', async ( { - page, - } ) => { + test( 'Overlay menu interactions', async ( { page } ) => { await page.goto( '/' ); const overlayMenuFirstElement = page.getByRole( 'link', { name: 'Item 1', @@ -874,87 +872,36 @@ test.describe( 'Navigation block - Frontend interactivity', () => { name: 'Open menu', } ); - await expect( overlayMenuFirstElement ).toBeHidden(); - await openMenuButton.click(); - await expect( overlayMenuFirstElement ).toBeVisible(); - } ); - - test( 'overlay menu closes on click on close menu button', async ( { - page, - } ) => { - await page.goto( '/' ); - const overlayMenuFirstElement = page.getByRole( 'link', { - name: 'Item 1', - } ); - const openMenuButton = page.getByRole( 'button', { - name: 'Open menu', - } ); const closeMenuButton = page.getByRole( 'button', { name: 'Close menu', } ); - await expect( overlayMenuFirstElement ).toBeHidden(); - await openMenuButton.click(); - await expect( overlayMenuFirstElement ).toBeVisible(); - await closeMenuButton.click(); - await expect( overlayMenuFirstElement ).toBeHidden(); - } ); - test( 'overlay menu closes on ESC key', async ( { page } ) => { - await page.goto( '/' ); - const overlayMenuFirstElement = page.getByRole( 'link', { - name: 'Item 1', - } ); - const openMenuButton = page.getByRole( 'button', { - name: 'Open menu', - } ); + // Test: overlay menu opens on click on open menu button await expect( overlayMenuFirstElement ).toBeHidden(); - await openMenuButton.focus(); - await page.keyboard.press( 'Enter' ); + await openMenuButton.click(); await expect( overlayMenuFirstElement ).toBeVisible(); - await page.keyboard.press( 'Escape' ); - await expect( overlayMenuFirstElement ).toBeHidden(); - await expect( openMenuButton ).toBeFocused(); - } ); - test( 'overlay menu focuses on first element after opening', async ( { - page, - } ) => { - await page.goto( '/' ); - const overlayMenuFirstElement = page.getByRole( 'link', { - name: 'Item 1', - } ); - const openMenuButton = page.getByRole( 'button', { - name: 'Open menu', - } ); - await expect( overlayMenuFirstElement ).toBeHidden(); - await openMenuButton.focus(); - await page.keyboard.press( 'Enter' ); - await expect( overlayMenuFirstElement ).toBeVisible(); + // Test: overlay menu focuses on first element after opening await expect( overlayMenuFirstElement ).toBeFocused(); - } ); - test( 'overlay menu traps focus', async ( { page } ) => { - await page.goto( '/' ); - const overlayMenuFirstElement = page.getByRole( 'link', { - name: 'Item 1', - } ); - const openMenuButton = page.getByRole( 'button', { - name: 'Open menu', - } ); - const closeMenuButton = page.getByRole( 'button', { - name: 'Close menu', - } ); - await expect( overlayMenuFirstElement ).toBeHidden(); - await openMenuButton.focus(); - await page.keyboard.press( 'Enter' ); - await expect( overlayMenuFirstElement ).toBeVisible(); - await expect( overlayMenuFirstElement ).toBeFocused(); + // Test: overlay menu traps focus await page.keyboard.press( 'Tab' ); await page.keyboard.press( 'Tab' ); await expect( closeMenuButton ).toBeFocused(); await page.keyboard.press( 'Shift+Tab' ); await page.keyboard.press( 'Shift+Tab' ); await expect( overlayMenuFirstElement ).toBeFocused(); + + // Test: overlay menu closes on click on close menu button + await closeMenuButton.click(); + await expect( overlayMenuFirstElement ).toBeHidden(); + + // Test: overlay menu closes on ESC key + await openMenuButton.click(); + await expect( overlayMenuFirstElement ).toBeVisible(); + await page.keyboard.press( 'Escape' ); + await expect( overlayMenuFirstElement ).toBeHidden(); + await expect( openMenuButton ).toBeFocused(); } ); } );