feat(pro): buy-box pricing section — feature list once, term choice as radio rows#195
Conversation
…rows Implements the winning prototype (PR #194 variant H). The /pro pricing section becomes a product page: the Pro feature list renders once (icons + descriptions from pro.features messages) beside a sticky buy box where yearly vs lifetime is price + term facts only — the feature checklist never repeats per plan. Static-first: the page is now partially prerendered — hero, features and FAQ are static HTML; only the buy box suspends (Medusa prices + checkout experiment from cookies). Buy box keeps the pro_checkout_v1 experiment (CTA label + exp params) and the click_start_checkout event, and adds trust facts sourced from live pages: 14-day refund (linked to /refunds), never-auto-renews, yearly-credits-toward-lifetime, 5,000+ stores. PricingCard and its test are deleted (only consumer was this page). The old standalone features section is subsumed by the new layout.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (19)
✅ Files skipped from review due to trivial changes (4)
🚧 Files skipped from review as they are similar to previous changes (13)
📝 WalkthroughWalkthroughThe Pro page now renders a localized buy box with yearly and lifetime options, static feature rows, and updated checkout tracking. The offer catalog shape is simplified, tests were updated for the new flow, and locale files add buy-box copy. ChangesPro Buy Box Feature
Estimated code review effort: 4 (Complex) | ~45 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
Greptile SummaryReplaces the two-card pricing layout with a single "buy box" — a sticky radio-row term selector beside a unified feature list — and moves
Confidence Score: 4/5Safe to merge; the page restructure is well-tested and the static/dynamic split is correctly implemented. The buy-box copy (plan titles, subtitles, CTA notes) is hard-coded English while everything else on the page flows through next-intl, which is an inconsistency on a locale-routed page. The custom radio group also sets role="radio" on button elements without the expected arrow-key keyboard navigation, which diverges from the ARIA radiogroup spec. Neither issue breaks the page for English-language users, but both are worth resolving before expanding to additional locales or auditing for accessibility. src/app/[locale]/(main)/pro/page.tsx (BUY_BOX_COPY), src/components/pro/pro-buy-box.tsx (radiogroup keyboard handling) Important Files Changed
Reviews (1): Last reviewed commit: "feat(pro): buy-box pricing — feature lis..." | Re-trigger Greptile |
|
🚀 Preview: https://wcpos-710lj0hdm-wcpos.vercel.app |
|
Triage before fixes (fresh unresolved review-thread inventory):
Skipped threads: none. CI scope: no failing checks at inventory time; Deploy Preview is still in progress. |
|
Round 3 triage before fixes (fresh unresolved review-thread inventory):
Skipped threads: none. CI scope: |
There was a problem hiding this comment.
kilbot has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.
|
Post-fix triage (fresh unresolved review-thread inventory after push/resolve: 0):
Skipped threads: none. Validation:
CI scope: checks are currently running on pushed head |
|
🚀 Preview: https://wcpos-6x8pdghcd-wcpos.vercel.app |
Review of PR #195 (8 finder angles + adversarial verification) surfaced 9 findings; this applies them: - a11y (CONFIRMED): real radio keyboard model — roving tabindex plus arrow-key navigation with wrap-around and focus tracking. - stale-selection crash (PLAUSIBLE): current falls back to options[0] when a revalidated payload drops the selected plan. - price-ratio copy (CONFIRMED): 'About N years of Yearly' is now derived from live catalog prices (with a ratio-free fallback), never hardcoded. - split-brain plan copy (CONFIRMED): OFFER_COPY shrinks to schema.org names; ProOffer drops the six orphaned presentation fields; buy-box copy moves to the pro.buyBox message namespace (keys in all 10 locales, matching the pro.* convention). - i18n (CONFIRMED): every buy-box string (incl. the radiogroup aria-label and the unavailable state) now routes through messages. - primitives (CONFIRMED): Card(elevated) for box/skeleton/fallback, EmptyState for the unavailable state, TextLink for the refunds link, SectionHeading(align=left) for the features heading. - redundant experiment channel (PLAUSIBLE): analytics eventProperties are built server-side next to the checkout href in a new pure buildProBuyBoxOptions; the client component no longer knows about experiments. - coverage gap (CONFIRMED): buildProBuyBoxOptions unit tests cover the offers→options mapping, years derivation, and experiment wiring; buy-box tests add keyboard-model and stale-selection cases. - catalog cache is now keyed by the catalog alone (one entry shared by buy box + JSON-LD instead of one per experiment variant). Remaining CONFIRMED finding (pre-existing on main, out of scope): transient Medusa failures cache the unavailable fallback for ~15-60min.
|
Post-creation review complete (8 finder angles → adversarial verification → fixes applied in the latest commit): Confirmed & fixed:
Confirmed, pre-existing, deferred (identical on main): a transient Medusa outage at revalidation caches the "pricing unavailable" fallback for ~15–60 min ( Refuted in verification (for the record): pre-hydration wrong-plan CTA (selection UI and href freeze together; React replays the click); integration-spec CTA label mismatch (variant resolution is consent-gated — deterministic Note: the bot's through-the-page buy-box test was superseded by direct Validation after fixes: tsc/eslint clean, 916 unit tests (135 files), production build |
There was a problem hiding this comment.
kilbot has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/app/[locale]/(main)/pro/page.tsx (2)
101-110: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winFallback "unavailable" copy isn't translated.
tis already in scope inBuyBoxSection, but the empty-offers fallback text ("Pricing information is currently unavailable...") is a hardcoded English string, unlike the rest of the buy-box copy which goes throughgetTranslations.🩹 Proposed fix
if (offers.length === 0) { return ( <div className="rounded-2xl border bg-card p-6 text-center"> <p className="text-muted-foreground"> - Pricing information is currently unavailable. Please try again - later. + {t('buyBox.unavailable')} </p> </div> ) }(requires adding a
buyBox.unavailablekey to the message files.)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/app/`[locale]/(main)/pro/page.tsx around lines 101 - 110, The empty-offers fallback in BuyBoxSection is hardcoded English instead of using the existing translation flow. Update the offers.length === 0 branch in pro/page.tsx to render the unavailable copy via the scoped t from getTranslations, and add the corresponding buyBox.unavailable key to the message files so the fallback is localized like the rest of the buy-box content.
94-110: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winAvoid caching the empty-catalog fallback for the full
productslifetime
src/services/core/external/medusa-client.ts:getProducts()swallows Medusa failures and returns[], soBuyBoxSectioncan cache the "Pricing information is currently unavailable" state under'use cache'+cacheTag('products'). A transient upstream outage would then keep serving the fallback until the next tag revalidation. Make empty results bypass this cache path or throw so the page doesn’t cache outage state.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/app/`[locale]/(main)/pro/page.tsx around lines 94 - 110, The cached fallback in pro/page.tsx is currently allowing an empty offer catalog from getProOfferCatalog() to be stored under the products cache. Update the BuyBoxSection/pro page caching path so empty offers do not go through the 'use cache' products lifetime cache: either bypass caching when offers.length is 0 or have getProducts()/getProOfferCatalog() surface the Medusa failure instead of returning []. Keep the fix anchored around getProOfferCatalog(), getProducts(), and the cacheTag('products') usage so transient outages do not get cached as the unavailable-pricing state.
🧹 Nitpick comments (2)
messages/en.json (1)
72-77: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winWhitespace-dependent
priceSuffixis fragile for i18n.
lifetime.priceSuffixembeds a leading space (" once") that only works becauseProBuyBoxconcatenatespriceTextandpriceSuffixadjacently without an explicit separator. This is invisible in the JSON and easy for a translator/tooling pass to trim, silently breaking spacing across all locales at once.yearly.priceSuffixavoids this by using a/-prefixed style instead, so the convention isn't even consistent within this same object.Consider handling the visual spacing in the component (e.g., a
gap/margin utility or an explicit space rendered in JSX) rather than relying on leading whitespace baked into translated strings.Example component-side fix
-<span className="text-xl font-bold">{option.priceText}</span> -<span className="text-sm text-muted-foreground"> - {option.priceSuffix} -</span> +<span className="text-xl font-bold">{option.priceText}</span> +<span className="text-sm text-muted-foreground ml-1"> + {option.priceSuffix} +</span>🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@messages/en.json` around lines 72 - 77, The `lifetime.priceSuffix` string is relying on a leading space for layout, which is fragile for translations and inconsistent with the `yearly.priceSuffix` convention. Update `ProBuyBox` to handle spacing between `priceText` and `priceSuffix` in the component itself, and remove the whitespace dependency from the `lifetime` entry in `messages/en.json` so the localized string is just the suffix text.e2e/pro.spec.ts (1)
55-61: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAvoid hard-coded
waitForTimeout.
page.waitForTimeout(2000)afterwaitForLoadState('networkidle')is a flaky-test anti-pattern that adds fixed latency to every run without guaranteeing readiness. The subsequentgetByRole('radio', ...)assertions already auto-wait/retry, so the explicit timeout is redundant and can be dropped.Suggested fix
test('displays yearly and lifetime term options', async ({ page }) => { await skipIfPricingUnavailable(page) await page.waitForLoadState('networkidle') - await page.waitForTimeout(2000) await expect(page.getByRole('radio', { name: /Yearly/ })).toBeVisible() await expect(page.getByRole('radio', { name: /Lifetime/ })).toBeVisible() })🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@e2e/pro.spec.ts` around lines 55 - 61, Remove the hard-coded delay in the pricing terms test and rely on Playwright’s built-in waiting instead. In the `displays yearly and lifetime term options` test, drop the `page.waitForTimeout(2000)` call after `page.waitForLoadState('networkidle')`; the `expect(page.getByRole('radio', ...)).toBeVisible()` assertions already auto-wait. Keep the rest of the flow in `skipIfPricingUnavailable` and the radio checks unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/components/pro/pro-buy-box.tsx`:
- Line 79: The row click handler in ProBuyBox is only updating selection state
and not moving focus, which breaks Safari mouse-to-keyboard continuity. Update
the button/list item click path in pro-buy-box.tsx so the same selected option
is also focused by calling the relevant ref’s focus() after setSelected,
matching the behavior already used by moveSelection and keeping the roving
tabIndex in sync. Apply this to the onClick handlers for the option rows that
use optionRefs.current and setSelected(option.planId).
- Around line 53-58: The static BuyBoxSection copy is hardcoded in English,
including the header, subtitle, radiogroup aria-label, and trust-facts block, so
non-English locales miss critical localized content. Move these strings out of
the client component and source them from the existing getTranslations flow in
BuyBoxSection, then pass them into pro-buy-box.tsx as props (or pre-rendered
content) using the existing buyBox.* translation keys and any new keys needed
for the trust block and aria-label. Update the BuyBoxSection and BuyBox-related
component props so the localizable text is resolved server-side instead of
embedded directly in the ProBuyBox component.
---
Outside diff comments:
In `@src/app/`[locale]/(main)/pro/page.tsx:
- Around line 101-110: The empty-offers fallback in BuyBoxSection is hardcoded
English instead of using the existing translation flow. Update the offers.length
=== 0 branch in pro/page.tsx to render the unavailable copy via the scoped t
from getTranslations, and add the corresponding buyBox.unavailable key to the
message files so the fallback is localized like the rest of the buy-box content.
- Around line 94-110: The cached fallback in pro/page.tsx is currently allowing
an empty offer catalog from getProOfferCatalog() to be stored under the products
cache. Update the BuyBoxSection/pro page caching path so empty offers do not go
through the 'use cache' products lifetime cache: either bypass caching when
offers.length is 0 or have getProducts()/getProOfferCatalog() surface the Medusa
failure instead of returning []. Keep the fix anchored around
getProOfferCatalog(), getProducts(), and the cacheTag('products') usage so
transient outages do not get cached as the unavailable-pricing state.
---
Nitpick comments:
In `@e2e/pro.spec.ts`:
- Around line 55-61: Remove the hard-coded delay in the pricing terms test and
rely on Playwright’s built-in waiting instead. In the `displays yearly and
lifetime term options` test, drop the `page.waitForTimeout(2000)` call after
`page.waitForLoadState('networkidle')`; the `expect(page.getByRole('radio',
...)).toBeVisible()` assertions already auto-wait. Keep the rest of the flow in
`skipIfPricingUnavailable` and the radio checks unchanged.
In `@messages/en.json`:
- Around line 72-77: The `lifetime.priceSuffix` string is relying on a leading
space for layout, which is fragile for translations and inconsistent with the
`yearly.priceSuffix` convention. Update `ProBuyBox` to handle spacing between
`priceText` and `priceSuffix` in the component itself, and remove the whitespace
dependency from the `lifetime` entry in `messages/en.json` so the localized
string is just the suffix text.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 5ce8665a-7968-428e-9b1a-f74e5500f5cd
📒 Files selected for processing (18)
e2e/pro.spec.tsmessages/de.jsonmessages/en.jsonmessages/es.jsonmessages/fr.jsonmessages/it.jsonmessages/ja.jsonmessages/ko.jsonmessages/nl.jsonmessages/pt.jsonmessages/zh.jsonsrc/app/[locale]/(main)/pro/page.test.tsxsrc/app/[locale]/(main)/pro/page.tsxsrc/components/pro/pricing-card.test.tsxsrc/components/pro/pricing-card.tsxsrc/components/pro/pro-buy-box.test.tsxsrc/components/pro/pro-buy-box.tsxsrc/components/pro/pro-features.tsx
💤 Files with no reviewable changes (2)
- src/components/pro/pricing-card.test.tsx
- src/components/pro/pricing-card.tsx
|
🚀 Preview: https://wcpos-fcr1jn69o-wcpos.vercel.app |
|
Round 3 follow-up triage (fresh unresolved review-thread inventory after remote updates):
Skipped threads: none. CI scope: current PR checks are green for Test, E2E, CodeQL and CodeRabbit; Deploy Preview is still in progress. |
There was a problem hiding this comment.
kilbot has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.
|
Round 3 final triage after fixes (fresh unresolved review-thread inventory: 0):
Skipped threads: none.
CI scope: local |
|
🚀 Preview: https://wcpos-qa93fmn89-wcpos.vercel.app |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
src/components/pro/pro-buy-box-options.ts (2)
23-24: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
eventProperties: Record<string, unknown>loses the known shape.The actual payload is always
{ experiment, variant, product, plan }. Typing it precisely would give compile-time protection against a future field being dropped or misnamed at either the builder or the (client) consumer.Also applies to: 65-70
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/pro/pro-buy-box-options.ts` around lines 23 - 24, The eventProperties field is too loosely typed and hides the known payload shape. Update the type in pro-buy-box-options so the builder and client consumer both use the exact object shape with experiment, variant, product, and plan instead of Record<string, unknown>. Also apply the same precise typing in the related builder/consumer code around the referenced section so future field drops or renames are caught at compile time.
31-45: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low valueLifetime-years derivation looks correct.
Logic correctly guards against a missing yearly/lifetime offer and division by zero, and the ≥2 threshold avoids making a weak "years of yearly" claim. Matches the documented intent in the header comment (never hardcode the ratio).
One edge case worth noting:
Math.roundwill round e.g. a 1.6× ratio up toyears: 2, slightly overstating the value claim right at the boundary. Given catalog prices are static and controlled, this is unlikely to bite in practice.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/pro/pro-buy-box-options.ts` around lines 31 - 45, The lifetime CTA year count in lifetimeCtaNote can be overstated because Math.round may promote a non-integer ratio (for example, 1.6) to 2 and trigger the stronger copy. Update the years derivation in lifetimeCtaNote to avoid rounding up—prefer a conservative calculation such as flooring or otherwise requiring a true whole-number ratio—so the t('buyBox.lifetime.ctaNote', { years }) path only uses accurate years values.src/components/pro/pro-buy-box.tsx (1)
39-44: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low valueMinor:
options[0]assumes a non-empty array.
useState<PlanId>(options[0].planId)and thecurrentfallback both dereferenceoptions[0]unconditionally. Today the only caller (BuyBoxWithExperimentinpage.tsx) guards againstoffers.length === 0before renderingProBuyBox, so this isn't currently reachable, but nothing inProBuyBoxPropsenforces a non-emptyoptionsarray, so a future caller/refactor could reintroduce a crash.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/components/pro/pro-buy-box.tsx` around lines 39 - 44, `ProBuyBox` assumes `options[0]` always exists when initializing `selected` and computing `current`, which can crash if an empty options array is ever passed. Update `ProBuyBox` to avoid unconditional indexing by adding a non-empty guard or a safe fallback before using `options[0]`, and ensure the logic around `useState`, `current`, and any dependent rendering handles the empty-array case explicitly. Refer to `ProBuyBox` and `ProBuyBoxProps` when making the fix so the component is robust even if future callers skip the current `offers.length === 0` guard.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/app/`[locale]/(main)/pro/page.tsx:
- Around line 110-116: The primary CTA text is still hardcoded in English via
getProCheckoutCtaLabel(experimentVariant), which bypasses localization on the
Pro page. Update the CTA label source in pro-offer-catalog.ts to use translation
keys resolved through the existing translate/t flow, similar to
buildProBuyBoxOptions, and thread the localized value back into the ProBuyBox
ctaLabel prop instead of returning literal English strings.
---
Nitpick comments:
In `@src/components/pro/pro-buy-box-options.ts`:
- Around line 23-24: The eventProperties field is too loosely typed and hides
the known payload shape. Update the type in pro-buy-box-options so the builder
and client consumer both use the exact object shape with experiment, variant,
product, and plan instead of Record<string, unknown>. Also apply the same
precise typing in the related builder/consumer code around the referenced
section so future field drops or renames are caught at compile time.
- Around line 31-45: The lifetime CTA year count in lifetimeCtaNote can be
overstated because Math.round may promote a non-integer ratio (for example, 1.6)
to 2 and trigger the stronger copy. Update the years derivation in
lifetimeCtaNote to avoid rounding up—prefer a conservative calculation such as
flooring or otherwise requiring a true whole-number ratio—so the
t('buyBox.lifetime.ctaNote', { years }) path only uses accurate years values.
In `@src/components/pro/pro-buy-box.tsx`:
- Around line 39-44: `ProBuyBox` assumes `options[0]` always exists when
initializing `selected` and computing `current`, which can crash if an empty
options array is ever passed. Update `ProBuyBox` to avoid unconditional indexing
by adding a non-empty guard or a safe fallback before using `options[0]`, and
ensure the logic around `useState`, `current`, and any dependent rendering
handles the empty-array case explicitly. Refer to `ProBuyBox` and
`ProBuyBoxProps` when making the fix so the component is robust even if future
callers skip the current `offers.length === 0` guard.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 8a1d940f-0242-49d8-9e35-b782f3b07612
📒 Files selected for processing (19)
messages/de.jsonmessages/en.jsonmessages/es.jsonmessages/fr.jsonmessages/it.jsonmessages/ja.jsonmessages/ko.jsonmessages/nl.jsonmessages/pt.jsonmessages/zh.jsonsrc/app/[locale]/(main)/pro/page.test.tsxsrc/app/[locale]/(main)/pro/page.tsxsrc/components/pro/pro-buy-box-options.test.tssrc/components/pro/pro-buy-box-options.tssrc/components/pro/pro-buy-box.test.tsxsrc/components/pro/pro-buy-box.tsxsrc/components/pro/pro-features.tsxsrc/lib/pro-offer-catalog.test.tssrc/lib/pro-offer-catalog.ts
✅ Files skipped from review due to trivial changes (5)
- messages/en.json
- messages/de.json
- messages/es.json
- messages/ja.json
- messages/nl.json
🚧 Files skipped from review as they are similar to previous changes (7)
- src/components/pro/pro-features.tsx
- messages/fr.json
- messages/ko.json
- messages/it.json
- messages/zh.json
- messages/pt.json
- src/app/[locale]/(main)/pro/page.test.tsx
|
Round 4 triage before fixes (fresh unresolved review-thread inventory):
Skipped threads: none. CI scope: |
There was a problem hiding this comment.
kilbot has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.
|
Round 4 final triage after fixes (fresh unresolved review-thread inventory: 0):
Skipped threads:
Validation:
CI scope: checks for pushed head |
|
🚀 Preview: https://wcpos-3x7yj5vbd-wcpos.vercel.app |
Summary
Implements the pricing design picked in #194 (prototype variant H, "the buy box"). The /pro pricing section becomes a product page rather than a pricing page:
pro.featuresmessages), replacing both the old duplicate per-plan checklists and the separate features section. Owner rule from prototype: /pro pricing + checkout variants (do not merge) #194: never repeat the feature checklist per plan./prois now ◐ partially prerendered: hero, features and FAQ are static HTML; only the buy box suspends (Medusa prices + checkout experiment cookie). This closes the original complaint about the whole pricing blocks skeletoning.Kept intact:
pro_checkout_v1experiment (CTA label +exp/exp_variantparams viabuildProCheckoutHref/getProCheckoutCtaLabel),click_start_checkoutanalytics event with the same properties, JSON-LD product schema, graceful "pricing unavailable" fallback, FAQ.Removed:
PricingCard+ test (this page was its only consumer).Validation
tsc --noEmitclean, eslint cleanpro-buy-boxtests cover default selection, term switching, analytics payload, refunds link)/prorenders as ◐ Partial Prerender (was ƒ-dynamic-on-request for the pricing block)e2e/pro.spec.tsupdated for the buy box — 7/7 passing against the mocked Medusa backend (chromium)Notes
Summary by CodeRabbit