Commit f7d7cb5c01e for woocommerce

commit f7d7cb5c01e98539a7722c5e61115f7df101b093
Author: Taha Paksu <3295+tpaksu@users.noreply.github.com>
Date:   Mon Mar 2 10:12:49 2026 +0300

    Fix remaining E2E test failures for WordPress 7.0 compatibility (#63484)

    * Fix remaining E2E test failures for WordPress 7.0 compatibility

    - Brands test: replace getByLabel('"Name" (Edit)') with getByRole('link') scoped to #posts-filter, as WP 7.0 changed taxonomy term link aria-labels
    - Onboarding wizard: refactor plugin cleanup to use data-slug row selectors with getByRole('link', { name: 'Deactivate', exact: true }) instead of getByLabel which broke with WP 7.0 plugin list changes
    - Setup checklist: add exact: true to Connect button locator to avoid matching the new "Connectors" sidebar link in WP 7.0
    - JS file monitor: bump WC Dashboard threshold from 84 to 90 for WP 7.0 extra core scripts

    * Fix brands test: use .row-title selector instead of role-based link matching

    The taxonomy term list table link text includes child indentation prefixes,
    so exact name matching with getByRole fails. Use .row-title class selector
    with hasText filter instead.

    * Fix product reviews test: handle smart quotes in reviewer names

    WordPress wptexturize may convert straight apostrophes to curly quotes
    in reviewer names (e.g. D'Amore). Check for both variants to handle
    the text with or without smart quote conversion.

diff --git a/plugins/woocommerce/tests/e2e-pw/tests/brands/create-product-brand.spec.ts b/plugins/woocommerce/tests/e2e-pw/tests/brands/create-product-brand.spec.ts
index 46eea81dc28..26840ef4491 100644
--- a/plugins/woocommerce/tests/e2e-pw/tests/brands/create-product-brand.spec.ts
+++ b/plugins/woocommerce/tests/e2e-pw/tests/brands/create-product-brand.spec.ts
@@ -89,7 +89,11 @@ test( 'Merchant can add brands', async ( { page } ) => {
 	 * After a brand is edited, you will be redirected to the Brands page.
 	 */
 	const editBrand = async ( currentName: string, brand: Brand ) => {
-		await page.getByLabel( `“${ currentName }” (Edit)` ).click();
+		await page
+			.locator( '#posts-filter .row-title' )
+			.filter( { hasText: currentName } )
+			.first()
+			.click();
 		await page.getByLabel( 'Name' ).fill( brand.name );
 		await page.getByLabel( 'Slug' ).fill( brand.slug );
 		await page
@@ -129,7 +133,11 @@ test( 'Merchant can add brands', async ( { page } ) => {
 	 * After a brand is deleted, you will be redirected to the Brands page.
 	 */
 	const deleteBrand = async ( name: string ) => {
-		await page.getByLabel( `“${ name }” (Edit)` ).click();
+		await page
+			.locator( '#posts-filter .row-title' )
+			.filter( { hasText: name } )
+			.first()
+			.click();

 		// After clicking the "Delete" button, there will be a confirmation dialog.
 		page.once( 'dialog', ( dialog ) => {
diff --git a/plugins/woocommerce/tests/e2e-pw/tests/js-file-monitor/monitor-js-file-number.spec.ts b/plugins/woocommerce/tests/e2e-pw/tests/js-file-monitor/monitor-js-file-number.spec.ts
index 569f34da516..17ef58a2a5a 100644
--- a/plugins/woocommerce/tests/e2e-pw/tests/js-file-monitor/monitor-js-file-number.spec.ts
+++ b/plugins/woocommerce/tests/e2e-pw/tests/js-file-monitor/monitor-js-file-number.spec.ts
@@ -27,7 +27,9 @@ const pageGroups = [
 			{
 				name: 'WC Dashboard',
 				url: 'wp-admin/admin.php?page=wc-admin',
-				expectedCount: 84,
+				// TODO: WP 7.0 compat - threshold bumped from 84 for WP 7.0 extra
+				// core scripts. Re-evaluate when WP 7.0 is the minimum version.
+				expectedCount: 90,
 			},
 			{
 				name: 'Reports',
diff --git a/plugins/woocommerce/tests/e2e-pw/tests/onboarding/onboarding-wizard.spec.ts b/plugins/woocommerce/tests/e2e-pw/tests/onboarding/onboarding-wizard.spec.ts
index bf4ba29393f..9801006a809 100644
--- a/plugins/woocommerce/tests/e2e-pw/tests/onboarding/onboarding-wizard.spec.ts
+++ b/plugins/woocommerce/tests/e2e-pw/tests/onboarding/onboarding-wizard.spec.ts
@@ -422,47 +422,45 @@ test.describe(
 			} );

 			await test.step( 'Clean up installed extensions', async () => {
-				await page.goto( 'wp-admin/plugins.php' );
-				await page.getByLabel( 'Deactivate Google' ).click();
-				await expect(
-					page.getByText( 'Plugin deactivated.' )
-				).toBeVisible();
-				// delete plugin regularly or, if attempted, accept deleting data as well
-				try {
-					await page.getByLabel( 'Delete Google' ).click();
-					await expect(
-						page.getByText( 'was successfully deleted.' )
-					).toBeVisible( { timeout: 5000 } );
-				} catch ( e ) {
-					await page
-						.getByText( 'Yes, delete these files and data' )
-						.click();
-					await page
-						.getByText( 'The selected plugin has been deleted.' )
-						.waitFor();
-				}
-				await expect( page.getByLabel( 'Delete Google' ) ).toBeHidden();
-				await page.getByLabel( 'Deactivate Pinterest for' ).click();
-				await expect(
-					page.getByText( 'Plugin deactivated.' )
-				).toBeVisible();
-				// delete plugin regularly or, if attempted, accept deleting data as well
-				try {
-					await page.getByLabel( 'Delete Pinterest for' ).click();
-					await expect(
-						page.getByText( 'was successfully deleted.' )
-					).toBeVisible( { timeout: 5000 } );
-				} catch ( e ) {
-					await page
-						.getByText( 'Yes, delete these files and data' )
-						.click();
-					await page
-						.getByText( 'The selected plugin has been deleted.' )
-						.waitFor();
-				}
-				await expect(
-					page.getByLabel( 'Delete Pinterest for' )
-				).toBeHidden();
+				const deactivateAndDeletePlugin = async ( slug: string ) => {
+					await page.goto( 'wp-admin/plugins.php' );
+					const pluginRow = page.locator( `tr[data-slug="${ slug }"]` );
+
+					// Skip if plugin is not present
+					if ( ! ( await pluginRow.isVisible() ) ) {
+						return;
+					}
+
+					// Deactivate if active
+					const deactivateLink = pluginRow.getByRole( 'link', { name: 'Deactivate', exact: true } );
+					if ( await deactivateLink.isVisible() ) {
+						await deactivateLink.click();
+						await expect(
+							page.getByText( 'Plugin deactivated.' )
+						).toBeVisible();
+					}
+
+					// Delete plugin
+					const deleteLink = pluginRow.getByRole( 'link', { name: 'Delete', exact: true } );
+					if ( await deleteLink.isVisible() ) {
+						try {
+							await deleteLink.click();
+							await expect(
+								page.getByText( 'was successfully deleted.' )
+							).toBeVisible( { timeout: 5000 } );
+						} catch ( e ) {
+							await page
+								.getByText( 'Yes, delete these files and data' )
+								.click();
+							await page
+								.getByText( 'The selected plugin has been deleted.' )
+								.waitFor();
+						}
+					}
+				};
+
+				await deactivateAndDeletePlugin( 'google-listings-and-ads' );
+				await deactivateAndDeletePlugin( 'pinterest-for-woocommerce' );
 			} );

 			await test.step( 'Confirm that the store is in coming soon mode after completing the core profiler', async () => {
diff --git a/plugins/woocommerce/tests/e2e-pw/tests/onboarding/setup-checklist.spec.ts b/plugins/woocommerce/tests/e2e-pw/tests/onboarding/setup-checklist.spec.ts
index 0d4331f9ffa..a2b00ef2980 100644
--- a/plugins/woocommerce/tests/e2e-pw/tests/onboarding/setup-checklist.spec.ts
+++ b/plugins/woocommerce/tests/e2e-pw/tests/onboarding/setup-checklist.spec.ts
@@ -125,6 +125,7 @@ test( 'Can connect to WooCommerce.com', async ( { page } ) => {
 	await test.step( 'Go to the extensions tab and connect store', async () => {
 		const connectButton = page.getByRole( 'link', {
 			name: 'Connect',
+			exact: true,
 		} );

 		// Set up response waiter BEFORE navigation to avoid race condition
diff --git a/plugins/woocommerce/tests/e2e-pw/tests/product/product-reviews.spec.ts b/plugins/woocommerce/tests/e2e-pw/tests/product/product-reviews.spec.ts
index d36e8c9bcfb..7033901feeb 100644
--- a/plugins/woocommerce/tests/e2e-pw/tests/product/product-reviews.spec.ts
+++ b/plugins/woocommerce/tests/e2e-pw/tests/product/product-reviews.spec.ts
@@ -313,11 +313,16 @@ test.describe( 'Product Reviews', () => {
 			await reviewRow.hover();

 			await reviewRow.getByRole( 'button', { name: 'Trash' } ).click();
-			await expect(
-				page.locator( '.trash-undo-inside' ).first()
-			).toContainText(
-				`Comment by ${ review.reviewer } moved to the Trash`
-			);
+			// WordPress wptexturize may convert straight apostrophes (') to
+			// smart quotes (\u2019) in the reviewer name, so check for both.
+			const trashMessage = `Comment by ${ review.reviewer } moved to the Trash`;
+			const trashMessageSmart = trashMessage.replace( /'/g, '\u2019' );
+			const trashNotice = page.locator( '.trash-undo-inside' ).first();
+			const trashNoticeText = await trashNotice.textContent();
+			expect(
+				trashNoticeText?.includes( trashMessage ) ||
+				trashNoticeText?.includes( trashMessageSmart )
+			).toBeTruthy();
 			await page.getByRole( 'button', { name: 'Undo' } ).click();

 			await expect(
@@ -326,11 +331,12 @@ test.describe( 'Product Reviews', () => {

 			await reviewRow.getByRole( 'button', { name: 'Trash' } ).click();

-			await expect(
-				page.locator( '.trash-undo-inside' ).first()
-			).toContainText(
-				`Comment by ${ review.reviewer } moved to the Trash`
-			);
+			const trashNotice2 = page.locator( '.trash-undo-inside' ).first();
+			const trashNoticeText2 = await trashNotice2.textContent();
+			expect(
+				trashNoticeText2?.includes( trashMessage ) ||
+				trashNoticeText2?.includes( trashMessageSmart )
+			).toBeTruthy();

 			await page.click( 'a[href*="comment_status=trash"]' );