mirror of
https://github.com/vernu/textbee.git
synced 2026-07-30 17:07:46 -04:00
The status pill hardcoded a check mark and varied only its colour, so a past_due or canceled subscriber was shown a tick beside the bad news. It also fell back to the label "Active" when the payload carried no status at all, inventing a healthy state on a billing screen. The icon now comes from the status, and an absent status reads "Unknown". formatPrice returned "Free" whenever the currency was missing, even with a real amount. Since the badge only renders when amount > 0, the one case it could produce was a paying customer being shown "Free / monthly". Default the currency instead. The page also derived its usage numbers inline instead of calling deriveUsage, which exists precisely so billing and the dashboard cannot disagree. The inline copy skipped the helper's 0-100 clamp, so the invariant was already broken. Monthly is a rolling 30-day window server-side, not a calendar month, which the dashboard already labels correctly. Billing said "this month", so a user capping out late in the month would wait for a reset that never arrives. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
64 lines
1.9 KiB
TypeScript
64 lines
1.9 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import {
|
|
formatDate,
|
|
formatLimit,
|
|
formatPrice,
|
|
getBillingInterval,
|
|
titleCaseStatus,
|
|
} from './format'
|
|
|
|
describe('formatLimit', () => {
|
|
it('renders -1 as Unlimited', () => {
|
|
expect(formatLimit(-1)).toBe('Unlimited')
|
|
})
|
|
it('renders null/undefined as 0', () => {
|
|
expect(formatLimit(null)).toBe('0')
|
|
expect(formatLimit(undefined)).toBe('0')
|
|
})
|
|
it('thousands-separates numbers', () => {
|
|
expect(formatLimit(100000)).toBe('100,000')
|
|
})
|
|
})
|
|
|
|
describe('formatPrice', () => {
|
|
it('formats cents into a currency string', () => {
|
|
expect(formatPrice(1900, 'usd')).toBe('$19.00')
|
|
})
|
|
it('returns Free only when there is no amount', () => {
|
|
expect(formatPrice(null, null)).toBe('Free')
|
|
})
|
|
|
|
// A real amount with a missing currency used to render as "Free", which put
|
|
// the badge "Free / monthly" in front of paying customers.
|
|
it('falls back to USD rather than claiming a paid plan is free', () => {
|
|
expect(formatPrice(1900, null)).toBe('$19.00')
|
|
expect(formatPrice(1900, '')).toBe('$19.00')
|
|
})
|
|
})
|
|
|
|
describe('getBillingInterval', () => {
|
|
it('maps month to monthly and anything else to yearly', () => {
|
|
expect(getBillingInterval('month')).toBe('monthly')
|
|
expect(getBillingInterval('year')).toBe('yearly')
|
|
expect(getBillingInterval(null)).toBe('')
|
|
})
|
|
})
|
|
|
|
describe('formatDate', () => {
|
|
it('returns N/A for empty values', () => {
|
|
expect(formatDate(null)).toBe('N/A')
|
|
expect(formatDate(undefined)).toBe('N/A')
|
|
})
|
|
it('formats an ISO date', () => {
|
|
expect(formatDate('2026-08-01T00:00:00.000Z')).toMatch(/2026/)
|
|
})
|
|
})
|
|
|
|
describe('titleCaseStatus', () => {
|
|
it('title-cases underscore separated statuses', () => {
|
|
expect(titleCaseStatus('past_due')).toBe('Past Due')
|
|
expect(titleCaseStatus('active')).toBe('Active')
|
|
expect(titleCaseStatus(null)).toBe('')
|
|
})
|
|
})
|