From 4a7dd0f39443ea5c289f60cfc0f90c879fb74655 Mon Sep 17 00:00:00 2001 From: freddie Date: Wed, 15 Apr 2026 18:22:14 +0100 Subject: [PATCH 1/4] fix: add ShopifyProvider to skeleton template for locale-aware formatting The Money component (re-exported from @shopify/hydrogen-react) depends on ShopifyProvider context for correct locale formatting via Intl.NumberFormat. Without it, all monetary values default to en-US regardless of the store's configured locale. This commit: - Re-exports ShopifyProvider, useShop, and SFAPI_VERSION from @shopify/hydrogen - Adds readonly apiVersion to the Storefront object for clean server-to-client data flow - Wraps the skeleton App component with ShopifyProvider, fed by storefront.i18n - Fixes the hardcoded to use the configured language Fixes #3432 Co-Authored-By: Claude Opus 4.6 (1M context) --- .../hydrogen-shopify-provider-reexport.md | 5 +++ .changeset/skeleton-shopify-provider.md | 7 ++++ packages/hydrogen/src/index.ts | 3 ++ packages/hydrogen/src/storefront.ts | 6 +++ templates/skeleton/app/root.tsx | 38 ++++++++++++++----- 5 files changed, 49 insertions(+), 10 deletions(-) create mode 100644 .changeset/hydrogen-shopify-provider-reexport.md create mode 100644 .changeset/skeleton-shopify-provider.md diff --git a/.changeset/hydrogen-shopify-provider-reexport.md b/.changeset/hydrogen-shopify-provider-reexport.md new file mode 100644 index 0000000000..e73a165536 --- /dev/null +++ b/.changeset/hydrogen-shopify-provider-reexport.md @@ -0,0 +1,5 @@ +--- +"@shopify/hydrogen": patch +--- + +Re-export `ShopifyProvider`, `useShop`, and `SFAPI_VERSION` from `@shopify/hydrogen` so these can be imported without reaching into `@shopify/hydrogen-react` directly. Add `apiVersion` to the `storefront` object returned by `createStorefrontClient`, giving loaders access to the resolved Storefront API version. diff --git a/.changeset/skeleton-shopify-provider.md b/.changeset/skeleton-shopify-provider.md new file mode 100644 index 0000000000..2df5dc7344 --- /dev/null +++ b/.changeset/skeleton-shopify-provider.md @@ -0,0 +1,7 @@ +--- +"skeleton": patch +"@shopify/cli-hydrogen": patch +"@shopify/create-hydrogen": patch +--- + +Add `ShopifyProvider` to the skeleton template so that `Money` and other locale-aware components format values using your store's configured locale instead of defaulting to `en-US`. Also sets the `` attribute dynamically based on the store's language setting. diff --git a/packages/hydrogen/src/index.ts b/packages/hydrogen/src/index.ts index 5dadfadecb..4fbab96cdd 100644 --- a/packages/hydrogen/src/index.ts +++ b/packages/hydrogen/src/index.ts @@ -168,11 +168,14 @@ export { parseGid, parseMetafield, sendShopifyAnalytics, + ShopifyProvider, ShopifySalesChannel, storefrontApiCustomScalars, useLoadScript, useMoney, useSelectedOptionInUrlParam, + useShop, useShopifyCookies, Video, } from '@shopify/hydrogen-react'; +export {SFAPI_VERSION} from '@shopify/hydrogen-react/storefront-api-constants'; diff --git a/packages/hydrogen/src/storefront.ts b/packages/hydrogen/src/storefront.ts index 4fd2e520ba..152defff2d 100644 --- a/packages/hydrogen/src/storefront.ts +++ b/packages/hydrogen/src/storefront.ts @@ -7,6 +7,7 @@ import { SHOPIFY_VISIT_TOKEN_HEADER, type StorefrontClientProps, } from '@shopify/hydrogen-react'; +import {SFAPI_VERSION} from '@shopify/hydrogen-react/storefront-api-constants'; import type {WritableDeep} from 'type-fest'; import {fetchWithServerCache} from './cache/server-fetch'; import { @@ -173,6 +174,8 @@ export type Storefront = { typeof createStorefrontUtilities >['getStorefrontApiUrl']; i18n: TI18n; + /** The resolved Storefront API version used by this client. */ + readonly apiVersion: string; getHeaders: () => Record; /** * Checks if the request URL matches the Storefront API GraphQL endpoint. @@ -555,6 +558,7 @@ export function createStorefrontClient( getShopifyDomain, getApiUrl: getStorefrontApiUrl, i18n: (i18n ?? defaultI18n) as TI18n, + apiVersion: clientOptions.storefrontApiVersion ?? SFAPI_VERSION, /** * Checks if the request is targeting the Storefront API endpoint. @@ -825,6 +829,8 @@ export type StorefrontForDoc = { >['getStorefrontApiUrl']; /** The `i18n` object passed in from the `createStorefrontClient` argument. */ i18n?: TI18n; + /** The resolved Storefront API version used by this client. */ + readonly apiVersion?: string; }; export type StorefrontQueryOptionsForDocs = { diff --git a/templates/skeleton/app/root.tsx b/templates/skeleton/app/root.tsx index df87425c57..b7eb815137 100644 --- a/templates/skeleton/app/root.tsx +++ b/templates/skeleton/app/root.tsx @@ -1,4 +1,9 @@ -import {Analytics, getShopAnalytics, useNonce} from '@shopify/hydrogen'; +import { + Analytics, + getShopAnalytics, + ShopifyProvider, + useNonce, +} from '@shopify/hydrogen'; import { Outlet, useRouteError, @@ -78,6 +83,9 @@ export async function loader(args: Route.LoaderArgs) { ...deferredData, ...criticalData, publicStoreDomain: env.PUBLIC_STORE_DOMAIN, + publicStorefrontToken: env.PUBLIC_STOREFRONT_API_TOKEN, + storefrontApiVersion: storefront.apiVersion, + i18n: storefront.i18n, shop: getShopAnalytics({ storefront, publicStorefrontId: env.PUBLIC_STOREFRONT_ID, @@ -143,9 +151,11 @@ function loadDeferredData({context}: Route.LoaderArgs) { export function Layout({children}: {children?: React.ReactNode}) { const nonce = useNonce(); + const data = useRouteLoaderData('root'); + const locale = data?.i18n?.language?.toLowerCase() ?? 'en'; return ( - + @@ -171,15 +181,23 @@ export default function App() { } return ( - - - - - + + + + + + ); } From 4ec22ec9bbe53d7f4c5a30831f812f534fe042eb Mon Sep 17 00:00:00 2001 From: freddie Date: Wed, 15 Apr 2026 19:01:29 +0100 Subject: [PATCH 2/4] fix(cookbook): regenerate root.tsx patches for all recipes The ShopifyProvider wrapping in root.tsx changed the import line, loader return, and JSX nesting structure. All 8 recipe patches targeting root.tsx needed regeneration via three-way merge against the updated skeleton. Affected recipes: b2b, express, gtm, legacy-customer-account-flow, markets, metaobjects, multipass, partytown. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../recipes/b2b/patches/root.tsx.8c60e9.patch | 36 +++++++++--------- .../express/patches/root.tsx.8c60e9.patch | 38 +++++++++---------- .../recipes/gtm/patches/root.tsx.5e9998.patch | 32 ++++++++-------- .../patches/root.tsx.8c60e9.patch | 25 ++++++++---- .../markets/patches/root.tsx.9594cb.patch | 32 ++++++++-------- .../metaobjects/patches/root.tsx.8c60e9.patch | 4 +- .../multipass/patches/root.tsx.8c60e9.patch | 18 ++++----- .../partytown/patches/root.tsx.8c60e9.patch | 34 +++++++++-------- 8 files changed, 116 insertions(+), 103 deletions(-) diff --git a/cookbook/recipes/b2b/patches/root.tsx.8c60e9.patch b/cookbook/recipes/b2b/patches/root.tsx.8c60e9.patch index c0d86c4c17..75750180d5 100644 --- a/cookbook/recipes/b2b/patches/root.tsx.8c60e9.patch +++ b/cookbook/recipes/b2b/patches/root.tsx.8c60e9.patch @@ -1,7 +1,7 @@ -index df87425c..5a0fef09 100644 +index b7eb81513..c2ae52c9b 100644 --- a/templates/skeleton/app/root.tsx +++ b/templates/skeleton/app/root.tsx -@@ -16,9 +16,39 @@ import {FOOTER_QUERY, HEADER_QUERY} from '~/lib/fragments'; +@@ -21,9 +21,39 @@ import {FOOTER_QUERY, HEADER_QUERY} from '~/lib/fragments'; import resetStyles from '~/styles/reset.css?url'; import appStyles from '~/styles/app.css?url'; import {PageLayout} from './components/PageLayout'; @@ -41,20 +41,20 @@ index df87425c..5a0fef09 100644 /** * This is important to avoid re-fetching root queries on sub-navigations */ -@@ -176,9 +206,13 @@ export default function App() { - shop={data.shop} - consent={data.consent} - > -- -- -- -+ {/* @description Wrap PageLayout with B2B location provider for company location management */} -+ -+ -+ -+ -+ -+ - +@@ -193,9 +223,13 @@ export default function App() { + shop={data.shop} + consent={data.consent} + > +- +- +- ++ {/* @description Wrap PageLayout with B2B location provider for company location management */} ++ ++ ++ ++ ++ ++ + + ); - } diff --git a/cookbook/recipes/express/patches/root.tsx.8c60e9.patch b/cookbook/recipes/express/patches/root.tsx.8c60e9.patch index ebd7551343..22d9e7a8d4 100644 --- a/cookbook/recipes/express/patches/root.tsx.8c60e9.patch +++ b/cookbook/recipes/express/patches/root.tsx.8c60e9.patch @@ -1,7 +1,7 @@ -index df87425c..1ba9888f 100644 +index b7eb81513..859bccb7e 100644 --- a/templates/skeleton/app/root.tsx +++ b/templates/skeleton/app/root.tsx -@@ -11,46 +11,20 @@ import { +@@ -16,46 +16,20 @@ import { useRouteLoaderData, } from 'react-router'; import type {Route} from './+types/root'; @@ -49,7 +49,7 @@ index df87425c..1ba9888f 100644 export function links() { return [ { -@@ -61,18 +35,19 @@ export function links() { +@@ -66,18 +40,19 @@ export function links() { rel: 'preconnect', href: 'https://shop.app', }, @@ -76,7 +76,7 @@ index df87425c..1ba9888f 100644 return { ...deferredData, -@@ -86,59 +61,29 @@ export async function loader(args: Route.LoaderArgs) { +@@ -94,59 +69,29 @@ export async function loader(args: Route.LoaderArgs) { checkoutDomain: env.PUBLIC_CHECKOUT_DOMAIN, storefrontAccessToken: env.PUBLIC_STOREFRONT_API_TOKEN, withPrivacyBanner: false, @@ -149,7 +149,7 @@ index df87425c..1ba9888f 100644 } export function Layout({children}: {children?: React.ReactNode}) { -@@ -149,8 +94,7 @@ export function Layout({children}: {children?: React.ReactNode}) { +@@ -159,8 +104,7 @@ export function Layout({children}: {children?: React.ReactNode}) { @@ -159,21 +159,21 @@ index df87425c..1ba9888f 100644 -@@ -176,9 +120,11 @@ export default function App() { - shop={data.shop} - consent={data.consent} - > -- -+
-+

