From 74b0c57337776f27d5ded798e041581db6ab86be Mon Sep 17 00:00:00 2001 From: Jerry Jones Date: Wed, 4 Dec 2024 09:05:08 -0600 Subject: [PATCH 01/16] Add e2e tests to cover scenarios for useZoomOut hook exiting --- .../site-editor/site-editor-inserter.spec.js | 384 ++++++++++++++++-- 1 file changed, 361 insertions(+), 23 deletions(-) diff --git a/test/e2e/specs/site-editor/site-editor-inserter.spec.js b/test/e2e/specs/site-editor/site-editor-inserter.spec.js index 04075cbedab30..442cb71bc36f0 100644 --- a/test/e2e/specs/site-editor/site-editor-inserter.spec.js +++ b/test/e2e/specs/site-editor/site-editor-inserter.spec.js @@ -5,11 +5,8 @@ const { test, expect } = require( '@wordpress/e2e-test-utils-playwright' ); test.describe( 'Site Editor Inserter', () => { test.beforeAll( async ( { requestUtils } ) => { - await Promise.all( [ - requestUtils.activateTheme( 'emptytheme' ), - requestUtils.deleteAllTemplates( 'wp_template' ), - requestUtils.deleteAllTemplates( 'wp_template_part' ), - ] ); + // We need the theme to have a section root so zoom out is enabled + await requestUtils.activateTheme( 'twentytwentyfour' ); } ); test.afterAll( async ( { requestUtils } ) => { @@ -21,39 +18,40 @@ test.describe( 'Site Editor Inserter', () => { await editor.canvas.locator( 'body' ).click(); } ); + test.use( { + InserterUtils: async ( { editor, page }, use ) => { + await use( new InserterUtils( { editor, page } ) ); + }, + } ); + test( 'inserter toggle button should toggle global inserter', async ( { - page, + InserterUtils, } ) => { - await page.click( 'role=button[name="Block Inserter"i]' ); + const inserterButton = InserterUtils.getInserterButton(); + + await inserterButton.click(); + + const blockLibrary = InserterUtils.getBlockLibrary(); // Visibility check - await expect( - page.locator( 'role=searchbox[name="Search"i]' ) - ).toBeVisible(); - await page.click( 'role=button[name="Block Inserter"i]' ); + await expect( blockLibrary ).toBeVisible(); + await inserterButton.click(); //Hidden State check - await expect( - page.locator( 'role=searchbox[name="Search"i]' ) - ).toBeHidden(); + await expect( blockLibrary ).toBeHidden(); } ); // A test for https://github.com/WordPress/gutenberg/issues/43090. test( 'should close the inserter when clicking on the toggle button', async ( { - page, editor, + InserterUtils, } ) => { - const inserterButton = page.getByRole( 'button', { - name: 'Block Inserter', - exact: true, - } ); - const blockLibrary = page.getByRole( 'region', { - name: 'Block Library', - } ); + const inserterButton = InserterUtils.getInserterButton(); + const blockLibrary = InserterUtils.getBlockLibrary(); const beforeBlocks = await editor.getBlocks(); await inserterButton.click(); - await blockLibrary.getByRole( 'tab', { name: 'Blocks' } ).click(); + await InserterUtils.getBlockLibraryTab( 'Blocks' ).click(); await blockLibrary.getByRole( 'option', { name: 'Buttons' } ).click(); await expect @@ -64,4 +62,344 @@ test.describe( 'Site Editor Inserter', () => { await expect( blockLibrary ).toBeHidden(); } ); + + test( 'should open the inserter to patterns tab if using zoom out and stay in zoom out when closing the inserter', async ( { + InserterUtils, + } ) => { + const zoomOutButton = InserterUtils.getZoomOutButton(); + const inserterButton = InserterUtils.getInserterButton(); + const blockLibrary = InserterUtils.getBlockLibrary(); + + await zoomOutButton.click(); + await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + + await inserterButton.click(); + const patternsTab = InserterUtils.getBlockLibraryTab( 'Patterns' ); + await expect( patternsTab ).toHaveAttribute( + 'data-active-item', + 'true' + ); + await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + + await inserterButton.click(); + + await expect( blockLibrary ).toBeHidden(); + + // We should still be in Zoom Out + await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + } ); + + test( 'should enter zoom out from patterns tab and exit zoom out when closing the inserter', async ( { + InserterUtils, + } ) => { + const inserterButton = InserterUtils.getInserterButton(); + const blockLibrary = InserterUtils.getBlockLibrary(); + + await inserterButton.click(); + await expect( blockLibrary ).toBeVisible(); + await expect( await InserterUtils.getZoomCanvas() ).toBeHidden(); + + const blocksTab = InserterUtils.getBlockLibraryTab( 'Blocks' ); + await expect( blocksTab ).toHaveAttribute( 'data-active-item', 'true' ); + + const patternsTab = InserterUtils.getBlockLibraryTab( 'Patterns' ); + await patternsTab.click(); + await expect( patternsTab ).toHaveAttribute( + 'data-active-item', + 'true' + ); + await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + + await inserterButton.click(); + await expect( blockLibrary ).toBeHidden(); + + await expect( await InserterUtils.getZoomCanvas() ).toBeHidden(); + } ); + + test( 'should always exit zoom out from blocks tab and does not change mode when closing the inserter', async ( { + InserterUtils, + } ) => { + const inserterButton = InserterUtils.getInserterButton(); + const blockLibrary = InserterUtils.getBlockLibrary(); + + // Open inserter + await inserterButton.click(); + await expect( blockLibrary ).toBeVisible(); + + // Blocks tab should be active, not in zoomed out state + const blocksTab = InserterUtils.getBlockLibraryTab( 'Blocks' ); + await expect( blocksTab ).toHaveAttribute( 'data-active-item', 'true' ); + await expect( await InserterUtils.getZoomCanvas() ).toBeHidden(); + + // Click to patterns, should enter zoom out + const patternsTab = InserterUtils.getBlockLibraryTab( 'Patterns' ); + await patternsTab.click(); + await expect( patternsTab ).toHaveAttribute( + 'data-active-item', + 'true' + ); + await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + + // Click to blocks tab, zooms back in + await blocksTab.click(); + await expect( blocksTab ).toHaveAttribute( 'data-active-item', 'true' ); + await expect( await InserterUtils.getZoomCanvas() ).toBeHidden(); + + // Close inserter + await inserterButton.click(); + + await expect( blockLibrary ).toBeHidden(); + + // Canvas stays zoomed in + await expect( await InserterUtils.getZoomCanvas() ).toBeHidden(); + } ); + + // Same test as above, but starting from zoom out + test( 'should always exit zoom out from blocks tab and does not change mode when closing the inserter (even if starting from zoom out)', async ( { + InserterUtils, + } ) => { + const inserterButton = InserterUtils.getInserterButton(); + const blockLibrary = InserterUtils.getBlockLibrary(); + + // Open inserter + await inserterButton.click(); + await expect( blockLibrary ).toBeVisible(); + + // Patterns tab should be active + const patternsTab = InserterUtils.getBlockLibraryTab( 'Patterns' ); + await expect( patternsTab ).toHaveAttribute( + 'data-active-item', + 'true' + ); + await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + + // Click to blocks tab, zooms back in + const blocksTab = InserterUtils.getBlockLibraryTab( 'Blocks' ); + await blocksTab.click(); + await expect( blocksTab ).toHaveAttribute( 'data-active-item', 'true' ); + await expect( await InserterUtils.getZoomCanvas() ).toBeHidden(); + + // Close inserter + await inserterButton.click(); + + await expect( blockLibrary ).toBeHidden(); + + // Canvas stays zoomed in + await expect( await InserterUtils.getZoomCanvas() ).toBeHidden(); + } ); + + // Same test as above but exiting from zoom out + test( 'If we change the zoom level for them via an inserter tab change, always exit zoom out when closing the inserter', async ( { + InserterUtils, + } ) => { + const zoomOutButton = InserterUtils.getZoomOutButton(); + const inserterButton = InserterUtils.getInserterButton(); + const blockLibrary = InserterUtils.getBlockLibrary(); + + await zoomOutButton.click(); + await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + + await inserterButton.click(); + const patternsTab = InserterUtils.getBlockLibraryTab( 'Patterns' ); + const blocksTab = InserterUtils.getBlockLibraryTab( 'Blocks' ); + const mediaTab = InserterUtils.getBlockLibraryTab( 'Media' ); + + // Should start with pattern tab selected in zoom out state + await expect( patternsTab ).toHaveAttribute( + 'data-active-item', + 'true' + ); + await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + + // Go to blocks tab which should exit zoom out + // We changed the zoom state for them here, so we "take over" control of the zoom state + await blocksTab.click(); + await expect( blocksTab ).toHaveAttribute( 'data-active-item', 'true' ); + await expect( await InserterUtils.getZoomCanvas() ).toBeHidden(); + + // Go to media tab which should enter zoom out again since that's the starting state + await mediaTab.click(); + await expect( mediaTab ).toHaveAttribute( 'data-active-item', 'true' ); + await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + + // Close the inserter + await inserterButton.click(); + await expect( blockLibrary ).toBeHidden(); + + // We should stay in zoomed out state since we had control over the zoom state and we always exit zoom out when closing the inserter + await expect( await InserterUtils.getZoomCanvas() ).toBeHidden(); + } ); + + test( 'should always exit zoom out if we have most recently changed zoom level for them', async ( { + InserterUtils, + } ) => { + const zoomOutButton = InserterUtils.getZoomOutButton(); + const inserterButton = InserterUtils.getInserterButton(); + const blockLibrary = InserterUtils.getBlockLibrary(); + + // Enter zoom out + await zoomOutButton.click(); + await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + // Open inserter + await inserterButton.click(); + await expect( blockLibrary ).toBeVisible(); + + // Patterns tab should be active + const patternsTab = InserterUtils.getBlockLibraryTab( 'Patterns' ); + await expect( patternsTab ).toHaveAttribute( + 'data-active-item', + 'true' + ); + await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + + // Click to blocks tab, zooms back in + const blocksTab = InserterUtils.getBlockLibraryTab( 'Blocks' ); + await blocksTab.click(); + await expect( blocksTab ).toHaveAttribute( 'data-active-item', 'true' ); + await expect( await InserterUtils.getZoomCanvas() ).toBeHidden(); + + // Click to media tab, to zoom back out + const mediaTab = InserterUtils.getBlockLibraryTab( 'Media' ); + await mediaTab.click(); + await expect( mediaTab ).toHaveAttribute( 'data-active-item', 'true' ); + await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + + // Close inserter + await inserterButton.click(); + + await expect( blockLibrary ).toBeHidden(); + + // We have taken over zoom state control, so we should exit for them. + await expect( await InserterUtils.getZoomCanvas() ).toBeHidden(); + } ); + + // Test for https://github.com/WordPress/gutenberg/issues/66328 + test( 'should not return you to zoom out if manually disengaged', async ( { + InserterUtils, + } ) => { + const zoomOutButton = InserterUtils.getZoomOutButton(); + const inserterButton = InserterUtils.getInserterButton(); + const blockLibrary = InserterUtils.getBlockLibrary(); + + await zoomOutButton.click(); + await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + + await inserterButton.click(); + await expect( blockLibrary ).toBeVisible(); + const patternsTab = InserterUtils.getBlockLibraryTab( 'Patterns' ); + await expect( patternsTab ).toHaveAttribute( + 'data-active-item', + 'true' + ); + await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + + await zoomOutButton.click(); + await expect( await InserterUtils.getZoomCanvas() ).toBeHidden(); + + // Close the inserter + await inserterButton.click(); + + await expect( blockLibrary ).toBeHidden(); + + // We should not return to zoom out since it was manually disengaged + await expect( await InserterUtils.getZoomCanvas() ).toBeHidden(); + } ); + + // Similar test to the above but starting from not zoomed in and toggle zoom level twice + test( 'starting from zoomed in, should not toggle zoom state when closing the inserter if the user manually changed zoom state', async ( { + InserterUtils, + } ) => { + const zoomOutButton = InserterUtils.getZoomOutButton(); + const inserterButton = InserterUtils.getInserterButton(); + const blockLibrary = InserterUtils.getBlockLibrary(); + + await inserterButton.click(); + + // Go to patterns tab which should enter zoom out + const patternsTab = InserterUtils.getBlockLibraryTab( 'Patterns' ); + await patternsTab.click(); + await expect( patternsTab ).toHaveAttribute( + 'data-active-item', + 'true' + ); + await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + + // Manually toggle zoom out off + await zoomOutButton.click(); + await expect( await InserterUtils.getZoomCanvas() ).toBeHidden(); + + // Manually toggle zoom out again to return to zoomed-in state set by the patterns tab. + await zoomOutButton.click(); + await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + + // Close the inserter + await inserterButton.click(); + + await expect( blockLibrary ).toBeHidden(); + + // We should stay in zoomed out state since it was manually engaged + await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + } ); + + // Similar to above ones, but doing it from the blocks tab (zoomed out) to zoom in + test( 'should not return you to zoom out if manually disengaged from blocks tab', async ( { + InserterUtils, + } ) => { + const zoomOutButton = InserterUtils.getZoomOutButton(); + const inserterButton = InserterUtils.getInserterButton(); + const blockLibrary = InserterUtils.getBlockLibrary(); + + await inserterButton.click(); + await expect( blockLibrary ).toBeVisible(); + + const blocksTab = InserterUtils.getBlockLibraryTab( 'Blocks' ); + await expect( blocksTab ).toHaveAttribute( 'data-active-item', 'true' ); + await expect( await InserterUtils.getZoomCanvas() ).toBeHidden(); + + await zoomOutButton.click(); + await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + + // Close the inserter + await inserterButton.click(); + + await expect( blockLibrary ).toBeHidden(); + + // We should not return to zoom in since it was manually disengaged + await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + } ); } ); + +class InserterUtils { + constructor( { editor, page } ) { + this.editor = editor; + this.page = page; + } + + getInserterButton() { + return this.page.getByRole( 'button', { + name: 'Block Inserter', + exact: true, + } ); + } + + getBlockLibrary() { + return this.page.getByRole( 'region', { + name: 'Block Library', + } ); + } + + getBlockLibraryTab( name ) { + return this.page.getByRole( 'tab', { name } ); + } + + getZoomOutButton() { + return this.page.getByRole( 'button', { + name: 'Zoom Out', + exact: true, + } ); + } + + getZoomCanvas() { + return this.page.locator( '.is-zoomed-out' ); + } +} From 70bb42e37ef6c29fcf4d63b3131b413d9e826960 Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Fri, 15 Nov 2024 17:06:03 +0400 Subject: [PATCH 02/16] Block Editor: Fix 'useZoomOut' hook conflicts --- .../block-editor/src/hooks/use-zoom-out.js | 27 +++++++------------ 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/packages/block-editor/src/hooks/use-zoom-out.js b/packages/block-editor/src/hooks/use-zoom-out.js index bcf5d9ff882f7..584dc55f152cb 100644 --- a/packages/block-editor/src/hooks/use-zoom-out.js +++ b/packages/block-editor/src/hooks/use-zoom-out.js @@ -13,31 +13,24 @@ import { unlock } from '../lock-unlock'; /** * A hook used to set the editor mode to zoomed out mode, invoking the hook sets the mode. * - * @param {boolean} zoomOut If we should enter into zoomOut mode or not + * @param {boolean} enabled If we should enter into zoomOut mode or not */ -export function useZoomOut( zoomOut = true ) { +export function useZoomOut( enabled = true ) { const { setZoomLevel, resetZoomLevel } = unlock( useDispatch( blockEditorStore ) ); const { isZoomOut } = unlock( useSelect( blockEditorStore ) ); useEffect( () => { - const isZoomOutOnMount = isZoomOut(); - - return () => { - if ( isZoomOutOnMount ) { - setZoomLevel( 'auto-scaled' ); - } else { - resetZoomLevel(); - } - }; - }, [] ); + if ( ! enabled ) { + return; + } - useEffect( () => { - if ( zoomOut ) { + const isAlreadyInZoomOut = isZoomOut(); + if ( ! isAlreadyInZoomOut ) { setZoomLevel( 'auto-scaled' ); - } else { - resetZoomLevel(); } - }, [ zoomOut, setZoomLevel, resetZoomLevel ] ); + + return () => ! isAlreadyInZoomOut && resetZoomLevel(); + }, [ enabled, isZoomOut, resetZoomLevel, setZoomLevel ] ); } From af2de843ae7940ba85449e6f56a55c3898e5796b Mon Sep 17 00:00:00 2001 From: Jerry Jones Date: Fri, 15 Nov 2024 10:21:49 -0600 Subject: [PATCH 03/16] Add controlled concept to useZoomOut hook --- .../block-editor/src/hooks/use-zoom-out.js | 35 ++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/packages/block-editor/src/hooks/use-zoom-out.js b/packages/block-editor/src/hooks/use-zoom-out.js index 584dc55f152cb..a51fca1268299 100644 --- a/packages/block-editor/src/hooks/use-zoom-out.js +++ b/packages/block-editor/src/hooks/use-zoom-out.js @@ -2,7 +2,7 @@ * WordPress dependencies */ import { useSelect, useDispatch } from '@wordpress/data'; -import { useEffect } from '@wordpress/element'; +import { useEffect, useRef } from '@wordpress/element'; /** * Internal dependencies @@ -21,16 +21,43 @@ export function useZoomOut( enabled = true ) { ); const { isZoomOut } = unlock( useSelect( blockEditorStore ) ); + const isZoomedOut = isZoomOut(); + // If starting from zoom out engaged, do not control zoom level for the user. + const controlZoomLevel = useRef( ! isZoomedOut ); + useEffect( () => { - if ( ! enabled ) { + if ( ! enabled || ! controlZoomLevel.current ) { return; } - const isAlreadyInZoomOut = isZoomOut(); if ( ! isAlreadyInZoomOut ) { setZoomLevel( 'auto-scaled' ); } - return () => ! isAlreadyInZoomOut && resetZoomLevel(); + return () => { + return ( + controlZoomLevel.current && + ! isAlreadyInZoomOut && + resetZoomLevel() + ); + }; }, [ enabled, isZoomOut, resetZoomLevel, setZoomLevel ] ); + + /** + * This hook tracks if the zoom state was changed manually by the user via clicking + * the zoom out button. + */ + useEffect( () => { + // If the zoom state changed (isZoomOut) and it does not match the requested zoom + // state (zoomOut), then it means the user manually changed the zoom state while + // this hook was mounted, and we should no longer control the zoom state. + if ( isZoomedOut !== enabled ) { + // Turn off all automatic zooming control. + controlZoomLevel.current = false; + } + + // Intentionally excluding `enabled` from the dependency array. We want to catch instances where + // the zoom out state changes due to user interaction and not due to the hook. + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [ isZoomedOut ] ); } From 2871313ed9d47e2e2025802b9b71707f1e7fd0b5 Mon Sep 17 00:00:00 2001 From: Jerry Jones Date: Wed, 4 Dec 2024 11:25:44 -0600 Subject: [PATCH 04/16] Codify useZoomOut behaviors --- .../block-editor/src/hooks/use-zoom-out.js | 37 ++++++------- .../site-editor/site-editor-inserter.spec.js | 53 +++++++++++++++++++ 2 files changed, 72 insertions(+), 18 deletions(-) diff --git a/packages/block-editor/src/hooks/use-zoom-out.js b/packages/block-editor/src/hooks/use-zoom-out.js index a51fca1268299..12d3ef06841bd 100644 --- a/packages/block-editor/src/hooks/use-zoom-out.js +++ b/packages/block-editor/src/hooks/use-zoom-out.js @@ -12,6 +12,9 @@ import { unlock } from '../lock-unlock'; /** * A hook used to set the editor mode to zoomed out mode, invoking the hook sets the mode. + * Concepts: + * - If we most recently changed the zoom level for them (in or out), we always resetZoomLevel() level when unmounting. + * - If the user most recently changed the zoom level (manually toggling), we do nothing when unmounting. * * @param {boolean} enabled If we should enter into zoomOut mode or not */ @@ -22,42 +25,40 @@ export function useZoomOut( enabled = true ) { const { isZoomOut } = unlock( useSelect( blockEditorStore ) ); const isZoomedOut = isZoomOut(); - // If starting from zoom out engaged, do not control zoom level for the user. - const controlZoomLevel = useRef( ! isZoomedOut ); + const controlZoomLevelRef = useRef( false ); + const isEnabledRef = useRef( enabled ); useEffect( () => { - if ( ! enabled || ! controlZoomLevel.current ) { - return; - } - const isAlreadyInZoomOut = isZoomOut(); - if ( ! isAlreadyInZoomOut ) { + isEnabledRef.current = enabled; + const isAlreadyZoomedOut = isZoomOut(); + + if ( enabled && ! isAlreadyZoomedOut ) { setZoomLevel( 'auto-scaled' ); + controlZoomLevelRef.current = true; + } else if ( ! enabled && isAlreadyZoomedOut ) { + resetZoomLevel(); + controlZoomLevelRef.current = true; } return () => { return ( - controlZoomLevel.current && - ! isAlreadyInZoomOut && - resetZoomLevel() + // If we are controlling zoom level and are zoomed out, reset the zoom level. + controlZoomLevelRef.current && isZoomOut() && resetZoomLevel() ); }; }, [ enabled, isZoomOut, resetZoomLevel, setZoomLevel ] ); /** * This hook tracks if the zoom state was changed manually by the user via clicking - * the zoom out button. + * the zoom out button. We only want this to run when isZoomedOut changes, so we use + * a ref to track the enabled state. */ useEffect( () => { // If the zoom state changed (isZoomOut) and it does not match the requested zoom // state (zoomOut), then it means the user manually changed the zoom state while // this hook was mounted, and we should no longer control the zoom state. - if ( isZoomedOut !== enabled ) { - // Turn off all automatic zooming control. - controlZoomLevel.current = false; + if ( isZoomedOut !== isEnabledRef.current ) { + controlZoomLevelRef.current = false; } - - // Intentionally excluding `enabled` from the dependency array. We want to catch instances where - // the zoom out state changes due to user interaction and not due to the hook. - // eslint-disable-next-line react-hooks/exhaustive-deps }, [ isZoomedOut ] ); } diff --git a/test/e2e/specs/site-editor/site-editor-inserter.spec.js b/test/e2e/specs/site-editor/site-editor-inserter.spec.js index 442cb71bc36f0..e5581fc39508f 100644 --- a/test/e2e/specs/site-editor/site-editor-inserter.spec.js +++ b/test/e2e/specs/site-editor/site-editor-inserter.spec.js @@ -158,9 +158,13 @@ test.describe( 'Site Editor Inserter', () => { test( 'should always exit zoom out from blocks tab and does not change mode when closing the inserter (even if starting from zoom out)', async ( { InserterUtils, } ) => { + const zoomOutButton = InserterUtils.getZoomOutButton(); const inserterButton = InserterUtils.getInserterButton(); const blockLibrary = InserterUtils.getBlockLibrary(); + await zoomOutButton.click(); + await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + // Open inserter await inserterButton.click(); await expect( blockLibrary ).toBeVisible(); @@ -305,6 +309,49 @@ test.describe( 'Site Editor Inserter', () => { await expect( await InserterUtils.getZoomCanvas() ).toBeHidden(); } ); + // Similar test to the above but toggle zoom level twice + test( 'should not toggle zoom state from pattern tab when closing the inserter if the user manually changed zoom state', async ( { + InserterUtils, + } ) => { + const zoomOutButton = InserterUtils.getZoomOutButton(); + const inserterButton = InserterUtils.getInserterButton(); + const blockLibrary = InserterUtils.getBlockLibrary(); + + // Open inserter + await inserterButton.click(); + await expect( blockLibrary ).toBeVisible(); + + // Start from blocks stab + const blocksTab = InserterUtils.getBlockLibraryTab( 'Blocks' ); + await expect( blocksTab ).toHaveAttribute( 'data-active-item', 'true' ); + await expect( await InserterUtils.getZoomCanvas() ).toBeHidden(); + + // Go to patterns tab which should enter zoom out + const patternsTab = InserterUtils.getBlockLibraryTab( 'Patterns' ); + await patternsTab.click(); + await expect( patternsTab ).toHaveAttribute( + 'data-active-item', + 'true' + ); + await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + + // Manually toggle zoom out off + await zoomOutButton.click(); + await expect( await InserterUtils.getZoomCanvas() ).toBeHidden(); + + // Manually toggle zoom out again to return to zoomed-in state set by the patterns tab. + await zoomOutButton.click(); + await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + + // Close the inserter + await inserterButton.click(); + + await expect( blockLibrary ).toBeHidden(); + + // We should stay in zoomed out state since it was manually engaged + await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + } ); + // Similar test to the above but starting from not zoomed in and toggle zoom level twice test( 'starting from zoomed in, should not toggle zoom state when closing the inserter if the user manually changed zoom state', async ( { InserterUtils, @@ -313,7 +360,13 @@ test.describe( 'Site Editor Inserter', () => { const inserterButton = InserterUtils.getInserterButton(); const blockLibrary = InserterUtils.getBlockLibrary(); + // Enter zoom out + await zoomOutButton.click(); + await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + + // Open inserter await inserterButton.click(); + await expect( blockLibrary ).toBeVisible(); // Go to patterns tab which should enter zoom out const patternsTab = InserterUtils.getBlockLibraryTab( 'Patterns' ); From cf013b903bc42bd3eda4f8b4629a5b2b01405a00 Mon Sep 17 00:00:00 2001 From: Jerry Jones Date: Wed, 4 Dec 2024 12:09:06 -0600 Subject: [PATCH 05/16] Fix bug where mounting to controlled state would get rest to not controlled state --- .../block-editor/src/hooks/use-zoom-out.js | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/block-editor/src/hooks/use-zoom-out.js b/packages/block-editor/src/hooks/use-zoom-out.js index 12d3ef06841bd..2c66df5f9f780 100644 --- a/packages/block-editor/src/hooks/use-zoom-out.js +++ b/packages/block-editor/src/hooks/use-zoom-out.js @@ -28,6 +28,20 @@ export function useZoomOut( enabled = true ) { const controlZoomLevelRef = useRef( false ); const isEnabledRef = useRef( enabled ); + /** + * This hook tracks if the zoom state was changed manually by the user via clicking + * the zoom out button. We only want this to run when isZoomedOut changes, so we use + * a ref to track the enabled state. + */ + useEffect( () => { + // If the zoom state changed (isZoomOut) and it does not match the requested zoom + // state (zoomOut), then it means the user manually changed the zoom state while + // this hook was mounted, and we should no longer control the zoom state. + if ( isZoomedOut !== isEnabledRef.current ) { + controlZoomLevelRef.current = false; + } + }, [ isZoomedOut ] ); + useEffect( () => { isEnabledRef.current = enabled; const isAlreadyZoomedOut = isZoomOut(); @@ -47,18 +61,4 @@ export function useZoomOut( enabled = true ) { ); }; }, [ enabled, isZoomOut, resetZoomLevel, setZoomLevel ] ); - - /** - * This hook tracks if the zoom state was changed manually by the user via clicking - * the zoom out button. We only want this to run when isZoomedOut changes, so we use - * a ref to track the enabled state. - */ - useEffect( () => { - // If the zoom state changed (isZoomOut) and it does not match the requested zoom - // state (zoomOut), then it means the user manually changed the zoom state while - // this hook was mounted, and we should no longer control the zoom state. - if ( isZoomedOut !== isEnabledRef.current ) { - controlZoomLevelRef.current = false; - } - }, [ isZoomedOut ] ); } From 2be7df01963c5fc86008c8a190d3706f8812c4ad Mon Sep 17 00:00:00 2001 From: Jerry Jones Date: Wed, 4 Dec 2024 13:25:39 -0600 Subject: [PATCH 06/16] remove unnecessary pattern button click in test --- test/e2e/specs/site-editor/site-editor-inserter.spec.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/e2e/specs/site-editor/site-editor-inserter.spec.js b/test/e2e/specs/site-editor/site-editor-inserter.spec.js index e5581fc39508f..0a7dc86b4897f 100644 --- a/test/e2e/specs/site-editor/site-editor-inserter.spec.js +++ b/test/e2e/specs/site-editor/site-editor-inserter.spec.js @@ -370,7 +370,6 @@ test.describe( 'Site Editor Inserter', () => { // Go to patterns tab which should enter zoom out const patternsTab = InserterUtils.getBlockLibraryTab( 'Patterns' ); - await patternsTab.click(); await expect( patternsTab ).toHaveAttribute( 'data-active-item', 'true' From 4f322de1845d942fcbf1556cff3d3b4e562b25b4 Mon Sep 17 00:00:00 2001 From: Jerry Jones Date: Wed, 4 Dec 2024 13:29:38 -0600 Subject: [PATCH 07/16] Refactor if statements for setting controlZoomLevelRef --- packages/block-editor/src/hooks/use-zoom-out.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/block-editor/src/hooks/use-zoom-out.js b/packages/block-editor/src/hooks/use-zoom-out.js index 2c66df5f9f780..4a9199573d33a 100644 --- a/packages/block-editor/src/hooks/use-zoom-out.js +++ b/packages/block-editor/src/hooks/use-zoom-out.js @@ -46,12 +46,14 @@ export function useZoomOut( enabled = true ) { isEnabledRef.current = enabled; const isAlreadyZoomedOut = isZoomOut(); - if ( enabled && ! isAlreadyZoomedOut ) { - setZoomLevel( 'auto-scaled' ); - controlZoomLevelRef.current = true; - } else if ( ! enabled && isAlreadyZoomedOut ) { - resetZoomLevel(); + if ( enabled !== isAlreadyZoomedOut ) { controlZoomLevelRef.current = true; + + if ( enabled ) { + setZoomLevel( 'auto-scaled' ); + } else { + resetZoomLevel(); + } } return () => { From d65720b804bc9d485d78c55c9b7ae3fe800b2cb1 Mon Sep 17 00:00:00 2001 From: Jerry Jones Date: Wed, 4 Dec 2024 13:43:56 -0600 Subject: [PATCH 08/16] Refactor useZoomOut for readability --- packages/block-editor/src/hooks/use-zoom-out.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/block-editor/src/hooks/use-zoom-out.js b/packages/block-editor/src/hooks/use-zoom-out.js index 4a9199573d33a..32f154c0bec98 100644 --- a/packages/block-editor/src/hooks/use-zoom-out.js +++ b/packages/block-editor/src/hooks/use-zoom-out.js @@ -44,9 +44,8 @@ export function useZoomOut( enabled = true ) { useEffect( () => { isEnabledRef.current = enabled; - const isAlreadyZoomedOut = isZoomOut(); - if ( enabled !== isAlreadyZoomedOut ) { + if ( enabled !== isZoomOut() ) { controlZoomLevelRef.current = true; if ( enabled ) { @@ -57,10 +56,10 @@ export function useZoomOut( enabled = true ) { } return () => { - return ( - // If we are controlling zoom level and are zoomed out, reset the zoom level. - controlZoomLevelRef.current && isZoomOut() && resetZoomLevel() - ); + // If we are controlling zoom level and are zoomed out, reset the zoom level. + if ( controlZoomLevelRef.current && isZoomOut() ) { + resetZoomLevel(); + } }; }, [ enabled, isZoomOut, resetZoomLevel, setZoomLevel ] ); } From 7ed1ddd843e8578a77707e9cde09e2c83b5604ee Mon Sep 17 00:00:00 2001 From: Jerry Jones Date: Wed, 4 Dec 2024 14:10:14 -0600 Subject: [PATCH 09/16] Refactor to get isZoomedOut within useSelect --- packages/block-editor/src/hooks/use-zoom-out.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/block-editor/src/hooks/use-zoom-out.js b/packages/block-editor/src/hooks/use-zoom-out.js index 32f154c0bec98..adcea8b605aeb 100644 --- a/packages/block-editor/src/hooks/use-zoom-out.js +++ b/packages/block-editor/src/hooks/use-zoom-out.js @@ -22,9 +22,19 @@ export function useZoomOut( enabled = true ) { const { setZoomLevel, resetZoomLevel } = unlock( useDispatch( blockEditorStore ) ); - const { isZoomOut } = unlock( useSelect( blockEditorStore ) ); - const isZoomedOut = isZoomOut(); + /** + * We need access to both the value and the function. The value is to trigger a useEffect hook + * and the function is to check zoom out within another hook without triggering a re-render. + */ + const { isZoomedOut, isZoomOut } = useSelect( ( select ) => { + const { isZoomOut: _isZoomOut } = unlock( select( blockEditorStore ) ); + return { + isZoomedOut: _isZoomOut(), + isZoomOut: _isZoomOut, + }; + }, [] ); + const controlZoomLevelRef = useRef( false ); const isEnabledRef = useRef( enabled ); From f143f312e6014f4e1d5668f0d77241e3344a833d Mon Sep 17 00:00:00 2001 From: Jerry Jones Date: Thu, 5 Dec 2024 11:25:44 -0600 Subject: [PATCH 10/16] Big refactor of zoom out insterter tests --- .../site-editor/site-editor-inserter.spec.js | 421 +++++++----------- 1 file changed, 172 insertions(+), 249 deletions(-) diff --git a/test/e2e/specs/site-editor/site-editor-inserter.spec.js b/test/e2e/specs/site-editor/site-editor-inserter.spec.js index 0a7dc86b4897f..e2fad932ab194 100644 --- a/test/e2e/specs/site-editor/site-editor-inserter.spec.js +++ b/test/e2e/specs/site-editor/site-editor-inserter.spec.js @@ -24,20 +24,22 @@ test.describe( 'Site Editor Inserter', () => { }, } ); + test.use( { + ZoomUtils: async ( { editor, page }, use ) => { + await use( new ZoomUtils( { editor, page } ) ); + }, + } ); + test( 'inserter toggle button should toggle global inserter', async ( { InserterUtils, } ) => { - const inserterButton = InserterUtils.getInserterButton(); - - await inserterButton.click(); - - const blockLibrary = InserterUtils.getBlockLibrary(); + await InserterUtils.toggleBlockLibrary(); // Visibility check - await expect( blockLibrary ).toBeVisible(); - await inserterButton.click(); + await expect( InserterUtils.blockLibrary ).toBeVisible(); + await InserterUtils.toggleBlockLibrary(); //Hidden State check - await expect( blockLibrary ).toBeHidden(); + await expect( InserterUtils.blockLibrary ).toBeHidden(); } ); // A test for https://github.com/WordPress/gutenberg/issues/43090. @@ -45,379 +47,281 @@ test.describe( 'Site Editor Inserter', () => { editor, InserterUtils, } ) => { - const inserterButton = InserterUtils.getInserterButton(); - const blockLibrary = InserterUtils.getBlockLibrary(); - const beforeBlocks = await editor.getBlocks(); - await inserterButton.click(); - await InserterUtils.getBlockLibraryTab( 'Blocks' ).click(); - await blockLibrary.getByRole( 'option', { name: 'Buttons' } ).click(); + await InserterUtils.toggleBlockLibrary(); + await InserterUtils.activateTab( 'Blocks' ); + await InserterUtils.blockLibrary + .getByRole( 'option', { name: 'Buttons' } ) + .click(); await expect .poll( editor.getBlocks ) .toMatchObject( [ ...beforeBlocks, { name: 'core/buttons' } ] ); - await inserterButton.click(); + await InserterUtils.toggleBlockLibrary(); - await expect( blockLibrary ).toBeHidden(); + await expect( InserterUtils.blockLibrary ).toBeHidden(); } ); test( 'should open the inserter to patterns tab if using zoom out and stay in zoom out when closing the inserter', async ( { InserterUtils, + ZoomUtils, } ) => { - const zoomOutButton = InserterUtils.getZoomOutButton(); - const inserterButton = InserterUtils.getInserterButton(); - const blockLibrary = InserterUtils.getBlockLibrary(); + await ZoomUtils.toggleZoomLevel(); + await expect( ZoomUtils.zoomCanvas ).toBeVisible(); - await zoomOutButton.click(); - await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); - - await inserterButton.click(); - const patternsTab = InserterUtils.getBlockLibraryTab( 'Patterns' ); - await expect( patternsTab ).toHaveAttribute( - 'data-active-item', - 'true' - ); - await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + await InserterUtils.toggleBlockLibrary(); + await InserterUtils.expectActiveTab( 'Patterns' ); + await expect( ZoomUtils.zoomCanvas ).toBeVisible(); - await inserterButton.click(); + await InserterUtils.toggleBlockLibrary(); - await expect( blockLibrary ).toBeHidden(); + await expect( InserterUtils.blockLibrary ).toBeHidden(); // We should still be in Zoom Out - await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + await expect( ZoomUtils.zoomCanvas ).toBeVisible(); } ); test( 'should enter zoom out from patterns tab and exit zoom out when closing the inserter', async ( { InserterUtils, + ZoomUtils, } ) => { - const inserterButton = InserterUtils.getInserterButton(); - const blockLibrary = InserterUtils.getBlockLibrary(); - - await inserterButton.click(); - await expect( blockLibrary ).toBeVisible(); - await expect( await InserterUtils.getZoomCanvas() ).toBeHidden(); - - const blocksTab = InserterUtils.getBlockLibraryTab( 'Blocks' ); - await expect( blocksTab ).toHaveAttribute( 'data-active-item', 'true' ); - - const patternsTab = InserterUtils.getBlockLibraryTab( 'Patterns' ); - await patternsTab.click(); - await expect( patternsTab ).toHaveAttribute( - 'data-active-item', - 'true' - ); - await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + // Open inserter + await InserterUtils.toggleBlockLibrary(); + await InserterUtils.expectActiveTab( 'Blocks' ); + await expect( ZoomUtils.zoomCanvas ).toBeHidden(); - await inserterButton.click(); - await expect( blockLibrary ).toBeHidden(); + await InserterUtils.activateTab( 'Patterns' ); + await expect( ZoomUtils.zoomCanvas ).toBeVisible(); - await expect( await InserterUtils.getZoomCanvas() ).toBeHidden(); + await InserterUtils.toggleBlockLibrary(); + await expect( InserterUtils.blockLibrary ).toBeHidden(); + await expect( ZoomUtils.zoomCanvas ).toBeHidden(); } ); test( 'should always exit zoom out from blocks tab and does not change mode when closing the inserter', async ( { InserterUtils, + ZoomUtils, } ) => { - const inserterButton = InserterUtils.getInserterButton(); - const blockLibrary = InserterUtils.getBlockLibrary(); - // Open inserter - await inserterButton.click(); - await expect( blockLibrary ).toBeVisible(); - - // Blocks tab should be active, not in zoomed out state - const blocksTab = InserterUtils.getBlockLibraryTab( 'Blocks' ); - await expect( blocksTab ).toHaveAttribute( 'data-active-item', 'true' ); - await expect( await InserterUtils.getZoomCanvas() ).toBeHidden(); - - // Click to patterns, should enter zoom out - const patternsTab = InserterUtils.getBlockLibraryTab( 'Patterns' ); - await patternsTab.click(); - await expect( patternsTab ).toHaveAttribute( - 'data-active-item', - 'true' - ); - await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + await InserterUtils.toggleBlockLibrary(); + await InserterUtils.expectActiveTab( 'Blocks' ); + await expect( ZoomUtils.zoomCanvas ).toBeHidden(); + + // Click to patterns should enter zoom out + await InserterUtils.activateTab( 'Patterns' ); + await expect( ZoomUtils.zoomCanvas ).toBeVisible(); // Click to blocks tab, zooms back in - await blocksTab.click(); - await expect( blocksTab ).toHaveAttribute( 'data-active-item', 'true' ); - await expect( await InserterUtils.getZoomCanvas() ).toBeHidden(); + await InserterUtils.activateTab( 'Blocks' ); + await expect( ZoomUtils.zoomCanvas ).toBeHidden(); // Close inserter - await inserterButton.click(); - - await expect( blockLibrary ).toBeHidden(); + await InserterUtils.toggleBlockLibrary(); + await expect( InserterUtils.blockLibrary ).toBeHidden(); // Canvas stays zoomed in - await expect( await InserterUtils.getZoomCanvas() ).toBeHidden(); + await expect( ZoomUtils.zoomCanvas ).toBeHidden(); } ); // Same test as above, but starting from zoom out test( 'should always exit zoom out from blocks tab and does not change mode when closing the inserter (even if starting from zoom out)', async ( { InserterUtils, + ZoomUtils, } ) => { - const zoomOutButton = InserterUtils.getZoomOutButton(); - const inserterButton = InserterUtils.getInserterButton(); - const blockLibrary = InserterUtils.getBlockLibrary(); - - await zoomOutButton.click(); - await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + await ZoomUtils.toggleZoomLevel(); + await expect( ZoomUtils.zoomCanvas ).toBeVisible(); // Open inserter - await inserterButton.click(); - await expect( blockLibrary ).toBeVisible(); + await InserterUtils.toggleBlockLibrary(); + await expect( InserterUtils.blockLibrary ).toBeVisible(); // Patterns tab should be active - const patternsTab = InserterUtils.getBlockLibraryTab( 'Patterns' ); - await expect( patternsTab ).toHaveAttribute( - 'data-active-item', - 'true' - ); - await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + await InserterUtils.activateTab( 'Patterns' ); + await expect( ZoomUtils.zoomCanvas ).toBeVisible(); // Click to blocks tab, zooms back in - const blocksTab = InserterUtils.getBlockLibraryTab( 'Blocks' ); - await blocksTab.click(); - await expect( blocksTab ).toHaveAttribute( 'data-active-item', 'true' ); - await expect( await InserterUtils.getZoomCanvas() ).toBeHidden(); + await InserterUtils.activateTab( 'Blocks' ); + await expect( ZoomUtils.zoomCanvas ).toBeHidden(); // Close inserter - await inserterButton.click(); - - await expect( blockLibrary ).toBeHidden(); + await InserterUtils.toggleBlockLibrary(); + await expect( InserterUtils.blockLibrary ).toBeHidden(); // Canvas stays zoomed in - await expect( await InserterUtils.getZoomCanvas() ).toBeHidden(); + await expect( ZoomUtils.zoomCanvas ).toBeHidden(); } ); // Same test as above but exiting from zoom out test( 'If we change the zoom level for them via an inserter tab change, always exit zoom out when closing the inserter', async ( { InserterUtils, + ZoomUtils, } ) => { - const zoomOutButton = InserterUtils.getZoomOutButton(); - const inserterButton = InserterUtils.getInserterButton(); - const blockLibrary = InserterUtils.getBlockLibrary(); - - await zoomOutButton.click(); - await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + await ZoomUtils.toggleZoomLevel(); + await expect( ZoomUtils.zoomCanvas ).toBeVisible(); - await inserterButton.click(); - const patternsTab = InserterUtils.getBlockLibraryTab( 'Patterns' ); - const blocksTab = InserterUtils.getBlockLibraryTab( 'Blocks' ); - const mediaTab = InserterUtils.getBlockLibraryTab( 'Media' ); + await InserterUtils.toggleBlockLibrary(); // Should start with pattern tab selected in zoom out state - await expect( patternsTab ).toHaveAttribute( - 'data-active-item', - 'true' - ); - await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + await InserterUtils.expectActiveTab( 'Patterns' ); + await expect( ZoomUtils.zoomCanvas ).toBeVisible(); // Go to blocks tab which should exit zoom out - // We changed the zoom state for them here, so we "take over" control of the zoom state - await blocksTab.click(); - await expect( blocksTab ).toHaveAttribute( 'data-active-item', 'true' ); - await expect( await InserterUtils.getZoomCanvas() ).toBeHidden(); + await InserterUtils.activateTab( 'Blocks' ); + await expect( ZoomUtils.zoomCanvas ).toBeHidden(); // Go to media tab which should enter zoom out again since that's the starting state - await mediaTab.click(); - await expect( mediaTab ).toHaveAttribute( 'data-active-item', 'true' ); - await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + await InserterUtils.activateTab( 'Media' ); + await expect( ZoomUtils.zoomCanvas ).toBeVisible(); // Close the inserter - await inserterButton.click(); - await expect( blockLibrary ).toBeHidden(); + await InserterUtils.toggleBlockLibrary(); + await expect( InserterUtils.blockLibrary ).toBeHidden(); // We should stay in zoomed out state since we had control over the zoom state and we always exit zoom out when closing the inserter - await expect( await InserterUtils.getZoomCanvas() ).toBeHidden(); + await expect( ZoomUtils.zoomCanvas ).toBeHidden(); } ); test( 'should always exit zoom out if we have most recently changed zoom level for them', async ( { InserterUtils, + ZoomUtils, } ) => { - const zoomOutButton = InserterUtils.getZoomOutButton(); - const inserterButton = InserterUtils.getInserterButton(); - const blockLibrary = InserterUtils.getBlockLibrary(); - // Enter zoom out - await zoomOutButton.click(); - await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + await ZoomUtils.toggleZoomLevel(); + await expect( ZoomUtils.zoomCanvas ).toBeVisible(); // Open inserter - await inserterButton.click(); - await expect( blockLibrary ).toBeVisible(); + await InserterUtils.toggleBlockLibrary(); // Patterns tab should be active - const patternsTab = InserterUtils.getBlockLibraryTab( 'Patterns' ); - await expect( patternsTab ).toHaveAttribute( - 'data-active-item', - 'true' - ); - await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + await InserterUtils.activateTab( 'Patterns' ); + await expect( ZoomUtils.zoomCanvas ).toBeVisible(); // Click to blocks tab, zooms back in - const blocksTab = InserterUtils.getBlockLibraryTab( 'Blocks' ); - await blocksTab.click(); - await expect( blocksTab ).toHaveAttribute( 'data-active-item', 'true' ); - await expect( await InserterUtils.getZoomCanvas() ).toBeHidden(); + await InserterUtils.activateTab( 'Blocks' ); + await expect( ZoomUtils.zoomCanvas ).toBeHidden(); // Click to media tab, to zoom back out - const mediaTab = InserterUtils.getBlockLibraryTab( 'Media' ); - await mediaTab.click(); - await expect( mediaTab ).toHaveAttribute( 'data-active-item', 'true' ); - await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + await InserterUtils.activateTab( 'Media' ); + await expect( ZoomUtils.zoomCanvas ).toBeVisible(); // Close inserter - await inserterButton.click(); - - await expect( blockLibrary ).toBeHidden(); + await InserterUtils.toggleBlockLibrary(); + await expect( InserterUtils.blockLibrary ).toBeHidden(); // We have taken over zoom state control, so we should exit for them. - await expect( await InserterUtils.getZoomCanvas() ).toBeHidden(); + await expect( ZoomUtils.zoomCanvas ).toBeHidden(); } ); // Test for https://github.com/WordPress/gutenberg/issues/66328 test( 'should not return you to zoom out if manually disengaged', async ( { InserterUtils, + ZoomUtils, } ) => { - const zoomOutButton = InserterUtils.getZoomOutButton(); - const inserterButton = InserterUtils.getInserterButton(); - const blockLibrary = InserterUtils.getBlockLibrary(); + await ZoomUtils.toggleZoomLevel(); + await expect( ZoomUtils.zoomCanvas ).toBeVisible(); - await zoomOutButton.click(); - await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + await InserterUtils.toggleBlockLibrary(); + await expect( InserterUtils.blockLibrary ).toBeVisible(); - await inserterButton.click(); - await expect( blockLibrary ).toBeVisible(); - const patternsTab = InserterUtils.getBlockLibraryTab( 'Patterns' ); - await expect( patternsTab ).toHaveAttribute( - 'data-active-item', - 'true' - ); - await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + await InserterUtils.activateTab( 'Patterns' ); + await expect( ZoomUtils.zoomCanvas ).toBeVisible(); - await zoomOutButton.click(); - await expect( await InserterUtils.getZoomCanvas() ).toBeHidden(); + await ZoomUtils.toggleZoomLevel(); + await expect( ZoomUtils.zoomCanvas ).toBeHidden(); // Close the inserter - await inserterButton.click(); - - await expect( blockLibrary ).toBeHidden(); + await InserterUtils.toggleBlockLibrary(); + await expect( InserterUtils.blockLibrary ).toBeHidden(); // We should not return to zoom out since it was manually disengaged - await expect( await InserterUtils.getZoomCanvas() ).toBeHidden(); + await expect( ZoomUtils.zoomCanvas ).toBeHidden(); } ); // Similar test to the above but toggle zoom level twice - test( 'should not toggle zoom state from pattern tab when closing the inserter if the user manually changed zoom state', async ( { + test( 'starting from default view, should not toggle zoom state from pattern tab when closing the inserter if the user manually changed zoom state tweice', async ( { InserterUtils, + ZoomUtils, } ) => { - const zoomOutButton = InserterUtils.getZoomOutButton(); - const inserterButton = InserterUtils.getInserterButton(); - const blockLibrary = InserterUtils.getBlockLibrary(); - // Open inserter - await inserterButton.click(); - await expect( blockLibrary ).toBeVisible(); + await InserterUtils.toggleBlockLibrary(); + await expect( InserterUtils.blockLibrary ).toBeVisible(); - // Start from blocks stab - const blocksTab = InserterUtils.getBlockLibraryTab( 'Blocks' ); - await expect( blocksTab ).toHaveAttribute( 'data-active-item', 'true' ); - await expect( await InserterUtils.getZoomCanvas() ).toBeHidden(); + await InserterUtils.activateTab( 'Blocks' ); + await expect( ZoomUtils.zoomCanvas ).toBeHidden(); // Go to patterns tab which should enter zoom out - const patternsTab = InserterUtils.getBlockLibraryTab( 'Patterns' ); - await patternsTab.click(); - await expect( patternsTab ).toHaveAttribute( - 'data-active-item', - 'true' - ); - await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + await InserterUtils.activateTab( 'Patterns' ); + await expect( ZoomUtils.zoomCanvas ).toBeVisible(); // Manually toggle zoom out off - await zoomOutButton.click(); - await expect( await InserterUtils.getZoomCanvas() ).toBeHidden(); + await ZoomUtils.toggleZoomLevel(); + await expect( ZoomUtils.zoomCanvas ).toBeHidden(); // Manually toggle zoom out again to return to zoomed-in state set by the patterns tab. - await zoomOutButton.click(); - await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + await ZoomUtils.toggleZoomLevel(); + await expect( ZoomUtils.zoomCanvas ).toBeVisible(); // Close the inserter - await inserterButton.click(); - - await expect( blockLibrary ).toBeHidden(); + await InserterUtils.toggleBlockLibrary(); + await expect( InserterUtils.blockLibrary ).toBeHidden(); // We should stay in zoomed out state since it was manually engaged - await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + await expect( ZoomUtils.zoomCanvas ).toBeVisible(); } ); - // Similar test to the above but starting from not zoomed in and toggle zoom level twice - test( 'starting from zoomed in, should not toggle zoom state when closing the inserter if the user manually changed zoom state', async ( { + test( 'starting from zoomed out, should not toggle zoom state when closing the inserter if the user manually changed zoom state twice', async ( { InserterUtils, + ZoomUtils, } ) => { - const zoomOutButton = InserterUtils.getZoomOutButton(); - const inserterButton = InserterUtils.getInserterButton(); - const blockLibrary = InserterUtils.getBlockLibrary(); - // Enter zoom out - await zoomOutButton.click(); - await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + await ZoomUtils.toggleZoomLevel(); + await expect( ZoomUtils.zoomCanvas ).toBeVisible(); // Open inserter - await inserterButton.click(); - await expect( blockLibrary ).toBeVisible(); + await InserterUtils.toggleBlockLibrary(); + await expect( InserterUtils.blockLibrary ).toBeVisible(); - // Go to patterns tab which should enter zoom out - const patternsTab = InserterUtils.getBlockLibraryTab( 'Patterns' ); - await expect( patternsTab ).toHaveAttribute( - 'data-active-item', - 'true' - ); - await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + // Go to patterns tab which should remain in zoom out + await InserterUtils.activateTab( 'Patterns' ); + await expect( ZoomUtils.zoomCanvas ).toBeVisible(); // Manually toggle zoom out off - await zoomOutButton.click(); - await expect( await InserterUtils.getZoomCanvas() ).toBeHidden(); + await ZoomUtils.toggleZoomLevel(); + await expect( ZoomUtils.zoomCanvas ).toBeHidden(); // Manually toggle zoom out again to return to zoomed-in state set by the patterns tab. - await zoomOutButton.click(); - await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + await ZoomUtils.toggleZoomLevel(); + await expect( ZoomUtils.zoomCanvas ).toBeVisible(); // Close the inserter - await inserterButton.click(); - - await expect( blockLibrary ).toBeHidden(); + await InserterUtils.toggleBlockLibrary(); + await expect( InserterUtils.blockLibrary ).toBeHidden(); // We should stay in zoomed out state since it was manually engaged - await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + await expect( ZoomUtils.zoomCanvas ).toBeVisible(); } ); // Similar to above ones, but doing it from the blocks tab (zoomed out) to zoom in - test( 'should not return you to zoom out if manually disengaged from blocks tab', async ( { + test( 'should not reset zoom level if zoom level manually toggled from blocks tab', async ( { InserterUtils, + ZoomUtils, } ) => { - const zoomOutButton = InserterUtils.getZoomOutButton(); - const inserterButton = InserterUtils.getInserterButton(); - const blockLibrary = InserterUtils.getBlockLibrary(); - - await inserterButton.click(); - await expect( blockLibrary ).toBeVisible(); + await InserterUtils.toggleBlockLibrary(); + await expect( InserterUtils.blockLibrary ).toBeVisible(); - const blocksTab = InserterUtils.getBlockLibraryTab( 'Blocks' ); - await expect( blocksTab ).toHaveAttribute( 'data-active-item', 'true' ); - await expect( await InserterUtils.getZoomCanvas() ).toBeHidden(); + await InserterUtils.expectActiveTab( 'Blocks' ); + await expect( ZoomUtils.zoomCanvas ).toBeHidden(); - await zoomOutButton.click(); - await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + await ZoomUtils.toggleZoomLevel(); + await expect( ZoomUtils.zoomCanvas ).toBeVisible(); // Close the inserter - await inserterButton.click(); - - await expect( blockLibrary ).toBeHidden(); + await InserterUtils.toggleBlockLibrary(); + await expect( InserterUtils.blockLibrary ).toBeHidden(); // We should not return to zoom in since it was manually disengaged - await expect( await InserterUtils.getZoomCanvas() ).toBeVisible(); + await expect( ZoomUtils.zoomCanvas ).toBeVisible(); } ); } ); @@ -425,33 +329,52 @@ class InserterUtils { constructor( { editor, page } ) { this.editor = editor; this.page = page; - } - - getInserterButton() { - return this.page.getByRole( 'button', { + this.blockLibrary = this.page.getByRole( 'region', { + name: 'Block Library', + } ); + this.inserterButton = this.page.getByRole( 'button', { name: 'Block Inserter', exact: true, } ); + this.blocksTab = this.getBlockLibraryTab( 'Blocks' ); + this.patternsTab = this.getBlockLibraryTab( 'Patterns' ); + this.mediaTab = this.getBlockLibraryTab( 'Media' ); } - getBlockLibrary() { - return this.page.getByRole( 'region', { - name: 'Block Library', - } ); + async toggleBlockLibrary() { + await this.inserterButton.click(); } getBlockLibraryTab( name ) { return this.page.getByRole( 'tab', { name } ); } - getZoomOutButton() { - return this.page.getByRole( 'button', { + async expectActiveTab( name ) { + await expect( this.getBlockLibraryTab( name ) ).toHaveAttribute( + 'data-active-item', + 'true' + ); + } + + async activateTab( name ) { + await this.getBlockLibraryTab( name ).click(); + // For brevity, adding this check here. It should always be done after the tab is clicked + await this.expectActiveTab( name ); + } +} + +class ZoomUtils { + constructor( { editor, page } ) { + this.editor = editor; + this.page = page; + this.zoomCanvas = this.page.locator( '.is-zoomed-out' ); + this.zoomButton = this.page.getByRole( 'button', { name: 'Zoom Out', exact: true, } ); } - getZoomCanvas() { - return this.page.locator( '.is-zoomed-out' ); + async toggleZoomLevel() { + await this.zoomButton.click(); } } From 95cb64291b88cebf7167b1742d25eaf034153858 Mon Sep 17 00:00:00 2001 From: Jerry Jones Date: Thu, 5 Dec 2024 14:15:42 -0600 Subject: [PATCH 11/16] Refactor to use test steps --- .../site-editor/site-editor-inserter.spec.js | 458 ++++++++---------- 1 file changed, 214 insertions(+), 244 deletions(-) diff --git a/test/e2e/specs/site-editor/site-editor-inserter.spec.js b/test/e2e/specs/site-editor/site-editor-inserter.spec.js index e2fad932ab194..1c4d8e690144d 100644 --- a/test/e2e/specs/site-editor/site-editor-inserter.spec.js +++ b/test/e2e/specs/site-editor/site-editor-inserter.spec.js @@ -24,12 +24,6 @@ test.describe( 'Site Editor Inserter', () => { }, } ); - test.use( { - ZoomUtils: async ( { editor, page }, use ) => { - await use( new ZoomUtils( { editor, page } ) ); - }, - } ); - test( 'inserter toggle button should toggle global inserter', async ( { InserterUtils, } ) => { @@ -64,264 +58,240 @@ test.describe( 'Site Editor Inserter', () => { await expect( InserterUtils.blockLibrary ).toBeHidden(); } ); - test( 'should open the inserter to patterns tab if using zoom out and stay in zoom out when closing the inserter', async ( { - InserterUtils, - ZoomUtils, - } ) => { - await ZoomUtils.toggleZoomLevel(); - await expect( ZoomUtils.zoomCanvas ).toBeVisible(); - - await InserterUtils.toggleBlockLibrary(); - await InserterUtils.expectActiveTab( 'Patterns' ); - await expect( ZoomUtils.zoomCanvas ).toBeVisible(); - - await InserterUtils.toggleBlockLibrary(); - - await expect( InserterUtils.blockLibrary ).toBeHidden(); - - // We should still be in Zoom Out - await expect( ZoomUtils.zoomCanvas ).toBeVisible(); - } ); - - test( 'should enter zoom out from patterns tab and exit zoom out when closing the inserter', async ( { - InserterUtils, - ZoomUtils, - } ) => { - // Open inserter - await InserterUtils.toggleBlockLibrary(); - await InserterUtils.expectActiveTab( 'Blocks' ); - await expect( ZoomUtils.zoomCanvas ).toBeHidden(); - - await InserterUtils.activateTab( 'Patterns' ); - await expect( ZoomUtils.zoomCanvas ).toBeVisible(); - - await InserterUtils.toggleBlockLibrary(); - await expect( InserterUtils.blockLibrary ).toBeHidden(); - await expect( ZoomUtils.zoomCanvas ).toBeHidden(); - } ); - - test( 'should always exit zoom out from blocks tab and does not change mode when closing the inserter', async ( { - InserterUtils, - ZoomUtils, - } ) => { - // Open inserter - await InserterUtils.toggleBlockLibrary(); - await InserterUtils.expectActiveTab( 'Blocks' ); - await expect( ZoomUtils.zoomCanvas ).toBeHidden(); - - // Click to patterns should enter zoom out - await InserterUtils.activateTab( 'Patterns' ); - await expect( ZoomUtils.zoomCanvas ).toBeVisible(); - - // Click to blocks tab, zooms back in - await InserterUtils.activateTab( 'Blocks' ); - await expect( ZoomUtils.zoomCanvas ).toBeHidden(); - - // Close inserter - await InserterUtils.toggleBlockLibrary(); - await expect( InserterUtils.blockLibrary ).toBeHidden(); - - // Canvas stays zoomed in - await expect( ZoomUtils.zoomCanvas ).toBeHidden(); - } ); - - // Same test as above, but starting from zoom out - test( 'should always exit zoom out from blocks tab and does not change mode when closing the inserter (even if starting from zoom out)', async ( { - InserterUtils, - ZoomUtils, - } ) => { - await ZoomUtils.toggleZoomLevel(); - await expect( ZoomUtils.zoomCanvas ).toBeVisible(); - - // Open inserter - await InserterUtils.toggleBlockLibrary(); - await expect( InserterUtils.blockLibrary ).toBeVisible(); - - // Patterns tab should be active - await InserterUtils.activateTab( 'Patterns' ); - await expect( ZoomUtils.zoomCanvas ).toBeVisible(); - - // Click to blocks tab, zooms back in - await InserterUtils.activateTab( 'Blocks' ); - await expect( ZoomUtils.zoomCanvas ).toBeHidden(); - - // Close inserter - await InserterUtils.toggleBlockLibrary(); - await expect( InserterUtils.blockLibrary ).toBeHidden(); - - // Canvas stays zoomed in - await expect( ZoomUtils.zoomCanvas ).toBeHidden(); - } ); - - // Same test as above but exiting from zoom out - test( 'If we change the zoom level for them via an inserter tab change, always exit zoom out when closing the inserter', async ( { - InserterUtils, - ZoomUtils, - } ) => { - await ZoomUtils.toggleZoomLevel(); - await expect( ZoomUtils.zoomCanvas ).toBeVisible(); - - await InserterUtils.toggleBlockLibrary(); - - // Should start with pattern tab selected in zoom out state - await InserterUtils.expectActiveTab( 'Patterns' ); - await expect( ZoomUtils.zoomCanvas ).toBeVisible(); - - // Go to blocks tab which should exit zoom out - await InserterUtils.activateTab( 'Blocks' ); - await expect( ZoomUtils.zoomCanvas ).toBeHidden(); - - // Go to media tab which should enter zoom out again since that's the starting state - await InserterUtils.activateTab( 'Media' ); - await expect( ZoomUtils.zoomCanvas ).toBeVisible(); - - // Close the inserter - await InserterUtils.toggleBlockLibrary(); - await expect( InserterUtils.blockLibrary ).toBeHidden(); - - // We should stay in zoomed out state since we had control over the zoom state and we always exit zoom out when closing the inserter - await expect( ZoomUtils.zoomCanvas ).toBeHidden(); - } ); - - test( 'should always exit zoom out if we have most recently changed zoom level for them', async ( { - InserterUtils, - ZoomUtils, - } ) => { - // Enter zoom out - await ZoomUtils.toggleZoomLevel(); - await expect( ZoomUtils.zoomCanvas ).toBeVisible(); - // Open inserter - await InserterUtils.toggleBlockLibrary(); - - // Patterns tab should be active - await InserterUtils.activateTab( 'Patterns' ); - await expect( ZoomUtils.zoomCanvas ).toBeVisible(); - - // Click to blocks tab, zooms back in - await InserterUtils.activateTab( 'Blocks' ); - await expect( ZoomUtils.zoomCanvas ).toBeHidden(); - - // Click to media tab, to zoom back out - await InserterUtils.activateTab( 'Media' ); - await expect( ZoomUtils.zoomCanvas ).toBeVisible(); - - // Close inserter - await InserterUtils.toggleBlockLibrary(); - await expect( InserterUtils.blockLibrary ).toBeHidden(); - - // We have taken over zoom state control, so we should exit for them. - await expect( ZoomUtils.zoomCanvas ).toBeHidden(); - } ); - - // Test for https://github.com/WordPress/gutenberg/issues/66328 - test( 'should not return you to zoom out if manually disengaged', async ( { - InserterUtils, - ZoomUtils, - } ) => { - await ZoomUtils.toggleZoomLevel(); - await expect( ZoomUtils.zoomCanvas ).toBeVisible(); - - await InserterUtils.toggleBlockLibrary(); - await expect( InserterUtils.blockLibrary ).toBeVisible(); - - await InserterUtils.activateTab( 'Patterns' ); - await expect( ZoomUtils.zoomCanvas ).toBeVisible(); - - await ZoomUtils.toggleZoomLevel(); - await expect( ZoomUtils.zoomCanvas ).toBeHidden(); - - // Close the inserter - await InserterUtils.toggleBlockLibrary(); - await expect( InserterUtils.blockLibrary ).toBeHidden(); + test.describe( 'Inserter Zoom Level UX', () => { + test.use( { + ZoomUtils: async ( { editor, page }, use ) => { + await use( new ZoomUtils( { editor, page } ) ); + }, + } ); - // We should not return to zoom out since it was manually disengaged - await expect( ZoomUtils.zoomCanvas ).toBeHidden(); - } ); + test( 'should intialize correct active tab based on zoom level', async ( { + InserterUtils, + ZoomUtils, + } ) => { + await test.step( 'should open the inserter to blocks tab from default zoom level', async () => { + // Open inserter + await InserterUtils.toggleBlockLibrary(); + await InserterUtils.expectActiveTab( 'Blocks' ); + + // Zoom canvas should not be active + await expect( ZoomUtils.zoomCanvas ).toBeHidden(); + + // Close Block Library + await InserterUtils.toggleBlockLibrary(); + await expect( InserterUtils.blockLibrary ).toBeHidden(); + + // Zoom canvas should not be active + await expect( ZoomUtils.zoomCanvas ).toBeHidden(); + } ); + + await test.step( 'should open the inserter to patterns tab if zoomed out', async () => { + // Toggle Zoom Level + await ZoomUtils.toggleZoomLevel(); + await expect( ZoomUtils.zoomCanvas ).toBeVisible(); + + // Open inserter + await InserterUtils.toggleBlockLibrary(); + await InserterUtils.expectActiveTab( 'Patterns' ); + + // Zoom canvas should still be active + await expect( ZoomUtils.zoomCanvas ).toBeVisible(); + + // Close Block Library + await InserterUtils.toggleBlockLibrary(); + await expect( InserterUtils.blockLibrary ).toBeHidden(); + + // We should still be in Zoom Out + await expect( ZoomUtils.zoomCanvas ).toBeVisible(); + } ); + } ); - // Similar test to the above but toggle zoom level twice - test( 'starting from default view, should not toggle zoom state from pattern tab when closing the inserter if the user manually changed zoom state tweice', async ( { - InserterUtils, - ZoomUtils, - } ) => { - // Open inserter - await InserterUtils.toggleBlockLibrary(); - await expect( InserterUtils.blockLibrary ).toBeVisible(); + test( 'should set the correct zoom level when changing tabs', async ( { + InserterUtils, + ZoomUtils, + } ) => { + // Open inserter + await InserterUtils.toggleBlockLibrary(); + await InserterUtils.expectActiveTab( 'Blocks' ); + await expect( ZoomUtils.zoomCanvas ).toBeHidden(); + + await test.step( 'should zoom out when activating patterns tab', async () => { + await InserterUtils.activateTab( 'Patterns' ); + await expect( ZoomUtils.zoomCanvas ).toBeVisible(); + } ); + + await test.step( 'should reset zoom level when activating blocks tab', async () => { + await InserterUtils.activateTab( 'Blocks' ); + await expect( ZoomUtils.zoomCanvas ).toBeHidden(); + } ); + + await test.step( 'should zoom out when activating media tab', async () => { + await InserterUtils.activateTab( 'Media' ); + await expect( ZoomUtils.zoomCanvas ).toBeVisible(); + } ); + } ); - await InserterUtils.activateTab( 'Blocks' ); - await expect( ZoomUtils.zoomCanvas ).toBeHidden(); + test( 'should reset the zoom level when closing the inserter if we most recently changed the zoom level', async ( { + InserterUtils, + ZoomUtils, + } ) => { + await test.step( 'should reset zoom when closing from patterns tab', async () => { + // Open inserter + await InserterUtils.toggleBlockLibrary(); + await InserterUtils.expectActiveTab( 'Blocks' ); + await expect( ZoomUtils.zoomCanvas ).toBeHidden(); + + await InserterUtils.activateTab( 'Patterns' ); + await expect( ZoomUtils.zoomCanvas ).toBeVisible(); + + // Close inserter + await InserterUtils.toggleBlockLibrary(); + await expect( InserterUtils.blockLibrary ).toBeHidden(); + + // Zoom Level should be reset + await expect( ZoomUtils.zoomCanvas ).toBeHidden(); + } ); + + await test.step( 'should preserve default zoom level when closing from blocks tab', async () => { + // Open inserter + await InserterUtils.toggleBlockLibrary(); + await InserterUtils.expectActiveTab( 'Blocks' ); + await expect( ZoomUtils.zoomCanvas ).toBeHidden(); + + await InserterUtils.activateTab( 'Media' ); + await expect( ZoomUtils.zoomCanvas ).toBeVisible(); + + await InserterUtils.activateTab( 'Blocks' ); + await expect( ZoomUtils.zoomCanvas ).toBeHidden(); + + // Close inserter + await InserterUtils.toggleBlockLibrary(); + await expect( InserterUtils.blockLibrary ).toBeHidden(); + + // Zoom Level should stay at default level + await expect( ZoomUtils.zoomCanvas ).toBeHidden(); + } ); + + await test.step( 'should preserve default zoom level when closing from blocks tab even if user manually toggled zoom level on previous tab', async () => { + // Open inserter + await InserterUtils.toggleBlockLibrary(); + await InserterUtils.expectActiveTab( 'Blocks' ); + await expect( ZoomUtils.zoomCanvas ).toBeHidden(); + + await InserterUtils.activateTab( 'Media' ); + await expect( ZoomUtils.zoomCanvas ).toBeVisible(); + + // Toggle zoom level manually + await ZoomUtils.toggleZoomLevel(); + await expect( ZoomUtils.zoomCanvas ).toBeHidden(); + + await InserterUtils.activateTab( 'Blocks' ); + await expect( ZoomUtils.zoomCanvas ).toBeHidden(); + + // Close inserter + await InserterUtils.toggleBlockLibrary(); + await expect( InserterUtils.blockLibrary ).toBeHidden(); + + // Zoom Level should stay at default level + await expect( ZoomUtils.zoomCanvas ).toBeHidden(); + } ); + + await test.step( 'should preserve default zoom level when closing from blocks tab even if user manually toggled zoom level on previous tab twice', async () => { + // Open inserter + await InserterUtils.toggleBlockLibrary(); + await InserterUtils.expectActiveTab( 'Blocks' ); + await expect( ZoomUtils.zoomCanvas ).toBeHidden(); + + await InserterUtils.activateTab( 'Media' ); + await expect( ZoomUtils.zoomCanvas ).toBeVisible(); + + // Toggle zoom level manually twice + await ZoomUtils.toggleZoomLevel(); + await expect( ZoomUtils.zoomCanvas ).toBeHidden(); + await ZoomUtils.toggleZoomLevel(); + await expect( ZoomUtils.zoomCanvas ).toBeVisible(); + + await InserterUtils.activateTab( 'Blocks' ); + await expect( ZoomUtils.zoomCanvas ).toBeHidden(); + + // Close inserter + await InserterUtils.toggleBlockLibrary(); + await expect( InserterUtils.blockLibrary ).toBeHidden(); + + // Zoom Level should stay at default level + await expect( ZoomUtils.zoomCanvas ).toBeHidden(); + } ); + } ); - // Go to patterns tab which should enter zoom out - await InserterUtils.activateTab( 'Patterns' ); - await expect( ZoomUtils.zoomCanvas ).toBeVisible(); + test( 'should keep the zoom level manually set by the user if the user most recently set the zoom level', async ( { + InserterUtils, + ZoomUtils, + } ) => { + await test.step( 'should respect manual zoom level set when closing from patterns tab', async () => { + // Open inserter + await InserterUtils.toggleBlockLibrary(); + await InserterUtils.expectActiveTab( 'Blocks' ); + await expect( ZoomUtils.zoomCanvas ).toBeHidden(); - // Manually toggle zoom out off - await ZoomUtils.toggleZoomLevel(); - await expect( ZoomUtils.zoomCanvas ).toBeHidden(); + await InserterUtils.activateTab( 'Patterns' ); + await expect( ZoomUtils.zoomCanvas ).toBeVisible(); - // Manually toggle zoom out again to return to zoomed-in state set by the patterns tab. - await ZoomUtils.toggleZoomLevel(); - await expect( ZoomUtils.zoomCanvas ).toBeVisible(); + await ZoomUtils.toggleZoomLevel(); + await expect( ZoomUtils.zoomCanvas ).toBeHidden(); - // Close the inserter - await InserterUtils.toggleBlockLibrary(); - await expect( InserterUtils.blockLibrary ).toBeHidden(); + // Close inserter + await InserterUtils.toggleBlockLibrary(); + await expect( InserterUtils.blockLibrary ).toBeHidden(); - // We should stay in zoomed out state since it was manually engaged - await expect( ZoomUtils.zoomCanvas ).toBeVisible(); - } ); + // Zoom Level should stay reset + await expect( ZoomUtils.zoomCanvas ).toBeHidden(); + } ); - test( 'starting from zoomed out, should not toggle zoom state when closing the inserter if the user manually changed zoom state twice', async ( { - InserterUtils, - ZoomUtils, - } ) => { - // Enter zoom out - await ZoomUtils.toggleZoomLevel(); - await expect( ZoomUtils.zoomCanvas ).toBeVisible(); + await test.step( 'should respect manual zoom level set when closing from patterns tab when toggled twice', async () => { + // Open inserter + await InserterUtils.toggleBlockLibrary(); + await InserterUtils.expectActiveTab( 'Blocks' ); + await expect( ZoomUtils.zoomCanvas ).toBeHidden(); - // Open inserter - await InserterUtils.toggleBlockLibrary(); - await expect( InserterUtils.blockLibrary ).toBeVisible(); + await InserterUtils.activateTab( 'Patterns' ); + await expect( ZoomUtils.zoomCanvas ).toBeVisible(); - // Go to patterns tab which should remain in zoom out - await InserterUtils.activateTab( 'Patterns' ); - await expect( ZoomUtils.zoomCanvas ).toBeVisible(); + await ZoomUtils.toggleZoomLevel(); + await expect( ZoomUtils.zoomCanvas ).toBeHidden(); - // Manually toggle zoom out off - await ZoomUtils.toggleZoomLevel(); - await expect( ZoomUtils.zoomCanvas ).toBeHidden(); + await ZoomUtils.toggleZoomLevel(); + await expect( ZoomUtils.zoomCanvas ).toBeVisible(); - // Manually toggle zoom out again to return to zoomed-in state set by the patterns tab. - await ZoomUtils.toggleZoomLevel(); - await expect( ZoomUtils.zoomCanvas ).toBeVisible(); + // Close inserter + await InserterUtils.toggleBlockLibrary(); + await expect( InserterUtils.blockLibrary ).toBeHidden(); - // Close the inserter - await InserterUtils.toggleBlockLibrary(); - await expect( InserterUtils.blockLibrary ).toBeHidden(); + // Should stay zoomed out since it was manually engaged + await expect( ZoomUtils.zoomCanvas ).toBeVisible(); - // We should stay in zoomed out state since it was manually engaged - await expect( ZoomUtils.zoomCanvas ).toBeVisible(); - } ); + // Toggle to reset test + await ZoomUtils.toggleZoomLevel(); + await expect( ZoomUtils.zoomCanvas ).toBeHidden(); + } ); - // Similar to above ones, but doing it from the blocks tab (zoomed out) to zoom in - test( 'should not reset zoom level if zoom level manually toggled from blocks tab', async ( { - InserterUtils, - ZoomUtils, - } ) => { - await InserterUtils.toggleBlockLibrary(); - await expect( InserterUtils.blockLibrary ).toBeVisible(); + await test.step( 'should not reset zoom level if zoom level manually toggled from blocks tab', async () => { + await InserterUtils.toggleBlockLibrary(); + await expect( InserterUtils.blockLibrary ).toBeVisible(); - await InserterUtils.expectActiveTab( 'Blocks' ); - await expect( ZoomUtils.zoomCanvas ).toBeHidden(); + await InserterUtils.expectActiveTab( 'Blocks' ); + await expect( ZoomUtils.zoomCanvas ).toBeHidden(); - await ZoomUtils.toggleZoomLevel(); - await expect( ZoomUtils.zoomCanvas ).toBeVisible(); + await ZoomUtils.toggleZoomLevel(); + await expect( ZoomUtils.zoomCanvas ).toBeVisible(); - // Close the inserter - await InserterUtils.toggleBlockLibrary(); - await expect( InserterUtils.blockLibrary ).toBeHidden(); + // Close the inserter + await InserterUtils.toggleBlockLibrary(); + await expect( InserterUtils.blockLibrary ).toBeHidden(); - // We should not return to zoom in since it was manually disengaged - await expect( ZoomUtils.zoomCanvas ).toBeVisible(); + // Should stay zoomed out since it was manually engaged + await expect( ZoomUtils.zoomCanvas ).toBeVisible(); + } ); + } ); } ); } ); From 75659362098657206300edd347820d359fe43036 Mon Sep 17 00:00:00 2001 From: Jerry Jones Date: Thu, 5 Dec 2024 14:30:35 -0600 Subject: [PATCH 12/16] Refactor from toggle to open/close methods for readability --- .../site-editor/site-editor-inserter.spec.js | 135 +++++++----------- 1 file changed, 54 insertions(+), 81 deletions(-) diff --git a/test/e2e/specs/site-editor/site-editor-inserter.spec.js b/test/e2e/specs/site-editor/site-editor-inserter.spec.js index 1c4d8e690144d..a542f21ea4c41 100644 --- a/test/e2e/specs/site-editor/site-editor-inserter.spec.js +++ b/test/e2e/specs/site-editor/site-editor-inserter.spec.js @@ -24,16 +24,12 @@ test.describe( 'Site Editor Inserter', () => { }, } ); + // eslint-disable-next-line playwright/expect-expect test( 'inserter toggle button should toggle global inserter', async ( { InserterUtils, } ) => { - await InserterUtils.toggleBlockLibrary(); - - // Visibility check - await expect( InserterUtils.blockLibrary ).toBeVisible(); - await InserterUtils.toggleBlockLibrary(); - //Hidden State check - await expect( InserterUtils.blockLibrary ).toBeHidden(); + await InserterUtils.openBlockLibrary(); + await InserterUtils.closeBlockLibrary(); } ); // A test for https://github.com/WordPress/gutenberg/issues/43090. @@ -43,8 +39,8 @@ test.describe( 'Site Editor Inserter', () => { } ) => { const beforeBlocks = await editor.getBlocks(); - await InserterUtils.toggleBlockLibrary(); - await InserterUtils.activateTab( 'Blocks' ); + await InserterUtils.openBlockLibrary(); + await InserterUtils.expectActiveTab( 'Blocks' ); await InserterUtils.blockLibrary .getByRole( 'option', { name: 'Buttons' } ) .click(); @@ -53,9 +49,7 @@ test.describe( 'Site Editor Inserter', () => { .poll( editor.getBlocks ) .toMatchObject( [ ...beforeBlocks, { name: 'core/buttons' } ] ); - await InserterUtils.toggleBlockLibrary(); - - await expect( InserterUtils.blockLibrary ).toBeHidden(); + await InserterUtils.closeBlockLibrary(); } ); test.describe( 'Inserter Zoom Level UX', () => { @@ -70,36 +64,27 @@ test.describe( 'Site Editor Inserter', () => { ZoomUtils, } ) => { await test.step( 'should open the inserter to blocks tab from default zoom level', async () => { - // Open inserter - await InserterUtils.toggleBlockLibrary(); + await InserterUtils.openBlockLibrary(); await InserterUtils.expectActiveTab( 'Blocks' ); // Zoom canvas should not be active await expect( ZoomUtils.zoomCanvas ).toBeHidden(); - // Close Block Library - await InserterUtils.toggleBlockLibrary(); - await expect( InserterUtils.blockLibrary ).toBeHidden(); + await InserterUtils.closeBlockLibrary(); // Zoom canvas should not be active await expect( ZoomUtils.zoomCanvas ).toBeHidden(); } ); await test.step( 'should open the inserter to patterns tab if zoomed out', async () => { - // Toggle Zoom Level - await ZoomUtils.toggleZoomLevel(); - await expect( ZoomUtils.zoomCanvas ).toBeVisible(); - - // Open inserter - await InserterUtils.toggleBlockLibrary(); + await ZoomUtils.enterZoomOut(); + await InserterUtils.openBlockLibrary(); await InserterUtils.expectActiveTab( 'Patterns' ); // Zoom canvas should still be active await expect( ZoomUtils.zoomCanvas ).toBeVisible(); - // Close Block Library - await InserterUtils.toggleBlockLibrary(); - await expect( InserterUtils.blockLibrary ).toBeHidden(); + await InserterUtils.closeBlockLibrary(); // We should still be in Zoom Out await expect( ZoomUtils.zoomCanvas ).toBeVisible(); @@ -110,8 +95,7 @@ test.describe( 'Site Editor Inserter', () => { InserterUtils, ZoomUtils, } ) => { - // Open inserter - await InserterUtils.toggleBlockLibrary(); + await InserterUtils.openBlockLibrary(); await InserterUtils.expectActiveTab( 'Blocks' ); await expect( ZoomUtils.zoomCanvas ).toBeHidden(); @@ -136,25 +120,21 @@ test.describe( 'Site Editor Inserter', () => { ZoomUtils, } ) => { await test.step( 'should reset zoom when closing from patterns tab', async () => { - // Open inserter - await InserterUtils.toggleBlockLibrary(); + await InserterUtils.openBlockLibrary(); await InserterUtils.expectActiveTab( 'Blocks' ); await expect( ZoomUtils.zoomCanvas ).toBeHidden(); await InserterUtils.activateTab( 'Patterns' ); await expect( ZoomUtils.zoomCanvas ).toBeVisible(); - // Close inserter - await InserterUtils.toggleBlockLibrary(); - await expect( InserterUtils.blockLibrary ).toBeHidden(); + await InserterUtils.closeBlockLibrary(); // Zoom Level should be reset await expect( ZoomUtils.zoomCanvas ).toBeHidden(); } ); await test.step( 'should preserve default zoom level when closing from blocks tab', async () => { - // Open inserter - await InserterUtils.toggleBlockLibrary(); + await InserterUtils.openBlockLibrary(); await InserterUtils.expectActiveTab( 'Blocks' ); await expect( ZoomUtils.zoomCanvas ).toBeHidden(); @@ -164,17 +144,14 @@ test.describe( 'Site Editor Inserter', () => { await InserterUtils.activateTab( 'Blocks' ); await expect( ZoomUtils.zoomCanvas ).toBeHidden(); - // Close inserter - await InserterUtils.toggleBlockLibrary(); - await expect( InserterUtils.blockLibrary ).toBeHidden(); + await InserterUtils.closeBlockLibrary(); // Zoom Level should stay at default level await expect( ZoomUtils.zoomCanvas ).toBeHidden(); } ); await test.step( 'should preserve default zoom level when closing from blocks tab even if user manually toggled zoom level on previous tab', async () => { - // Open inserter - await InserterUtils.toggleBlockLibrary(); + await InserterUtils.openBlockLibrary(); await InserterUtils.expectActiveTab( 'Blocks' ); await expect( ZoomUtils.zoomCanvas ).toBeHidden(); @@ -182,15 +159,12 @@ test.describe( 'Site Editor Inserter', () => { await expect( ZoomUtils.zoomCanvas ).toBeVisible(); // Toggle zoom level manually - await ZoomUtils.toggleZoomLevel(); - await expect( ZoomUtils.zoomCanvas ).toBeHidden(); + await ZoomUtils.exitZoomOut(); await InserterUtils.activateTab( 'Blocks' ); await expect( ZoomUtils.zoomCanvas ).toBeHidden(); - // Close inserter - await InserterUtils.toggleBlockLibrary(); - await expect( InserterUtils.blockLibrary ).toBeHidden(); + await InserterUtils.closeBlockLibrary(); // Zoom Level should stay at default level await expect( ZoomUtils.zoomCanvas ).toBeHidden(); @@ -198,7 +172,7 @@ test.describe( 'Site Editor Inserter', () => { await test.step( 'should preserve default zoom level when closing from blocks tab even if user manually toggled zoom level on previous tab twice', async () => { // Open inserter - await InserterUtils.toggleBlockLibrary(); + await InserterUtils.openBlockLibrary(); await InserterUtils.expectActiveTab( 'Blocks' ); await expect( ZoomUtils.zoomCanvas ).toBeHidden(); @@ -206,17 +180,13 @@ test.describe( 'Site Editor Inserter', () => { await expect( ZoomUtils.zoomCanvas ).toBeVisible(); // Toggle zoom level manually twice - await ZoomUtils.toggleZoomLevel(); - await expect( ZoomUtils.zoomCanvas ).toBeHidden(); - await ZoomUtils.toggleZoomLevel(); - await expect( ZoomUtils.zoomCanvas ).toBeVisible(); + await ZoomUtils.exitZoomOut(); + await ZoomUtils.enterZoomOut(); await InserterUtils.activateTab( 'Blocks' ); await expect( ZoomUtils.zoomCanvas ).toBeHidden(); - // Close inserter - await InserterUtils.toggleBlockLibrary(); - await expect( InserterUtils.blockLibrary ).toBeHidden(); + await InserterUtils.closeBlockLibrary(); // Zoom Level should stay at default level await expect( ZoomUtils.zoomCanvas ).toBeHidden(); @@ -228,65 +198,52 @@ test.describe( 'Site Editor Inserter', () => { ZoomUtils, } ) => { await test.step( 'should respect manual zoom level set when closing from patterns tab', async () => { - // Open inserter - await InserterUtils.toggleBlockLibrary(); + await InserterUtils.openBlockLibrary(); await InserterUtils.expectActiveTab( 'Blocks' ); await expect( ZoomUtils.zoomCanvas ).toBeHidden(); await InserterUtils.activateTab( 'Patterns' ); await expect( ZoomUtils.zoomCanvas ).toBeVisible(); - await ZoomUtils.toggleZoomLevel(); - await expect( ZoomUtils.zoomCanvas ).toBeHidden(); + await ZoomUtils.exitZoomOut(); - // Close inserter - await InserterUtils.toggleBlockLibrary(); - await expect( InserterUtils.blockLibrary ).toBeHidden(); + await InserterUtils.closeBlockLibrary(); // Zoom Level should stay reset await expect( ZoomUtils.zoomCanvas ).toBeHidden(); } ); await test.step( 'should respect manual zoom level set when closing from patterns tab when toggled twice', async () => { - // Open inserter - await InserterUtils.toggleBlockLibrary(); + await InserterUtils.openBlockLibrary(); await InserterUtils.expectActiveTab( 'Blocks' ); await expect( ZoomUtils.zoomCanvas ).toBeHidden(); await InserterUtils.activateTab( 'Patterns' ); await expect( ZoomUtils.zoomCanvas ).toBeVisible(); - await ZoomUtils.toggleZoomLevel(); - await expect( ZoomUtils.zoomCanvas ).toBeHidden(); + await ZoomUtils.exitZoomOut(); - await ZoomUtils.toggleZoomLevel(); - await expect( ZoomUtils.zoomCanvas ).toBeVisible(); + await ZoomUtils.enterZoomOut(); - // Close inserter - await InserterUtils.toggleBlockLibrary(); - await expect( InserterUtils.blockLibrary ).toBeHidden(); + await InserterUtils.closeBlockLibrary(); // Should stay zoomed out since it was manually engaged await expect( ZoomUtils.zoomCanvas ).toBeVisible(); - // Toggle to reset test - await ZoomUtils.toggleZoomLevel(); - await expect( ZoomUtils.zoomCanvas ).toBeHidden(); + // Reset test + await ZoomUtils.exitZoomOut(); } ); - await test.step( 'should not reset zoom level if zoom level manually toggled from blocks tab', async () => { - await InserterUtils.toggleBlockLibrary(); + await test.step( 'should not reset zoom level if zoom level manually changed from blocks tab', async () => { + await InserterUtils.openBlockLibrary(); await expect( InserterUtils.blockLibrary ).toBeVisible(); await InserterUtils.expectActiveTab( 'Blocks' ); await expect( ZoomUtils.zoomCanvas ).toBeHidden(); - await ZoomUtils.toggleZoomLevel(); - await expect( ZoomUtils.zoomCanvas ).toBeVisible(); + await ZoomUtils.enterZoomOut(); - // Close the inserter - await InserterUtils.toggleBlockLibrary(); - await expect( InserterUtils.blockLibrary ).toBeHidden(); + await InserterUtils.closeBlockLibrary(); // Should stay zoomed out since it was manually engaged await expect( ZoomUtils.zoomCanvas ).toBeVisible(); @@ -311,8 +268,16 @@ class InserterUtils { this.mediaTab = this.getBlockLibraryTab( 'Media' ); } - async toggleBlockLibrary() { + // Manually naming as open and close these makes it clearer when reading + // through the test instead of using a toggle method with a boolean + async openBlockLibrary() { await this.inserterButton.click(); + await expect( this.blockLibrary ).toBeVisible(); + } + + async closeBlockLibrary() { + await this.inserterButton.click(); + await expect( this.blockLibrary ).toBeHidden(); } getBlockLibraryTab( name ) { @@ -344,7 +309,15 @@ class ZoomUtils { } ); } - async toggleZoomLevel() { + // Manually naming as enter and exit these makes it clearer when reading + // through the test instead of using a toggle method with a boolean + async enterZoomOut() { + await this.zoomButton.click(); + await expect( this.zoomCanvas ).toBeVisible(); + } + + async exitZoomOut() { await this.zoomButton.click(); + await expect( this.zoomCanvas ).toBeHidden(); } } From 7980e26daee276517b8b9baec18a4b0d4b844f84 Mon Sep 17 00:00:00 2001 From: Jerry Jones Date: Thu, 5 Dec 2024 14:32:13 -0600 Subject: [PATCH 13/16] use aria-selected instead of data-active-item to check for active block tab --- test/e2e/specs/site-editor/site-editor-inserter.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/specs/site-editor/site-editor-inserter.spec.js b/test/e2e/specs/site-editor/site-editor-inserter.spec.js index a542f21ea4c41..d34d2d7e313d8 100644 --- a/test/e2e/specs/site-editor/site-editor-inserter.spec.js +++ b/test/e2e/specs/site-editor/site-editor-inserter.spec.js @@ -286,7 +286,7 @@ class InserterUtils { async expectActiveTab( name ) { await expect( this.getBlockLibraryTab( name ) ).toHaveAttribute( - 'data-active-item', + 'aria-selected', 'true' ); } From 3318d088e9cb99e3eb1d389636dcc12a8599b08f Mon Sep 17 00:00:00 2001 From: Jerry Jones Date: Thu, 5 Dec 2024 15:32:57 -0600 Subject: [PATCH 14/16] Remove unused seleectors --- test/e2e/specs/site-editor/site-editor-inserter.spec.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/e2e/specs/site-editor/site-editor-inserter.spec.js b/test/e2e/specs/site-editor/site-editor-inserter.spec.js index d34d2d7e313d8..db1d435e66f14 100644 --- a/test/e2e/specs/site-editor/site-editor-inserter.spec.js +++ b/test/e2e/specs/site-editor/site-editor-inserter.spec.js @@ -263,9 +263,6 @@ class InserterUtils { name: 'Block Inserter', exact: true, } ); - this.blocksTab = this.getBlockLibraryTab( 'Blocks' ); - this.patternsTab = this.getBlockLibraryTab( 'Patterns' ); - this.mediaTab = this.getBlockLibraryTab( 'Media' ); } // Manually naming as open and close these makes it clearer when reading From 0e05eb3e2fb9df39bb5e6660607a09020b5da050 Mon Sep 17 00:00:00 2001 From: Jerry Jones Date: Fri, 6 Dec 2024 08:47:09 -0600 Subject: [PATCH 15/16] Add deleteAllTemplates calls back in --- test/e2e/specs/site-editor/site-editor-inserter.spec.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/e2e/specs/site-editor/site-editor-inserter.spec.js b/test/e2e/specs/site-editor/site-editor-inserter.spec.js index db1d435e66f14..a730367d841bf 100644 --- a/test/e2e/specs/site-editor/site-editor-inserter.spec.js +++ b/test/e2e/specs/site-editor/site-editor-inserter.spec.js @@ -6,7 +6,11 @@ const { test, expect } = require( '@wordpress/e2e-test-utils-playwright' ); test.describe( 'Site Editor Inserter', () => { test.beforeAll( async ( { requestUtils } ) => { // We need the theme to have a section root so zoom out is enabled - await requestUtils.activateTheme( 'twentytwentyfour' ); + await Promise.all( [ + requestUtils.activateTheme( 'twentytwentyfour' ), + requestUtils.deleteAllTemplates( 'wp_template' ), + requestUtils.deleteAllTemplates( 'wp_template_part' ), + ] ); } ); test.afterAll( async ( { requestUtils } ) => { From 011597d02dc0e999bd617b5bf02f96b0a2f3af64 Mon Sep 17 00:00:00 2001 From: Jerry Jones Date: Fri, 6 Dec 2024 11:36:42 -0600 Subject: [PATCH 16/16] Normalize preload test by resetting preferences before the test starts This test kept failing for me, and I isolated it to if a test before it had run await admin.visitSiteEditor(), then the preload test would fail because the user had previously visited the site editor. By resetting preferences before the test runs, it allows a cleaner enviroment and the test has consistent results. --- test/e2e/specs/site-editor/preload.spec.js | 1 + 1 file changed, 1 insertion(+) diff --git a/test/e2e/specs/site-editor/preload.spec.js b/test/e2e/specs/site-editor/preload.spec.js index 2cd61283fbd9e..e731e932e3052 100644 --- a/test/e2e/specs/site-editor/preload.spec.js +++ b/test/e2e/specs/site-editor/preload.spec.js @@ -6,6 +6,7 @@ const { test, expect } = require( '@wordpress/e2e-test-utils-playwright' ); test.describe( 'Preload', () => { test.beforeAll( async ( { requestUtils } ) => { await requestUtils.activateTheme( 'emptytheme' ); + await requestUtils.resetPreferences(); } ); test.afterAll( async ( { requestUtils } ) => {