From bb982a801c8bafd0752ff6a87bc328ae578cf7ce Mon Sep 17 00:00:00 2001 From: Aki Hamano <54422211+t-hamano@users.noreply.github.com> Date: Sat, 4 Nov 2023 02:23:55 +0900 Subject: [PATCH 01/15] Update `blockEditor.__unstableCanInsertBlockType` hook namespace (#55845) --- packages/block-library/src/form/index.js | 2 +- packages/block-library/src/template-part/index.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/block-library/src/form/index.js b/packages/block-library/src/form/index.js index a67fc67ca06f0c..1e45c642b6d48e 100644 --- a/packages/block-library/src/form/index.js +++ b/packages/block-library/src/form/index.js @@ -27,7 +27,7 @@ export const init = () => { const DISALLOWED_PARENTS = [ 'core/form' ]; addFilter( 'blockEditor.__unstableCanInsertBlockType', - 'removeTemplatePartsFromPostTemplates', + 'core/block-library/preventInsertingFormIntoAnotherForm', ( canInsert, blockType, diff --git a/packages/block-library/src/template-part/index.js b/packages/block-library/src/template-part/index.js index c64f093427f95f..a68dd2301be22c 100644 --- a/packages/block-library/src/template-part/index.js +++ b/packages/block-library/src/template-part/index.js @@ -60,7 +60,7 @@ export const init = () => { const DISALLOWED_PARENTS = [ 'core/post-template', 'core/post-content' ]; addFilter( 'blockEditor.__unstableCanInsertBlockType', - 'removeTemplatePartsFromPostTemplates', + 'core/block-library/removeTemplatePartsFromPostTemplates', ( canInsert, blockType, From d4d857134a0a4d439c528bb5c303acae7a91f014 Mon Sep 17 00:00:00 2001 From: Ella <4710635+ellatrix@users.noreply.github.com> Date: Fri, 3 Nov 2023 19:25:29 +0200 Subject: [PATCH 02/15] Data Views: add initial "Side by side" prototype (#55343) --- .../src/components/dataviews/dataviews.js | 18 ++++- .../src/components/dataviews/index.js | 2 +- .../src/components/dataviews/view-actions.js | 4 ++ .../components/dataviews/view-side-by-side.js | 9 +++ .../src/components/layout/style.scss | 7 +- .../src/components/page-pages/index.js | 70 ++++++++++++++----- .../src/components/page-pages/side-editor.js | 14 ++++ .../use-init-edited-entity-from-url.js | 8 ++- 8 files changed, 111 insertions(+), 21 deletions(-) create mode 100644 packages/edit-site/src/components/dataviews/view-side-by-side.js create mode 100644 packages/edit-site/src/components/page-pages/side-editor.js diff --git a/packages/edit-site/src/components/dataviews/dataviews.js b/packages/edit-site/src/components/dataviews/dataviews.js index 81a1224b4c9fec..cc983f25e9e719 100644 --- a/packages/edit-site/src/components/dataviews/dataviews.js +++ b/packages/edit-site/src/components/dataviews/dataviews.js @@ -16,6 +16,22 @@ import ViewActions from './view-actions'; import Filters from './filters'; import Search from './search'; import { ViewGrid } from './view-grid'; +import { ViewSideBySide } from './view-side-by-side'; + +// To do: convert to view type registry. +export const viewTypeSupportsMap = { + list: {}, + grid: {}, + 'side-by-side': { + preview: true, + }, +}; + +const viewTypeMap = { + list: ViewList, + grid: ViewGrid, + 'side-by-side': ViewSideBySide, +}; export default function DataViews( { view, @@ -28,7 +44,7 @@ export default function DataViews( { isLoading = false, paginationInfo, } ) { - const ViewComponent = view.type === 'list' ? ViewList : ViewGrid; + const ViewComponent = viewTypeMap[ view.type ]; const _fields = useMemo( () => { return fields.map( ( field ) => ( { ...field, diff --git a/packages/edit-site/src/components/dataviews/index.js b/packages/edit-site/src/components/dataviews/index.js index 422d128b1461d0..eebdb77220c689 100644 --- a/packages/edit-site/src/components/dataviews/index.js +++ b/packages/edit-site/src/components/dataviews/index.js @@ -1 +1 @@ -export { default as DataViews } from './dataviews'; +export { default as DataViews, viewTypeSupportsMap } from './dataviews'; diff --git a/packages/edit-site/src/components/dataviews/view-actions.js b/packages/edit-site/src/components/dataviews/view-actions.js index b0a7cb0412b0e1..035ab6e36facf2 100644 --- a/packages/edit-site/src/components/dataviews/view-actions.js +++ b/packages/edit-site/src/components/dataviews/view-actions.js @@ -38,6 +38,10 @@ const availableViews = [ id: 'grid', label: __( 'Grid' ), }, + { + id: 'side-by-side', + label: __( 'Side by side' ), + }, ]; function ViewTypeMenu( { view, onChangeView } ) { diff --git a/packages/edit-site/src/components/dataviews/view-side-by-side.js b/packages/edit-site/src/components/dataviews/view-side-by-side.js new file mode 100644 index 00000000000000..47b1551b379b31 --- /dev/null +++ b/packages/edit-site/src/components/dataviews/view-side-by-side.js @@ -0,0 +1,9 @@ +/** + * Internal dependencies + */ +import ViewList from './view-list'; + +export function ViewSideBySide( props ) { + // To do: change to email-like preview list. + return ; +} diff --git a/packages/edit-site/src/components/layout/style.scss b/packages/edit-site/src/components/layout/style.scss index 11c7bdeeaf2a19..088217776b4d29 100644 --- a/packages/edit-site/src/components/layout/style.scss +++ b/packages/edit-site/src/components/layout/style.scss @@ -157,11 +157,16 @@ } // This shouldn't be necessary (we should have a way to say that a skeletton is relative -.edit-site-layout__canvas .interface-interface-skeleton { +.edit-site-layout__canvas .interface-interface-skeleton, +.edit-site-page-pages-preview .interface-interface-skeleton { position: relative !important; min-height: 100% !important; } +.edit-site-page-pages-preview { + height: 100%; +} + .edit-site-layout__view-mode-toggle.components-button { position: relative; color: $white; diff --git a/packages/edit-site/src/components/page-pages/index.js b/packages/edit-site/src/components/page-pages/index.js index 7076794f27a7ee..4ea187cb3a5225 100644 --- a/packages/edit-site/src/components/page-pages/index.js +++ b/packages/edit-site/src/components/page-pages/index.js @@ -17,7 +17,7 @@ import { privateApis as routerPrivateApis } from '@wordpress/router'; */ import Page from '../page'; import Link from '../routes/link'; -import { DataViews } from '../dataviews'; +import { DataViews, viewTypeSupportsMap } from '../dataviews'; import { default as DEFAULT_VIEWS } from './default-views'; import { useTrashPostAction, @@ -27,6 +27,7 @@ import { viewPostAction, useEditPostAction, } from '../actions'; +import SideEditor from './side-editor'; import Media from '../media'; import { unlock } from '../../lock-unlock'; const { useLocation } = unlock( routerPrivateApis ); @@ -44,6 +45,8 @@ const defaultConfigPerViewType = { export const DEFAULT_STATUSES = 'draft,future,pending,private,publish'; // All statuses but 'trash'. export default function PagePages() { + const postType = 'page'; + const [ selection, setSelection ] = useState( [] ); const { params: { path, activeView = 'all' }, } = useLocation(); @@ -99,7 +102,7 @@ export default function PagePages() { isResolving: isLoadingPages, totalItems, totalPages, - } = useEntityRecords( 'postType', 'page', queryArgs ); + } = useEntityRecords( 'postType', postType, queryArgs ); const { records: authors, isResolving: isLoadingAuthors } = useEntityRecords( 'root', 'user' ); @@ -136,7 +139,7 @@ export default function PagePages() { header: __( 'Title' ), id: 'title', getValue: ( { item } ) => item.title?.rendered || item.slug, - render: ( { item } ) => { + render: ( { item, view: { type } } ) => { return ( @@ -146,6 +149,14 @@ export default function PagePages() { postType: item.type, canvas: 'edit', } } + onClick={ ( event ) => { + if ( + viewTypeSupportsMap[ type ].preview + ) { + event.preventDefault(); + setSelection( [ item.id ] ); + } + } } > { decodeEntities( item.title?.rendered || item.slug @@ -250,18 +261,45 @@ export default function PagePages() { // TODO: we need to handle properly `data={ data || EMPTY_ARRAY }` for when `isLoading`. return ( - - - + <> + + + + { viewTypeSupportsMap[ view.type ].preview && ( + + + { selection.length === 1 && ( + + ) } + { selection.length !== 1 && ( + + { __( 'Select a page to preview' ) } + + ) } + + + ) } + > ); } diff --git a/packages/edit-site/src/components/page-pages/side-editor.js b/packages/edit-site/src/components/page-pages/side-editor.js new file mode 100644 index 00000000000000..fca561cf9f4d5d --- /dev/null +++ b/packages/edit-site/src/components/page-pages/side-editor.js @@ -0,0 +1,14 @@ +/** + * Internal dependencies + */ +import Editor from '../editor'; +import { useInitEditedEntity } from '../sync-state-with-url/use-init-edited-entity-from-url'; + +export default function SideEditor( { postType, postId } ) { + useInitEditedEntity( { + postId, + postType, + } ); + + return ; +} diff --git a/packages/edit-site/src/components/sync-state-with-url/use-init-edited-entity-from-url.js b/packages/edit-site/src/components/sync-state-with-url/use-init-edited-entity-from-url.js index b178ce501301ef..f94428e6bf0881 100644 --- a/packages/edit-site/src/components/sync-state-with-url/use-init-edited-entity-from-url.js +++ b/packages/edit-site/src/components/sync-state-with-url/use-init-edited-entity-from-url.js @@ -20,8 +20,7 @@ import { const { useLocation } = unlock( routerPrivateApis ); -export default function useInitEditedEntityFromURL() { - const { params: { postId, postType } = {} } = useLocation(); +export function useInitEditedEntity( { postId, postType } ) { const { isRequestingSite, homepageId, url } = useSelect( ( select ) => { const { getSite, getUnstableBase } = select( coreDataStore ); const siteData = getSite(); @@ -92,3 +91,8 @@ export default function useInitEditedEntityFromURL() { setNavigationMenu, ] ); } + +export default function useInitEditedEntityFromURL() { + const { params = {} } = useLocation(); + return useInitEditedEntity( params ); +} From 75a44898003590cf808ddae603f44c74a5fc805b Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Fri, 3 Nov 2023 18:09:33 +0000 Subject: [PATCH 03/15] Fix: Use of integer value in a conditional rendering condition on Gradients. (#55855) --- packages/components/src/gradient-picker/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/components/src/gradient-picker/index.tsx b/packages/components/src/gradient-picker/index.tsx index 13e2a430660380..b435ded2bcd0d8 100644 --- a/packages/components/src/gradient-picker/index.tsx +++ b/packages/components/src/gradient-picker/index.tsx @@ -257,7 +257,7 @@ export function GradientPicker( { onChange={ onChange } /> ) } - { ( gradients.length || clearable ) && ( + { ( gradients.length > 0 || clearable ) && ( Date: Fri, 3 Nov 2023 17:10:20 -0400 Subject: [PATCH 04/15] Fix lightbox trigger styles (#55859) * Update icons * Update styles * Tweak offset values to 16 --- packages/block-library/src/image/index.php | 7 +++--- packages/block-library/src/image/style.scss | 25 ++++++++++++--------- packages/block-library/src/image/view.js | 12 +++++----- 3 files changed, 24 insertions(+), 20 deletions(-) diff --git a/packages/block-library/src/image/index.php b/packages/block-library/src/image/index.php index c465677a986e05..acefd5714bbd47 100644 --- a/packages/block-library/src/image/index.php +++ b/packages/block-library/src/image/index.php @@ -242,10 +242,9 @@ class="lightbox-trigger" data-wp-on--click="actions.core.image.showLightbox" data-wp-style--right="context.core.image.imageButtonRight" data-wp-style--top="context.core.image.imageButtonTop" - style="background: #000" > - - + + '; @@ -303,7 +302,7 @@ class="lightbox-trigger" } } - $close_button_icon = ''; + $close_button_icon = ''; $close_button_label = esc_attr__( 'Close' ); $lightbox_html = << { From c56f8d450c3d5043f443a292982d5a6eb00be56e Mon Sep 17 00:00:00 2001 From: Peter Wilson <519727+peterwilsoncc@users.noreply.github.com> Date: Sat, 4 Nov 2023 09:23:09 +1100 Subject: [PATCH 05/15] Add default type labels to issue templates. (#55826) --- .github/ISSUE_TEMPLATE/Bug_report.yml | 1 + .github/ISSUE_TEMPLATE/Feature_request.md | 1 + .github/ISSUE_TEMPLATE/New_release.md | 1 + 3 files changed, 3 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/Bug_report.yml b/.github/ISSUE_TEMPLATE/Bug_report.yml index ab001b41ff793e..1109056e7e5d56 100644 --- a/.github/ISSUE_TEMPLATE/Bug_report.yml +++ b/.github/ISSUE_TEMPLATE/Bug_report.yml @@ -1,5 +1,6 @@ name: Bug report description: Report a bug with the WordPress block editor or Gutenberg plugin +labels: ['[Type] Bug'] body: - type: markdown attributes: diff --git a/.github/ISSUE_TEMPLATE/Feature_request.md b/.github/ISSUE_TEMPLATE/Feature_request.md index cfae99f42ff9ea..1dd8097974e11b 100644 --- a/.github/ISSUE_TEMPLATE/Feature_request.md +++ b/.github/ISSUE_TEMPLATE/Feature_request.md @@ -1,6 +1,7 @@ --- name: Feature request about: Propose an idea for a feature or an enhancement +labels: [Type] Enhancement --- diff --git a/.github/ISSUE_TEMPLATE/New_release.md b/.github/ISSUE_TEMPLATE/New_release.md index d6732a659731f6..629a4dafa5ba56 100644 --- a/.github/ISSUE_TEMPLATE/New_release.md +++ b/.github/ISSUE_TEMPLATE/New_release.md @@ -1,6 +1,7 @@ --- name: Gutenberg Release about: A checklist for the Gutenberg plugin release process +labels: Gutenberg Plugin, [Type] Project Management --- This issue is to provide visibility on the progress of the release process of Gutenberg VERSION_NUMBER and to centralize any conversations about it. The ultimate goal of this issue is to keep the reference of the steps, resources, work, and conversations about this release so it can be helpful for the next contributors releasing a new Gutenberg version. From d137227a67c43d04a6cba0cfacf8dd7f95cb74d5 Mon Sep 17 00:00:00 2001 From: Peter Wilson <519727+peterwilsoncc@users.noreply.github.com> Date: Sat, 4 Nov 2023 09:36:12 +1100 Subject: [PATCH 06/15] Quote feature request label in issue template. (#55862) --- .github/ISSUE_TEMPLATE/Feature_request.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/Feature_request.md b/.github/ISSUE_TEMPLATE/Feature_request.md index 1dd8097974e11b..66bd0943c31b45 100644 --- a/.github/ISSUE_TEMPLATE/Feature_request.md +++ b/.github/ISSUE_TEMPLATE/Feature_request.md @@ -1,7 +1,7 @@ --- name: Feature request about: Propose an idea for a feature or an enhancement -labels: [Type] Enhancement +labels: "[Type] Enhancement" --- From 74f5af440c02681bbe54e1b7c58358edbd543b2b Mon Sep 17 00:00:00 2001 From: Renatho De Carli Rosa Date: Sun, 5 Nov 2023 08:56:38 -0300 Subject: [PATCH 07/15] Make sure it doesn't break if current theme is not ready yet (#55858) --- packages/block-library/src/pattern/edit.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/block-library/src/pattern/edit.js b/packages/block-library/src/pattern/edit.js index e8068faf5013d9..43d78755304814 100644 --- a/packages/block-library/src/pattern/edit.js +++ b/packages/block-library/src/pattern/edit.js @@ -20,7 +20,7 @@ const PatternEdit = ( { attributes, clientId } ) => { ); const currentThemeStylesheet = useSelect( - ( select ) => select( coreStore ).getCurrentTheme().stylesheet + ( select ) => select( coreStore ).getCurrentTheme()?.stylesheet ); const { replaceBlocks, __unstableMarkNextChangeAsNotPersistent } = From b4857fda09a8f0c6a70efe1e7603666852b824cc Mon Sep 17 00:00:00 2001 From: Nick Diego Date: Sun, 5 Nov 2023 09:38:57 -0600 Subject: [PATCH 08/15] Fix formatting issue. (#55872) --- docs/getting-started/devenv/get-started-with-create-block.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started/devenv/get-started-with-create-block.md b/docs/getting-started/devenv/get-started-with-create-block.md index 8b3a7b5867476f..a01c08a4ce2f44 100644 --- a/docs/getting-started/devenv/get-started-with-create-block.md +++ b/docs/getting-started/devenv/get-started-with-create-block.md @@ -57,7 +57,7 @@ See the `wp-scripts` [package documentation](https://developer.wordpress.org/blo ### Interactive mode -For developers who prefer a more guided experience, the `create-block package` provides an interactive mode. Instead of manually specifying all options upfront, like the `slug` in the above example, this mode will prompt you for inputs step-by-step. +For developers who prefer a more guided experience, the `create-block` package provides an interactive mode. Instead of manually specifying all options upfront, like the `slug` in the above example, this mode will prompt you for inputs step-by-step. To use this mode, run the command: From 7d93901d449236d8507404dacf09d424a76cdee2 Mon Sep 17 00:00:00 2001 From: Ramon Date: Mon, 6 Nov 2023 15:56:03 +1100 Subject: [PATCH 09/15] Image block: don't show pointer cursor on linked image in the editor (#55882) * When the Image block is linked it's wrapped with a disabled tag. This created a small regression in the editor: the cursor shows the "pointer" style. In this PR we restore cursor style, so it doesn't appear 'clickable'. * Move the cursor rule to nest underneath `.wp-block-image {` for less specificity --- packages/block-library/src/image/editor.scss | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/block-library/src/image/editor.scss b/packages/block-library/src/image/editor.scss index 934682ed91b7de..e1721928362149 100644 --- a/packages/block-library/src/image/editor.scss +++ b/packages/block-library/src/image/editor.scss @@ -62,6 +62,13 @@ figure.wp-block-image:not(.wp-block) { left: 50%; transform: translate(-50%, -50%); } + + // When the Image block is linked, + // it's wrapped with a disabled tag. + // Restore cursor style so it doesn't appear 'clickable'. + > a { + cursor: default; + } } // This is necessary for the editor resize handles to accurately work on a non-floated, non-resized, small image. From ce3ef3e2fdb52c1d0ba9a8ae6f3dfe28b2e242e0 Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Mon, 6 Nov 2023 12:56:39 +0400 Subject: [PATCH 10/15] Migrate 'meta-attribute-block' e2e tests to Playwright (#55830) * Migrate 'meta-attribute-block' e2e tests to Playwright * Remove old test files * Fix plugin name --- .../meta-attribute-block.test.js.snap | 9 -- .../plugins/meta-attribute-block.test.js | 100 ----------------- .../plugins/meta-attribute-block.spec.js | 104 ++++++++++++++++++ 3 files changed, 104 insertions(+), 109 deletions(-) delete mode 100644 packages/e2e-tests/specs/editor/plugins/__snapshots__/meta-attribute-block.test.js.snap delete mode 100644 packages/e2e-tests/specs/editor/plugins/meta-attribute-block.test.js create mode 100644 test/e2e/specs/editor/plugins/meta-attribute-block.spec.js diff --git a/packages/e2e-tests/specs/editor/plugins/__snapshots__/meta-attribute-block.test.js.snap b/packages/e2e-tests/specs/editor/plugins/__snapshots__/meta-attribute-block.test.js.snap deleted file mode 100644 index 268c8b45d059f2..00000000000000 --- a/packages/e2e-tests/specs/editor/plugins/__snapshots__/meta-attribute-block.test.js.snap +++ /dev/null @@ -1,9 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Block with a meta attribute Early Registration Should persist the meta attribute properly 1`] = `""`; - -exports[`Block with a meta attribute Early Registration Should persist the meta attribute properly in a different post type 1`] = `""`; - -exports[`Block with a meta attribute Late Registration Should persist the meta attribute properly 1`] = `""`; - -exports[`Block with a meta attribute Late Registration Should persist the meta attribute properly in a different post type 1`] = `""`; diff --git a/packages/e2e-tests/specs/editor/plugins/meta-attribute-block.test.js b/packages/e2e-tests/specs/editor/plugins/meta-attribute-block.test.js deleted file mode 100644 index a95d11b4f7dadb..00000000000000 --- a/packages/e2e-tests/specs/editor/plugins/meta-attribute-block.test.js +++ /dev/null @@ -1,100 +0,0 @@ -/** - * WordPress dependencies - */ -import { - activatePlugin, - createNewPost, - deactivatePlugin, - getEditedPostContent, - insertBlock, - saveDraft, - pressKeyTimes, -} from '@wordpress/e2e-test-utils'; - -describe( 'Block with a meta attribute', () => { - beforeAll( async () => { - await activatePlugin( 'gutenberg-test-meta-attribute-block' ); - } ); - - beforeEach( async () => { - await createNewPost(); - } ); - - afterAll( async () => { - await deactivatePlugin( 'gutenberg-test-meta-attribute-block' ); - } ); - - describe.each( [ [ 'Early Registration' ], [ 'Late Registration' ] ] )( - '%s', - ( variant ) => { - it( 'Should persist the meta attribute properly', async () => { - await insertBlock( `Test Meta Attribute Block (${ variant })` ); - await page.keyboard.type( 'Value' ); - - // Regression Test: Previously the caret would wrongly reset to the end - // of any input for meta-sourced attributes, due to syncing behavior of - // meta attribute updates. - // - // See: https://github.com/WordPress/gutenberg/issues/15739 - await pressKeyTimes( 'ArrowLeft', 5 ); - await page.keyboard.type( 'Meta ' ); - - await saveDraft(); - await page.reload(); - await page.waitForSelector( '.edit-post-layout' ); - - expect( await getEditedPostContent() ).toMatchSnapshot(); - const persistedValue = await page.evaluate( - () => document.querySelector( '.my-meta-input' ).value - ); - expect( persistedValue ).toBe( 'Meta Value' ); - } ); - - it( 'Should use the same value in all the blocks', async () => { - await insertBlock( `Test Meta Attribute Block (${ variant })` ); - await insertBlock( `Test Meta Attribute Block (${ variant })` ); - await insertBlock( `Test Meta Attribute Block (${ variant })` ); - await page.keyboard.type( 'Meta Value' ); - - const inputs = await page.$$( '.my-meta-input' ); - await Promise.all( - inputs.map( async ( input ) => { - // Clicking the input selects the block, - // and selecting the block enables the sync data mode - // as otherwise the asynchronous re-rendering of unselected blocks - // may cause the input to have not yet been updated for the other blocks. - await input.click(); - const inputValue = await input.getProperty( 'value' ); - expect( await inputValue.jsonValue() ).toBe( - 'Meta Value' - ); - } ) - ); - } ); - - it( 'Should persist the meta attribute properly in a different post type', async () => { - await createNewPost( { postType: 'page' } ); - await insertBlock( `Test Meta Attribute Block (${ variant })` ); - await page.keyboard.type( 'Value' ); - - // Regression Test: Previously the caret would wrongly reset to the end - // of any input for meta-sourced attributes, due to syncing behavior of - // meta attribute updates. - // - // See: https://github.com/WordPress/gutenberg/issues/15739 - await pressKeyTimes( 'ArrowLeft', 5 ); - await page.keyboard.type( 'Meta ' ); - - await saveDraft(); - await page.reload(); - await page.waitForSelector( '.edit-post-layout' ); - - expect( await getEditedPostContent() ).toMatchSnapshot(); - const persistedValue = await page.evaluate( - () => document.querySelector( '.my-meta-input' ).value - ); - expect( persistedValue ).toBe( 'Meta Value' ); - } ); - } - ); -} ); diff --git a/test/e2e/specs/editor/plugins/meta-attribute-block.spec.js b/test/e2e/specs/editor/plugins/meta-attribute-block.spec.js new file mode 100644 index 00000000000000..f11d59b39dc6d8 --- /dev/null +++ b/test/e2e/specs/editor/plugins/meta-attribute-block.spec.js @@ -0,0 +1,104 @@ +/** + * WordPress dependencies + */ +const { test, expect } = require( '@wordpress/e2e-test-utils-playwright' ); + +const VARIATIONS = [ + [ 'Early Registration', 'test/test-meta-attribute-block-early' ], + [ 'Late Registration', 'test/test-meta-attribute-block-late' ], +]; + +test.describe( 'Block with a meta attribute', () => { + test.beforeAll( async ( { requestUtils } ) => { + await requestUtils.activatePlugin( + 'gutenberg-test-meta-attribute-block' + ); + } ); + + test.afterAll( async ( { requestUtils } ) => { + await requestUtils.deactivatePlugin( + 'gutenberg-test-meta-attribute-block' + ); + } ); + + for ( const [ title, blockName ] of VARIATIONS ) { + test.describe( title, () => { + test( 'Should persist the meta attribute properly', async ( { + admin, + editor, + page, + pageUtils, + } ) => { + await admin.createNewPost(); + await editor.insertBlock( { name: blockName } ); + await page.keyboard.type( 'Value' ); + + // Regression Test: Previously the caret would wrongly reset to the end + // of any input for meta-sourced attributes, due to syncing behavior of + // meta attribute updates. + // + // See: https://github.com/WordPress/gutenberg/issues/15739 + await pageUtils.pressKeys( 'ArrowLeft', { times: 5 } ); + await page.keyboard.type( 'Meta ' ); + + await editor.saveDraft(); + await page.reload(); + + const block = page.getByRole( 'document', { + name: `Block: Test Meta Attribute Block (${ title })`, + } ); + await expect( block ).toBeVisible(); + await expect( block.locator( '.my-meta-input' ) ).toHaveValue( + 'Meta Value' + ); + } ); + + test( 'Should use the same value in all the blocks', async ( { + admin, + editor, + page, + } ) => { + await admin.createNewPost(); + await editor.insertBlock( { name: blockName } ); + await editor.insertBlock( { name: blockName } ); + await editor.insertBlock( { name: blockName } ); + await page.keyboard.type( 'Meta Value' ); + + const inputs = await page.locator( '.my-meta-input' ).all(); + for ( const input of inputs ) { + await expect( input ).toHaveValue( 'Meta Value' ); + } + } ); + + test( 'Should persist the meta attribute properly in a different post type', async ( { + admin, + editor, + page, + pageUtils, + } ) => { + await admin.createNewPost( { postType: 'page' } ); + await editor.insertBlock( { name: blockName } ); + await page.keyboard.type( 'Value' ); + + // Regression Test: Previously the caret would wrongly reset to the end + // of any input for meta-sourced attributes, due to syncing behavior of + // meta attribute updates. + // + // See: https://github.com/WordPress/gutenberg/issues/15739 + await pageUtils.pressKeys( 'ArrowLeft', { times: 5 } ); + await page.keyboard.type( 'Meta ' ); + + await editor.saveDraft(); + await page.reload(); + + const block = page.getByRole( 'document', { + name: `Block: Test Meta Attribute Block (${ title })`, + } ); + await expect( block ).toBeVisible(); + await expect( block.locator( '.my-meta-input' ) ).toHaveValue( + 'Meta Value' + ); + } ); + } ); + } +} ); From bc704e140ce6844ce2dc1666bb3697801970bdc7 Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Mon, 6 Nov 2023 09:58:04 +0000 Subject: [PATCH 11/15] lint fixes (+3 squashed commits) (#55773) Squashed commits: [b107c819e2] Feedback application [8ba71aaab4] Post rebase conflicts [13eb412e35] Add: Ability to crate custom DataViews. --- .../src/components/page-pages/index.js | 75 +++++++-- .../sidebar-dataviews/add-new-view.js | 142 ++++++++++++++++++ .../custom-dataviews-list.js | 89 +++++++++++ .../sidebar-dataviews/dataview-item.js | 49 ++++++ .../default-views.js | 50 +++--- .../src/components/sidebar-dataviews/index.js | 81 +++++----- 6 files changed, 406 insertions(+), 80 deletions(-) create mode 100644 packages/edit-site/src/components/sidebar-dataviews/add-new-view.js create mode 100644 packages/edit-site/src/components/sidebar-dataviews/custom-dataviews-list.js create mode 100644 packages/edit-site/src/components/sidebar-dataviews/dataview-item.js rename packages/edit-site/src/components/{page-pages => sidebar-dataviews}/default-views.js (51%) diff --git a/packages/edit-site/src/components/page-pages/index.js b/packages/edit-site/src/components/page-pages/index.js index 4ea187cb3a5225..529b22f01ca530 100644 --- a/packages/edit-site/src/components/page-pages/index.js +++ b/packages/edit-site/src/components/page-pages/index.js @@ -6,11 +6,12 @@ import { __experimentalVStack as VStack, } from '@wordpress/components'; import { __ } from '@wordpress/i18n'; -import { useEntityRecords } from '@wordpress/core-data'; +import { useEntityRecords, store as coreStore } from '@wordpress/core-data'; import { decodeEntities } from '@wordpress/html-entities'; import { useState, useMemo, useCallback, useEffect } from '@wordpress/element'; import { dateI18n, getDate, getSettings } from '@wordpress/date'; import { privateApis as routerPrivateApis } from '@wordpress/router'; +import { useSelect, useDispatch } from '@wordpress/data'; /** * Internal dependencies @@ -18,7 +19,7 @@ import { privateApis as routerPrivateApis } from '@wordpress/router'; import Page from '../page'; import Link from '../routes/link'; import { DataViews, viewTypeSupportsMap } from '../dataviews'; -import { default as DEFAULT_VIEWS } from './default-views'; +import { default as DEFAULT_VIEWS } from '../sidebar-dataviews/default-views'; import { useTrashPostAction, usePermanentlyDeletePostAction, @@ -44,21 +45,69 @@ const defaultConfigPerViewType = { // The reason for that is to match the default statuses coming from the endpoint (entity request). export const DEFAULT_STATUSES = 'draft,future,pending,private,publish'; // All statuses but 'trash'. -export default function PagePages() { - const postType = 'page'; - const [ selection, setSelection ] = useState( [] ); +function useView( type ) { const { - params: { path, activeView = 'all' }, + params: { activeView = 'all', isCustom = 'false' }, } = useLocation(); - const initialView = DEFAULT_VIEWS.find( - ( { slug } ) => slug === activeView - ).view; - const [ view, setView ] = useState( initialView ); + const selectedDefaultView = + isCustom === 'false' && + DEFAULT_VIEWS[ type ].find( ( { slug } ) => slug === activeView )?.view; + const [ view, setView ] = useState( selectedDefaultView ); + useEffect( () => { - setView( - DEFAULT_VIEWS.find( ( { slug } ) => slug === activeView ).view + if ( selectedDefaultView ) { + setView( selectedDefaultView ); + } + }, [ selectedDefaultView ] ); + const editedViewRecord = useSelect( + ( select ) => { + if ( isCustom !== 'true' ) { + return; + } + const { getEditedEntityRecord } = select( coreStore ); + const dataviewRecord = getEditedEntityRecord( + 'postType', + 'wp_dataviews', + Number( activeView ) + ); + return dataviewRecord; + }, + [ activeView, isCustom ] + ); + const { editEntityRecord } = useDispatch( coreStore ); + + const customView = useMemo( () => { + return ( + editedViewRecord?.content && JSON.parse( editedViewRecord?.content ) ); - }, [ path, activeView ] ); + }, [ editedViewRecord?.content ] ); + const setCustomView = useCallback( + ( viewToSet ) => { + editEntityRecord( + 'postType', + 'wp_dataviews', + editedViewRecord?.id, + { + content: JSON.stringify( viewToSet ), + } + ); + }, + [ editEntityRecord, editedViewRecord?.id ] + ); + + if ( isCustom === 'false' ) { + return [ view, setView ]; + } else if ( isCustom === 'true' && customView ) { + return [ customView, setCustomView ]; + } + // Loading state where no the view was not found on custom views or default views. + return [ DEFAULT_VIEWS[ type ][ 0 ].view, setView ]; +} + +export default function PagePages() { + const postType = 'page'; + const [ view, setView ] = useView( postType ); + const [ selection, setSelection ] = useState( [] ); const { records: statuses, isResolving: isLoadingStatus } = useEntityRecords( 'root', 'status' ); const defaultStatuses = useMemo( () => { diff --git a/packages/edit-site/src/components/sidebar-dataviews/add-new-view.js b/packages/edit-site/src/components/sidebar-dataviews/add-new-view.js new file mode 100644 index 00000000000000..220634c54e09b5 --- /dev/null +++ b/packages/edit-site/src/components/sidebar-dataviews/add-new-view.js @@ -0,0 +1,142 @@ +/** + * WordPress dependencies + */ +import { + Modal, + TextControl, + __experimentalHStack as HStack, + __experimentalVStack as VStack, + Button, +} from '@wordpress/components'; +import { __ } from '@wordpress/i18n'; +import { useDispatch, resolveSelect } from '@wordpress/data'; +import { store as coreStore } from '@wordpress/core-data'; +import { useState } from '@wordpress/element'; +import { plus } from '@wordpress/icons'; +import { privateApis as routerPrivateApis } from '@wordpress/router'; + +/** + * Internal dependencies + */ +import SidebarNavigationItem from '../sidebar-navigation-item'; +import DEFAULT_VIEWS from './default-views'; +import { unlock } from '../../lock-unlock'; + +const { useHistory, useLocation } = unlock( routerPrivateApis ); + +function AddNewItemModalContent( { type, setIsAdding } ) { + const { + params: { path }, + } = useLocation(); + const history = useHistory(); + const { saveEntityRecord } = useDispatch( coreStore ); + const [ title, setTitle ] = useState( '' ); + const [ isSaving, setIsSaving ] = useState( false ); + return ( + { + event.preventDefault(); + setIsSaving( true ); + const { getEntityRecords } = resolveSelect( coreStore ); + let dataViewTaxonomyId; + const dataViewTypeRecords = await getEntityRecords( + 'taxonomy', + 'wp_dataviews_type', + { slug: type } + ); + if ( dataViewTypeRecords && dataViewTypeRecords.length > 0 ) { + dataViewTaxonomyId = dataViewTypeRecords[ 0 ].id; + } else { + const record = await saveEntityRecord( + 'taxonomy', + 'wp_dataviews_type', + { name: type } + ); + if ( record && record.id ) { + dataViewTaxonomyId = record.id; + } + } + const savedRecord = await saveEntityRecord( + 'postType', + 'wp_dataviews', + { + title, + status: 'publish', + wp_dataviews_type: dataViewTaxonomyId, + content: JSON.stringify( + DEFAULT_VIEWS[ type ][ 0 ].view + ), + } + ); + history.push( { + path, + activeView: savedRecord.id, + isCustom: 'true', + } ); + setIsSaving( false ); + setIsAdding( false ); + } } + > + + + + { + setIsAdding( false ); + } } + > + { __( 'Cancel' ) } + + + + { __( 'Create' ) } + + + + + ); +} + +export default function AddNewItem( { type } ) { + const [ isAdding, setIsAdding ] = useState( false ); + return ( + <> + { + setIsAdding( true ); + } } + className="dataviews__siderbar-content-add-new-item" + > + { __( 'New view' ) } + + { isAdding && ( + { + setIsAdding( false ); + } } + overlayClassName="" + > + + + ) } + > + ); +} diff --git a/packages/edit-site/src/components/sidebar-dataviews/custom-dataviews-list.js b/packages/edit-site/src/components/sidebar-dataviews/custom-dataviews-list.js new file mode 100644 index 00000000000000..f9b0cddb7d8e1e --- /dev/null +++ b/packages/edit-site/src/components/sidebar-dataviews/custom-dataviews-list.js @@ -0,0 +1,89 @@ +/** + * WordPress dependencies + */ +import { useSelect } from '@wordpress/data'; +import { store as coreStore } from '@wordpress/core-data'; +import { __experimentalItemGroup as ItemGroup } from '@wordpress/components'; +import { useMemo } from '@wordpress/element'; + +/** + * Internal dependencies + */ +import DataViewItem from './dataview-item'; +import AddNewItem from './add-new-view'; + +const EMPTY_ARRAY = []; + +function CustomDataViewItem( { dataviewId, isActive } ) { + const { dataview } = useSelect( + ( select ) => { + const { getEditedEntityRecord } = select( coreStore ); + return { + dataview: getEditedEntityRecord( + 'postType', + 'wp_dataviews', + dataviewId + ), + }; + }, + [ dataviewId ] + ); + const type = useMemo( () => { + const viewContent = JSON.parse( dataview.content ); + return viewContent.type; + }, [ dataview.content ] ); + return ( + + ); +} + +export function useCustomDataViews( type ) { + const customDataViews = useSelect( ( select ) => { + const { getEntityRecords } = select( coreStore ); + const dataViewTypeRecords = getEntityRecords( + 'taxonomy', + 'wp_dataviews_type', + { slug: type } + ); + if ( ! dataViewTypeRecords || dataViewTypeRecords.length === 0 ) { + return EMPTY_ARRAY; + } + const dataViews = getEntityRecords( 'postType', 'wp_dataviews', { + wp_dataviews_type: dataViewTypeRecords[ 0 ].id, + orderby: 'date', + order: 'asc', + } ); + if ( ! dataViews ) { + return EMPTY_ARRAY; + } + return dataViews; + } ); + return customDataViews; +} + +export default function CustomDataViewsList( { type, activeView, isCustom } ) { + const customDataViews = useCustomDataViews( type ); + return ( + + { customDataViews.map( ( customViewRecord ) => { + return ( + + ); + } ) } + + + ); +} diff --git a/packages/edit-site/src/components/sidebar-dataviews/dataview-item.js b/packages/edit-site/src/components/sidebar-dataviews/dataview-item.js new file mode 100644 index 00000000000000..45e3a9d50f3f6f --- /dev/null +++ b/packages/edit-site/src/components/sidebar-dataviews/dataview-item.js @@ -0,0 +1,49 @@ +/** + * WordPress dependencies + */ +import { page, columns } from '@wordpress/icons'; +import { privateApis as routerPrivateApis } from '@wordpress/router'; + +/** + * Internal dependencies + */ +import { useLink } from '../routes/link'; +import SidebarNavigationItem from '../sidebar-navigation-item'; +import { unlock } from '../../lock-unlock'; +const { useLocation } = unlock( routerPrivateApis ); + +function getDataViewIcon( type ) { + const icons = { list: page, grid: columns }; + return icons[ type ]; +} + +export default function DataViewItem( { + title, + slug, + customViewId, + type, + icon, + isActive, + isCustom, +} ) { + const { + params: { path }, + } = useLocation(); + + const iconToUse = icon || getDataViewIcon( type ); + + const linkInfo = useLink( { + path, + activeView: isCustom === 'true' ? customViewId : slug, + isCustom, + } ); + return ( + + { title } + + ); +} diff --git a/packages/edit-site/src/components/page-pages/default-views.js b/packages/edit-site/src/components/sidebar-dataviews/default-views.js similarity index 51% rename from packages/edit-site/src/components/page-pages/default-views.js rename to packages/edit-site/src/components/sidebar-dataviews/default-views.js index fda1ef789e3c84..3a2f5991bdd015 100644 --- a/packages/edit-site/src/components/page-pages/default-views.js +++ b/packages/edit-site/src/components/sidebar-dataviews/default-views.js @@ -21,29 +21,35 @@ const DEFAULT_PAGE_BASE = { layout: {}, }; -const DEFAULT_VIEWS = [ - { - title: __( 'All' ), - slug: 'all', - view: DEFAULT_PAGE_BASE, - }, - { - title: __( 'Drafts' ), - slug: 'drafts', - view: { - ...DEFAULT_PAGE_BASE, - filters: [ { field: 'status', operator: 'in', value: 'draft' } ], +const DEFAULT_VIEWS = { + page: [ + { + title: __( 'All' ), + slug: 'all', + view: DEFAULT_PAGE_BASE, }, - }, - { - title: __( 'Trash' ), - slug: 'trash', - icon: trash, - view: { - ...DEFAULT_PAGE_BASE, - filters: [ { field: 'status', operator: 'in', value: 'trash' } ], + { + title: __( 'Drafts' ), + slug: 'drafts', + view: { + ...DEFAULT_PAGE_BASE, + filters: [ + { field: 'status', operator: 'in', value: 'draft' }, + ], + }, }, - }, -]; + { + title: __( 'Trash' ), + slug: 'trash', + icon: trash, + view: { + ...DEFAULT_PAGE_BASE, + filters: [ + { field: 'status', operator: 'in', value: 'trash' }, + ], + }, + }, + ], +}; export default DEFAULT_VIEWS; diff --git a/packages/edit-site/src/components/sidebar-dataviews/index.js b/packages/edit-site/src/components/sidebar-dataviews/index.js index 7704c0637b4904..9e4534ab342745 100644 --- a/packages/edit-site/src/components/sidebar-dataviews/index.js +++ b/packages/edit-site/src/components/sidebar-dataviews/index.js @@ -2,65 +2,56 @@ * WordPress dependencies */ import { __experimentalItemGroup as ItemGroup } from '@wordpress/components'; -import { page, columns } from '@wordpress/icons'; -import { privateApis as routerPrivateApis } from '@wordpress/router'; +import { privateApis as routerPrivateApis } from '@wordpress/router'; /** * Internal dependencies */ -import { useLink } from '../routes/link'; -import { default as DEFAULT_VIEWS } from '../page-pages/default-views'; + +import { default as DEFAULT_VIEWS } from './default-views'; import { unlock } from '../../lock-unlock'; const { useLocation } = unlock( routerPrivateApis ); -import SidebarNavigationItem from '../sidebar-navigation-item'; - -function getDataViewIcon( dataview ) { - const icons = { list: page, grid: columns }; - return icons[ dataview.view.type ]; -} - -function DataViewItem( { dataview, isActive, icon } ) { - const { - params: { path }, - } = useLocation(); - - const _icon = icon || getDataViewIcon( dataview ); +import DataViewItem from './dataview-item'; +import CustomDataViewsList from './custom-dataviews-list'; - const linkInfo = useLink( { - path, - activeView: dataview.slug, - } ); - return ( - - { dataview.title } - - ); -} +const PATH_TO_TYPE = { + '/pages': 'page', +}; export default function DataViewsSidebarContent() { const { - params: { path, activeView = 'all' }, + params: { path, activeView = 'all', isCustom = 'false' }, } = useLocation(); - if ( ! path || path !== '/pages' ) { + if ( ! path || ! PATH_TO_TYPE[ path ] ) { return null; } + const type = PATH_TO_TYPE[ path ]; return ( - - { DEFAULT_VIEWS.map( ( dataview ) => { - return ( - - ); - } ) } - + <> + + { DEFAULT_VIEWS[ type ].map( ( dataview ) => { + return ( + + ); + } ) } + + + > ); } From ef5887d972d1ba18214b7c33a668a23c9e36d4e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= <583546+oandregal@users.noreply.github.com> Date: Mon, 6 Nov 2023 12:29:43 +0100 Subject: [PATCH 12/15] DataViews: fix status filter upon switching the default views from the sidebar (#55856) --- packages/edit-site/src/components/dataviews/in-filter.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/edit-site/src/components/dataviews/in-filter.js b/packages/edit-site/src/components/dataviews/in-filter.js index e1f3dcca4c8c92..826e94de652de3 100644 --- a/packages/edit-site/src/components/dataviews/in-filter.js +++ b/packages/edit-site/src/components/dataviews/in-filter.js @@ -9,9 +9,14 @@ import { const OPERATOR_IN = 'in'; export default ( { filter, view, onChangeView } ) => { - const activeValue = view.filters.find( + const valueFound = view.filters.find( ( f ) => f.field === filter.id && f.operator === OPERATOR_IN - )?.value; + ); + + const activeValue = + ! valueFound || ! valueFound.hasOwnProperty( 'value' ) + ? '' + : valueFound.value; return ( Date: Mon, 6 Nov 2023 16:45:30 +0400 Subject: [PATCH 13/15] Migrate 'inner-blocks-render-appender' e2e tests to Playwright (#55814) * Migrate 'inner-blocks-render-appender' e2e tests to Playwright * Remove old test files * Feedback --- .../inner-blocks-render-appender.test.js.snap | 25 ---- .../inner-blocks-render-appender.test.js | 126 ----------------- .../inner-blocks-render-appender.spec.js | 129 ++++++++++++++++++ 3 files changed, 129 insertions(+), 151 deletions(-) delete mode 100644 packages/e2e-tests/specs/editor/plugins/__snapshots__/inner-blocks-render-appender.test.js.snap delete mode 100644 packages/e2e-tests/specs/editor/plugins/inner-blocks-render-appender.test.js create mode 100644 test/e2e/specs/editor/plugins/inner-blocks-render-appender.spec.js diff --git a/packages/e2e-tests/specs/editor/plugins/__snapshots__/inner-blocks-render-appender.test.js.snap b/packages/e2e-tests/specs/editor/plugins/__snapshots__/inner-blocks-render-appender.test.js.snap deleted file mode 100644 index 232e6e02b398eb..00000000000000 --- a/packages/e2e-tests/specs/editor/plugins/__snapshots__/inner-blocks-render-appender.test.js.snap +++ /dev/null @@ -1,25 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`RenderAppender prop of InnerBlocks Users can customize the appender and can still insert blocks using exposed components 1`] = ` -" - - - - - -" -`; - -exports[`RenderAppender prop of InnerBlocks Users can dynamically customize the appender 1`] = ` -" - - - - - - - - - -" -`; diff --git a/packages/e2e-tests/specs/editor/plugins/inner-blocks-render-appender.test.js b/packages/e2e-tests/specs/editor/plugins/inner-blocks-render-appender.test.js deleted file mode 100644 index 1322713b033e24..00000000000000 --- a/packages/e2e-tests/specs/editor/plugins/inner-blocks-render-appender.test.js +++ /dev/null @@ -1,126 +0,0 @@ -/** - * WordPress dependencies - */ -import { - activatePlugin, - createNewPost, - deactivatePlugin, - getAllBlockInserterItemTitles, - getEditedPostContent, - insertBlock, - closeGlobalBlockInserter, -} from '@wordpress/e2e-test-utils'; - -const INSERTER_RESULTS_SELECTOR = - '.block-editor-inserter__quick-inserter-results'; -const QUOTE_INSERT_BUTTON_SELECTOR = '//button[.="Quote"]'; -const APPENDER_SELECTOR = '.my-custom-awesome-appender'; -const DYNAMIC_APPENDER_SELECTOR = 'my-dynamic-blocks-appender'; - -describe( 'RenderAppender prop of InnerBlocks', () => { - beforeAll( async () => { - await activatePlugin( 'gutenberg-test-innerblocks-render-appender' ); - } ); - - beforeEach( async () => { - await createNewPost(); - } ); - - afterAll( async () => { - await deactivatePlugin( 'gutenberg-test-innerblocks-render-appender' ); - } ); - - it( 'Users can customize the appender and can still insert blocks using exposed components', async () => { - // Insert the InnerBlocks renderAppender block. - await insertBlock( 'InnerBlocks renderAppender' ); - await closeGlobalBlockInserter(); - // Wait for the custom block appender to appear. - await page.waitForSelector( APPENDER_SELECTOR ); - // Verify if the custom block appender text is the expected one. - expect( - await page.evaluate( - ( el ) => el.innerText, - await page.$( `${ APPENDER_SELECTOR } > span` ) - ) - ).toEqual( 'My custom awesome appender' ); - - // Open the inserter of our custom block appender and expand all the categories. - await page.click( - `${ APPENDER_SELECTOR } .block-editor-button-block-appender` - ); - // Verify if the blocks the custom inserter is rendering are the expected ones. - expect( await getAllBlockInserterItemTitles() ).toEqual( [ - 'Quote', - 'Video', - ] ); - - // Find the quote block insert button option within the inserter popover. - const inserterPopover = await page.$( INSERTER_RESULTS_SELECTOR ); - const quoteButton = ( - await inserterPopover.$x( QUOTE_INSERT_BUTTON_SELECTOR ) - )[ 0 ]; - - // Insert a quote block. - await quoteButton.click(); - // Verify if the post content is the expected one e.g: the quote was inserted. - expect( await getEditedPostContent() ).toMatchSnapshot(); - } ); - - it( 'Users can dynamically customize the appender', async () => { - // Insert the InnerBlocks renderAppender dynamic block. - await insertBlock( 'InnerBlocks renderAppender dynamic' ); - await closeGlobalBlockInserter(); - - // Wait for the custom dynamic block appender to appear. - await page.waitForSelector( '.' + DYNAMIC_APPENDER_SELECTOR ); - - // Verify if the custom block appender text is the expected one. - await page.waitForXPath( - `//*[contains(@class, "${ DYNAMIC_APPENDER_SELECTOR }")]/span[contains(@class, "empty-blocks-appender")][contains(text(), "Empty Blocks Appender")]` - ); - - // Open the inserter of our custom block appender and expand all the categories. - const blockAppenderButtonSelector = `.${ DYNAMIC_APPENDER_SELECTOR } .block-editor-button-block-appender`; - await page.click( blockAppenderButtonSelector ); - - // Verify if the blocks the custom inserter is rendering are the expected ones. - expect( await getAllBlockInserterItemTitles() ).toEqual( [ - 'Quote', - 'Video', - ] ); - - // Find the quote block insert button option within the inserter popover. - const inserterPopover = await page.$( INSERTER_RESULTS_SELECTOR ); - const quoteButton = ( - await inserterPopover.$x( QUOTE_INSERT_BUTTON_SELECTOR ) - )[ 0 ]; - - // Insert a quote block. - await quoteButton.click(); - - // Select the quote block. - await page.keyboard.press( 'ArrowDown' ); - - // Verify if the custom block appender text changed as expected. - await page.waitForXPath( - `//*[contains(@class, "${ DYNAMIC_APPENDER_SELECTOR }")]/span[contains(@class, "single-blocks-appender")][contains(text(), "Single Blocks Appender")]` - ); - - // Verify that the custom appender button is still being rendered. - expect( await page.$( blockAppenderButtonSelector ) ).toBeTruthy(); - - // Insert a video block. - await insertBlock( 'Video' ); - - // Verify if the custom block appender text changed as expected. - await page.waitForXPath( - `//*[contains(@class, "${ DYNAMIC_APPENDER_SELECTOR }")]/span[contains(@class, "multiple-blocks-appender")][contains(text(), "Multiple Blocks Appender")]` - ); - - // Verify that the custom appender button is now not being rendered. - expect( await page.$( blockAppenderButtonSelector ) ).toBeFalsy(); - - // Verify that final block markup is the expected one. - expect( await getEditedPostContent() ).toMatchSnapshot(); - } ); -} ); diff --git a/test/e2e/specs/editor/plugins/inner-blocks-render-appender.spec.js b/test/e2e/specs/editor/plugins/inner-blocks-render-appender.spec.js new file mode 100644 index 00000000000000..9886bd00fe2b66 --- /dev/null +++ b/test/e2e/specs/editor/plugins/inner-blocks-render-appender.spec.js @@ -0,0 +1,129 @@ +/** + * WordPress dependencies + */ +const { test, expect } = require( '@wordpress/e2e-test-utils-playwright' ); + +test.describe( 'RenderAppender prop of InnerBlocks', () => { + test.beforeAll( async ( { requestUtils } ) => { + await requestUtils.activatePlugin( + 'gutenberg-test-innerblocks-render-appender' + ); + } ); + + test.beforeEach( async ( { admin } ) => { + await admin.createNewPost(); + } ); + + test.afterAll( async ( { requestUtils } ) => { + await requestUtils.deactivatePlugin( + 'gutenberg-test-innerblocks-render-appender' + ); + } ); + + test( 'Users can customize the appender and can still insert blocks using exposed components', async ( { + editor, + page, + } ) => { + await editor.insertBlock( { + name: 'test/inner-blocks-render-appender', + } ); + + const customAppender = page.locator( '.my-custom-awesome-appender' ); + + // Verify if the custom block appender text is the expected one. + await expect( customAppender ).toContainText( + 'My custom awesome appender' + ); + + // Open the inserter of our custom block appender. + await customAppender + .getByRole( 'button', { name: 'Add block' } ) + .click(); + + // Verify if the blocks the custom inserter is rendering are the expected ones. + const blockListBox = page.getByRole( 'listbox', { name: 'Blocks' } ); + await expect( blockListBox.getByRole( 'option' ) ).toHaveText( [ + 'Quote', + 'Video', + ] ); + + // Insert a quote block. + await blockListBox.getByRole( 'option', { name: 'Quote' } ).click(); + + // Verify if the post content is the expected one. + await expect.poll( editor.getBlocks ).toMatchObject( [ + { + name: 'test/inner-blocks-render-appender', + innerBlocks: [ + { + name: 'core/quote', + }, + ], + }, + ] ); + } ); + + test( 'Users can dynamically customize the appender', async ( { + editor, + page, + } ) => { + await editor.insertBlock( { + name: 'test/inner-blocks-render-appender-dynamic', + } ); + + const dynamimcAppender = page.locator( '.my-dynamic-blocks-appender' ); + const addBlockBtn = dynamimcAppender.getByRole( 'button', { + name: 'Add block', + } ); + + // Verify if the custom block appender text is the expected one. + await expect( dynamimcAppender ).toContainText( + 'Empty Blocks Appender' + ); + + // Open the inserter of our custom block appender. + await addBlockBtn.click(); + + // Verify if the blocks the custom inserter is rendering are the expected ones. + const blockListBox = page.getByRole( 'listbox', { name: 'Blocks' } ); + await expect( blockListBox.getByRole( 'option' ) ).toHaveText( [ + 'Quote', + 'Video', + ] ); + + // Insert a quote block. + await blockListBox.getByRole( 'option', { name: 'Quote' } ).click(); + + // Verify if the custom block appender text changed as expected. + await expect( + dynamimcAppender.getByText( 'Single Blocks Appender' ) + ).toBeVisible(); + + // Insert a video block. + await addBlockBtn.click(); + await blockListBox.getByRole( 'option', { name: 'Video' } ).click(); + + // Verify if the custom block appender text changed as expected. + await expect( + dynamimcAppender.getByText( 'Multiple Blocks Appender' ) + ).toBeVisible(); + + // Verify that the custom appender button is now not being rendered. + await expect( addBlockBtn ).toBeHidden(); + + // Verify if the post content is the expected one. + await expect.poll( editor.getBlocks ).toMatchObject( [ + { + name: 'test/inner-blocks-render-appender-dynamic', + innerBlocks: [ + { + name: 'core/quote', + }, + { + name: 'core/video', + }, + ], + }, + ] ); + } ); +} ); From f8025b98578c0096f3e10236fd9a903a5ef3276e Mon Sep 17 00:00:00 2001 From: Bart Kalisz Date: Mon, 6 Nov 2023 13:07:55 +0000 Subject: [PATCH 14/15] E2E Utils: add setPreferences and editPost utils (#55099) --- .../src/admin/create-new-post.js | 47 ----------- .../src/admin/create-new-post.ts | 38 +++++++++ .../src/admin/edit-post.ts | 24 ++++++ .../src/admin/index.ts | 13 ++- .../src/admin/visit-site-editor.ts | 83 +++++++------------ .../src/editor/index.ts | 3 + .../src/editor/set-preferences.ts | 37 +++++++++ .../e2e-test-utils-playwright/src/test.ts | 4 +- test/e2e/specs/editor/blocks/query.spec.js | 5 +- test/e2e/specs/editor/local/demo.spec.js | 17 +--- .../editor/various/block-renaming.spec.js | 6 +- .../various/post-editor-template-mode.spec.js | 6 +- test/e2e/specs/editor/various/preview.spec.js | 5 +- .../editor/various/switch-to-draft.spec.js | 15 +--- test/e2e/specs/site-editor/list-view.spec.js | 13 ++- .../specs/widgets/customizing-widgets.spec.js | 20 +++-- test/performance/fixtures/perf-utils.ts | 4 +- test/performance/specs/post-editor.spec.js | 64 +++++++------- 18 files changed, 215 insertions(+), 189 deletions(-) delete mode 100644 packages/e2e-test-utils-playwright/src/admin/create-new-post.js create mode 100644 packages/e2e-test-utils-playwright/src/admin/create-new-post.ts create mode 100644 packages/e2e-test-utils-playwright/src/admin/edit-post.ts create mode 100644 packages/e2e-test-utils-playwright/src/editor/set-preferences.ts diff --git a/packages/e2e-test-utils-playwright/src/admin/create-new-post.js b/packages/e2e-test-utils-playwright/src/admin/create-new-post.js deleted file mode 100644 index 81822e2514a731..00000000000000 --- a/packages/e2e-test-utils-playwright/src/admin/create-new-post.js +++ /dev/null @@ -1,47 +0,0 @@ -/** - * WordPress dependencies - */ -import { addQueryArgs } from '@wordpress/url'; - -/** - * Creates new post. - * - * @this {import('.').Editor} - * @param {Object} object Object to create new post, along with tips enabling option. - * @param {string} [object.postType] Post type of the new post. - * @param {string} [object.title] Title of the new post. - * @param {string} [object.content] Content of the new post. - * @param {string} [object.excerpt] Excerpt of the new post. - * @param {boolean} [object.showWelcomeGuide] Whether to show the welcome guide. - */ -export async function createNewPost( { - postType, - title, - content, - excerpt, - showWelcomeGuide = false, -} = {} ) { - const query = addQueryArgs( '', { - post_type: postType, - post_title: title, - content, - excerpt, - } ).slice( 1 ); - - await this.visitAdminPage( 'post-new.php', query ); - - await this.page.waitForFunction( ( welcomeGuide ) => { - if ( ! window?.wp?.data?.dispatch ) { - return false; - } - window.wp.data - .dispatch( 'core/preferences' ) - .set( 'core/edit-post', 'welcomeGuide', welcomeGuide ); - - window.wp.data - .dispatch( 'core/preferences' ) - .set( 'core/edit-post', 'fullscreenMode', false ); - - return true; - }, showWelcomeGuide ); -} diff --git a/packages/e2e-test-utils-playwright/src/admin/create-new-post.ts b/packages/e2e-test-utils-playwright/src/admin/create-new-post.ts new file mode 100644 index 00000000000000..e9cfefd9f65d5a --- /dev/null +++ b/packages/e2e-test-utils-playwright/src/admin/create-new-post.ts @@ -0,0 +1,38 @@ +/** + * Internal dependencies + */ +import type { Admin } from './'; + +interface NewPostOptions { + postType?: string; + title?: string; + content?: string; + excerpt?: string; + showWelcomeGuide?: boolean; +} + +/** + * Creates new post. + * + * @param this + * @param options Options to create new post. + */ +export async function createNewPost( + this: Admin, + options: NewPostOptions = {} +) { + const query = new URLSearchParams(); + const { postType, title, content, excerpt } = options; + + if ( postType ) query.set( 'post_type', postType ); + if ( title ) query.set( 'post_title', title ); + if ( content ) query.set( 'content', content ); + if ( excerpt ) query.set( 'excerpt', excerpt ); + + await this.visitAdminPage( 'post-new.php', query.toString() ); + + await this.editor.setPreferences( 'core/edit-post', { + welcomeGuide: options.showWelcomeGuide ?? false, + fullscreenMode: false, + } ); +} diff --git a/packages/e2e-test-utils-playwright/src/admin/edit-post.ts b/packages/e2e-test-utils-playwright/src/admin/edit-post.ts new file mode 100644 index 00000000000000..77cf390d02aa01 --- /dev/null +++ b/packages/e2e-test-utils-playwright/src/admin/edit-post.ts @@ -0,0 +1,24 @@ +/** + * Internal dependencies + */ +import type { Admin } from '.'; + +/** + * Open the post with given ID in the editor. + * + * @param this + * @param postId Post ID to visit. + */ +export async function editPost( this: Admin, postId: string | number ) { + const query = new URLSearchParams(); + + query.set( 'post', String( postId ) ); + query.set( 'action', 'edit' ); + + await this.visitAdminPage( 'post.php', query.toString() ); + + await this.editor.setPreferences( 'core/edit-post', { + welcomeGuide: false, + fullscreenMode: false, + } ); +} diff --git a/packages/e2e-test-utils-playwright/src/admin/index.ts b/packages/e2e-test-utils-playwright/src/admin/index.ts index ed16564f8f4abb..08d2baf4b6520d 100644 --- a/packages/e2e-test-utils-playwright/src/admin/index.ts +++ b/packages/e2e-test-utils-playwright/src/admin/index.ts @@ -9,29 +9,36 @@ import type { Browser, Page, BrowserContext } from '@playwright/test'; import { createNewPost } from './create-new-post'; import { getPageError } from './get-page-error'; import { visitAdminPage } from './visit-admin-page'; +import { editPost } from './edit-post'; import { visitSiteEditor } from './visit-site-editor'; import type { PageUtils } from '../page-utils'; +import type { Editor } from '../editor'; type AdminConstructorProps = { page: Page; pageUtils: PageUtils; + editor: Editor; }; export class Admin { - browser: Browser; page: Page; - pageUtils: PageUtils; context: BrowserContext; + browser: Browser; + pageUtils: PageUtils; + editor: Editor; - constructor( { page, pageUtils }: AdminConstructorProps ) { + constructor( { page, pageUtils, editor }: AdminConstructorProps ) { this.page = page; this.context = page.context(); this.browser = this.context.browser()!; this.pageUtils = pageUtils; + this.editor = editor; } /** @borrows createNewPost as this.createNewPost */ createNewPost: typeof createNewPost = createNewPost.bind( this ); + /** @borrows editPost as this.editPost */ + editPost: typeof editPost = editPost.bind( this ); /** @borrows getPageError as this.getPageError */ getPageError: typeof getPageError = getPageError.bind( this ); /** @borrows visitAdminPage as this.visitAdminPage */ diff --git a/packages/e2e-test-utils-playwright/src/admin/visit-site-editor.ts b/packages/e2e-test-utils-playwright/src/admin/visit-site-editor.ts index a545bdc704341c..da21f17aade117 100644 --- a/packages/e2e-test-utils-playwright/src/admin/visit-site-editor.ts +++ b/packages/e2e-test-utils-playwright/src/admin/visit-site-editor.ts @@ -1,72 +1,51 @@ -/** - * WordPress dependencies - */ -import { addQueryArgs } from '@wordpress/url'; - /** * Internal dependencies */ import type { Admin } from './'; -export interface SiteEditorQueryParams { - postId: string | number; - postType: string; +interface SiteEditorOptions { + postId?: string | number; + postType?: string; + path?: string; + canvas?: string; + showWelcomeGuide?: boolean; } -const CANVAS_SELECTOR = 'iframe[title="Editor canvas"i] >> visible=true'; - /** - * Visits the Site Editor main page - * - * By default, it also skips the welcome guide. The option can be disabled if need be. + * Visits the Site Editor main page. * * @param this - * @param query Query params to be serialized as query portion of URL. - * @param skipWelcomeGuide Whether to skip the welcome guide as part of the navigation. + * @param options Options to visit the site editor. */ export async function visitSiteEditor( this: Admin, - query: SiteEditorQueryParams, - skipWelcomeGuide = true + options: SiteEditorOptions = {} ) { - const path = addQueryArgs( '', { - ...query, - } ).slice( 1 ); - - await this.visitAdminPage( 'site-editor.php', path ); - - if ( skipWelcomeGuide ) { - await this.page.evaluate( () => { - window.wp.data - .dispatch( 'core/preferences' ) - .set( 'core/edit-site', 'welcomeGuide', false ); - - window.wp.data - .dispatch( 'core/preferences' ) - .set( 'core/edit-site', 'welcomeGuideStyles', false ); - - window.wp.data - .dispatch( 'core/preferences' ) - .set( 'core/edit-site', 'welcomeGuidePage', false ); - - window.wp.data - .dispatch( 'core/preferences' ) - .set( 'core/edit-site', 'welcomeGuideTemplate', false ); + const { postId, postType, path, canvas } = options; + const query = new URLSearchParams(); + + if ( postId ) query.set( 'postId', String( postId ) ); + if ( postType ) query.set( 'postType', postType ); + if ( path ) query.set( 'path', path ); + if ( canvas ) query.set( 'canvas', canvas ); + + await this.visitAdminPage( 'site-editor.php', query.toString() ); + + if ( ! options.showWelcomeGuide ) { + await this.editor.setPreferences( 'core/edit-site', { + welcomeGuide: false, + welcomeGuideStyles: false, + welcomeGuidePage: false, + welcomeGuideTemplate: false, } ); } - // Check if the current page has an editor canvas first. - if ( ( await this.page.locator( CANVAS_SELECTOR ).count() ) > 0 ) { - // The site editor initially loads with an empty body, - // we need to wait for the editor canvas to be rendered. - await this.page - .frameLocator( CANVAS_SELECTOR ) - .locator( 'body > *' ) - .first() - .waitFor(); - } - - // TODO: Ideally the content underneath the canvas loader should be marked inert until it's ready. + /** + * @todo This is a workaround for the fact that the editor canvas is seen as + * ready and visible before the loading spinner is hidden. Ideally, the + * content underneath the loading overlay should be marked inert until the + * loading is done. + */ await this.page .locator( '.edit-site-canvas-loader' ) // Bigger timeout is needed for larger entities, for example the large diff --git a/packages/e2e-test-utils-playwright/src/editor/index.ts b/packages/e2e-test-utils-playwright/src/editor/index.ts index 8c10ba370b1a92..c222f68aecc90a 100644 --- a/packages/e2e-test-utils-playwright/src/editor/index.ts +++ b/packages/e2e-test-utils-playwright/src/editor/index.ts @@ -22,6 +22,7 @@ import { publishPost } from './publish-post'; import { saveDraft } from './save-draft'; import { selectBlocks } from './select-blocks'; import { setContent } from './set-content'; +import { setPreferences } from './set-preferences'; import { showBlockToolbar } from './show-block-toolbar'; import { saveSiteEditorEntities } from './site-editor'; import { setIsFixedToolbar } from './set-is-fixed-toolbar'; @@ -76,6 +77,8 @@ export class Editor { selectBlocks: typeof selectBlocks = selectBlocks.bind( this ); /** @borrows setContent as this.setContent */ setContent: typeof setContent = setContent.bind( this ); + /** @borrows setPreferences as this.setPreferences */ + setPreferences: typeof setPreferences = setPreferences.bind( this ); /** @borrows showBlockToolbar as this.showBlockToolbar */ showBlockToolbar: typeof showBlockToolbar = showBlockToolbar.bind( this ); /** @borrows setIsFixedToolbar as this.setIsFixedToolbar */ diff --git a/packages/e2e-test-utils-playwright/src/editor/set-preferences.ts b/packages/e2e-test-utils-playwright/src/editor/set-preferences.ts new file mode 100644 index 00000000000000..9e5345db4b9e39 --- /dev/null +++ b/packages/e2e-test-utils-playwright/src/editor/set-preferences.ts @@ -0,0 +1,37 @@ +/** + * Internal dependencies + */ +import type { Editor } from './index'; + +type PreferencesContext = + | 'core/edit-post' + | 'core/edit-site' + | 'core/customize-widgets'; + +/** + * Set the preferences of the editor. + * + * @param this + * @param context Context to set preferences for. + * @param preferences Preferences to set. + */ +export async function setPreferences( + this: Editor, + context: PreferencesContext, + preferences: Record< string, any > +) { + await this.page.waitForFunction( () => window?.wp?.data ); + + await this.page.evaluate( + async ( props ) => { + for ( const [ key, value ] of Object.entries( + props.preferences + ) ) { + await window.wp.data + .dispatch( 'core/preferences' ) + .set( props.context, key, value ); + } + }, + { context, preferences } + ); +} diff --git a/packages/e2e-test-utils-playwright/src/test.ts b/packages/e2e-test-utils-playwright/src/test.ts index 778f71b6d770e1..677eff31955bd1 100644 --- a/packages/e2e-test-utils-playwright/src/test.ts +++ b/packages/e2e-test-utils-playwright/src/test.ts @@ -119,8 +119,8 @@ const test = base.extend< lighthousePort: number; } >( { - admin: async ( { page, pageUtils }, use ) => { - await use( new Admin( { page, pageUtils } ) ); + admin: async ( { page, pageUtils, editor }, use ) => { + await use( new Admin( { page, pageUtils, editor } ) ); }, editor: async ( { page }, use ) => { await use( new Editor( { page } ) ); diff --git a/test/e2e/specs/editor/blocks/query.spec.js b/test/e2e/specs/editor/blocks/query.spec.js index 79b15222630efa..dbefb66e353bc7 100644 --- a/test/e2e/specs/editor/blocks/query.spec.js +++ b/test/e2e/specs/editor/blocks/query.spec.js @@ -21,7 +21,10 @@ test.describe( 'Query block', () => { } ); test.beforeEach( async ( { admin } ) => { - await admin.createNewPost( { postType: 'page', title: 'Query Page' } ); + await admin.createNewPost( { + postType: 'page', + title: 'Query Page', + } ); } ); test.afterEach( async ( { requestUtils } ) => { diff --git a/test/e2e/specs/editor/local/demo.spec.js b/test/e2e/specs/editor/local/demo.spec.js index acfee9296e2324..2782461812ea84 100644 --- a/test/e2e/specs/editor/local/demo.spec.js +++ b/test/e2e/specs/editor/local/demo.spec.js @@ -7,21 +7,12 @@ test.describe( 'New editor state', () => { test( 'content should load, making the post dirty', async ( { page, admin, + editor, } ) => { await admin.visitAdminPage( 'post-new.php', 'gutenberg-demo' ); - await page.waitForFunction( () => { - if ( ! window?.wp?.data?.dispatch ) { - return false; - } - window.wp.data - .dispatch( 'core/preferences' ) - .set( 'core/edit-post', 'welcomeGuide', false ); - - window.wp.data - .dispatch( 'core/preferences' ) - .set( 'core/edit-post', 'fullscreenMode', false ); - - return true; + await editor.setPreferences( 'core/edit-site', { + welcomeGuide: false, + fullscreenMode: false, } ); const isDirty = await page.evaluate( () => { diff --git a/test/e2e/specs/editor/various/block-renaming.spec.js b/test/e2e/specs/editor/various/block-renaming.spec.js index 4150be64bd33d6..f8d9548fbe8667 100644 --- a/test/e2e/specs/editor/various/block-renaming.spec.js +++ b/test/e2e/specs/editor/various/block-renaming.spec.js @@ -15,10 +15,8 @@ test.describe( 'Block Renaming', () => { pageUtils, } ) => { // Turn on block list view by default. - await page.evaluate( () => { - window.wp.data - .dispatch( 'core/preferences' ) - .set( 'core/edit-site', 'showListViewByDefault', true ); + await editor.setPreferences( 'core/edit-site', { + showListViewByDefault: true, } ); const listView = page.getByRole( 'treegrid', { diff --git a/test/e2e/specs/editor/various/post-editor-template-mode.spec.js b/test/e2e/specs/editor/various/post-editor-template-mode.spec.js index 6f8bb5596bf2a5..b9bfbf9dd6b05e 100644 --- a/test/e2e/specs/editor/various/post-editor-template-mode.spec.js +++ b/test/e2e/specs/editor/various/post-editor-template-mode.spec.js @@ -121,10 +121,8 @@ class PostEditorTemplateMode { async disableTemplateWelcomeGuide() { // Turn off the welcome guide. - await this.page.evaluate( () => { - window.wp.data - .dispatch( 'core/preferences' ) - .set( 'core/edit-post', 'welcomeGuideTemplate', false ); + await this.editor.setPreferences( 'core/edit-post', { + welcomeGuideTemplate: false, } ); } diff --git a/test/e2e/specs/editor/various/preview.spec.js b/test/e2e/specs/editor/various/preview.spec.js index ea920270e093e8..8a4ee5a6bd81d2 100644 --- a/test/e2e/specs/editor/various/preview.spec.js +++ b/test/e2e/specs/editor/various/preview.spec.js @@ -295,7 +295,10 @@ test.describe( 'Preview with private custom post type', () => { admin, page, } ) => { - await admin.createNewPost( { postType: 'not_public', title: 'aaaaa' } ); + await admin.createNewPost( { + postType: 'not_public', + title: 'aaaaa', + } ); // Open the view menu. await page.click( 'role=button[name="Preview"i]' ); diff --git a/test/e2e/specs/editor/various/switch-to-draft.spec.js b/test/e2e/specs/editor/various/switch-to-draft.spec.js index 59837a3d3c7657..5cfeda60a2d185 100644 --- a/test/e2e/specs/editor/various/switch-to-draft.spec.js +++ b/test/e2e/specs/editor/various/switch-to-draft.spec.js @@ -139,20 +139,7 @@ class SwitchToDraftUtils { id = page.id; } - await this.#admin.visitAdminPage( - 'post.php', - `post=${ id }&action=edit` - ); - - // Disable welcome guide and full screen mode. - await this.#page.evaluate( () => { - window.wp.data - .dispatch( 'core/preferences' ) - .set( 'core/edit-post', 'welcomeGuide', false ); - window.wp.data - .dispatch( 'core/preferences' ) - .set( 'core/edit-post', 'fullscreenMode', false ); - } ); + await this.#admin.editPost( id ); }; getPostStatus = async () => { diff --git a/test/e2e/specs/site-editor/list-view.spec.js b/test/e2e/specs/site-editor/list-view.spec.js index ed64574168bd02..74d3559d4e3d27 100644 --- a/test/e2e/specs/site-editor/list-view.spec.js +++ b/test/e2e/specs/site-editor/list-view.spec.js @@ -23,16 +23,15 @@ test.describe( 'Site Editor List View', () => { test( 'should open by default when preference is enabled', async ( { page, + editor, } ) => { await expect( page.locator( 'role=region[name="List View"i]' ) ).toBeHidden(); // Turn on block list view by default. - await page.evaluate( () => { - window.wp.data - .dispatch( 'core/preferences' ) - .set( 'core/edit-site', 'showListViewByDefault', true ); + await editor.setPreferences( 'core/edit-site', { + showListViewByDefault: true, } ); await page.reload(); @@ -42,10 +41,8 @@ test.describe( 'Site Editor List View', () => { ).toBeVisible(); // The preferences cleanup. - await page.evaluate( () => { - window.wp.data - .dispatch( 'core/preferences' ) - .set( 'core/edit-site', 'showListViewByDefault', false ); + await editor.setPreferences( 'core/edit-site', { + showListViewByDefault: false, } ); } ); diff --git a/test/e2e/specs/widgets/customizing-widgets.spec.js b/test/e2e/specs/widgets/customizing-widgets.spec.js index 6a6a51cae26860..34400ea00976e2 100644 --- a/test/e2e/specs/widgets/customizing-widgets.spec.js +++ b/test/e2e/specs/widgets/customizing-widgets.spec.js @@ -12,11 +12,17 @@ const { * @typedef {import('@playwright/test').FrameLocator} FrameLocator * @typedef {import('@wordpress/e2e-test-utils-playwright').PageUtils} PageUtils * @typedef {import('@wordpress/e2e-test-utils-playwright').RequestUtils} RequestUtils + * @typedef {import('@wordpress/e2e-test-utils-playwright').Editor} Editor */ test.use( { - widgetsCustomizerPage: async ( { admin, page, pageUtils }, use ) => { - await use( new WidgetsCustomizerPage( { admin, page, pageUtils } ) ); + widgetsCustomizerPage: async ( + { admin, page, pageUtils, editor }, + use + ) => { + await use( + new WidgetsCustomizerPage( { admin, page, pageUtils, editor } ) + ); }, } ); @@ -613,11 +619,13 @@ class WidgetsCustomizerPage { * @param {Admin} config.admin * @param {Page} config.page * @param {PageUtils} config.pageUtils + * @param {Editor} config.editor */ - constructor( { admin, page, pageUtils } ) { + constructor( { admin, page, pageUtils, editor } ) { this.admin = admin; this.page = page; this.pageUtils = pageUtils; + this.editor = editor; /** @type {FrameLocator} */ this.previewFrame = this.page @@ -631,10 +639,8 @@ class WidgetsCustomizerPage { await this.admin.visitAdminPage( 'customize.php' ); // Disable welcome guide. - await this.page.evaluate( () => { - window.wp.data - .dispatch( 'core/preferences' ) - .set( 'core/customize-widgets', 'welcomeGuide', false ); + await this.editor.setPreferences( 'core/customize-widgets', { + welcomeGuide: false, } ); } diff --git a/test/performance/fixtures/perf-utils.ts b/test/performance/fixtures/perf-utils.ts index dcd9579364e10b..d17eec2c935b1b 100644 --- a/test/performance/fixtures/perf-utils.ts +++ b/test/performance/fixtures/perf-utils.ts @@ -59,7 +59,9 @@ export class PerfUtils { this.page.getByRole( 'button', { name: 'Saved' } ) ).toBeDisabled(); - return this.page.url(); + const postId = new URL( this.page.url() ).searchParams.get( 'post' ); + + return postId; } /** diff --git a/test/performance/specs/post-editor.spec.js b/test/performance/specs/post-editor.spec.js index da20e3c3e667b5..d5ff40570afd78 100644 --- a/test/performance/specs/post-editor.spec.js +++ b/test/performance/specs/post-editor.spec.js @@ -48,12 +48,12 @@ test.describe( 'Post Editor Performance', () => { } ); test.describe( 'Loading', () => { - let draftURL = null; + let draftId = null; test( 'Setup the test post', async ( { admin, perfUtils } ) => { await admin.createNewPost(); await perfUtils.loadBlocksForLargePost(); - draftURL = await perfUtils.saveDraft(); + draftId = await perfUtils.saveDraft(); } ); const samples = 10; @@ -61,12 +61,12 @@ test.describe( 'Post Editor Performance', () => { const iterations = samples + throwaway; for ( let i = 1; i <= iterations; i++ ) { test( `Run the test (${ i } of ${ iterations })`, async ( { - page, + admin, perfUtils, metrics, } ) => { // Open the test draft. - await page.goto( draftURL ); + await admin.editPost( draftId ); const canvas = await perfUtils.getCanvas(); // Wait for the first block. @@ -92,17 +92,17 @@ test.describe( 'Post Editor Performance', () => { } ); test.describe( 'Typing', () => { - let draftURL = null; + let draftId = null; test( 'Setup the test post', async ( { admin, perfUtils, editor } ) => { await admin.createNewPost(); await perfUtils.loadBlocksForLargePost(); await editor.insertBlock( { name: 'core/paragraph' } ); - draftURL = await perfUtils.saveDraft(); + draftId = await perfUtils.saveDraft(); } ); - test( 'Run the test', async ( { page, perfUtils, metrics } ) => { - await page.goto( draftURL ); + test( 'Run the test', async ( { admin, perfUtils, metrics } ) => { + await admin.editPost( draftId ); await perfUtils.disableAutosave(); const canvas = await perfUtils.getCanvas(); @@ -145,16 +145,16 @@ test.describe( 'Post Editor Performance', () => { } ); test.describe( 'Typing within containers', () => { - let draftURL = null; + let draftId = null; test( 'Set up the test post', async ( { admin, perfUtils } ) => { await admin.createNewPost(); await perfUtils.loadBlocksForSmallPostWithContainers(); - draftURL = await perfUtils.saveDraft(); + draftId = await perfUtils.saveDraft(); } ); - test( 'Run the test', async ( { page, perfUtils, metrics } ) => { - await page.goto( draftURL ); + test( 'Run the test', async ( { admin, perfUtils, metrics } ) => { + await admin.editPost( draftId ); await perfUtils.disableAutosave(); const canvas = await perfUtils.getCanvas(); @@ -201,16 +201,16 @@ test.describe( 'Post Editor Performance', () => { } ); test.describe( 'Selecting blocks', () => { - let draftURL = null; + let draftId = null; test( 'Set up the test post', async ( { admin, perfUtils } ) => { await admin.createNewPost(); await perfUtils.load1000Paragraphs(); - draftURL = await perfUtils.saveDraft(); + draftId = await perfUtils.saveDraft(); } ); - test( 'Run the test', async ( { page, perfUtils, metrics } ) => { - await page.goto( draftURL ); + test( 'Run the test', async ( { admin, page, perfUtils, metrics } ) => { + await admin.editPost( draftId ); await perfUtils.disableAutosave(); const canvas = await perfUtils.getCanvas(); @@ -251,16 +251,16 @@ test.describe( 'Post Editor Performance', () => { } ); test.describe( 'Opening persistent List View', () => { - let draftURL = null; + let draftId = null; test( 'Set up the test page', async ( { admin, perfUtils } ) => { await admin.createNewPost(); await perfUtils.load1000Paragraphs(); - draftURL = await perfUtils.saveDraft(); + draftId = await perfUtils.saveDraft(); } ); - test( 'Run the test', async ( { page, perfUtils, metrics } ) => { - await page.goto( draftURL ); + test( 'Run the test', async ( { page, admin, perfUtils, metrics } ) => { + await admin.editPost( draftId ); await perfUtils.disableAutosave(); const listViewToggle = page.getByRole( 'button', { @@ -301,17 +301,17 @@ test.describe( 'Post Editor Performance', () => { } ); test.describe( 'Opening Inserter', () => { - let draftURL = null; + let draftId = null; test( 'Set up the test page', async ( { admin, perfUtils } ) => { await admin.createNewPost(); await perfUtils.load1000Paragraphs(); - draftURL = await perfUtils.saveDraft(); + draftId = await perfUtils.saveDraft(); } ); - test( 'Run the test', async ( { page, perfUtils, metrics } ) => { + test( 'Run the test', async ( { page, admin, perfUtils, metrics } ) => { // Go to the test page. - await page.goto( draftURL ); + await admin.editPost( draftId ); await perfUtils.disableAutosave(); const globalInserterToggle = page.getByRole( 'button', { name: 'Toggle block inserter', @@ -357,17 +357,17 @@ test.describe( 'Post Editor Performance', () => { } ); test.describe( 'Searching Inserter', () => { - let draftURL = null; + let draftId = null; test( 'Set up the test page', async ( { admin, perfUtils } ) => { await admin.createNewPost(); await perfUtils.load1000Paragraphs(); - draftURL = await perfUtils.saveDraft(); + draftId = await perfUtils.saveDraft(); } ); - test( 'Run the test', async ( { page, perfUtils, metrics } ) => { + test( 'Run the test', async ( { page, admin, perfUtils, metrics } ) => { // Go to the test page. - await page.goto( draftURL ); + await admin.editPost( draftId ); await perfUtils.disableAutosave(); const globalInserterToggle = page.getByRole( 'button', { name: 'Toggle block inserter', @@ -413,17 +413,17 @@ test.describe( 'Post Editor Performance', () => { } ); test.describe( 'Hovering Inserter items', () => { - let draftURL = null; + let draftId = null; test( 'Set up the test page', async ( { admin, perfUtils } ) => { await admin.createNewPost(); await perfUtils.load1000Paragraphs(); - draftURL = await perfUtils.saveDraft(); + draftId = await perfUtils.saveDraft(); } ); - test( 'Run the test', async ( { page, perfUtils, metrics } ) => { + test( 'Run the test', async ( { page, admin, perfUtils, metrics } ) => { // Go to the test page. - await page.goto( draftURL ); + await admin.editPost( draftId ); await perfUtils.disableAutosave(); const globalInserterToggle = page.getByRole( 'button', { From c19c9d8fb387f02366814fb145025d32410d6b24 Mon Sep 17 00:00:00 2001 From: George Mamadashvili Date: Mon, 6 Nov 2023 17:14:22 +0400 Subject: [PATCH 15/15] ListViewBlock: Combine 'useSelect' hooks (#55889) --- .../src/components/list-view/block.js | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/block-editor/src/components/list-view/block.js b/packages/block-editor/src/components/list-view/block.js index 375f39a7cc3c81..4957f79fa0d481 100644 --- a/packages/block-editor/src/components/list-view/block.js +++ b/packages/block-editor/src/components/list-view/block.js @@ -69,17 +69,17 @@ function ListViewBlock( { const blockTitle = blockInformation?.name || blockInformation?.title || __( 'Untitled' ); - const block = useSelect( - ( select ) => select( blockEditorStore ).getBlock( clientId ), - [ clientId ] - ); - const blockName = useSelect( - ( select ) => select( blockEditorStore ).getBlockName( clientId ), - [ clientId ] - ); - const blockEditingMode = useSelect( - ( select ) => - select( blockEditorStore ).getBlockEditingMode( clientId ), + const { block, blockName, blockEditingMode } = useSelect( + ( select ) => { + const { getBlock, getBlockName, getBlockEditingMode } = + select( blockEditorStore ); + + return { + block: getBlock( clientId ), + blockName: getBlockName( clientId ), + blockEditingMode: getBlockEditingMode( clientId ), + }; + }, [ clientId ] );
{ __( 'Select a page to preview' ) }
- -