Commit da78473f05 for woocommerce

commit da78473f050d6a26284a2a37c92d8033bb50d584
Author: Luigi Teschio <gigitux@gmail.com>
Date:   Thu May 29 15:01:07 2025 +0200

    Blocks: Remove multiple div wrappers (#58081)

    * Refactor ProductPicker component avoid not necessary re-rendering removing useBlockProps

    * fix lint errors

    * Add changefile(s) from automation for the following project(s): woocommerce

    * fix E2E test

    * fix lint error

    * fix E2E test

    * fix Product Collection wrapper

    * Add changefile(s) from automation for the following project(s): woocommerce

    * fix lint errors

    * Add changefile(s) from automation for the following project(s): woocommerce

    * remove old changelog

    * remove not necessary check

    ---------

    Co-authored-by: github-actions <github-actions@github.com>

diff --git a/plugins/woocommerce/changelog/58081-fix-wooplug-2976-product-collection-cross-sells-product-selection-error-when b/plugins/woocommerce/changelog/58081-fix-wooplug-2976-product-collection-cross-sells-product-selection-error-when
new file mode 100644
index 0000000000..22d3dbeb1c
--- /dev/null
+++ b/plugins/woocommerce/changelog/58081-fix-wooplug-2976-product-collection-cross-sells-product-selection-error-when
@@ -0,0 +1,4 @@
+Significance: minor
+Type: fix
+
+Blocks: Remove multiple div wrappers
\ No newline at end of file
diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/product-collection/edit/ProductPicker.tsx b/plugins/woocommerce/client/blocks/assets/js/blocks/product-collection/edit/ProductPicker.tsx
index 927d3d31ab..e04e48741a 100644
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/product-collection/edit/ProductPicker.tsx
+++ b/plugins/woocommerce/client/blocks/assets/js/blocks/product-collection/edit/ProductPicker.tsx
@@ -2,18 +2,16 @@
  * External dependencies
  */
 import { __, sprintf } from '@wordpress/i18n';
-import { useBlockProps } from '@wordpress/block-editor';
 import { Icon, info } from '@wordpress/icons';
 import ProductControl from '@woocommerce/editor-components/product-control';
 import type { SelectedOption } from '@woocommerce/block-hocs';
 import { createInterpolateElement } from '@wordpress/element';
 import {
 	Placeholder,
-	// @ts-expect-error Using experimental features
 	__experimentalHStack as HStack,
-	// @ts-expect-error Using experimental features
 	__experimentalText as Text,
 } from '@wordpress/components';
+import { useBlockProps } from '@wordpress/block-editor';

 /**
  * Internal dependencies
@@ -26,9 +24,10 @@ const ProductPicker = (
 		isDeletedProductReference: boolean;
 	}
 ) => {
-	const blockProps = useBlockProps();
 	const { attributes, isDeletedProductReference } = props;

+	const blockProps = useBlockProps();
+
 	const collection = getCollectionByName( attributes.collection );
 	if ( ! collection ) {
 		return null;
diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/product-collection/edit/inspector-controls/index.tsx b/plugins/woocommerce/client/blocks/assets/js/blocks/product-collection/edit/inspector-controls/index.tsx
index ca5409d141..d665e29585 100644
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/product-collection/edit/inspector-controls/index.tsx
+++ b/plugins/woocommerce/client/blocks/assets/js/blocks/product-collection/edit/inspector-controls/index.tsx
@@ -349,7 +349,7 @@ const CollectionSpecificControls = (
 const withCollectionSpecificControls =
 	< T extends EditorBlock< T > >( BlockEdit: ElementType ) =>
 	( props: ProductCollectionEditComponentProps ) => {
-		if ( ! isProductCollection( props.name ) || ! props.isSelected ) {
+		if ( ! isProductCollection( props.name ) ) {
 			return <BlockEdit { ...props } />;
 		}

diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/product-collection/edit/product-collection-content.tsx b/plugins/woocommerce/client/blocks/assets/js/blocks/product-collection/edit/product-collection-content.tsx
index 7ef304bc31..d242689078 100644
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/product-collection/edit/product-collection-content.tsx
+++ b/plugins/woocommerce/client/blocks/assets/js/blocks/product-collection/edit/product-collection-content.tsx
@@ -88,9 +88,12 @@ const ProductCollectionContent = ( {
 	} );

 	const blockProps = useBlockProps();
-	const innerBlocksProps = useInnerBlocksProps( blockProps, {
-		template: INNER_BLOCKS_TEMPLATE,
-	} );
+	const innerBlocksProps = useInnerBlocksProps(
+		{},
+		{
+			template: INNER_BLOCKS_TEMPLATE,
+		}
+	);

 	const queryId = useQueryId(
 		clientId,
diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/reviews/editor-container-block.tsx b/plugins/woocommerce/client/blocks/assets/js/blocks/reviews/editor-container-block.tsx
index 0c1329bc02..384a9f5252 100644
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/reviews/editor-container-block.tsx
+++ b/plugins/woocommerce/client/blocks/assets/js/blocks/reviews/editor-container-block.tsx
@@ -4,14 +4,13 @@
 import { __ } from '@wordpress/i18n';
 import { debounce } from '@woocommerce/base-utils';
 import { Placeholder } from '@wordpress/components';
-import { useBlockProps } from '@wordpress/block-editor';
 import { EditorContainerBlockProps } from '@woocommerce/blocks/reviews/types';

 /**
  * Internal dependencies
  */
 import EditorBlock from './editor-block';
-import { getBlockClassName, getSortArgs } from './utils.js';
+import { getSortArgs } from './utils.js';

 const EditorContainerBlock = ( {
 	attributes,
@@ -39,10 +38,6 @@ const EditorContainerBlock = ( {
 		! showReviewImage &&
 		! showProductName;

-	const blockProps = useBlockProps( {
-		className: getBlockClassName( attributes ),
-	} );
-
 	if ( isAllContentHidden ) {
 		return (
 			<Placeholder icon={ icon } label={ name }>
@@ -55,7 +50,7 @@ const EditorContainerBlock = ( {
 	}

 	return (
-		<div { ...blockProps }>
+		<>
 			<EditorBlock
 				attributes={ attributes }
 				categoryIds={ categoryIds }
@@ -68,7 +63,7 @@ const EditorContainerBlock = ( {
 				productId={ productId }
 				reviewsToDisplay={ reviewsOnPageLoad }
 			/>
-		</div>
+		</>
 	);
 };

diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/reviews/reviews-by-product/edit.tsx b/plugins/woocommerce/client/blocks/assets/js/blocks/reviews/reviews-by-product/edit.tsx
index 4afd650603..c423479ab0 100644
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/reviews/reviews-by-product/edit.tsx
+++ b/plugins/woocommerce/client/blocks/assets/js/blocks/reviews/reviews-by-product/edit.tsx
@@ -2,7 +2,7 @@
  * External dependencies
  */
 import { __, _n, sprintf } from '@wordpress/i18n';
-import { InspectorControls } from '@wordpress/block-editor';
+import { InspectorControls, useBlockProps } from '@wordpress/block-editor';
 import {
 	Button,
 	PanelBody,
@@ -33,6 +33,8 @@ const ReviewsByProductEditor = ( {
 }: ReviewsByProductEditorProps ) => {
 	const { editMode, productId } = attributes;

+	const blockProps = useBlockProps();
+
 	const renderProductControlItem = ( args ) => {
 		const { item = 0 } = args;

@@ -149,7 +151,7 @@ const ReviewsByProductEditor = ( {
 	const buttonTitle = __( 'Edit selected product', 'woocommerce' );

 	return (
-		<>
+		<div { ...blockProps }>
 			{ getBlockControls( editMode, setAttributes, buttonTitle ) }
 			{ getInspectorControls() }
 			<EditorContainerBlock
@@ -163,7 +165,7 @@ const ReviewsByProductEditor = ( {
 				name={ __( 'Reviews by Product', 'woocommerce' ) }
 				noReviewsPlaceholder={ NoReviewsPlaceholder }
 			/>
-		</>
+		</div>
 	);
 };

diff --git a/plugins/woocommerce/client/blocks/tests/e2e/tests/product-collection/register-product-collection.block_theme.spec.ts b/plugins/woocommerce/client/blocks/tests/e2e/tests/product-collection/register-product-collection.block_theme.spec.ts
index fd454ae3de..9c10e17a9c 100644
--- a/plugins/woocommerce/client/blocks/tests/e2e/tests/product-collection/register-product-collection.block_theme.spec.ts
+++ b/plugins/woocommerce/client/blocks/tests/e2e/tests/product-collection/register-product-collection.block_theme.spec.ts
@@ -242,8 +242,7 @@ test.describe( 'Product Collection: Register Product Collection', () => {
 				.locator( 'visible=true' );
 			await expect( products ).toHaveCount( 9 );

-			// Check if the preview button is visible
-			const previewButtonLocator = block.getByTestId(
+			const previewButtonLocator = editor.canvas.getByTestId(
 				SELECTORS.previewButtonTestID
 			);
 			await expect( previewButtonLocator ).toBeVisible();
@@ -305,10 +304,10 @@ test.describe( 'Product Collection: Register Product Collection', () => {
 					.label
 			);

-			// Check if the preview button is visible
-			const previewButtonLocator = block.getByTestId(
+			const previewButtonLocator = editor.canvas.getByTestId(
 				SELECTORS.previewButtonTestID
 			);
+
 			await expect( previewButtonLocator ).toBeVisible();

 			// Check if products are visible
@@ -375,8 +374,8 @@ test.describe( 'Product Collection: Register Product Collection', () => {
 					collection.id as Collections
 				);

-				const block = editor.canvas.getByLabel( collection.label );
-				const previewButtonLocator = block.getByTestId(
+				// Check if the preview button is visible
+				const previewButtonLocator = editor.canvas.getByTestId(
 					SELECTORS.previewButtonTestID
 				);

@@ -392,8 +391,7 @@ test.describe( 'Product Collection: Register Product Collection', () => {
 				collection.id as Collections
 			);

-			const block = editor.canvas.getByLabel( collection.label );
-			const previewButtonLocator = block.getByTestId(
+			const previewButtonLocator = editor.canvas.getByTestId(
 				SELECTORS.previewButtonTestID
 			);

@@ -408,8 +406,7 @@ test.describe( 'Product Collection: Register Product Collection', () => {
 				collection.id as Collections
 			);

-			const block = editor.canvas.getByLabel( collection.label );
-			const previewButtonLocator = block.getByTestId(
+			const previewButtonLocator = editor.canvas.getByTestId(
 				SELECTORS.previewButtonTestID
 			);

@@ -565,8 +562,7 @@ test.describe( 'Product Collection: Register Product Collection', () => {
 						collection.id as Collections
 					);

-					const block = editor.canvas.getByLabel( collection.label );
-					const previewButtonLocator = block.getByTestId(
+					const previewButtonLocator = editor.canvas.getByTestId(
 						SELECTORS.previewButtonTestID
 					);

@@ -604,8 +600,7 @@ test.describe( 'Product Collection: Register Product Collection', () => {
 				await expect( editorProductPicker ).toBeHidden();

 				// Check visibility of preview label
-				const block = editor.canvas.getByLabel( collection.label );
-				const previewButtonLocator = block.getByTestId(
+				const previewButtonLocator = editor.canvas.getByTestId(
 					SELECTORS.previewButtonTestID
 				);

@@ -620,8 +615,7 @@ test.describe( 'Product Collection: Register Product Collection', () => {
 					collection.id as Collections
 				);

-				const block = editor.canvas.getByLabel( collection.label );
-				const previewButtonLocator = block.getByTestId(
+				const previewButtonLocator = editor.canvas.getByTestId(
 					SELECTORS.previewButtonTestID
 				);

diff --git a/plugins/woocommerce/tests/e2e-pw/tests/editor/create-woocommerce-blocks.spec.js b/plugins/woocommerce/tests/e2e-pw/tests/editor/create-woocommerce-blocks.spec.js
index a23d762c3c..8441f4e058 100644
--- a/plugins/woocommerce/tests/e2e-pw/tests/editor/create-woocommerce-blocks.spec.js
+++ b/plugins/woocommerce/tests/e2e-pw/tests/editor/create-woocommerce-blocks.spec.js
@@ -24,27 +24,117 @@ const singleProductPrice = '555.00';
 // All WooCommerce blocks except:
 // - default cart and checkout blocks, mini-cart
 // - Product Gallery (Beta) - it's not intended to be used in posts
-const blocks = [
-	'All Reviews',
-	'Best Sellers',
-	'Cross-Sells',
-	'Customer account',
-	'Featured Category',
-	'Featured Product',
-	'Featured Products',
-	'Hand-Picked Products',
-	'New Arrivals',
-	'On Sale Products',
-	'Product Categories List',
-	'Product Collection',
-	'Product Search',
-	'Reviews by Category',
-	'Reviews by Product',
-	'Single Product',
-	'Store Notices',
-	'Top Rated Products',
-	'Upsells',
-];
+
+/**
+ * The key of the object is the block name
+ * The value is custom function to check the block
+ * If the value is null, there is a default check for the block
+ */
+const blocks = {
+	'All Reviews': null,
+	'Best Sellers': null,
+	'Cross-Sells': async ( canvas ) => {
+		await canvas
+			.getByRole( 'listitem' )
+			.filter( { hasText: /^Simplest Product$/ } )
+			.click();
+		await expect(
+			canvas
+				.getByRole( 'document', {
+					name: `Block: Cross-Sells`,
+					exact: true,
+				} )
+				.first()
+		).toBeVisible();
+	},
+	'Customer account': null,
+	'Featured Category': async ( canvas ) => {
+		await canvas
+			.getByRole( 'listitem' )
+			.filter( { hasText: 'simple category' } )
+			.click();
+
+		await canvas.getByRole( 'button', { name: 'Done' } ).click();
+
+		await expect(
+			canvas.getByRole( 'document', { name: `Block: Featured Category` } )
+		).toBeVisible();
+	},
+	'Featured Product': async ( canvas ) => {
+		await canvas
+			.getByRole( 'listitem' )
+			.filter( { hasText: /^Simplest Product$/ } )
+			.click();
+
+		await canvas.getByRole( 'button', { name: 'Done' } ).click();
+
+		await expect(
+			canvas.getByRole( 'document', { name: `Block: Featured Product` } )
+		).toBeVisible();
+	},
+	'Featured Products': null,
+	'Hand-Picked Products': null,
+	'New Arrivals': null,
+	'On Sale Products': null,
+	'Product Categories List': null,
+	'Product Collection': null,
+	'Product Search': null,
+	'Reviews by Category': async ( canvas ) => {
+		const block = canvas.getByRole( 'document', {
+			name: `Block: Reviews by Category`,
+		} );
+
+		await block.filter( { hasText: 'simple category' } ).click();
+		await canvas.getByRole( 'button', { name: 'Done' } ).click();
+
+		await expect( block ).toBeVisible();
+	},
+	'Reviews by Product': async ( canvas ) => {
+		await canvas
+			.locator( '.wc-block-reviews-by-product' )
+			.getByLabel( simpleProductName )
+			.click();
+		await canvas
+			.locator( '.wc-block-reviews-by-product' )
+			.getByRole( 'button', {
+				name: 'Done',
+				exact: true,
+			} )
+			.click();
+
+		// verify added blocks into page
+		await expect(
+			canvas.getByRole( 'document', {
+				name: `Block: Reviews by Product`,
+				exact: true,
+			} )
+		).toBeVisible();
+	},
+	'Single Product': async ( canvas ) => {
+		await canvas
+			.getByRole( 'listitem' )
+			.filter( { hasText: /^Simplest Product$/ } )
+			.click();
+
+		await canvas.getByRole( 'button', { name: 'Done' } ).click();
+
+		await expect(
+			canvas.getByRole( 'document', { name: `Block: Single Product` } )
+		).toBeVisible();
+	},
+	'Store Notices': null,
+	'Top Rated Products': null,
+	Upsells: async ( canvas ) => {
+		await canvas
+			.getByRole( 'listitem' )
+			.filter( { hasText: /^Simplest Product$/ } )
+			.click();
+
+		await expect(
+			canvas.getByRole( 'document', { name: `Block: Upsells` } )
+		).toBeVisible();
+	},
+};

 let productId, shippingZoneId, productTagId, attributeId, productCategoryId;

@@ -168,39 +258,23 @@ test.describe(

 			const wordPressVersion = await getInstalledWordPressVersion();

-			for ( let i = 0; i < blocks.length; i++ ) {
-				await test.step( `Insert ${ blocks[ i ] } block`, async () => {
-					await insertBlock( page, blocks[ i ], wordPressVersion );
+			for ( const [ blockName, check ] of Object.entries( blocks ) ) {
+				await test.step( `Insert ${ blockName } block`, async () => {
+					await insertBlock( page, blockName, wordPressVersion );

 					const canvas = await getCanvas( page );

 					// eslint-disable-next-line playwright/no-conditional-in-test
-					if ( blocks[ i ] === 'Reviews by Product' ) {
-						// Use click() instead of check().
-						// check() causes occasional flakiness:
-						//     - "Error: locator.check: Clicking the checkbox did not change its state"
-						await canvas
-							.locator( '.wc-block-reviews-by-product' )
-							.getByLabel( simpleProductName )
-							.click();
-						await canvas
-							.locator( '.wc-block-reviews-by-product' )
-							.getByRole( 'button', {
-								name: 'Done',
-								exact: true,
-							} )
-							.click();
-						// Click on the Reviews by Product block to show the Block Tools to be used later.
-						await canvas
-							.getByLabel( 'Block: Reviews by Product' )
-							.click();
+					if ( check ) {
+						await check( canvas );
+						return;
 					}

 					// verify added blocks into page
 					await expect(
 						canvas
 							.getByRole( 'document', {
-								name: `Block: ${ blocks[ i ] }`,
+								name: `Block: ${ blockName }`,
 								exact: true,
 							} )
 							.first()
@@ -220,12 +294,12 @@ test.describe(
 			// check all blocks inside the page after publishing
 			// except the product price due to invisibility and false-positive
 			const canvas = await getCanvas( page );
-			for ( let i = 1; i < blocks.length; i++ ) {
+			for ( const [ blockName ] of Object.entries( blocks ) ) {
 				// verify added blocks into page
 				await expect(
 					canvas
 						.getByRole( 'document', {
-							name: `Block: ${ blocks[ i ] }`,
+							name: `Block: ${ blockName }`,
 							exact: true,
 						} )
 						.first()