Commit 155b34e73b7 for woocommerce
commit 155b34e73b7278292f3657b1c3ad596b0d50f633
Author: Vlad Olaru <vlad.olaru@automattic.com>
Date: Tue Sep 15 19:42:40 2026 +0300
[tests] Demote the product archive title fallback test to PHPUnit (#68642)
* test(shop): Move the product archive title fallback below E2E
One browser test covered the Shop page title after the page is
deleted, added with #46429. It trashed the Shop page through the REST
API, loaded shop/, and asserted the document title, which reads Shop
followed by the site name.
wc_update_product_archive_title() reads the configured Shop page's
title and falls back to "Shop" only when that title is empty. A
trashed page is still a post, and get_the_title() still returns
"Shop" for it - measured, not assumed. So the removed test returned
through the first branch and never reached the fallback, and could
not have told the two apart, because both emit "Shop".
wc-template-functions-test.php gains
test_product_archive_title_falls_back_to_shop_when_shop_page_is_missing,
which hard-deletes the page so the title really is empty, asserts
the filter is registered at priority 10, and asserts the filter
returns "Shop". That covers the branch the browser test never
reached.
Three things the removed test did uniquely are not replaced, and are
listed in the pull request rather than implied away. The one worth
weighing is that shop/ still resolves while the page is trashed.
WooCommerce protects that on purpose:
queue_rewrite_rules_on_shop_page_save() skips queuing a rewrite flush
when the saved status is trash (#65967). Drop that guard and trashing
queues a flush, the archive re-registers under the renamed shop__trashed
URI, and shop/ 404s - and the removed spec, which trashed the page and
immediately loaded shop/, was the only thing that would have gone red.
The filter's wiring keeps browser coverage:
blocks/templates/shop-page.block_theme.spec.ts asserts the level-1
"Shop" heading on shop/, which resolves through the same filter.
wc-template-functions-test.php is taken from trunk with only this
batch's own method applied. Trunk added a regression test to it for
#68567 after the migration branch was cut, and a whole-file checkout
would have deleted that.
The spec's entry in serialRunSpecs goes with it. Leaving it would
point the config at a file that no longer exists, and the migration
branch's own commit removes those three lines.
Consolidates one mega-branch commit, subject verbatim:
- test(shop): Move title fallback below E2E
Refs TESTOPS-288
Refs #68046
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* test(php): Drop the redundant teardown from the archive title test
The transaction rollback already covers the `woocommerce_shop_page_id`
option and the page the test creates, and
`WP_UnitTestCase_Base::tear_down()` replaces `$wp_query` and
`$wp_the_query` with a fresh `WP_Query` before the next test runs. The
try/finally restored all four by hand and the post a second time.
Refs TESTOPS-288
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
diff --git a/plugins/woocommerce/changelog/testops-288-shop-title-fallback b/plugins/woocommerce/changelog/testops-288-shop-title-fallback
new file mode 100644
index 00000000000..340f604921f
--- /dev/null
+++ b/plugins/woocommerce/changelog/testops-288-shop-title-fallback
@@ -0,0 +1,4 @@
+Significance: patch
+Type: dev
+Comment: Move the product archive title fallback check from E2E to PHPUnit.
+
diff --git a/plugins/woocommerce/tests/e2e/playwright.config.ts b/plugins/woocommerce/tests/e2e/playwright.config.ts
index ae0a5bec63e..9e3a243d3a4 100644
--- a/plugins/woocommerce/tests/e2e/playwright.config.ts
+++ b/plugins/woocommerce/tests/e2e/playwright.config.ts
@@ -189,9 +189,6 @@ const serialRunSpecs = [
// Toggles the global `woocommerce_cart_redirect_after_add` setting, which
// changes add-to-cart behavior for every other worker — not parallel-safe.
'**/tests/shop/cart-redirection.spec.ts',
- // Trashes and restores the global Shop page in a fixture; while trashed, every
- // other worker's shop/cart/account navigation 404s.
- '**/tests/shop/shop-title-after-deletion.spec.ts',
];
/**
diff --git a/plugins/woocommerce/tests/e2e/tests/shop/shop-title-after-deletion.spec.ts b/plugins/woocommerce/tests/e2e/tests/shop/shop-title-after-deletion.spec.ts
deleted file mode 100644
index 79374b1e27b..00000000000
--- a/plugins/woocommerce/tests/e2e/tests/shop/shop-title-after-deletion.spec.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-/**
- * External dependencies
- */
-import { WP_API_PATH } from '@woocommerce/e2e-utils-playwright';
-
-/**
- * Internal dependencies
- */
-import { test as baseTest, expect, tags } from '../../fixtures/fixtures';
-import { ADMIN_STATE_PATH } from '../../playwright.config';
-
-// test case for bug https://github.com/woocommerce/woocommerce/pull/46429
-const test = baseTest.extend( {
- storageState: ADMIN_STATE_PATH,
- page: async ( { page, restApi }, use ) => {
- const response = await restApi.get(
- `${ WP_API_PATH }/pages?slug=shop`,
- {
- data: {
- _fields: [ 'id' ],
- },
- }
- );
-
- const pages = await response.data;
- const pageId = pages[ 0 ].id;
-
- await restApi.delete( `${ WP_API_PATH }/pages/${ pageId }`, {
- data: {
- force: false,
- },
- } );
-
- await use( page );
-
- await restApi.post( `${ WP_API_PATH }/pages/${ pageId }`, {
- data: {
- status: 'publish',
- },
- } );
- },
-} );
-
-test(
- 'Check the title of the shop page after the page has been deleted',
- { tag: [ tags.COULD_BE_LOWER_LEVEL_TEST ] },
- async ( { page } ) => {
- await page.goto( 'shop/' );
- expect( await page.title() ).toBe(
- 'Shop – WooCommerce Core E2E Test Suite'
- );
- }
-);
diff --git a/plugins/woocommerce/tests/php/includes/wc-template-functions-test.php b/plugins/woocommerce/tests/php/includes/wc-template-functions-test.php
index 10ebdb9cb50..9f5a670e688 100644
--- a/plugins/woocommerce/tests/php/includes/wc-template-functions-test.php
+++ b/plugins/woocommerce/tests/php/includes/wc-template-functions-test.php
@@ -84,6 +84,43 @@ class WC_Template_Functions_Tests extends \WC_Unit_Test_Case {
wp_cache_flush();
}
+ /**
+ * @testdox Product archive titles fall back to Shop when the configured Shop page is missing.
+ */
+ public function test_product_archive_title_falls_back_to_shop_when_shop_page_is_missing(): void {
+ global $wp_query, $wp_the_query;
+
+ // Nothing is restored by hand. The transaction rollback covers the option
+ // and the page, and `WP_UnitTestCase_Base::tear_down()` replaces both
+ // query globals with a fresh `WP_Query` before the next test runs.
+ $shop_page_id = self::factory()->post->create(
+ array(
+ 'post_type' => 'page',
+ 'post_status' => 'publish',
+ 'post_title' => 'Retired catalog',
+ )
+ );
+ update_option( 'woocommerce_shop_page_id', $shop_page_id );
+ wp_delete_post( $shop_page_id, true );
+
+ $query = new WP_Query( array( 'post_type' => 'product' ) );
+ $query->is_post_type_archive = true;
+ $query->is_archive = true;
+ $query->is_tax = false;
+ $query->is_home = false;
+ $wp_query = $query; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
+ $wp_the_query = $query; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
+
+ $this->assertTrue( is_shop(), 'The query must represent the product archive.' );
+ $this->assertSame( '', get_the_title( $shop_page_id ), 'The configured Shop page must be missing.' );
+ $this->assertSame( 10, has_filter( 'post_type_archive_title', 'wc_update_product_archive_title' ) );
+
+ // phpcs:ignore WooCommerce.Commenting.CommentHooks.MissingHookComment -- WordPress core owns this hook; the test exercises WooCommerce's registered callback.
+ $title = apply_filters( 'post_type_archive_title', 'Products', 'product' );
+
+ $this->assertSame( __( 'Shop', 'woocommerce' ), $title );
+ }
+
/**
* @testdox woocommerce_get_product_subcategories caches results under the expected key.
*/