metatron-open-seo/src/client/features/billing/HostedBillingContentUtils.test.ts
Ben Senescu 570b995248 Refactor billing + onboarding (#61)
* fix: use full page reload after email verification

Client-side navigation via TanStack Router during the auth→app
transition can race with Vite HMR, causing "action is not a function"
server function errors.

* feat: add minimal /subscribe onboarding page

New post-auth subscribe page at /subscribe using the same centered
layout as auth pages. Shows plan details and a single Subscribe CTA.
Redirects PAYMENT_REQUIRED users here instead of /billing.

* redesign: rewrite billing page with usage chart and cleaner layout

Delete the sprawling multi-component billing page and replace it with a
single-file implementation. Two cards sit side by side at the top
(subscription summary + buy credits), with a 30-day usage bar chart
below powered by Autumn's useAggregateEvents hook and recharts.

Removed BillingRouteParts.tsx, HostedBillingContent.tsx, and trimmed
HostedBillingContentUtils to only parseTopUpAmount.

* polish: billing page improvements and OpenSEO nav link

- Two-column layout with subscription summary and buy credits side by side
- Usage bar chart using ResizeObserver instead of ResponsiveContainer
- Input validation with inline error message
- Full-page redirect state when navigating to Stripe
- Make OpenSEO logo in navbar link to /

* fix: guard app routes and include top-up usage

* fix: restore billing onboarding guards

Keep unpaid orgs on /subscribe and avoid misleading billing states when Autumn customer lookups fail.

* fix: split billing usage chart for ci checks
2026-04-08 14:09:01 -04:00

23 lines
819 B
TypeScript

import { describe, expect, it } from "vitest";
import { parseTopUpAmount } from "./HostedBillingContentUtils";
describe("parseTopUpAmount", () => {
it("accepts valid whole-dollar amounts", () => {
expect(parseTopUpAmount("20")).toEqual({ isValid: true, parsed: 20 });
expect(parseTopUpAmount("10")).toEqual({ isValid: true, parsed: 10 });
expect(parseTopUpAmount("99")).toEqual({ isValid: true, parsed: 99 });
});
it("rejects amounts below minimum", () => {
expect(parseTopUpAmount("9")).toEqual({ isValid: false, parsed: 20 });
});
it("rejects amounts above maximum", () => {
expect(parseTopUpAmount("100")).toEqual({ isValid: false, parsed: 20 });
});
it("rejects non-numeric input", () => {
expect(parseTopUpAmount("abc")).toEqual({ isValid: false, parsed: 20 });
});
});