diff --git a/dotcom-rendering/src/components/AffiliateProducts/livePriceUtils.test.tsx b/dotcom-rendering/src/components/AffiliateProducts/livePriceUtils.test.tsx index 1842251234e..7fe9219e3f4 100644 --- a/dotcom-rendering/src/components/AffiliateProducts/livePriceUtils.test.tsx +++ b/dotcom-rendering/src/components/AffiliateProducts/livePriceUtils.test.tsx @@ -3,6 +3,7 @@ import { createAccessibleProductLabel, createStrikeThroughProductLabel, formatPrice, + getProductCtaLivePrice, rewriteLabelWithLatestPrice, shouldPutOldPriceInStrikethrough, } from './livePriceUtils'; @@ -212,3 +213,44 @@ describe('shouldPutOldPriceInStrikethrough', () => { expect(result).toBe(true); }); }); + +describe('getProductCtaLivePrice', () => { + const cta = { + url: 'https://example.com', + text: '', + retailer: 'Shop', + price: '£10', + }; + + it('returns the article price when there is no latest price', () => { + const { container } = render(<>{getProductCtaLivePrice(cta)}); + expect(container.textContent).toBe('£10'); + }); + + it('uses the latest price for dollar prices', () => { + const { container } = render( + <> + {getProductCtaLivePrice({ + ...cta, + price: '$10', + latestPrice: { currencySymbol: '$', price: '11' }, + })} + , + ); + expect(container.textContent).toBe('$11'); + }); + + it('handles article prices with thousands separators', () => { + const { container } = render( + <> + {getProductCtaLivePrice({ + ...cta, + price: '£1,299', + latestPrice: { currencySymbol: '£', price: '1000' }, + })} + , + ); + expect(container.querySelector('s')).toHaveTextContent('£1,299'); + expect(container.textContent).toBe('£1,299 £1,000'); + }); +}); diff --git a/dotcom-rendering/src/components/AffiliateProducts/livePriceUtils.tsx b/dotcom-rendering/src/components/AffiliateProducts/livePriceUtils.tsx index c5d2f45e4f8..4137505956a 100644 --- a/dotcom-rendering/src/components/AffiliateProducts/livePriceUtils.tsx +++ b/dotcom-rendering/src/components/AffiliateProducts/livePriceUtils.tsx @@ -183,7 +183,7 @@ export const getProductCtaLivePrice = ({ price, latestPrice }: ProductCta) => { } const formattedLatestPrice = getFormattedLatestPrice(latestPrice); - const numericArticlePrice = Number.parseFloat(price.replace(/£|$/, '')); + const numericArticlePrice = Number.parseFloat(price.replace(/[£$,]/g, '')); if ( Number.isNaN(numericArticlePrice) || diff --git a/dotcom-rendering/src/model/enhanceProductElement.test.ts b/dotcom-rendering/src/model/enhanceProductElement.test.ts index c2a34c26504..1b3a5b82453 100644 --- a/dotcom-rendering/src/model/enhanceProductElement.test.ts +++ b/dotcom-rendering/src/model/enhanceProductElement.test.ts @@ -205,7 +205,7 @@ describe('enhanceProductBlockElements', () => { throw new Error('Expected a ProductBlockElement'); } - expect(enhanced.lowestPrice).toBe('19.99'); + expect(enhanced.lowestPrice).toBe('£19.99'); }); it('uses the latestPrice for lowest price even when it is higher than the CTA price', () => { @@ -235,7 +235,36 @@ describe('enhanceProductBlockElements', () => { throw new Error('Expected a ProductBlockElement'); } - expect(enhanced.lowestPrice).toBe('25.99'); + expect(enhanced.lowestPrice).toBe('£25.99'); + }); + + it('includes the currency symbol of the latest price', () => { + const productBlockWithDollarPrice: ProductBlockElement = { + ...productBlockElement, + productCtas: [ + { + ...productBlockElement.productCtas[0]!, + price: '$29.99', + latestPrice: { + currencySymbol: '$', + price: '9.99', + }, + }, + ], + }; + + const [enhanced] = enhanceProductElement(elementsEnhancer)([ + productBlockWithDollarPrice, + ]); + + if ( + enhanced?._type !== + 'model.dotcomrendering.pageElements.ProductBlockElement' + ) { + throw new Error('Expected a ProductBlockElement'); + } + + expect(enhanced.lowestPrice).toBe('$9.99'); }); it('ignores an invalid latest price and still considers the CTA price', () => { diff --git a/dotcom-rendering/src/model/enhanceProductElement.ts b/dotcom-rendering/src/model/enhanceProductElement.ts index 1ab8ad07d48..ba12b990e4b 100644 --- a/dotcom-rendering/src/model/enhanceProductElement.ts +++ b/dotcom-rendering/src/model/enhanceProductElement.ts @@ -47,7 +47,9 @@ const parsePrice = (price: string): number | undefined => { */ const getLowestPrice = (ctas: ProductCta[]): string | undefined => { const candidates = ctas.flatMap(({ price, latestPrice }) => { - const display = latestPrice?.price ?? price; + const display = latestPrice + ? `${latestPrice.currencySymbol}${latestPrice.price}` + : price; const value = parsePrice(display); return value === undefined ? [] : [{ value, display }];