diff --git a/apps/web/src/components/Charts/PriceChart/utils.test.ts b/apps/web/src/components/Charts/PriceChart/utils.test.ts new file mode 100644 index 00000000000..2dfc906d605 --- /dev/null +++ b/apps/web/src/components/Charts/PriceChart/utils.test.ts @@ -0,0 +1,45 @@ +import { FiatCurrency } from 'uniswap/src/features/fiatCurrency/constants' +import type { useLocalizationContext } from 'uniswap/src/features/language/LocalizationContext' +import { NumberType } from 'utilities/src/format/types' +import { describe, expect, it, vi } from 'vitest' +import { formatPriceAxisLabel } from '~/components/Charts/PriceChart/utils' + +function createFormat() { + return { + convertFiatAmount: vi.fn((amount: number) => ({ amount, currency: FiatCurrency.UnitedStatesDollar })), + convertFiatAmountFormatted: vi.fn((amount: number, type: NumberType) => `${type}:${amount}`), + } +} + +describe('formatPriceAxisLabel', () => { + it('formats a valid fixed precision as currency', () => { + const format = createFormat() + + expect( + formatPriceAxisLabel({ + scaledPrice: 1.234, + scaleFactor: 1, + decimals: 2, + format: format as unknown as ReturnType, + locale: 'en-US', + }), + ).toBe('$1.23') + expect(format.convertFiatAmountFormatted).not.toHaveBeenCalled() + }) + + it('falls back when precision exceeds Intl.NumberFormat limits', () => { + const format = createFormat() + + expect( + formatPriceAxisLabel({ + scaledPrice: 1.234, + scaleFactor: 1, + decimals: 101, + format: format as unknown as ReturnType, + locale: 'en-US', + }), + ).toBe(`fiat-token-price:1.234`) + expect(format.convertFiatAmount).not.toHaveBeenCalled() + expect(format.convertFiatAmountFormatted).toHaveBeenCalledWith(1.234, NumberType.FiatTokenPrice) + }) +}) diff --git a/apps/web/src/components/Charts/PriceChart/utils.ts b/apps/web/src/components/Charts/PriceChart/utils.ts index f21f25250a0..a8c802eb7fd 100644 --- a/apps/web/src/components/Charts/PriceChart/utils.ts +++ b/apps/web/src/components/Charts/PriceChart/utils.ts @@ -4,6 +4,12 @@ import { useLocalizationContext } from 'uniswap/src/features/language/Localizati import { NumberType } from 'utilities/src/format/types' import { PricePoint } from '~/data/util' +const MAX_INTL_FRACTION_DIGITS = 100 + +function isValidFractionDigits(decimals: number): boolean { + return Number.isInteger(decimals) && decimals >= 0 && decimals <= MAX_INTL_FRACTION_DIGITS +} + /** * Returns the minimum and maximum values in the given array of PricePoints. */ @@ -80,7 +86,7 @@ export function formatPriceAxisLabel({ if (tokenFormatType) { return format.formatNumberOrString({ value: price, type: tokenFormatType }) } - if (decimals !== undefined) { + if (decimals !== undefined && isValidFractionDigits(decimals)) { const { amount, currency } = format.convertFiatAmount(price) return new Intl.NumberFormat(locale, { style: 'currency',