[tests] Cut linked products E2E from 4 titles to 2, moving relation clearing to PHPUnit - #68648
Open
vladolaru wants to merge 2 commits into
Open
[tests] Cut linked products E2E from 4 titles to 2, moving relation clearing to PHPUnit#68648vladolaru wants to merge 2 commits into
vladolaru wants to merge 2 commits into
Conversation
Draft
15 tasks
The linked products spec drove the classic editor four times: twice to attach an up-sell or a cross-sell and see it on the storefront, and twice to detach one and see it gone. Attaching is a browser journey worth keeping, because it runs through the select2 search control that only exists in the editor. Detaching is a persistence assertion wearing a browser costume: it posts an empty field and checks the front end stops rendering the relation. The two `remove` titles go. WC_Meta_Box_Product_Data_Linked_Products_Test takes that behavior through WC_Meta_Box_Product_Data::save(), asserting both that the cleared relation is persisted as empty and that woocommerce_upsell_display() and woocommerce_cross_sell_display() stop rendering their sections. Those are the functions the single-product and cart templates hook, so it is the same markup the browser titles looked at. What does not survive is the removal gesture itself. Nothing now drives the select2 control's backspace and checks that it posts a shorter array. The two retained titles exercise that same control in the opposite direction, which is good evidence but is not proof. `add up-sells` and `add cross-sells` stay byte-identical to the diff base. Three deliberate changes to the new PHPUnit file before landing: - Five fixture names carried the campaign's internal slice identifiers; they are renamed to neutral values. - The clearing test seeded the relations and then asserted they were empty, without ever checking that the seed had persisted. It would have passed just as happily against a seed that stored nothing. It now proves its own precondition first. - The cross-sell assertions moved off the rendered markup and onto the cart's own cross-sell list. The reason is below, because it is not a preference. The cross-sell markup could not be asserted here, and the first version of this file was wrong to try. woocommerce_cross_sell_display() begins `if ( is_checkout() ) return;`. is_checkout() is true whenever WOOCOMMERCE_CHECKOUT is defined, and tests/legacy/unit-tests/coupon/coupon.php defines it -- a plain PHP define, which cannot be undone for the rest of the process. phpunit.xml sets defaultTestSuite="wc-phpunit-legacy,wc-phpunit-main", so the legacy suite always runs first and that constant is always set by the time these tests run. So on CI the renderer emitted nothing here, every time. The positive test failed asserting that '' contains div class="cross-sells", on all four PHP/WP matrix jobs including HPOS:off. Worse, the clearing test's matching assertion -- that the section does *not* render -- passed vacuously for the same reason, and would have kept passing if cross-sells had rendered perfectly. Reproducing it needs two tests rather than the full suite: run the coupon test that defines the constant together with either of these and the failure appears. Under --testsuite=wc-phpunit-main alone, which excludes the legacy suite, both tests pass, which is why this was not caught locally before. WC()->cart->get_cross_sells() is the contract WC_Meta_Box_Product_Data actually feeds, and it is assertable regardless of checkout state. Both tests now assert it: exact IDs in submitted order, no upsell IDs crossing over, and the cart product not cross-selling itself. That is stronger than the string matching it replaces, and the clearing test now has an assertion that can fail. The up-sell markup assertions are untouched: woocommerce_upsell_display() has no such guard. This is the linked products half of a batch that also covered product images. The two shared no commit, helper or fixture, so they were split; the images half is a separate PR. Carries the mega-branch commit: - ff6181c test(e2e): Reduce linked products browser coverage Refs TESTOPS-288 Refs #68046 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
vladolaru
force-pushed
the
testops-288/linked-products
branch
from
September 12, 2026 23:58
9c0f6dc to
558c3d9
Compare
vladolaru
marked this pull request as ready for review
September 13, 2026 14:06
Contributor
|
Warning Review limit reachedNext included review available in 59 minutes. View limit detailsLimit details: You’ve used all 10 included reviews currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Review configuration: ⚙️ Run configurationConfiguration used: Path: .coderabbit.yml Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (3)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Submission Review Guidelines:
Changes proposed in this Pull Request:
The linked products spec drove the classic editor four times: twice to attach an up-sell or a cross-sell and see it on the storefront, and twice to detach one and see it gone. Attaching is a browser journey worth keeping, because it runs through the select2 search control that only exists in the editor. Detaching is a persistence assertion wearing a browser costume. The two
removetitles move down a layer.Refs TESTOPS-288
Part of the #68046 split.
Browser titles go from 4 to 2. The new
WC_Meta_Box_Product_Data_Linked_Products_Testadds 2 tests and 35 assertions.remove up-sellsWC_Meta_Box_Product_Data_Linked_Products_Test::test_save_clears_and_hides_linked_productsremove cross-sellsadd up-sellsandadd cross-sellsare byte-identical to the diff base.What the PHP test actually proves
It posts through
WC_Meta_Box_Product_Data::save()with both linked-product fields omitted, then asserts two things the browser titles asserted:wc_get_product(), thenget_upsell_ids( 'edit' )andget_cross_sell_ids( 'edit' ));woocommerce_upsell_display()stops emitting its section and no longer names the products. That is the function the single-product template hooks, so it is the same markup the browser looked at, rendered by the same code;WC()->cart->get_cross_sells()rather than on rendered markup. That is a correction to an earlier version of this pull request, and the reason is worth reading.Why the cross-sell assertions are not on markup
The first version of this file asserted the rendered cart cross-sell section, exactly as it asserts the up-sell one. That failed on CI on all four PHP/WP matrix jobs, including
HPOS:off, withFailed asserting that '' contains "div class="cross-sells"".The cause is not the fixtures and not this test.
woocommerce_cross_sell_display()opens withif ( is_checkout() ) { return; }.is_checkout()is true wheneverWOOCOMMERCE_CHECKOUTis defined, andtests/legacy/unit-tests/coupon/coupon.phpdefines it. A PHPdefinecannot be undone, andphpunit.xmlsetsdefaultTestSuite="wc-phpunit-legacy,wc-phpunit-main", so the legacy suite always runs first and that constant is always set by the time these tests run. The renderer therefore emits nothing here, every time.Two consequences, and the second is the worse one:
It reproduces in two tests rather than the full suite: run the coupon test that defines the constant alongside either of these. Under
--testsuite=wc-phpunit-mainalone, which excludes the legacy suite, both pass — which is why it was not caught before the PR opened.WC()->cart->get_cross_sells()is the contractWC_Meta_Box_Product_Dataactually feeds, and it is assertable whatever the checkout state. Both tests now assert it: the exact IDs in submitted order, no up-sell IDs crossing over, and the cart product not cross-selling itself. It is stricter than the string matching it replaces, and the clearing test now has an assertion that can fail.What is no longer proven anywhere
The removal gesture. The deleted titles backspaced a token out of the select2 control and relied on the editor posting a shorter array; the PHP test supplies
$_POSTitself. Nothing in either layer now proves that the control produces an emptyupsell_idsorcrosssell_idsfield when you clear it.The two retained titles drive that same control in the opposite direction, adding a relation and seeing it persist and render, so the control is not untested — but "adding works, therefore removing works" is an inference, not a proof, and this PR is the place to say so rather than leave it to be discovered later.
Two deliberate changes to the new PHPUnit file
It is otherwise exactly the migration branch's version.
Scope of the browser-coverage claim
These two titles are the only E2E coverage of the classic linked-products controls.
tests/e2e/tests/blocks/cart-block.shopper.block_theme.spec.tsseparately covers the Cross-Sells block, which is a different surface and is untouched here.Why this is only the linked-products half
This started as one batch covering product images and up-sells/cross-sells. The two shared no commit, helper or fixture, so the batch was split. The images half is a separate PR.
Screenshots or screen recordings:
Not applicable. Test-only change.
How to test the changes in this Pull Request:
pnpm install --frozen-lockfilefrom the repository root.pnpm --filter=@woocommerce/plugin-woocommerce env:test.plugins/woocommerce/tests/also containsWC_Meta_Box_Product_Data_POS_Visibility_Test, and PHPUnit's--filteris an unanchored substring regex, so a loose filter runs more than it claims:pnpm --filter=@woocommerce/plugin-woocommerce test:php:env -- --filter '/^WC_Meta_Box_Product_Data_Linked_Products_Test::/'. ExpectOK (2 tests, 28 assertions).pnpm --filter=@woocommerce/plugin-woocommerce env:e2e.pnpm --filter=@woocommerce/plugin-woocommerce test:e2e:with-env default --project=core-parallel --retries=0 --workers=1 tests/e2e/tests/product/product-linked-products.spec.ts. Both retained titles should pass. The summary reads4 passedand1 skipped: the 4 are the 2 product titles plus theglobal authenticationandsite setupprojects, and the skip isinstall wc, which skips itself whenINSTALL_WCis unset.plugins/woocommerce/includes/admin/meta-boxes/class-wc-meta-box-product-data.php, change the'cross_sell_ids'fallback from: array(),to: $product->get_cross_sell_ids(),. Re-run step 3 and expecttest_save_clears_and_hides_linked_productsto fail atAn omitted cross-sell field should clear every stored cross-sell ID., expecting an empty array and receiving the previous IDs. Revert.'upsell_ids'source from$_POST['upsell_ids']to$_POST['crosssell_ids']. Re-run step 3 and expecttest_save_persists_and_renders_distinct_linked_productsto fail atUpsell IDs should retain their exact submitted order.. Revert.plugins/woocommerce/includes/class-wc-cart.php, inget_cross_sells(), change$cross_sells = array_merge( $values['data']->get_cross_sell_ids(), $cross_sells );to$cross_sells = array_merge( array(), $cross_sells );. The stored relations stay correct and only what the cart offers is emptied. Re-run step 3 and expecttest_save_persists_and_renders_distinct_linked_productsto fail atThe cart should offer exactly the saved cross-sells, in their submitted order.. Revert.9c0f6dc04d, then run the target test together with the legacy coupon test that definesWOOCOMMERCE_CHECKOUT:pnpm --filter=@woocommerce/plugin-woocommerce test:php:env -- --filter '/(test_percent_discount_item_limit|test_save_persists_and_renders_distinct_linked_products)/'. Expect 2 tests, 1 failure,Failed asserting that '' contains "div class="cross-sells"". Run the same command on this branch and expectOK. Note there is no--testsuiteflag: adding--testsuite=wc-phpunit-mainexcludes the legacy suite and both versions pass, which is the trap.'upsell_ids'fallback from: array(),to: array( 0 ),and re-run step 5;add up-sellsshould fail when the storefront does not list the product it just attached. Revert.Testing that has already taken place:
Everything below ran on this branch against a local WordPress, with retries disabled and one worker. Trunk was at
adefb5f971.--retries=0 --workers=1.WC_Meta_Box_Product_Data_Linked_Products_TestOK (2 tests, 28 assertions) under the anchored filter, and OK (3 tests, 29 assertions) when run together with the legacy coupon test that definesWOOCOMMERCE_CHECKOUT— the condition that used to fail. Before the fix that same pair of tests reported 1 failure. The assertion count fell from 35 because exact ID comparisons replaced several string matches, not because anything stopped being checked.Upsell IDs should retain their exact submitted order., and making the cross-sell field preserve its previous value when omitted turns the clearing test red atAn omitted cross-sell field should clear every stored cross-sell ID.. Each reverted cleanly and went green again. The second is the one that matters here: it is the direct evidence that the method absorbing the two removed titles really detects a failure to clear. Both were re-run with the legacy coupon test in the same process, so they are proven under the condition that broke this batch rather than only in a clean one.$values['data']->get_cross_sell_ids()witharray()inWC_Cart::get_cross_sells()leaves the stored relations correct but empties what the cart offers; the positive test then fails atThe cart should offer exactly the saved cross-sells, in their submitted order.and goes green on revert. That is what shows the replacement assertion carries weight rather than merely passing.lint:changes:branchexits 0. ESLint reports 1 warning on this branch's copy of the spec and 1 on trunk's — no delta, no errors.oxlintattributes no new finding to the change.phpstan.neonscopes towoocommerce.php,src/andincludes/; this batch's only PHP file is a test.Milestone
Changelog entry
Changelog Entry Details
Significance
Type
Message
Changelog Entry Comment
Comment
Created manually:
plugins/woocommerce/changelog/testops-288-linked-products.Use of AI Tools
The migration was produced by an agent-run campaign with per-test mutation verification (see #68046). This PR was assembled, verified in isolation, and reviewed by an agent; the author reviewed the diff and takes responsibility for it.
🤖 Generated with Claude Code