{data.layout?.shop?.name} (Express example)

-+

{data.layout?.shop?.description}

- -- -+
- +@@ -193,9 +137,11 @@ export default function App() { + shop={data.shop} + consent={data.consent} + > +- ++
++

{data.layout?.shop?.name} (Express example)

++

{data.layout?.shop?.description}

+ +- ++
+ + ); - } -@@ -207,3 +153,19 @@ export function ErrorBoundary() { +@@ -225,3 +171,19 @@ export function ErrorBoundary() { ); } diff --git a/cookbook/recipes/gtm/patches/root.tsx.5e9998.patch b/cookbook/recipes/gtm/patches/root.tsx.5e9998.patch index 013e333a98..8be3948e6c 100644 --- a/cookbook/recipes/gtm/patches/root.tsx.5e9998.patch +++ b/cookbook/recipes/gtm/patches/root.tsx.5e9998.patch @@ -1,13 +1,15 @@ -index df87425c..aa25c6d7 100644 +index b7eb81513..65cf4e992 100644 --- a/templates/skeleton/app/root.tsx +++ b/templates/skeleton/app/root.tsx -@@ -1,4 +1,4 @@ --import {Analytics, getShopAnalytics, useNonce} from '@shopify/hydrogen'; -+import {Analytics, getShopAnalytics, useNonce, Script} from '@shopify/hydrogen'; +@@ -3,6 +3,7 @@ import { + getShopAnalytics, + ShopifyProvider, + useNonce, ++ Script, + } from '@shopify/hydrogen'; import { Outlet, - useRouteError, -@@ -16,6 +16,7 @@ import {FOOTER_QUERY, HEADER_QUERY} from '~/lib/fragments'; +@@ -21,6 +22,7 @@ import {FOOTER_QUERY, HEADER_QUERY} from '~/lib/fragments'; import resetStyles from '~/styles/reset.css?url'; import appStyles from '~/styles/app.css?url'; import {PageLayout} from './components/PageLayout'; @@ -15,7 +17,7 @@ index df87425c..aa25c6d7 100644 export type RootLoader = typeof loader; -@@ -153,8 +154,32 @@ export function Layout({children}: {children?: React.ReactNode}) { +@@ -163,8 +165,32 @@ export function Layout({children}: {children?: React.ReactNode}) { @@ -48,12 +50,12 @@ index df87425c..aa25c6d7 100644 {children} -@@ -179,6 +204,8 @@ export default function App() { - - - -+ {/* @description Initialize Google Tag Manager analytics integration */} -+ - +@@ -196,6 +222,8 @@ export default function App() { + + + ++ {/* @description Initialize Google Tag Manager analytics integration */} ++ + + ); - } diff --git a/cookbook/recipes/legacy-customer-account-flow/patches/root.tsx.8c60e9.patch b/cookbook/recipes/legacy-customer-account-flow/patches/root.tsx.8c60e9.patch index e4c68a2cdf..9ec9ff9e49 100644 --- a/cookbook/recipes/legacy-customer-account-flow/patches/root.tsx.8c60e9.patch +++ b/cookbook/recipes/legacy-customer-account-flow/patches/root.tsx.8c60e9.patch @@ -1,14 +1,15 @@ -index df87425c..aa6f5166 100644 +index b7eb81513..7205a0143 100644 --- a/templates/skeleton/app/root.tsx +++ b/templates/skeleton/app/root.tsx -@@ -1,5 +1,6 @@ - import {Analytics, getShopAnalytics, useNonce} from '@shopify/hydrogen'; +@@ -5,6 +5,7 @@ import { + useNonce, + } from '@shopify/hydrogen'; import { + data, Outlet, useRouteError, isRouteErrorResponse, -@@ -11,6 +12,7 @@ import { +@@ -16,6 +17,7 @@ import { useRouteLoaderData, } from 'react-router'; import type {Route} from './+types/root'; @@ -16,7 +17,7 @@ index df87425c..aa6f5166 100644 import favicon from '~/assets/favicon.svg'; import {FOOTER_QUERY, HEADER_QUERY} from '~/lib/fragments'; import resetStyles from '~/styles/reset.css?url'; -@@ -65,6 +67,9 @@ export function links() { +@@ -70,6 +72,9 @@ export function links() { ]; } @@ -26,7 +27,7 @@ index df87425c..aa6f5166 100644 export async function loader(args: Route.LoaderArgs) { // Start fetching non-critical data without blocking time to first byte const deferredData = loadDeferredData(args); -@@ -74,23 +79,38 @@ export async function loader(args: Route.LoaderArgs) { +@@ -79,26 +84,45 @@ export async function loader(args: Route.LoaderArgs) { const {storefront, env} = args.context; @@ -34,6 +35,9 @@ index df87425c..aa6f5166 100644 - ...deferredData, - ...criticalData, - publicStoreDomain: env.PUBLIC_STORE_DOMAIN, +- publicStorefrontToken: env.PUBLIC_STOREFRONT_API_TOKEN, +- storefrontApiVersion: storefront.apiVersion, +- i18n: storefront.i18n, - shop: getShopAnalytics({ - storefront, - publicStorefrontId: env.PUBLIC_STOREFRONT_ID, @@ -61,6 +65,9 @@ index df87425c..aa6f5166 100644 + // @description Include isLoggedIn status for legacy authentication + isLoggedIn, + publicStoreDomain: env.PUBLIC_STORE_DOMAIN, ++ publicStorefrontToken: env.PUBLIC_STOREFRONT_API_TOKEN, ++ storefrontApiVersion: storefront.apiVersion, ++ i18n: storefront.i18n, + shop: getShopAnalytics({ + storefront, + publicStorefrontId: env.PUBLIC_STOREFRONT_ID, @@ -77,11 +84,15 @@ index df87425c..aa6f5166 100644 - }; + // @description Include headers for legacy authentication flow + {headers}, ++ ); ++ }, ++ // @description Include headers for legacy authentication flow ++ {headers}, + ); } /** -@@ -207,3 +227,39 @@ export function ErrorBoundary() { +@@ -225,3 +249,39 @@ export function ErrorBoundary() { ); } diff --git a/cookbook/recipes/markets/patches/root.tsx.9594cb.patch b/cookbook/recipes/markets/patches/root.tsx.9594cb.patch index 7cd7407428..d2fa3d7303 100644 --- a/cookbook/recipes/markets/patches/root.tsx.9594cb.patch +++ b/cookbook/recipes/markets/patches/root.tsx.9594cb.patch @@ -1,23 +1,23 @@ -index df87425c..97ca8174 100644 +index b7eb81513..7a64b33e8 100644 --- a/templates/skeleton/app/root.tsx +++ b/templates/skeleton/app/root.tsx -@@ -77,6 +77,7 @@ export async function loader(args: Route.LoaderArgs) { +@@ -82,6 +82,7 @@ export async function loader(args: Route.LoaderArgs) { return { ...deferredData, ...criticalData, + selectedLocale: args.context.storefront.i18n, publicStoreDomain: env.PUBLIC_STORE_DOMAIN, - shop: getShopAnalytics({ - storefront, -@@ -176,7 +177,10 @@ export default function App() { - shop={data.shop} - consent={data.consent} - > -- -+ - - - + publicStorefrontToken: env.PUBLIC_STOREFRONT_API_TOKEN, + storefrontApiVersion: storefront.apiVersion, +@@ -193,7 +194,10 @@ export default function App() { + shop={data.shop} + consent={data.consent} + > +- ++ + + + diff --git a/cookbook/recipes/metaobjects/patches/root.tsx.8c60e9.patch b/cookbook/recipes/metaobjects/patches/root.tsx.8c60e9.patch index fbe9fb46ec..953d7ebcff 100644 --- a/cookbook/recipes/metaobjects/patches/root.tsx.8c60e9.patch +++ b/cookbook/recipes/metaobjects/patches/root.tsx.8c60e9.patch @@ -1,7 +1,7 @@ -index df87425c..12434050 100644 +index b7eb81513..c265a7e69 100644 --- a/templates/skeleton/app/root.tsx +++ b/templates/skeleton/app/root.tsx -@@ -90,6 +90,8 @@ export async function loader(args: Route.LoaderArgs) { +@@ -98,6 +98,8 @@ export async function loader(args: Route.LoaderArgs) { country: args.context.storefront.i18n.country, language: args.context.storefront.i18n.language, }, diff --git a/cookbook/recipes/multipass/patches/root.tsx.8c60e9.patch b/cookbook/recipes/multipass/patches/root.tsx.8c60e9.patch index cf5b5ae939..4aeadf270c 100644 --- a/cookbook/recipes/multipass/patches/root.tsx.8c60e9.patch +++ b/cookbook/recipes/multipass/patches/root.tsx.8c60e9.patch @@ -1,14 +1,12 @@ -index df87425c..a2c2acc8 100644 +index b7eb81513..aeefab1a5 100644 --- a/templates/skeleton/app/root.tsx +++ b/templates/skeleton/app/root.tsx -@@ -1,4 +1,15 @@ --import {Analytics, getShopAnalytics, useNonce} from '@shopify/hydrogen'; -+import { -+ Analytics, -+ getShopAnalytics, -+ useNonce, +@@ -3,7 +3,14 @@ import { + getShopAnalytics, + ShopifyProvider, + useNonce, + type HydrogenSession, -+} from '@shopify/hydrogen'; + } from '@shopify/hydrogen'; + +// @description Define CustomerAccessToken type for multipass +type CustomerAccessToken = { @@ -18,7 +16,7 @@ index df87425c..a2c2acc8 100644 import { Outlet, useRouteError, -@@ -110,7 +121,14 @@ async function loadCriticalData({context}: Route.LoaderArgs) { +@@ -118,7 +125,14 @@ async function loadCriticalData({context}: Route.LoaderArgs) { // Add other queries here, so that they are loaded in parallel ]); @@ -34,7 +32,7 @@ index df87425c..a2c2acc8 100644 } /** -@@ -207,3 +225,24 @@ export function ErrorBoundary() { +@@ -225,3 +239,24 @@ export function ErrorBoundary() { ); } diff --git a/cookbook/recipes/partytown/patches/root.tsx.8c60e9.patch b/cookbook/recipes/partytown/patches/root.tsx.8c60e9.patch index 3083d48225..361ace16aa 100644 --- a/cookbook/recipes/partytown/patches/root.tsx.8c60e9.patch +++ b/cookbook/recipes/partytown/patches/root.tsx.8c60e9.patch @@ -1,13 +1,15 @@ -index df87425c..a2b8986a 100644 +index b7eb81513..401f31e87 100644 --- a/templates/skeleton/app/root.tsx +++ b/templates/skeleton/app/root.tsx -@@ -1,4 +1,4 @@ --import {Analytics, getShopAnalytics, useNonce} from '@shopify/hydrogen'; -+import {Analytics, getShopAnalytics, useNonce, Script} from '@shopify/hydrogen'; +@@ -3,6 +3,7 @@ import { + getShopAnalytics, + ShopifyProvider, + useNonce, ++ Script, + } from '@shopify/hydrogen'; import { Outlet, - useRouteError, -@@ -16,6 +16,10 @@ import {FOOTER_QUERY, HEADER_QUERY} from '~/lib/fragments'; +@@ -21,6 +22,10 @@ import {FOOTER_QUERY, HEADER_QUERY} from '~/lib/fragments'; import resetStyles from '~/styles/reset.css?url'; import appStyles from '~/styles/app.css?url'; import {PageLayout} from './components/PageLayout'; @@ -18,7 +20,7 @@ index df87425c..a2b8986a 100644 export type RootLoader = typeof loader; -@@ -90,6 +94,10 @@ export async function loader(args: Route.LoaderArgs) { +@@ -98,6 +103,10 @@ export async function loader(args: Route.LoaderArgs) { country: args.context.storefront.i18n.country, language: args.context.storefront.i18n.language, }, @@ -29,7 +31,7 @@ index df87425c..a2b8986a 100644 }; } -@@ -163,6 +171,38 @@ export function Layout({children}: {children?: React.ReactNode}) { +@@ -173,6 +182,38 @@ export function Layout({children}: {children?: React.ReactNode}) { ); } @@ -68,11 +70,11 @@ index df87425c..a2b8986a 100644 export default function App() { const data = useRouteLoaderData('root'); -@@ -177,6 +217,7 @@ export default function App() { - consent={data.consent} - > - -+ - - - +@@ -194,6 +235,7 @@ export default function App() { + consent={data.consent} + > + ++ + + + From c8d73f60d58828c5fba49cbb361e0b6b80c66bbc Mon Sep 17 00:00:00 2001 From: freddie Date: Wed, 15 Apr 2026 19:14:48 +0100 Subject: [PATCH 3/4] fix: add mock.shop fallbacks for ShopifyProvider props ShopifyProvider validates that storeDomain and storefrontToken are truthy. In mock.shop dev environments, these env vars are not set (only SESSION_SECRET is), causing the dev server to throw a 500. Providing fallbacks ('mock.shop' and 'mock') prevents the error while keeping the provider functional for real Shopify stores. Co-Authored-By: Claude Opus 4.6 (1M context) --- templates/skeleton/app/root.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/skeleton/app/root.tsx b/templates/skeleton/app/root.tsx index b7eb815137..c502c508a6 100644 --- a/templates/skeleton/app/root.tsx +++ b/templates/skeleton/app/root.tsx @@ -182,8 +182,8 @@ export default function App() { return ( Date: Wed, 15 Apr 2026 19:59:35 +0100 Subject: [PATCH 4/4] fix: fix legacy-customer-account-flow patch and update markets E2E expectations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The legacy-customer-account-flow recipe patch had a duplicated `{headers}, );` block from the three-way merge, producing a syntax error when applied. Removed the duplicate. The markets E2E test expected prices formatted as en-US (`CA$1,121.00`) because the old skeleton lacked ShopifyProvider. Now that ShopifyProvider correctly passes the store's i18n data, the Money component formats using the actual locale — fr-CA in this case (`1 121,00 $`). Updated CURRENCY_FORMATS to distinguish CAD_EN from CAD_FR and pointed the FR-CA locale tests at the correct format. Co-Authored-By: Claude Opus 4.6 (1M context) --- .../patches/root.tsx.8c60e9.patch | 8 ++------ e2e/fixtures/currency-formats.ts | 5 ++++- e2e/specs/recipes/markets.spec.ts | 6 +++--- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/cookbook/recipes/legacy-customer-account-flow/patches/root.tsx.8c60e9.patch b/cookbook/recipes/legacy-customer-account-flow/patches/root.tsx.8c60e9.patch index 9ec9ff9e49..f5ebef4785 100644 --- a/cookbook/recipes/legacy-customer-account-flow/patches/root.tsx.8c60e9.patch +++ b/cookbook/recipes/legacy-customer-account-flow/patches/root.tsx.8c60e9.patch @@ -27,7 +27,7 @@ index b7eb81513..7205a0143 100644 export async function loader(args: Route.LoaderArgs) { // Start fetching non-critical data without blocking time to first byte const deferredData = loadDeferredData(args); -@@ -79,26 +84,45 @@ export async function loader(args: Route.LoaderArgs) { +@@ -79,26 +84,41 @@ export async function loader(args: Route.LoaderArgs) { const {storefront, env} = args.context; @@ -84,15 +84,11 @@ index b7eb81513..7205a0143 100644 - }; + // @description Include headers for legacy authentication flow + {headers}, -+ ); -+ }, -+ // @description Include headers for legacy authentication flow -+ {headers}, + ); } /** -@@ -225,3 +249,39 @@ export function ErrorBoundary() { +@@ -225,3 +245,39 @@ export function ErrorBoundary() { ); } diff --git a/e2e/fixtures/currency-formats.ts b/e2e/fixtures/currency-formats.ts index ba3f6428ae..9510dc4a11 100644 --- a/e2e/fixtures/currency-formats.ts +++ b/e2e/fixtures/currency-formats.ts @@ -7,5 +7,8 @@ */ export const CURRENCY_FORMATS = { USD: /^\$[\d,]+\.\d{2}$/, - CAD: /^CA\$[\d,]+\.\d{2}$/, + /** English-formatted CAD price, e.g. CA$1,121.00 */ + CAD_EN: /^CA\$[\d,]+\.\d{2}$/, + /** French-Canadian-formatted CAD price, e.g. 1 121,00 $ */ + CAD_FR: /^[\d\u00A0\u202F ]+,\d{2}\s*\$$/, } as const; diff --git a/e2e/specs/recipes/markets.spec.ts b/e2e/specs/recipes/markets.spec.ts index 4675020ed9..a8e31cfff5 100644 --- a/e2e/specs/recipes/markets.spec.ts +++ b/e2e/specs/recipes/markets.spec.ts @@ -48,7 +48,7 @@ test.describe('Markets Recipe', () => { await page.goto(`/FR-CA/products/${KNOWN_PRODUCT.handle}`); const priceElement = recipe.getPriceElement(); - await recipe.assertPriceFormat(priceElement, CURRENCY_FORMATS.CAD); + await recipe.assertPriceFormat(priceElement, CURRENCY_FORMATS.CAD_FR); }); test('collection page URL includes locale prefix and products link with locale', async ({ @@ -75,12 +75,12 @@ test.describe('Markets Recipe', () => { // CAD in the drawer proves AddToCartButton posted to /FR-CA/cart rather than /cart, // creating the cart with the correct market context. - await recipe.assertCartSubtotalFormat(CURRENCY_FORMATS.CAD); + await recipe.assertCartSubtotalFormat(CURRENCY_FORMATS.CAD_FR); await page.goto('/FR-CA/cart'); await page.waitForURL(/\/FR-CA\/cart$/); - await recipe.assertCartSubtotalFormat(CURRENCY_FORMATS.CAD); + await recipe.assertCartSubtotalFormat(CURRENCY_FORMATS.CAD_FR); }); });