Commit 09de43c8fe7 for woocommerce

commit 09de43c8fe72d9ee9f486a4818e9f4fa56da6d1d
Author: Chris Lilitsas <1105590+xristos3490@users.noreply.github.com>
Date:   Tue Sep 15 12:59:09 2026 +0300

    Enable BIS feature flag per E2E spec instead of env-wide (#68515)

    * test: enable BIS feature flag per-spec instead of env-wide

    Claude-Session: https://claude.ai/code/session_01SxaGdqtPcuodXdnRAKWvki

    * test: always reset BIS feature flag in afterAll, clarify README

    * test: drop unjustified @services tag from BIS E2E specs

    * test: skip BIS E2E specs on external envs, assert pages load when disabled

    * fix: write the correct BIS allow-signups option on new installs

    * test: match BIS product heading exactly to skip the review heading

diff --git a/plugins/woocommerce/changelog/68515-fix-bis-new-install-allow-signups b/plugins/woocommerce/changelog/68515-fix-bis-new-install-allow-signups
new file mode 100644
index 00000000000..8d552d45d6d
--- /dev/null
+++ b/plugins/woocommerce/changelog/68515-fix-bis-new-install-allow-signups
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Enable Back in Stock Notifications sign-ups by default on new installs, as intended, instead of leaving the sign-up form off because the install hook wrote the wrong option name.
diff --git a/plugins/woocommerce/includes/class-wc-install.php b/plugins/woocommerce/includes/class-wc-install.php
index 282df2aff49..321be754747 100644
--- a/plugins/woocommerce/includes/class-wc-install.php
+++ b/plugins/woocommerce/includes/class-wc-install.php
@@ -1340,7 +1340,7 @@ class WC_Install {
 	 * @return void
 	 */
 	public static function enable_customer_stock_notifications_signups() {
-		update_option( 'woocommerce_back_in_stock_allow_signups', 'yes' );
+		update_option( 'woocommerce_customer_stock_notifications_allow_signups', 'yes' );
 	}

 	/**
diff --git a/plugins/woocommerce/tests/e2e/bin/test-env-setup.sh b/plugins/woocommerce/tests/e2e/bin/test-env-setup.sh
index b3fd7811e72..d0774115b3f 100755
--- a/plugins/woocommerce/tests/e2e/bin/test-env-setup.sh
+++ b/plugins/woocommerce/tests/e2e/bin/test-env-setup.sh
@@ -50,9 +50,6 @@ if ! $WP_CLI_PREFIX wp user get customer --field=ID >/dev/null 2>&1; then
 		--user_registered='2022-01-01 12:23:45'
 fi

-echo -e 'Enable Back in Stock Notifications feature \n'
-$WP_CLI_PREFIX wp option update woocommerce_feature_customer_stock_notifications_enabled 'yes'
-
 echo -e 'Update Blog Name \n'
 $WP_CLI_PREFIX wp option update blogname 'WooCommerce Core E2E Test Suite'

diff --git a/plugins/woocommerce/tests/e2e/tests/back-in-stock-notifications/README.md b/plugins/woocommerce/tests/e2e/tests/back-in-stock-notifications/README.md
index 720a9f09aa3..89fa56f9117 100644
--- a/plugins/woocommerce/tests/e2e/tests/back-in-stock-notifications/README.md
+++ b/plugins/woocommerce/tests/e2e/tests/back-in-stock-notifications/README.md
@@ -20,6 +20,8 @@ Covers the scenarios from the original plugin test plan that have a target in co
   emails, the back-in-stock email linking back to a fixed-value variation
   pre-selected, and the parent-level signup opt-out removing the form from the
   whole variable product page.
+- `feature-disabled.spec.ts` — with the feature flag off: no signup form on an
+  out-of-stock PDP, no "Customer stock notifications" settings section.

 ## Variation notes

@@ -86,10 +88,13 @@ respective feature tickets:
 ## Prerequisites

 - BIS is gated by the `customer_stock_notifications` feature toggle (WooCommerce
-  → Settings → Advanced → Features → Experimental), enabled for the tests env
-  via `plugins/woocommerce/tests/e2e/bin/test-env-setup.sh`. If you bring
-  the env up manually, set `woocommerce_feature_customer_stock_notifications_enabled`
-  to `'yes'`.
+  → Settings → Advanced → Features → Experimental), off by default. Each spec
+  file sets it explicitly in a top-level `beforeAll` (`'yes'` for the enabled
+  suites, `'no'` for `feature-disabled.spec.ts`), and the enabled suites reset
+  it to `'no'` in `afterAll`, through `setOption()` (never `deleteOption()` —
+  that skips the `updated_option` hook the feature's teardown relies on). That
+  toggling is safe only because these specs run serially, single worker — see
+  below.
 - The tests assume the WP Mail Logging plugin is installed and active (it is,
   via the `.wp-env.e2e.json` plugins list).
 - `woocommerce-e2e-test-helper` zeroes
diff --git a/plugins/woocommerce/tests/e2e/tests/back-in-stock-notifications/feature-disabled.spec.ts b/plugins/woocommerce/tests/e2e/tests/back-in-stock-notifications/feature-disabled.spec.ts
new file mode 100644
index 00000000000..d64e2befe36
--- /dev/null
+++ b/plugins/woocommerce/tests/e2e/tests/back-in-stock-notifications/feature-disabled.spec.ts
@@ -0,0 +1,61 @@
+/**
+ * Internal dependencies
+ */
+import { expect, request, tags } from '../../fixtures/fixtures';
+import { ADMIN_STATE_PATH } from '../../playwright.config';
+import {
+	BIS_FEATURE_OPTION,
+	bisFormLocator,
+	test,
+} from '../../utils/back-in-stock-notifications';
+import { setOption } from '../../utils/options';
+
+test.describe(
+	'Back in Stock Notifications — feature disabled',
+	{ tag: [ tags.SKIP_ON_EXTERNAL_ENV ] },
+	() => {
+		test.beforeAll( async ( { baseURL } ) => {
+			await setOption( request, baseURL!, BIS_FEATURE_OPTION, 'no' );
+		} );
+
+		test( 'no signup form on an out-of-stock product page', async ( {
+			page,
+			product,
+		} ) => {
+			await page.goto( product.permalink );
+
+			// Prove the product page rendered before asserting the form is absent.
+			await expect(
+				page.getByRole( 'heading', {
+					name: product.name,
+					exact: true,
+				} )
+			).toBeVisible();
+			await expect( bisFormLocator( page ) ).toHaveCount( 0 );
+		} );
+
+		test.describe( 'admin settings', () => {
+			test.use( { storageState: ADMIN_STATE_PATH } );
+
+			test( 'no Customer stock notifications settings section', async ( {
+				page,
+			} ) => {
+				await page.goto(
+					'wp-admin/admin.php?page=wc-settings&tab=products'
+				);
+
+				// Prove the Products settings page rendered before asserting the
+				// section link is absent: "Inventory" lives in the same section nav.
+				await expect(
+					page.getByRole( 'link', { name: 'Inventory' } )
+				).toBeVisible();
+
+				await expect(
+					page.getByRole( 'link', {
+						name: 'Customer stock notifications',
+					} )
+				).toHaveCount( 0 );
+			} );
+		} );
+	}
+);
diff --git a/plugins/woocommerce/tests/e2e/tests/back-in-stock-notifications/managing-notifications.spec.ts b/plugins/woocommerce/tests/e2e/tests/back-in-stock-notifications/managing-notifications.spec.ts
index 6202e9b1c11..15387b69f88 100644
--- a/plugins/woocommerce/tests/e2e/tests/back-in-stock-notifications/managing-notifications.spec.ts
+++ b/plugins/woocommerce/tests/e2e/tests/back-in-stock-notifications/managing-notifications.spec.ts
@@ -9,6 +9,7 @@ import type { Page } from '@playwright/test';
 import { expect, request, tags } from '../../fixtures/fixtures';
 import { ADMIN_STATE_PATH } from '../../playwright.config';
 import {
+	BIS_FEATURE_OPTION,
 	bisAdminListUrl,
 	bisEmailSubject,
 	resetBISOptions,
@@ -18,6 +19,7 @@ import {
 	uniqueGuestEmail,
 } from '../../utils/back-in-stock-notifications';
 import { expectEmail } from '../../utils/email';
+import { setOption } from '../../utils/options';

 /**
  * Click the notification edit-form "Update" button.
@@ -36,12 +38,20 @@ async function submitNotificationEditForm( page: Page ): Promise< void > {

 test.describe(
 	'Back in Stock Notifications — admin management',
-	{ tag: [ tags.SERVICES ] },
+	{ tag: [ tags.SKIP_ON_EXTERNAL_ENV ] },
 	() => {
 		test.use( { storageState: ADMIN_STATE_PATH } );

+		test.beforeAll( async ( { baseURL } ) => {
+			await setOption( request, baseURL!, BIS_FEATURE_OPTION, 'yes' );
+		} );
+
 		test.afterAll( async ( { baseURL } ) => {
-			await resetBISOptions( request, baseURL! );
+			try {
+				await resetBISOptions( request, baseURL! );
+			} finally {
+				await setOption( request, baseURL!, BIS_FEATURE_OPTION, 'no' );
+			}
 		} );

 		// Grouped by opt-in mode rather than flipping the option inside a test:
diff --git a/plugins/woocommerce/tests/e2e/tests/back-in-stock-notifications/my-account.spec.ts b/plugins/woocommerce/tests/e2e/tests/back-in-stock-notifications/my-account.spec.ts
index ab179f9c7d3..ee4cf2edd4f 100644
--- a/plugins/woocommerce/tests/e2e/tests/back-in-stock-notifications/my-account.spec.ts
+++ b/plugins/woocommerce/tests/e2e/tests/back-in-stock-notifications/my-account.spec.ts
@@ -8,6 +8,7 @@ import { WC_API_PATH } from '@woocommerce/e2e-utils-playwright';
  */
 import { expect, request, tags } from '../../fixtures/fixtures';
 import {
+	BIS_FEATURE_OPTION,
 	createOutOfStockProduct,
 	resetBISOptions,
 	setBISOptions,
@@ -15,6 +16,7 @@ import {
 	test,
 } from '../../utils/back-in-stock-notifications';
 import { logInFromMyAccount } from '../../utils/login';
+import { setOption } from '../../utils/options';

 const MY_ACCOUNT_ENDPOINT = 'my-account/stock-notifications/';
 const TABLE = '.woocommerce-customer-stock-notifications-table';
@@ -58,10 +60,18 @@ async function createTestCustomer( restApi ): Promise< TestCustomer > {

 test.describe(
 	'Back in Stock Notifications — My Account',
-	{ tag: [ tags.SERVICES ] },
+	{ tag: [ tags.SKIP_ON_EXTERNAL_ENV ] },
 	() => {
+		test.beforeAll( async ( { baseURL } ) => {
+			await setOption( request, baseURL!, BIS_FEATURE_OPTION, 'yes' );
+		} );
+
 		test.afterAll( async ( { baseURL } ) => {
-			await resetBISOptions( request, baseURL! );
+			try {
+				await resetBISOptions( request, baseURL! );
+			} finally {
+				await setOption( request, baseURL!, BIS_FEATURE_OPTION, 'no' );
+			}
 		} );

 		test.describe( 'Logged-in customer with signups', () => {
diff --git a/plugins/woocommerce/tests/e2e/tests/back-in-stock-notifications/receiving-confirmations.spec.ts b/plugins/woocommerce/tests/e2e/tests/back-in-stock-notifications/receiving-confirmations.spec.ts
index 71d858f3cb9..b71dd43740a 100644
--- a/plugins/woocommerce/tests/e2e/tests/back-in-stock-notifications/receiving-confirmations.spec.ts
+++ b/plugins/woocommerce/tests/e2e/tests/back-in-stock-notifications/receiving-confirmations.spec.ts
@@ -7,6 +7,7 @@ import { customer } from '../../test-data/data';
 import {
 	BIS_EMAIL_FOOTER,
 	BIS_EMAIL_LINKS,
+	BIS_FEATURE_OPTION,
 	bisAdminListUrl,
 	bisEmailBody,
 	bisEmailSubject,
@@ -24,14 +25,16 @@ import {
 } from '../../utils/back-in-stock-notifications';
 import { expectEmail, expectEmailContent } from '../../utils/email';
 import { clearFilters } from '../../utils/filters';
+import { setOption } from '../../utils/options';

 test.describe(
 	'Back in Stock Notifications — receiving confirmations',
-	{ tag: [ tags.SERVICES ] },
+	{ tag: [ tags.SKIP_ON_EXTERNAL_ENV ] },
 	() => {
 		test.use( { storageState: ADMIN_STATE_PATH } );

 		test.beforeAll( async ( { baseURL } ) => {
+			await setOption( request, baseURL!, BIS_FEATURE_OPTION, 'yes' );
 			await setBISOptions( request, baseURL!, {
 				allowSignups: true,
 				doubleOptIn: true,
@@ -41,7 +44,11 @@ test.describe(
 		} );

 		test.afterAll( async ( { baseURL } ) => {
-			await resetBISOptions( request, baseURL! );
+			try {
+				await resetBISOptions( request, baseURL! );
+			} finally {
+				await setOption( request, baseURL!, BIS_FEATURE_OPTION, 'no' );
+			}
 		} );

 		test( 'double-opt-in signup dispatches verify email with UTM params', async ( {
diff --git a/plugins/woocommerce/tests/e2e/tests/back-in-stock-notifications/receiving-notifications.spec.ts b/plugins/woocommerce/tests/e2e/tests/back-in-stock-notifications/receiving-notifications.spec.ts
index 4d6a5bccaab..93a150238e9 100644
--- a/plugins/woocommerce/tests/e2e/tests/back-in-stock-notifications/receiving-notifications.spec.ts
+++ b/plugins/woocommerce/tests/e2e/tests/back-in-stock-notifications/receiving-notifications.spec.ts
@@ -7,6 +7,7 @@ import { customer } from '../../test-data/data';
 import {
 	BIS_EMAIL_FOOTER,
 	BIS_EMAIL_LINKS,
+	BIS_FEATURE_OPTION,
 	bisAdminListUrl,
 	bisEmailBody,
 	bisEmailSubject,
@@ -24,14 +25,16 @@ import {
 	uniqueGuestEmail,
 } from '../../utils/back-in-stock-notifications';
 import { expectEmail } from '../../utils/email';
+import { setOption } from '../../utils/options';

 test.describe(
 	'Back in Stock Notifications — receiving back-in-stock emails',
-	{ tag: [ tags.SERVICES ] },
+	{ tag: [ tags.SKIP_ON_EXTERNAL_ENV ] },
 	() => {
 		test.use( { storageState: ADMIN_STATE_PATH } );

 		test.beforeAll( async ( { baseURL } ) => {
+			await setOption( request, baseURL!, BIS_FEATURE_OPTION, 'yes' );
 			// Single opt-in so the notification becomes ACTIVE immediately
 			// (no verify step), which is what the back-in-stock dispatch needs.
 			await setBISOptions( request, baseURL!, {
@@ -43,7 +46,11 @@ test.describe(
 		} );

 		test.afterAll( async ( { baseURL } ) => {
-			await resetBISOptions( request, baseURL! );
+			try {
+				await resetBISOptions( request, baseURL! );
+			} finally {
+				await setOption( request, baseURL!, BIS_FEATURE_OPTION, 'no' );
+			}
 		} );

 		test( 'restocking a product dispatches the back-in-stock email with UTM params', async ( {
diff --git a/plugins/woocommerce/tests/e2e/tests/back-in-stock-notifications/signing-up.spec.ts b/plugins/woocommerce/tests/e2e/tests/back-in-stock-notifications/signing-up.spec.ts
index b4d508a4577..2b999f02add 100644
--- a/plugins/woocommerce/tests/e2e/tests/back-in-stock-notifications/signing-up.spec.ts
+++ b/plugins/woocommerce/tests/e2e/tests/back-in-stock-notifications/signing-up.spec.ts
@@ -5,6 +5,7 @@ import { expect, request, tags } from '../../fixtures/fixtures';
 import { CUSTOMER_STATE_PATH } from '../../playwright.config';
 import { customer } from '../../test-data/data';
 import {
+	BIS_FEATURE_OPTION,
 	bisConsentCheckbox,
 	bisEmailSubject,
 	bisFormLocator,
@@ -20,13 +21,22 @@ import {
 	uniqueGuestEmail,
 } from '../../utils/back-in-stock-notifications';
 import { clearFilters, setFilterValue } from '../../utils/filters';
+import { setOption } from '../../utils/options';

 test.describe(
 	'Back in Stock Notifications — signing up',
-	{ tag: [ tags.SERVICES ] },
+	{ tag: [ tags.SKIP_ON_EXTERNAL_ENV ] },
 	() => {
+		test.beforeAll( async ( { baseURL } ) => {
+			await setOption( request, baseURL!, BIS_FEATURE_OPTION, 'yes' );
+		} );
+
 		test.afterAll( async ( { baseURL } ) => {
-			await resetBISOptions( request, baseURL! );
+			try {
+				await resetBISOptions( request, baseURL! );
+			} finally {
+				await setOption( request, baseURL!, BIS_FEATURE_OPTION, 'no' );
+			}
 		} );

 		test.describe( 'Signups disabled', () => {
diff --git a/plugins/woocommerce/tests/e2e/tests/back-in-stock-notifications/variations.spec.ts b/plugins/woocommerce/tests/e2e/tests/back-in-stock-notifications/variations.spec.ts
index 7fd00509c33..f3171ff0e92 100644
--- a/plugins/woocommerce/tests/e2e/tests/back-in-stock-notifications/variations.spec.ts
+++ b/plugins/woocommerce/tests/e2e/tests/back-in-stock-notifications/variations.spec.ts
@@ -6,6 +6,7 @@ import { ADMIN_STATE_PATH } from '../../playwright.config';
 import {
 	BIS_EMAIL_ELEMENTS,
 	BIS_EMAIL_LINKS,
+	BIS_FEATURE_OPTION,
 	bisEmailBody,
 	bisEmailSubject,
 	bisFormLocator,
@@ -24,15 +25,24 @@ import {
 	triggerStockNotificationsBatch,
 	uniqueGuestEmail,
 } from '../../utils/back-in-stock-notifications';
+import { setOption } from '../../utils/options';

 test.describe(
 	'Back in Stock Notifications — variable products and variations',
-	{ tag: [ tags.SERVICES ] },
+	{ tag: [ tags.SKIP_ON_EXTERNAL_ENV ] },
 	() => {
 		test.use( { storageState: ADMIN_STATE_PATH } );

+		test.beforeAll( async ( { baseURL } ) => {
+			await setOption( request, baseURL!, BIS_FEATURE_OPTION, 'yes' );
+		} );
+
 		test.afterAll( async ( { baseURL } ) => {
-			await resetBISOptions( request, baseURL! );
+			try {
+				await resetBISOptions( request, baseURL! );
+			} finally {
+				await setOption( request, baseURL!, BIS_FEATURE_OPTION, 'no' );
+			}
 		} );

 		test.describe( 'Single opt-in', () => {
diff --git a/plugins/woocommerce/tests/e2e/utils/back-in-stock-notifications.ts b/plugins/woocommerce/tests/e2e/utils/back-in-stock-notifications.ts
index 1b0d395f796..5bfffea5592 100644
--- a/plugins/woocommerce/tests/e2e/utils/back-in-stock-notifications.ts
+++ b/plugins/woocommerce/tests/e2e/utils/back-in-stock-notifications.ts
@@ -44,19 +44,13 @@ export const BIS_FEATURE_OPTION =
 /**
  * Fail early, with the fix, when the env can't run these specs.
  *
- * Both are provisioned by `bin/test-env-setup.sh`, which only runs on env
- * create or `--update`. On a stale env the feature UI simply never renders and
- * notification batches keep their one-minute delay, so every spec fails as an
- * unexplained timeout.
+ * Provisioned by `bin/test-env-setup.sh`, which only runs on env create or
+ * `--update`. On a stale env the notification batches keep their one-minute
+ * delay, so every spec fails as an unexplained timeout.
  */
 export async function assertBISEnvReady(): Promise< void > {
 	// wp-env prefixes its own lines onto stdout, so match rather than compare.
 	const checks = [
-		{
-			command: `wp option get ${ BIS_FEATURE_OPTION }`,
-			expected: /^yes$/m,
-			problem: `the "${ BIS_FEATURE_OPTION }" feature flag is not enabled, so none of the Back in Stock Notifications UI renders`,
-		},
 		{
 			command: 'wp plugin list --status=active --field=name',
 			expected: /^woocommerce-e2e-test-helper$/m,