From a520a0d983ae1a292d400d131e53a3825e37cc69 Mon Sep 17 00:00:00 2001 From: Mayank-Tripathi32 Date: Mon, 8 Jun 2026 03:28:57 +0530 Subject: [PATCH 1/3] Editor: Guard PostViewLink against post types without a labels object --- .../post-type-support-check/test/index.js | 14 ++++ .../src/components/post-view-link/index.js | 6 +- .../components/post-view-link/test/index.js | 77 +++++++++++++++++++ 3 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 packages/editor/src/components/post-view-link/test/index.js diff --git a/packages/editor/src/components/post-type-support-check/test/index.js b/packages/editor/src/components/post-type-support-check/test/index.js index 848a0227de81a9..96217500197287 100644 --- a/packages/editor/src/components/post-type-support-check/test/index.js +++ b/packages/editor/src/components/post-type-support-check/test/index.js @@ -54,6 +54,20 @@ describe( 'PostTypeSupportCheck', () => { expect( container ).not.toHaveTextContent( 'Supported' ); } ); + it( 'does not crash when the post type has no `supports` object', () => { + // Regression test for #62918: some custom post types (e.g. + // `wp_template_part`) are registered without a `supports` argument, + // so `postType.supports` is undefined. + setupUseSelectMock( {} ); + const { container } = render( + + Supported + + ); + + expect( container ).not.toHaveTextContent( 'Supported' ); + } ); + it( 'renders its children when post type is known and supports', () => { setupUseSelectMock( { supports: { diff --git a/packages/editor/src/components/post-view-link/index.js b/packages/editor/src/components/post-view-link/index.js index a15b7546fa7c9f..23b40ab3392ce5 100644 --- a/packages/editor/src/components/post-view-link/index.js +++ b/packages/editor/src/components/post-view-link/index.js @@ -24,7 +24,11 @@ export default function PostViewLink() { return { permalink: select( editorStore ).getPermalink(), isPublished: select( editorStore ).isCurrentPostPublished(), - label: postType?.labels.view_item, + // Guard against post types that don't expose `labels` (e.g. + // `wp_template_part` or custom post types registered without + // the `labels` argument). Falling back to the default + // translatable label below. + label: postType?.labels?.view_item, hasLoaded: !! postType, showIconLabels: get( 'core', 'showIconLabels' ), }; diff --git a/packages/editor/src/components/post-view-link/test/index.js b/packages/editor/src/components/post-view-link/test/index.js new file mode 100644 index 00000000000000..0f693eb22b17ff --- /dev/null +++ b/packages/editor/src/components/post-view-link/test/index.js @@ -0,0 +1,77 @@ +/** + * External dependencies + */ +import { render, screen } from '@testing-library/react'; + +/** + * WordPress dependencies + */ +import { useSelect } from '@wordpress/data'; + +/** + * Internal dependencies + */ +import PostViewLink from '../'; + +jest.mock( '@wordpress/data/src/components/use-select', () => { + // Allow tweaking the returned data on each test. + const mock = jest.fn(); + return mock; +} ); + +const DEFAULTS = { + postType: { labels: { view_item: 'View Post' } }, + permalink: 'https://example.com/sample/', + isPublished: true, + showIconLabels: false, +}; + +function setupUseSelectMock( overrides = {} ) { + // Use object spread (not destructure defaults) so an explicit `undefined` + // override actually overrides the default value. + const data = { ...DEFAULTS, ...overrides }; + useSelect.mockImplementation( ( cb ) => + cb( () => ( { + getCurrentPostType: () => 'post', + getPostType: () => data.postType, + getPermalink: () => data.permalink, + isCurrentPostPublished: () => data.isPublished, + get: () => data.showIconLabels, + } ) ) + ); +} + +describe( 'PostViewLink', () => { + it( 'renders the post type-specific view label when available', () => { + setupUseSelectMock(); + render( ); + expect( screen.getByLabelText( 'View Post' ) ).toBeInTheDocument(); + } ); + + it( 'falls back to "View post" without crashing when the post type has no labels', () => { + // Regression test for #62918: some custom post types are registered + // without a `labels` object (e.g. `wp_template_part`). Accessing + // `labels.view_item` on those used to throw. + setupUseSelectMock( { postType: {} } ); + render( ); + expect( screen.getByLabelText( 'View post' ) ).toBeInTheDocument(); + } ); + + it( 'renders nothing if the post is not published', () => { + setupUseSelectMock( { isPublished: false } ); + const { container } = render( ); + expect( container ).toBeEmptyDOMElement(); + } ); + + it( 'renders nothing if no permalink is available', () => { + setupUseSelectMock( { permalink: undefined } ); + const { container } = render( ); + expect( container ).toBeEmptyDOMElement(); + } ); + + it( 'renders nothing while the post type has not loaded', () => { + setupUseSelectMock( { postType: undefined } ); + const { container } = render( ); + expect( container ).toBeEmptyDOMElement(); + } ); +} ); From 8f34a68a6727e80096a6189301257bb11ee632db Mon Sep 17 00:00:00 2001 From: Mayank-Tripathi32 Date: Mon, 15 Jun 2026 22:11:10 +0530 Subject: [PATCH 2/3] Address review feedback: drop explanatory inline comments Remove the inline comments added in this PR per review, and collapse the use-select jest.mock factory to a direct `() => jest.fn()`. No functional change; both test suites still pass. --- .../components/post-type-support-check/test/index.js | 3 --- packages/editor/src/components/post-view-link/index.js | 4 ---- .../editor/src/components/post-view-link/test/index.js | 10 ++-------- 3 files changed, 2 insertions(+), 15 deletions(-) diff --git a/packages/editor/src/components/post-type-support-check/test/index.js b/packages/editor/src/components/post-type-support-check/test/index.js index 96217500197287..cf74d2a680337a 100644 --- a/packages/editor/src/components/post-type-support-check/test/index.js +++ b/packages/editor/src/components/post-type-support-check/test/index.js @@ -55,9 +55,6 @@ describe( 'PostTypeSupportCheck', () => { } ); it( 'does not crash when the post type has no `supports` object', () => { - // Regression test for #62918: some custom post types (e.g. - // `wp_template_part`) are registered without a `supports` argument, - // so `postType.supports` is undefined. setupUseSelectMock( {} ); const { container } = render( diff --git a/packages/editor/src/components/post-view-link/index.js b/packages/editor/src/components/post-view-link/index.js index 23b40ab3392ce5..6ad80f97783265 100644 --- a/packages/editor/src/components/post-view-link/index.js +++ b/packages/editor/src/components/post-view-link/index.js @@ -24,10 +24,6 @@ export default function PostViewLink() { return { permalink: select( editorStore ).getPermalink(), isPublished: select( editorStore ).isCurrentPostPublished(), - // Guard against post types that don't expose `labels` (e.g. - // `wp_template_part` or custom post types registered without - // the `labels` argument). Falling back to the default - // translatable label below. label: postType?.labels?.view_item, hasLoaded: !! postType, showIconLabels: get( 'core', 'showIconLabels' ), diff --git a/packages/editor/src/components/post-view-link/test/index.js b/packages/editor/src/components/post-view-link/test/index.js index 0f693eb22b17ff..c627944aedefd7 100644 --- a/packages/editor/src/components/post-view-link/test/index.js +++ b/packages/editor/src/components/post-view-link/test/index.js @@ -13,11 +13,7 @@ import { useSelect } from '@wordpress/data'; */ import PostViewLink from '../'; -jest.mock( '@wordpress/data/src/components/use-select', () => { - // Allow tweaking the returned data on each test. - const mock = jest.fn(); - return mock; -} ); +jest.mock( '@wordpress/data/src/components/use-select', () => jest.fn() ); const DEFAULTS = { postType: { labels: { view_item: 'View Post' } }, @@ -49,9 +45,7 @@ describe( 'PostViewLink', () => { } ); it( 'falls back to "View post" without crashing when the post type has no labels', () => { - // Regression test for #62918: some custom post types are registered - // without a `labels` object (e.g. `wp_template_part`). Accessing - // `labels.view_item` on those used to throw. + // See https://github.com/WordPress/gutenberg/issues/62918. setupUseSelectMock( { postType: {} } ); render( ); expect( screen.getByLabelText( 'View post' ) ).toBeInTheDocument(); From 30e8a1f2f2d80a349cd8266b61f28d7d928ce8f7 Mon Sep 17 00:00:00 2001 From: Mayank Tripathi <70465598+Mayank-Tripathi32@users.noreply.github.com> Date: Tue, 16 Jun 2026 02:19:48 +0530 Subject: [PATCH 3/3] Editor: Guard remaining post-type label accesses against missing labels --- packages/block-library/src/post-date/edit.js | 4 ++-- packages/block-library/src/post-featured-image/edit.js | 2 +- packages/editor/src/components/post-card-panel/index.js | 2 +- packages/editor/src/components/post-url/index.js | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/block-library/src/post-date/edit.js b/packages/block-library/src/post-date/edit.js index 9cc90f3d61dbee..e78de01032cab5 100644 --- a/packages/block-library/src/post-date/edit.js +++ b/packages/block-library/src/post-date/edit.js @@ -210,7 +210,7 @@ export default function PostDateEdit( props ) { isLink !== false } label={ - postType?.labels.singular_name + postType?.labels?.singular_name ? sprintf( // translators: %s: Name of the post type e.g: "post". __( 'Link to %s' ), @@ -223,7 +223,7 @@ export default function PostDateEdit( props ) { > ) } diff --git a/packages/editor/src/components/post-url/index.js b/packages/editor/src/components/post-url/index.js index f55ac973be50e6..05855b1ca240ee 100644 --- a/packages/editor/src/components/post-url/index.js +++ b/packages/editor/src/components/post-url/index.js @@ -58,7 +58,7 @@ export default function PostURL( { onClose } ) { postSlug: safeDecodeURIComponent( select( editorStore ).getEditedPostSlug() ), - viewPostLabel: postType?.labels.view_item, + viewPostLabel: postType?.labels?.view_item, postLink: post.link, permalinkPrefix: permalinkParts?.prefix, permalinkSuffix: permalinkParts?.suffix,