Commit 4a7ca9f99be for woocommerce

commit 4a7ca9f99be3173439cf6a364b25944f1ba40431
Author: Adrian Moldovan <3854374+adimoldovan@users.noreply.github.com>
Date:   Tue Oct 20 12:31:45 2026 +0200

    Move 9 more Blocks e2e specs to the parallel project (#69416)

    * Move 9 Blocks e2e specs to the parallel project

    * Add changelog entry for moving Blocks e2e specs to parallel

    * Run the parent-item-key Blocks e2e spec serially

diff --git a/plugins/woocommerce/changelog/dev-testops-231-blocks-e2e-m2-parallel-specs b/plugins/woocommerce/changelog/dev-testops-231-blocks-e2e-m2-parallel-specs
new file mode 100644
index 00000000000..0fd862d061f
--- /dev/null
+++ b/plugins/woocommerce/changelog/dev-testops-231-blocks-e2e-m2-parallel-specs
@@ -0,0 +1,3 @@
+Significance: patch
+Type: dev
+Comment: Move 9 more Blocks e2e specs to the parallel project; no production change.
diff --git a/plugins/woocommerce/tests/e2e/playwright.config.ts b/plugins/woocommerce/tests/e2e/playwright.config.ts
index 3fb4a77ffb1..5576776a108 100644
--- a/plugins/woocommerce/tests/e2e/playwright.config.ts
+++ b/plugins/woocommerce/tests/e2e/playwright.config.ts
@@ -205,7 +205,7 @@ const blocksSerialSpecs = [
 	'**/tests/blocks/widget-area/widget-area.classic_theme.spec.ts',

 	// Save site-wide templates, template parts or pages (single product, product
-	// archive, header, cart, checkout, order confirmation), or the
+	// archive, header, cart, checkout), or the
 	// `wc_blocks_use_blockified_product_grid_block_as_template` option. Every
 	// spec that visits those pages reads them.
 	'**/tests/blocks/add-to-cart-form/add-to-cart-form.block_theme.spec.ts',
@@ -230,8 +230,6 @@ const blocksSerialSpecs = [
 	'**/tests/blocks/rating-filter/rating-filter.block_theme.spec.ts',
 	'**/tests/blocks/stock-filter/stock-filter.block_theme.spec.ts',
 	'**/tests/blocks/templates/legacy-templates.block_theme.spec.ts',
-	'**/tests/blocks/templates/order-confirmation.block_theme.spec.ts',
-	'**/tests/blocks/templates/single-product-template.block_theme.spec.ts',

 	// Activate test plugins that change every cart, checkout or product page, or
 	// race other specs on the `active_plugins` option.
@@ -264,21 +262,13 @@ const blocksSerialSpecs = [
 	'**/tests/blocks/single-product-template/single-product-template.product-rating.spec.ts',
 	'**/tests/blocks/templates/shop-page.block_theme.spec.ts',

-	// Add to the cart as the admin user, whose cart all workers share.
-	'**/tests/blocks/cart-store/mutation-batcher.block_theme.spec.ts',
+	// Add to the cart as the admin user, whose cart all workers share, and
+	// place orders, which change the Best Sellers ranking.
 	'**/tests/blocks/cart/cart-checkout-block-coupons.shopper.block_theme.spec.ts',

 	// Create or edit products and categories that catalog specs count.
-	'**/tests/blocks/featured-category/featured-category.block_theme.spec.ts',
-	'**/tests/blocks/featured-product/featured-product.block_theme.spec.ts',
+	'**/tests/blocks/cart-store/parent-item-key.block_theme.spec.ts',
 	'**/tests/blocks/product-collection/product-collection-errors.block_theme.spec.ts',
-
-	// Create a template or pattern with a fixed slug or name, which collides
-	// with other specs or with a retry.
-	'**/tests/blocks/breadcrumbs/breadcrumbs.block_theme.spec.ts',
-	'**/tests/blocks/catalog-sorting/catalog-sorting.block_theme.spec.ts',
-	'**/tests/blocks/patterns/add-new-pattern.block_theme.spec.ts',
-	'**/tests/blocks/product-results-count/product-results-count.block_theme.spec.ts',
 ];

 export default defineConfig< { resetDatabaseAfterEachTest: boolean } >( {
diff --git a/plugins/woocommerce/tests/e2e/tests/blocks/breadcrumbs/breadcrumbs.block_theme.spec.ts b/plugins/woocommerce/tests/e2e/tests/blocks/breadcrumbs/breadcrumbs.block_theme.spec.ts
index 3a0f6b9b3e1..a7286de9564 100644
--- a/plugins/woocommerce/tests/e2e/tests/blocks/breadcrumbs/breadcrumbs.block_theme.spec.ts
+++ b/plugins/woocommerce/tests/e2e/tests/blocks/breadcrumbs/breadcrumbs.block_theme.spec.ts
@@ -15,27 +15,33 @@ test.describe( `${ blockData.slug } Block`, () => {
 		editor,
 	} ) => {
 		const template = await requestUtils.createTemplate( 'wp_template', {
-			slug: 'sorter',
-			title: 'Sorter',
+			slug: `breadcrumbs-test-${ test.info().repeatEachIndex }`,
+			title: `Breadcrumbs Test ${ test.info().repeatEachIndex }`,
 			content: 'placeholder',
 		} );

-		await admin.visitSiteEditor( {
-			postId: template.id,
-			postType: 'wp_template',
-			canvas: 'edit',
-		} );
+		try {
+			await admin.visitSiteEditor( {
+				postId: template.id,
+				postType: 'wp_template',
+				canvas: 'edit',
+			} );

-		await expect(
-			editor.getCustomHtmlBlockContentLocator( 'placeholder' )
-		).toBeVisible();
+			await expect(
+				editor.getCustomHtmlBlockContentLocator( 'placeholder' )
+			).toBeVisible();

-		await editor.insertBlock( {
-			name: blockData.slug,
-		} );
+			await editor.insertBlock( {
+				name: blockData.slug,
+			} );

-		const block = await editor.getBlockByName( blockData.slug );
+			const block = await editor.getBlockByName( blockData.slug );

-		await expect( block ).toHaveText( 'Breadcrumbs / Navigation / Path' );
+			await expect( block ).toHaveText(
+				'Breadcrumbs / Navigation / Path'
+			);
+		} finally {
+			await requestUtils.revertTemplate( 'wp_template', template.id );
+		}
 	} );
 } );
diff --git a/plugins/woocommerce/tests/e2e/tests/blocks/cart-store/mutation-batcher.block_theme.spec.ts b/plugins/woocommerce/tests/e2e/tests/blocks/cart-store/mutation-batcher.block_theme.spec.ts
index c4be682b4e4..47f81940be4 100644
--- a/plugins/woocommerce/tests/e2e/tests/blocks/cart-store/mutation-batcher.block_theme.spec.ts
+++ b/plugins/woocommerce/tests/e2e/tests/blocks/cart-store/mutation-batcher.block_theme.spec.ts
@@ -14,11 +14,13 @@
 /**
  * External dependencies
  */
-import { expect, test as base } from '@woocommerce/e2e-utils';
+import { expect, guestFile, test as base } from '@woocommerce/e2e-utils';

 const test = base.extend( {} );

 test.describe( 'Mutation Batcher', () => {
+	test.use( { storageState: guestFile } );
+
 	test.beforeEach( async ( { frontendUtils } ) => {
 		// The shop page has iAPI product-button blocks, which means the
 		// interactivity API and cart store are loaded and hydrated.
@@ -201,33 +203,6 @@ test.describe( 'Mutation Batcher', () => {
 		test( 'N concurrent successful adds fire each effect exactly once', async ( {
 			page,
 		} ) => {
-			// This project reuses one authenticated user's persistent cart
-			// across every test in the file (not a fresh guest cart per
-			// test), so start from a known-clean cart in a preliminary
-			// evaluate call, *before* the batch-request route is installed —
-			// otherwise the cleanup's own request(s) would pollute the count
-			// below.
-			await page.evaluate( async () => {
-				const { store } = await import( '@wordpress/interactivity' );
-				const unlockKey =
-					'I acknowledge that using a private store means my plugin will inevitably break on the next store release.';
-
-				await import( '@woocommerce/stores/woocommerce/cart' );
-				const { actions, state } = store(
-					'woocommerce',
-					{},
-					{ lock: unlockKey }
-				);
-
-				await actions.refreshCartItems();
-				const existingKeys = state.cart.items.map(
-					( item: { key: string } ) => item.key
-				);
-				for ( const key of existingKeys ) {
-					await actions.removeCartItem( key );
-				}
-			} );
-
 			const batchRequests: number[] = [];

 			await page.route( '**/wc/store/v1/batch**', async ( route ) => {
@@ -411,33 +386,6 @@ test.describe( 'Mutation Batcher', () => {
 		test( 'a mixed successful/failed add cycle fires each effect once and preserves the failed item', async ( {
 			page,
 		} ) => {
-			// This project reuses one authenticated user's persistent cart
-			// across every test in the file (not a fresh guest cart per
-			// test), so start from a known-clean cart in a preliminary
-			// evaluate call, *before* the batch-request route is installed —
-			// otherwise the cleanup's own request(s) would pollute the count
-			// below.
-			await page.evaluate( async () => {
-				const { store } = await import( '@wordpress/interactivity' );
-				const unlockKey =
-					'I acknowledge that using a private store means my plugin will inevitably break on the next store release.';
-
-				await import( '@woocommerce/stores/woocommerce/cart' );
-				const { actions, state } = store(
-					'woocommerce',
-					{},
-					{ lock: unlockKey }
-				);
-
-				await actions.refreshCartItems();
-				const existingKeys = state.cart.items.map(
-					( item: { key: string } ) => item.key
-				);
-				for ( const key of existingKeys ) {
-					await actions.removeCartItem( key );
-				}
-			} );
-
 			const batchRequests: number[] = [];

 			await page.route( '**/wc/store/v1/batch**', async ( route ) => {
diff --git a/plugins/woocommerce/tests/e2e/tests/blocks/catalog-sorting/catalog-sorting.block_theme.spec.ts b/plugins/woocommerce/tests/e2e/tests/blocks/catalog-sorting/catalog-sorting.block_theme.spec.ts
index 675f8fd6113..c831e7008ab 100644
--- a/plugins/woocommerce/tests/e2e/tests/blocks/catalog-sorting/catalog-sorting.block_theme.spec.ts
+++ b/plugins/woocommerce/tests/e2e/tests/blocks/catalog-sorting/catalog-sorting.block_theme.spec.ts
@@ -16,26 +16,30 @@ test.describe( `${ blockData.slug } Block`, () => {
 		editor,
 	} ) => {
 		const template = await requestUtils.createTemplate( 'wp_template', {
-			slug: 'sorter',
-			title: 'Sorter',
+			slug: `catalog-sorting-test-${ test.info().repeatEachIndex }`,
+			title: `Catalog Sorting Test ${ test.info().repeatEachIndex }`,
 			content: 'placeholder',
 		} );

-		await admin.visitSiteEditor( {
-			postId: template.id,
-			postType: 'wp_template',
-			canvas: 'edit',
-		} );
+		try {
+			await admin.visitSiteEditor( {
+				postId: template.id,
+				postType: 'wp_template',
+				canvas: 'edit',
+			} );

-		await expect(
-			editor.getCustomHtmlBlockContentLocator( 'placeholder' )
-		).toBeVisible();
+			await expect(
+				editor.getCustomHtmlBlockContentLocator( 'placeholder' )
+			).toBeVisible();

-		await editor.insertBlock( {
-			name: blockData.slug,
-		} );
+			await editor.insertBlock( {
+				name: blockData.slug,
+			} );

-		const block = await editor.getBlockByName( blockData.slug );
-		await expect( block ).toHaveText( 'Default sorting' );
+			const block = await editor.getBlockByName( blockData.slug );
+			await expect( block ).toHaveText( 'Default sorting' );
+		} finally {
+			await requestUtils.revertTemplate( 'wp_template', template.id );
+		}
 	} );
 } );
diff --git a/plugins/woocommerce/tests/e2e/tests/blocks/featured-category/featured-category.block_theme.spec.ts b/plugins/woocommerce/tests/e2e/tests/blocks/featured-category/featured-category.block_theme.spec.ts
index 6c76a6420c6..0abbb398edf 100644
--- a/plugins/woocommerce/tests/e2e/tests/blocks/featured-category/featured-category.block_theme.spec.ts
+++ b/plugins/woocommerce/tests/e2e/tests/blocks/featured-category/featured-category.block_theme.spec.ts
@@ -19,6 +19,9 @@ test.describe( `${ blockData.slug } Block`, () => {
 		const blockLocator = await editor.getBlockByName( blockData.slug );
 		await blockLocator.getByText( 'Music' ).click();
 		await blockLocator.getByText( 'Done' ).click();
+		// The inner blocks are added after the category loads. Publishing
+		// before that saves the block without its title and button.
+		await expect( blockLocator.getByText( 'Shop now' ) ).toBeVisible();
 		await editor.publishAndVisitPost();
 		const blockLocatorFrontend = await frontendUtils.getBlockByName(
 			blockData.slug
@@ -32,71 +35,34 @@ test.describe( `${ blockData.slug } Block`, () => {

 	test( 'image can be edited', async ( { editor, admin, requestUtils } ) => {
 		let editedMediaId: number | undefined;
-		let productId: string | undefined;
-		let categoryId: string | undefined;
-		let originalCategoryIds: string[] | undefined;
 		const media = await requestUtils.uploadMedia(
 			path.resolve( __dirname, '../../../test-data/images/image-01.png' )
 		);

 		try {
-			await test.step( 'Create a product category with an image', async () => {
-				const productCliOutput = await wpCLI(
-					`post list --post_type=product --title=Cap --field=ID`
-				);
-				productId = productCliOutput.stdout.match( /^\d+$/m )?.[ 0 ];
-				if ( ! productId ) {
-					throw new Error(
-						`Failed to find Cap product: ${ productCliOutput.stdout }`
-					);
-				}
-
-				// `wc product update --categories` replaces the list rather than
-				// appending to it, so Cap's own categories have to come back below.
-				//
-				// npm writes its own banner to stdout ahead of the command output,
-				// and a product with no categories prints nothing at all, so the
-				// value goes inside a marker that can be matched on its own line.
-				// The banner echoes the command back, marker text included, but
-				// always behind a "> " prefix, which the anchor excludes.
-				const categoriesCliOutput = await wpCLI(
-					`eval 'echo "CATEGORY_IDS[" . implode( ",", wp_get_post_terms( ${ productId }, "product_cat", array( "fields" => "ids" ) ) ) . "]";'`
-				);
-				const capturedCategoryIds = categoriesCliOutput.stdout.match(
-					/^CATEGORY_IDS\[([\d,]*)\]$/m
-				);
-				if ( ! capturedCategoryIds ) {
-					throw new Error(
-						`Failed to read Cap's product categories: ${ categoriesCliOutput.stdout }`
-					);
-				}
-				originalCategoryIds = capturedCategoryIds[ 1 ]
-					.split( ',' )
-					.filter( Boolean );
-
-				// --porcelain prints only the new term id. Match it on its own line,
-				// like productId above: without that, the last number anywhere in
-				// stdout wins, and this id is force-deleted in the finally below.
-				const categoryCliOutput = await wpCLI(
-					`wc product_cat create --name="Test Category" --slug="test-category" --image='{ "id": ${ media.id } }' --porcelain --user=1`
-				);
-				categoryId =
-					categoryCliOutput.stdout.match( /^[1-9]\d*$/m )?.[ 0 ];
-				if ( ! categoryId ) {
-					throw new Error(
-						`Failed to read the created category id: ${ categoryCliOutput.stdout }`
-					);
-				}
-				await wpCLI(
-					`wc product update ${ productId } --categories='[ { "id": ${ categoryId } } ]' --user=1`
+			const cliOutput = await wpCLI(
+				'term list product_cat --slug=music --field=term_id'
+			);
+			const categoryId = Number(
+				cliOutput.stdout.match( /^[1-9]\d*$/m )?.[ 0 ]
+			);
+			if ( ! categoryId ) {
+				throw new Error(
+					`Failed to find the Music category: ${ cliOutput.stdout }`
 				);
-			} );
+			}

+			// The block's own image overrides the category image, so the test
+			// does not change any category that other specs read.
 			await admin.createNewPost();
-			await editor.insertBlock( { name: blockData.slug } );
-			const blockLocator = await editor.getBlockByName( blockData.slug );
-			await blockLocator.getByText( 'Test Category' ).click();
-			await blockLocator.getByText( 'Done' ).click();
+			await editor.insertBlock( {
+				name: blockData.slug,
+				attributes: {
+					categoryId,
+					mediaId: media.id,
+					mediaSrc: media.source_url,
+				},
+			} );
 			await editor.clickBlockToolbarButton( 'Edit category image' );
 			await editor.clickBlockToolbarButton( 'Rotate' );
 			const editImageResponse = editor.page.waitForResponse(
@@ -119,36 +85,15 @@ test.describe( `${ blockData.slug } Block`, () => {
 			}
 			editedMediaId = editedMedia.id;
 			await expect(
-				editor.canvas.locator(
-					'img[alt="Test Category"][src*="-edited"]'
-				)
+				editor.canvas.locator( 'img[alt="Music"][src*="-edited"]' )
 			).toBeVisible();
 		} finally {
 			try {
-				if ( productId && originalCategoryIds ) {
-					const categories = originalCategoryIds
-						.map( ( id ) => `{ "id": ${ id } }` )
-						.join( ', ' );
-					await wpCLI(
-						`wc product update ${ productId } --categories='[ ${ categories } ]' --user=1`
-					);
+				if ( editedMediaId !== undefined ) {
+					await requestUtils.deleteMedia( editedMediaId );
 				}
 			} finally {
-				try {
-					if ( categoryId ) {
-						await wpCLI(
-							`wc product_cat delete ${ categoryId } --force=true --user=1`
-						);
-					}
-				} finally {
-					try {
-						if ( editedMediaId !== undefined ) {
-							await requestUtils.deleteMedia( editedMediaId );
-						}
-					} finally {
-						await requestUtils.deleteMedia( media.id );
-					}
-				}
+				await requestUtils.deleteMedia( media.id );
 			}
 		}
 	} );
diff --git a/plugins/woocommerce/tests/e2e/tests/blocks/featured-product/featured-product.block_theme.spec.ts b/plugins/woocommerce/tests/e2e/tests/blocks/featured-product/featured-product.block_theme.spec.ts
index 874c4784643..1ac838495f2 100644
--- a/plugins/woocommerce/tests/e2e/tests/blocks/featured-product/featured-product.block_theme.spec.ts
+++ b/plugins/woocommerce/tests/e2e/tests/blocks/featured-product/featured-product.block_theme.spec.ts
@@ -19,6 +19,9 @@ test.describe( `${ blockData.slug } Block`, () => {
 		const blockLocator = await editor.getBlockByName( blockData.slug );
 		await blockLocator.getByText( 'Album' ).click();
 		await blockLocator.getByText( 'Done' ).click();
+		// The inner blocks are added after the product loads. Publishing
+		// before that saves the block without its title and button.
+		await expect( blockLocator.getByText( 'Shop now' ) ).toBeVisible();
 		await editor.publishAndVisitPost();
 		const blockLocatorFrontend = await frontendUtils.getBlockByName(
 			blockData.slug
@@ -32,51 +35,34 @@ test.describe( `${ blockData.slug } Block`, () => {

 	test( 'image can be edited', async ( { editor, admin, requestUtils } ) => {
 		let editedMediaId: number | undefined;
-		let productId: string | undefined;
-		let originalThumbnailId: string | undefined;
 		const media = await requestUtils.uploadMedia(
 			path.resolve( __dirname, '../../../test-data/images/image-01.png' )
 		);

 		try {
-			const productCliOutput = await wpCLI(
+			const cliOutput = await wpCLI(
 				'post list --post_type=product --title=Album --field=ID'
 			);
-			productId = productCliOutput.stdout.match( /^\d+$/m )?.[ 0 ];
-			if ( ! productId ) {
-				throw new Error(
-					`Failed to find Album product: ${ productCliOutput.stdout }`
-				);
-			}
-
-			// The uploaded media is deleted below, so Album's own thumbnail has to go
-			// back or the product is left pointing at an attachment that no longer
-			// exists. `get_post_thumbnail_id` returns 0 rather than erroring when the
-			// meta key is absent, unlike `wp post meta get`.
-			const thumbnailCliOutput = await wpCLI(
-				`eval 'echo (string) get_post_thumbnail_id( ${ productId } );'`
+			const productId = Number(
+				cliOutput.stdout.match( /^[1-9]\d*$/m )?.[ 0 ]
 			);
-			// npm writes its own banner to stdout ahead of the command output, so
-			// match the digits on their own line the way the product lookup above
-			// does. Trimming the whole buffer keeps the banner, and feeding that
-			// back into a shell command makes the restore fail on its own `>`.
-			originalThumbnailId =
-				thumbnailCliOutput.stdout.match( /^\d+$/m )?.[ 0 ];
-			if ( ! originalThumbnailId ) {
+			if ( ! productId ) {
 				throw new Error(
-					`Failed to read Album's thumbnail ID: ${ thumbnailCliOutput.stdout }`
+					`Failed to find the Album product: ${ cliOutput.stdout }`
 				);
 			}

-			await wpCLI(
-				`post meta update ${ productId } _thumbnail_id ${ media.id }`
-			);
-
+			// The block's own image overrides the product image, so the test
+			// does not change any product that other specs read.
 			await admin.createNewPost();
-			await editor.insertBlock( { name: blockData.slug } );
-			const blockLocator = await editor.getBlockByName( blockData.slug );
-			await blockLocator.getByText( 'Album' ).click();
-			await blockLocator.getByText( 'Done' ).click();
+			await editor.insertBlock( {
+				name: blockData.slug,
+				attributes: {
+					productId,
+					mediaId: media.id,
+					mediaSrc: media.source_url,
+				},
+			} );
 			await editor.clickBlockToolbarButton( 'Edit product image' );
 			await editor.clickBlockToolbarButton( 'Rotate' );
 			const editImageResponse = editor.page.waitForResponse(
@@ -103,24 +89,11 @@ test.describe( `${ blockData.slug } Block`, () => {
 			).toBeVisible();
 		} finally {
 			try {
-				if ( productId && originalThumbnailId !== undefined ) {
-					// get_post_thumbnail_id() echoes 0 when the meta key is absent.
-					const hadThumbnail = originalThumbnailId !== '0';
-
-					await wpCLI(
-						hadThumbnail
-							? `post meta update ${ productId } _thumbnail_id ${ originalThumbnailId }`
-							: `post meta delete ${ productId } _thumbnail_id`
-					);
+				if ( editedMediaId !== undefined ) {
+					await requestUtils.deleteMedia( editedMediaId );
 				}
 			} finally {
-				try {
-					if ( editedMediaId !== undefined ) {
-						await requestUtils.deleteMedia( editedMediaId );
-					}
-				} finally {
-					await requestUtils.deleteMedia( media.id );
-				}
+				await requestUtils.deleteMedia( media.id );
 			}
 		}
 	} );
diff --git a/plugins/woocommerce/tests/e2e/tests/blocks/patterns/add-new-pattern.block_theme.spec.ts b/plugins/woocommerce/tests/e2e/tests/blocks/patterns/add-new-pattern.block_theme.spec.ts
index 89f43ec2c40..d8a56869a8a 100644
--- a/plugins/woocommerce/tests/e2e/tests/blocks/patterns/add-new-pattern.block_theme.spec.ts
+++ b/plugins/woocommerce/tests/e2e/tests/blocks/patterns/add-new-pattern.block_theme.spec.ts
@@ -12,12 +12,39 @@ test.describe( 'Patterns in block theme', () => {
 	test( 'Synced Pattern can be created with basic blocks', async ( {
 		admin,
 		editor,
+		requestUtils,
 	} ) => {
-		await admin.createNewPattern( 'Woo Blocks Synced Pattern' );
-		const { productTitles, productPrices } =
-			await addTestingBlocks( editor );
+		const patternName = `Woo Blocks Synced Pattern ${
+			test.info().repeatEachIndex
+		}`;

-		await expect( productTitles ).toHaveText( expectedTitles );
-		await expect( productPrices ).toHaveText( expectedPrices );
+		try {
+			await admin.createNewPattern( patternName );
+			const { productTitles, productPrices } =
+				await addTestingBlocks( editor );
+
+			await expect( productTitles ).toHaveText( expectedTitles );
+			await expect( productPrices ).toHaveText( expectedPrices );
+		} finally {
+			const patterns: { id: number; title: { raw: string } }[] =
+				await requestUtils.rest( {
+					path: '/wp/v2/blocks',
+					params: {
+						search: patternName,
+						status: 'any',
+						context: 'edit',
+						per_page: 100,
+					},
+				} );
+			for ( const { id } of patterns.filter(
+				( { title } ) => title.raw === patternName
+			) ) {
+				await requestUtils.rest( {
+					method: 'DELETE',
+					path: `/wp/v2/blocks/${ id }`,
+					params: { force: true },
+				} );
+			}
+		}
 	} );
 } );
diff --git a/plugins/woocommerce/tests/e2e/tests/blocks/product-results-count/product-results-count.block_theme.spec.ts b/plugins/woocommerce/tests/e2e/tests/blocks/product-results-count/product-results-count.block_theme.spec.ts
index aa27489404d..dba88ddc7f2 100644
--- a/plugins/woocommerce/tests/e2e/tests/blocks/product-results-count/product-results-count.block_theme.spec.ts
+++ b/plugins/woocommerce/tests/e2e/tests/blocks/product-results-count/product-results-count.block_theme.spec.ts
@@ -16,26 +16,32 @@ test.describe( `${ blockData.slug } Block`, () => {
 		editor,
 	} ) => {
 		const template = await requestUtils.createTemplate( 'wp_template', {
-			slug: 'sorter',
-			title: 'Sorter',
+			slug: `product-results-count-test-${ test.info().repeatEachIndex }`,
+			title: `Product Results Count Test ${
+				test.info().repeatEachIndex
+			}`,
 			content: 'placeholder',
 		} );

-		await admin.visitSiteEditor( {
-			postId: template.id,
-			postType: 'wp_template',
-			canvas: 'edit',
-		} );
+		try {
+			await admin.visitSiteEditor( {
+				postId: template.id,
+				postType: 'wp_template',
+				canvas: 'edit',
+			} );

-		await expect(
-			editor.getCustomHtmlBlockContentLocator( 'placeholder' )
-		).toBeVisible();
-		await editor.insertBlock( {
-			name: blockData.slug,
-		} );
+			await expect(
+				editor.getCustomHtmlBlockContentLocator( 'placeholder' )
+			).toBeVisible();
+			await editor.insertBlock( {
+				name: blockData.slug,
+			} );

-		const block = await editor.getBlockByName( blockData.slug );
+			const block = await editor.getBlockByName( blockData.slug );

-		await expect( block ).toHaveText( 'Showing 1-X of X results' );
+			await expect( block ).toHaveText( 'Showing 1-X of X results' );
+		} finally {
+			await requestUtils.revertTemplate( 'wp_template', template.id );
+		}
 	} );
 } );
diff --git a/plugins/woocommerce/tests/e2e/tests/blocks/templates/order-confirmation.block_theme.spec.ts b/plugins/woocommerce/tests/e2e/tests/blocks/templates/order-confirmation.block_theme.spec.ts
index 3c6df25f5d3..7df2f0afc7d 100644
--- a/plugins/woocommerce/tests/e2e/tests/blocks/templates/order-confirmation.block_theme.spec.ts
+++ b/plugins/woocommerce/tests/e2e/tests/blocks/templates/order-confirmation.block_theme.spec.ts
@@ -13,7 +13,6 @@ test.describe( 'Test the order confirmation template', () => {
 			postType: 'wp_template',
 			canvas: 'edit',
 		} );
-		await editor.transformIntoBlocks();
 		await expect(
 			editor.canvas.getByText(
 				'Thank you. Your order has been received.'
diff --git a/plugins/woocommerce/tests/e2e/tests/blocks/templates/single-product-template.block_theme.spec.ts b/plugins/woocommerce/tests/e2e/tests/blocks/templates/single-product-template.block_theme.spec.ts
index 0e96c27d29a..3c9415c1b88 100644
--- a/plugins/woocommerce/tests/e2e/tests/blocks/templates/single-product-template.block_theme.spec.ts
+++ b/plugins/woocommerce/tests/e2e/tests/blocks/templates/single-product-template.block_theme.spec.ts
@@ -8,6 +8,7 @@ test.describe( 'Single Product template', () => {
 		admin,
 		editor,
 		page,
+		requestUtils,
 		wpCoreVersion,
 	} ) => {
 		const testData = {
@@ -19,51 +20,73 @@ test.describe( 'Single Product template', () => {
 		};
 		const userText = 'Hello World in the Belt template';

-		// Create the specific product template.
-		await admin.visitSiteEditor( { path: `/${ testData.templateType }` } );
+		try {
+			// Create the specific product template.
+			await admin.visitSiteEditor( {
+				path: `/${ testData.templateType }`,
+			} );

-		await page
-			.getByRole( 'button', {
-				name:
-					wpCoreVersion >= 6.8 ? 'Add Template' : 'Add New Template',
-			} )
-			.click();
+			await page
+				.getByRole( 'button', {
+					name:
+						wpCoreVersion >= 6.8
+							? 'Add Template'
+							: 'Add New Template',
+				} )
+				.click();

-		await page
-			.getByRole( 'button', { name: 'Single item: Product' } )
-			.click();
+			await page
+				.getByRole( 'button', { name: 'Single item: Product' } )
+				.click();

-		await page
-			.getByPlaceholder( 'Search products' )
-			.fill( testData.productName );
-		await page
-			.getByRole( 'option', { name: testData.productName } )
-			.click();
-		await page.getByLabel( 'Close', { exact: true } ).click();
+			await page
+				.getByPlaceholder( 'Search products' )
+				.fill( testData.productName );
+			await page
+				.getByRole( 'option', { name: testData.productName } )
+				.click();
+			await page.getByLabel( 'Close', { exact: true } ).click();

-		await editor.canvas.locator( 'body' ).waitFor( { timeout: 20000 } );
+			await editor.canvas.locator( 'body' ).waitFor( { timeout: 20000 } );

-		// Edit the template.
-		await editor.insertBlock( {
-			name: 'core/paragraph',
-			attributes: { content: userText },
-		} );
-		await editor.saveSiteEditorEntities( {
-			isOnlyCurrentEntityDirty: true,
-		} );
+			// Edit the template.
+			await editor.insertBlock( {
+				name: 'core/paragraph',
+				attributes: { content: userText },
+			} );
+			await editor.saveSiteEditorEntities( {
+				isOnlyCurrentEntityDirty: true,
+			} );

-		// Verify edits are visible.
-		await page.goto( testData.permalink );
-		await expect( page.getByText( userText ).first() ).toBeVisible();
+			// Verify edits are visible.
+			await page.goto( testData.permalink );
+			await expect( page.getByText( userText ).first() ).toBeVisible();

-		// Revert edition.
-		await admin.visitSiteEditor( {
-			postType: testData.templateType,
-		} );
-		await editor.revertTemplate( { templateName: testData.templateName } );
-		await page.goto( testData.permalink );
+			// Revert edition.
+			await admin.visitSiteEditor( {
+				postType: testData.templateType,
+			} );
+			await editor.revertTemplate( {
+				templateName: testData.templateName,
+			} );
+			await page.goto( testData.permalink );

-		// Verify the edits are no longer visible.
-		await expect( page.getByText( userText ) ).toHaveCount( 0 );
+			// Verify the edits are no longer visible.
+			await expect( page.getByText( userText ) ).toHaveCount( 0 );
+		} finally {
+			const templates = (
+				await requestUtils.getTemplates( 'wp_template' )
+			).filter(
+				( { slug, wp_id: wpId } ) =>
+					slug === testData.templatePath && wpId
+			);
+			for ( const { id } of templates ) {
+				await requestUtils.rest( {
+					method: 'DELETE',
+					path: `/wp/v2/templates/${ id }`,
+					params: { force: true },
+				} );
+			}
+		}
 	} );
 } );