From c21ded64ad896281db5ab8fe1b464acab1a27bcb Mon Sep 17 00:00:00 2001 From: bymyself Date: Sun, 30 Nov 2025 12:52:43 -0800 Subject: [PATCH 1/2] feat: add comfy credit domain helpers --- src/base/credits/comfyCredits.ts | 197 ++++++++++++++++++ .../tests/base/credits/comfyCredits.test.ts | 55 +++++ 2 files changed, 252 insertions(+) create mode 100644 src/base/credits/comfyCredits.ts create mode 100644 tests-ui/tests/base/credits/comfyCredits.test.ts diff --git a/src/base/credits/comfyCredits.ts b/src/base/credits/comfyCredits.ts new file mode 100644 index 0000000000..459b06d961 --- /dev/null +++ b/src/base/credits/comfyCredits.ts @@ -0,0 +1,197 @@ +/** + * Fixed conversion rate between USD and Comfy credits. + * 1 credit costs 210 cents ($2.10). + */ +export const COMFY_CREDIT_RATE_CENTS = 210 + +export const COMFY_CREDIT_RATE_USD = COMFY_CREDIT_RATE_CENTS / 100 + +const DEFAULT_NUMBER_FORMAT: Intl.NumberFormatOptions = { + minimumFractionDigits: 2, + maximumFractionDigits: 2 +} + +const formatNumber = ( + value: number, + options: Intl.NumberFormatOptions = DEFAULT_NUMBER_FORMAT, + locale?: string +) => { + const merged: Intl.NumberFormatOptions = { + ...DEFAULT_NUMBER_FORMAT, + ...options + } + + if ( + typeof merged.maximumFractionDigits === 'number' && + typeof merged.minimumFractionDigits === 'number' && + merged.maximumFractionDigits < merged.minimumFractionDigits + ) { + merged.minimumFractionDigits = merged.maximumFractionDigits + } + + return new Intl.NumberFormat(locale, merged).format(value) +} + +export const centsToUsd = (cents: number): number => cents / 100 +export const usdToCents = (usd: number): number => Math.round(usd * 100) + +/** + * Converts a USD amount into Comfy credits. + */ +export function usdToComfyCredits(usd: number): number { + return usd / COMFY_CREDIT_RATE_USD +} + +/** + * Converts USD cents into Comfy credits. + */ +export function centsToComfyCredits(cents: number): number { + return cents / COMFY_CREDIT_RATE_CENTS +} + +/** + * Converts Comfy credits back to USD. + */ +export function comfyCreditsToUsd(credits: number): number { + return credits * COMFY_CREDIT_RATE_USD +} + +/** + * Converts Comfy credits to cents. + */ +export function comfyCreditsToCents(credits: number): number { + return credits * COMFY_CREDIT_RATE_CENTS +} + +export function formatUsdFromCents( + cents: number, + options?: Intl.NumberFormatOptions, + locale?: string +): string { + return formatNumber( + centsToUsd(cents), + { ...DEFAULT_NUMBER_FORMAT, ...options }, + locale + ) +} + +/** + * Formats credits to a localized numeric string (no unit suffix). + */ +export function formatComfyCreditsAmount( + credits: number, + options?: Intl.NumberFormatOptions, + locale?: string +): string { + return formatNumber(credits, { ...DEFAULT_NUMBER_FORMAT, ...options }, locale) +} + +type FormatCreditsOptions = { + unit?: string | null + numberOptions?: Intl.NumberFormatOptions + locale?: string +} + +export function formatComfyCreditsLabel( + credits: number, + { unit = 'credits', numberOptions, locale }: FormatCreditsOptions = {} +): string { + const formatted = formatComfyCreditsAmount(credits, numberOptions, locale) + return unit ? `${formatted} ${unit}` : formatted +} + +export function formatComfyCreditsLabelFromCents( + cents: number, + options?: FormatCreditsOptions +): string { + return formatComfyCreditsLabel(centsToComfyCredits(cents), options) +} + +export function formatComfyCreditsLabelFromUsd( + usd: number, + options?: FormatCreditsOptions +): string { + return formatComfyCreditsLabel(usdToComfyCredits(usd), options) +} + +export function formatComfyCreditsRangeLabelFromUsd( + minUsd: number, + maxUsd: number, + { + unit = 'credits', + numberOptions, + locale, + separator = '–' + }: FormatCreditsOptions & { + separator?: string + } = {} +): string { + const min = formatComfyCreditsAmount( + usdToComfyCredits(minUsd), + numberOptions, + locale + ) + const max = formatComfyCreditsAmount( + usdToComfyCredits(maxUsd), + numberOptions, + locale + ) + const joined = `${min}${separator}${max}` + return unit ? `${joined} ${unit}` : joined +} + +const USD_RANGE_REGEX = /(~?)\$(\d+(?:\.\d+)?)\s*[-–]\s*\$?(\d+(?:\.\d+)?)/g +const USD_VALUE_REGEX = /(~?)\$(\d+(?:\.\d+)?)/g + +/** + * Converts a USD-denoted string (e.g., "$0.45-1.2/Run") into a credits string. + * Any "$X" occurrences become "Y credits". Ranges are rendered as "Y–Z credits". + */ +export function convertUsdLabelToCredits( + label: string, + options?: FormatCreditsOptions +): string { + if (!label) return label + const unit = options?.unit ?? 'credits' + const numberOptions = options?.numberOptions + const locale = options?.locale + + const formatSingle = (usd: number) => + formatComfyCreditsLabel(usdToComfyCredits(usd), { + unit, + numberOptions, + locale + }) + + const formatRange = (min: number, max: number, prefix = '') => { + const minStr = formatComfyCreditsAmount( + usdToComfyCredits(min), + numberOptions, + locale + ) + const maxStr = formatComfyCreditsAmount( + usdToComfyCredits(max), + numberOptions, + locale + ) + const joined = `${minStr}–${maxStr}` + return unit ? `${prefix}${joined} ${unit}` : `${prefix}${joined}` + } + + let converted = label + converted = converted.replace( + USD_RANGE_REGEX, + (_match, prefix = '', minUsd, maxUsd) => + formatRange(parseFloat(minUsd), parseFloat(maxUsd), prefix) + ) + + converted = converted.replace( + USD_VALUE_REGEX, + (_match, prefix = '', amount) => { + const formatted = formatSingle(parseFloat(amount)) + return `${prefix}${formatted}` + } + ) + + return converted +} diff --git a/tests-ui/tests/base/credits/comfyCredits.test.ts b/tests-ui/tests/base/credits/comfyCredits.test.ts new file mode 100644 index 0000000000..70b9c16d77 --- /dev/null +++ b/tests-ui/tests/base/credits/comfyCredits.test.ts @@ -0,0 +1,55 @@ +import { describe, expect, it } from 'vitest' + +import { + COMFY_CREDIT_RATE_CENTS, + COMFY_CREDIT_RATE_USD, + centsToComfyCredits, + comfyCreditsToCents, + comfyCreditsToUsd, + convertUsdLabelToCredits, + formatComfyCreditsAmount, + formatComfyCreditsLabel, + formatComfyCreditsRangeLabelFromUsd, + usdToComfyCredits +} from '@/base/credits/comfyCredits' + +describe('comfyCredits helpers', () => { + it('exposes the fixed conversion rate', () => { + expect(COMFY_CREDIT_RATE_CENTS).toBe(210) + expect(COMFY_CREDIT_RATE_USD).toBeCloseTo(2.1) + }) + + it('converts USD and cents to credits', () => { + expect(usdToComfyCredits(2.1)).toBeCloseTo(1) + expect(usdToComfyCredits(10.5)).toBeCloseTo(5) + expect(centsToComfyCredits(210)).toBeCloseTo(1) + expect(centsToComfyCredits(1050)).toBeCloseTo(5) + }) + + it('converts credits back to USD and cents', () => { + expect(comfyCreditsToUsd(1)).toBeCloseTo(2.1) + expect(comfyCreditsToUsd(3.5)).toBeCloseTo(7.35) + expect(comfyCreditsToCents(1)).toBe(210) + expect(comfyCreditsToCents(3.5)).toBeCloseTo(735) + }) + + it('formats credits with localized precision', () => { + expect(formatComfyCreditsAmount(1234.5678)).toBe('1,234.57') + expect( + formatComfyCreditsLabel(1.2345, { + unit: 'credits', + numberOptions: { maximumFractionDigits: 1 } + }) + ).toBe('1.2 credits') + }) + + it('formats ranges and USD strings into credits', () => { + expect(formatComfyCreditsRangeLabelFromUsd(2.1, 4.2)).toBe( + '1.00–2.00 credits' + ) + expect(convertUsdLabelToCredits('$2.10/Run')).toBe('1.00 credits/Run') + expect(convertUsdLabelToCredits('~$2.10-$4.20/Run')).toBe( + '~1.00–2.00 credits/Run' + ) + }) +}) From b23ab6bd23ddddf0f6ef7409215b0445cf65f0b4 Mon Sep 17 00:00:00 2001 From: bymyself Date: Sun, 30 Nov 2025 13:54:20 -0800 Subject: [PATCH 2/2] feat: add comfy credit domain helpers --- src/base/credits/comfyCredits.ts | 242 ++++++------------ src/components/common/UserCredit.vue | 15 +- .../content/credit/CreditTopUpOption.vue | 70 +++-- .../composables/useSubscriptionCredits.ts | 35 +-- .../tests/base/credits/comfyCredits.test.ts | 63 ++--- .../content/credit/CreditTopUpOption.test.ts | 67 +++++ .../components/SubscriptionPanel.test.ts | 10 +- .../useSubscriptionCredits.test.ts | 59 +++-- 8 files changed, 293 insertions(+), 268 deletions(-) create mode 100644 tests-ui/tests/components/dialog/content/credit/CreditTopUpOption.test.ts diff --git a/src/base/credits/comfyCredits.ts b/src/base/credits/comfyCredits.ts index 459b06d961..b2407210ce 100644 --- a/src/base/credits/comfyCredits.ts +++ b/src/base/credits/comfyCredits.ts @@ -1,21 +1,17 @@ -/** - * Fixed conversion rate between USD and Comfy credits. - * 1 credit costs 210 cents ($2.10). - */ -export const COMFY_CREDIT_RATE_CENTS = 210 - -export const COMFY_CREDIT_RATE_USD = COMFY_CREDIT_RATE_CENTS / 100 - const DEFAULT_NUMBER_FORMAT: Intl.NumberFormatOptions = { minimumFractionDigits: 2, maximumFractionDigits: 2 } -const formatNumber = ( - value: number, - options: Intl.NumberFormatOptions = DEFAULT_NUMBER_FORMAT, +const formatNumber = ({ + value, + locale, + options +}: { + value: number locale?: string -) => { + options?: Intl.NumberFormatOptions +}): string => { const merged: Intl.NumberFormatOptions = { ...DEFAULT_NUMBER_FORMAT, ...options @@ -32,166 +28,88 @@ const formatNumber = ( return new Intl.NumberFormat(locale, merged).format(value) } -export const centsToUsd = (cents: number): number => cents / 100 +export const COMFY_CREDIT_RATE_CENTS = 210 +export const COMFY_CREDIT_RATE_USD = COMFY_CREDIT_RATE_CENTS / 100 + export const usdToCents = (usd: number): number => Math.round(usd * 100) -/** - * Converts a USD amount into Comfy credits. - */ -export function usdToComfyCredits(usd: number): number { - return usd / COMFY_CREDIT_RATE_USD -} +export const centsToCredits = (cents: number): number => + cents / COMFY_CREDIT_RATE_CENTS -/** - * Converts USD cents into Comfy credits. - */ -export function centsToComfyCredits(cents: number): number { - return cents / COMFY_CREDIT_RATE_CENTS -} +export const creditsToCents = (credits: number): number => + Math.round(credits * COMFY_CREDIT_RATE_CENTS) -/** - * Converts Comfy credits back to USD. - */ -export function comfyCreditsToUsd(credits: number): number { - return credits * COMFY_CREDIT_RATE_USD -} +export const usdToCredits = (usd: number): number => + centsToCredits(usdToCents(usd)) -/** - * Converts Comfy credits to cents. - */ -export function comfyCreditsToCents(credits: number): number { - return credits * COMFY_CREDIT_RATE_CENTS -} +export const creditsToUsd = (credits: number): number => + creditsToCents(credits) / 100 -export function formatUsdFromCents( - cents: number, - options?: Intl.NumberFormatOptions, +export type FormatOptions = { + value: number locale?: string -): string { - return formatNumber( - centsToUsd(cents), - { ...DEFAULT_NUMBER_FORMAT, ...options }, - locale - ) + numberOptions?: Intl.NumberFormatOptions } -/** - * Formats credits to a localized numeric string (no unit suffix). - */ -export function formatComfyCreditsAmount( - credits: number, - options?: Intl.NumberFormatOptions, +export const formatCredits = ({ + value, + locale, + numberOptions +}: FormatOptions): string => + formatNumber({ value, locale, options: numberOptions }) + +export const formatCreditsFromCents = ({ + cents, + locale, + numberOptions +}: { + cents: number locale?: string -): string { - return formatNumber(credits, { ...DEFAULT_NUMBER_FORMAT, ...options }, locale) -} - -type FormatCreditsOptions = { - unit?: string | null numberOptions?: Intl.NumberFormatOptions +}): string => + formatCredits({ + value: centsToCredits(cents), + locale, + numberOptions + }) + +export const formatCreditsFromUsd = ({ + usd, + locale, + numberOptions +}: { + usd: number locale?: string -} - -export function formatComfyCreditsLabel( - credits: number, - { unit = 'credits', numberOptions, locale }: FormatCreditsOptions = {} -): string { - const formatted = formatComfyCreditsAmount(credits, numberOptions, locale) - return unit ? `${formatted} ${unit}` : formatted -} - -export function formatComfyCreditsLabelFromCents( - cents: number, - options?: FormatCreditsOptions -): string { - return formatComfyCreditsLabel(centsToComfyCredits(cents), options) -} - -export function formatComfyCreditsLabelFromUsd( - usd: number, - options?: FormatCreditsOptions -): string { - return formatComfyCreditsLabel(usdToComfyCredits(usd), options) -} - -export function formatComfyCreditsRangeLabelFromUsd( - minUsd: number, - maxUsd: number, - { - unit = 'credits', - numberOptions, + numberOptions?: Intl.NumberFormatOptions +}): string => + formatCredits({ + value: usdToCredits(usd), locale, - separator = '–' - }: FormatCreditsOptions & { - separator?: string - } = {} -): string { - const min = formatComfyCreditsAmount( - usdToComfyCredits(minUsd), - numberOptions, - locale - ) - const max = formatComfyCreditsAmount( - usdToComfyCredits(maxUsd), - numberOptions, - locale - ) - const joined = `${min}${separator}${max}` - return unit ? `${joined} ${unit}` : joined -} - -const USD_RANGE_REGEX = /(~?)\$(\d+(?:\.\d+)?)\s*[-–]\s*\$?(\d+(?:\.\d+)?)/g -const USD_VALUE_REGEX = /(~?)\$(\d+(?:\.\d+)?)/g - -/** - * Converts a USD-denoted string (e.g., "$0.45-1.2/Run") into a credits string. - * Any "$X" occurrences become "Y credits". Ranges are rendered as "Y–Z credits". - */ -export function convertUsdLabelToCredits( - label: string, - options?: FormatCreditsOptions -): string { - if (!label) return label - const unit = options?.unit ?? 'credits' - const numberOptions = options?.numberOptions - const locale = options?.locale - - const formatSingle = (usd: number) => - formatComfyCreditsLabel(usdToComfyCredits(usd), { - unit, - numberOptions, - locale - }) - - const formatRange = (min: number, max: number, prefix = '') => { - const minStr = formatComfyCreditsAmount( - usdToComfyCredits(min), - numberOptions, - locale - ) - const maxStr = formatComfyCreditsAmount( - usdToComfyCredits(max), - numberOptions, - locale - ) - const joined = `${minStr}–${maxStr}` - return unit ? `${prefix}${joined} ${unit}` : `${prefix}${joined}` - } - - let converted = label - converted = converted.replace( - USD_RANGE_REGEX, - (_match, prefix = '', minUsd, maxUsd) => - formatRange(parseFloat(minUsd), parseFloat(maxUsd), prefix) - ) - - converted = converted.replace( - USD_VALUE_REGEX, - (_match, prefix = '', amount) => { - const formatted = formatSingle(parseFloat(amount)) - return `${prefix}${formatted}` - } - ) - - return converted -} + numberOptions + }) + +export const formatUsd = ({ + value, + locale, + numberOptions +}: FormatOptions): string => + formatNumber({ + value, + locale, + options: numberOptions + }) + +export const formatUsdFromCents = ({ + cents, + locale, + numberOptions +}: { + cents: number + locale?: string + numberOptions?: Intl.NumberFormatOptions +}): string => + formatUsd({ + value: cents / 100, + locale, + numberOptions + }) diff --git a/src/components/common/UserCredit.vue b/src/components/common/UserCredit.vue index aac405b90c..825467dbe5 100644 --- a/src/components/common/UserCredit.vue +++ b/src/components/common/UserCredit.vue @@ -9,7 +9,7 @@
@@ -21,9 +21,10 @@ import Skeleton from 'primevue/skeleton' import Tag from 'primevue/tag' import { computed } from 'vue' +import { useI18n } from 'vue-i18n' +import { formatCreditsFromCents } from '@/base/credits/comfyCredits' import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore' -import { formatMetronomeCurrency } from '@/utils/formatUtil' const { textClass } = defineProps<{ textClass?: string @@ -31,9 +32,15 @@ const { textClass } = defineProps<{ const authStore = useFirebaseAuthStore() const balanceLoading = computed(() => authStore.isFetchingBalance) +const { t, locale } = useI18n() const formattedBalance = computed(() => { - if (!authStore.balance) return '0.00' - return formatMetronomeCurrency(authStore.balance.amount_micros, 'usd') + // Backend returns cents despite the *_micros naming convention. + const cents = authStore.balance?.amount_micros ?? 0 + const amount = formatCreditsFromCents({ + cents, + locale: locale.value + }) + return `${amount} ${t('credits.credits')}` }) diff --git a/src/components/dialog/content/credit/CreditTopUpOption.vue b/src/components/dialog/content/credit/CreditTopUpOption.vue index f134aba5e2..bdca252fec 100644 --- a/src/components/dialog/content/credit/CreditTopUpOption.vue +++ b/src/components/dialog/content/credit/CreditTopUpOption.vue @@ -2,24 +2,36 @@
- - {{ amount }} +
+ + {{ formattedCredits }} +
+
+ {{ formattedCredits }} + {{ formattedUsd }} +
' }, + InputNumber: { + props: ['modelValue'], + emits: ['update:modelValue'], + template: + '' + }, + ProgressSpinner: { template: '
' } + } + } + }) + +describe('CreditTopUpOption', () => { + it('renders converted credit price for preset amounts', () => { + const wrapper = mountOption({ amount: 2.1 }) + expect(wrapper.text()).toContain('1.00 Credits') + expect(wrapper.text()).toContain('$2.10') + }) + + it('updates credit label when editable amount changes', async () => { + const wrapper = mountOption({ editable: true }) + const vm = wrapper.vm as unknown as { customAmount: number } + vm.customAmount = 4.2 + await wrapper.vm.$nextTick() + expect(wrapper.text()).toContain('2.00 Credits') + }) +}) diff --git a/tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts b/tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts index b7bff37a50..5be9f7d80c 100644 --- a/tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts +++ b/tests-ui/tests/platform/cloud/subscription/components/SubscriptionPanel.test.ts @@ -17,9 +17,9 @@ const mockSubscriptionData = { } const mockCreditsData = { - totalCredits: '10.00', - monthlyBonusCredits: '5.00', - prepaidCredits: '5.00', + totalCredits: '10.00 Credits', + monthlyBonusCredits: '5.00 Credits', + prepaidCredits: '5.00 Credits', isLoadingBalance: false } @@ -154,8 +154,8 @@ describe('SubscriptionPanel', () => { describe('credit display functionality', () => { it('displays dynamic credit values correctly', () => { const wrapper = createWrapper() - expect(wrapper.text()).toContain('$10.00') // totalCredits - expect(wrapper.text()).toContain('$5.00') // both monthlyBonus and prepaid + expect(wrapper.text()).toContain('10.00 Credits') + expect(wrapper.text()).toContain('5.00 Credits') }) it('shows loading skeleton when fetching balance', () => { diff --git a/tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts b/tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts index 1d64129a40..5cb17af670 100644 --- a/tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts +++ b/tests-ui/tests/platform/cloud/subscription/composables/useSubscriptionCredits.test.ts @@ -1,9 +1,21 @@ import { createPinia, setActivePinia } from 'pinia' import { beforeEach, describe, expect, it, vi } from 'vitest' +import * as comfyCredits from '@/base/credits/comfyCredits' import { useSubscriptionCredits } from '@/platform/cloud/subscription/composables/useSubscriptionCredits' import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore' +vi.mock('vue-i18n', async (importOriginal) => { + const actual = await importOriginal() + return { + ...actual, + useI18n: () => ({ + t: () => 'Credits', + locale: { value: 'en-US' } + }) + } +}) + // Mock Firebase Auth and related modules vi.mock('vuefire', () => ({ useFirebaseAuth: vi.fn(() => ({ @@ -55,14 +67,6 @@ vi.mock('@/stores/apiKeyAuthStore', () => ({ }) })) -// Mock formatMetronomeCurrency -vi.mock('@/utils/formatUtil', () => ({ - formatMetronomeCurrency: vi.fn((micros: number) => { - // Simple mock that converts micros to dollars - return (micros / 1000000).toFixed(2) - }) -})) - describe('useSubscriptionCredits', () => { let authStore: ReturnType @@ -73,63 +77,62 @@ describe('useSubscriptionCredits', () => { }) describe('totalCredits', () => { - it('should return "0.00" when balance is null', () => { + it('should return "0.00 Credits" when balance is null', () => { authStore.balance = null const { totalCredits } = useSubscriptionCredits() - expect(totalCredits.value).toBe('0.00') + expect(totalCredits.value).toBe('0.00 Credits') }) - it('should return "0.00" when amount_micros is missing', () => { + it('should return "0.00 Credits" when amount_micros is missing', () => { authStore.balance = {} as any const { totalCredits } = useSubscriptionCredits() - expect(totalCredits.value).toBe('0.00') + expect(totalCredits.value).toBe('0.00 Credits') }) it('should format amount_micros correctly', () => { - authStore.balance = { amount_micros: 5000000 } as any + authStore.balance = { amount_micros: 210 } as any const { totalCredits } = useSubscriptionCredits() - expect(totalCredits.value).toBe('5.00') + expect(totalCredits.value).toBe('1.00 Credits') }) it('should handle formatting errors gracefully', async () => { - const mockFormatMetronomeCurrency = vi.mocked( - await import('@/utils/formatUtil') - ).formatMetronomeCurrency - mockFormatMetronomeCurrency.mockImplementationOnce(() => { + const formatSpy = vi.spyOn(comfyCredits, 'formatCreditsFromCents') + formatSpy.mockImplementationOnce(() => { throw new Error('Formatting error') }) - authStore.balance = { amount_micros: 5000000 } as any + authStore.balance = { amount_micros: 210 } as any const { totalCredits } = useSubscriptionCredits() - expect(totalCredits.value).toBe('0.00') + expect(totalCredits.value).toBe('0.00 Credits') + formatSpy.mockRestore() }) }) describe('monthlyBonusCredits', () => { - it('should return "0.00" when cloud_credit_balance_micros is missing', () => { + it('should return "0.00 Credits" when cloud_credit_balance_micros is missing', () => { authStore.balance = {} as any const { monthlyBonusCredits } = useSubscriptionCredits() - expect(monthlyBonusCredits.value).toBe('0.00') + expect(monthlyBonusCredits.value).toBe('0.00 Credits') }) it('should format cloud_credit_balance_micros correctly', () => { - authStore.balance = { cloud_credit_balance_micros: 2500000 } as any + authStore.balance = { cloud_credit_balance_micros: 420 } as any const { monthlyBonusCredits } = useSubscriptionCredits() - expect(monthlyBonusCredits.value).toBe('2.50') + expect(monthlyBonusCredits.value).toBe('2.00 Credits') }) }) describe('prepaidCredits', () => { - it('should return "0.00" when prepaid_balance_micros is missing', () => { + it('should return "0.00 Credits" when prepaid_balance_micros is missing', () => { authStore.balance = {} as any const { prepaidCredits } = useSubscriptionCredits() - expect(prepaidCredits.value).toBe('0.00') + expect(prepaidCredits.value).toBe('0.00 Credits') }) it('should format prepaid_balance_micros correctly', () => { - authStore.balance = { prepaid_balance_micros: 7500000 } as any + authStore.balance = { prepaid_balance_micros: 630 } as any const { prepaidCredits } = useSubscriptionCredits() - expect(prepaidCredits.value).toBe('7.50') + expect(prepaidCredits.value).toBe('3.00 Credits') }) })