Files
zeekay 6c65e3e941 @hanzo/app 0.2.0: the app SDK, renamed from @hanzo/rooms
Every import, the catalog pin and the docs name @hanzo/app and
github.com/hanzoai/app. lib/rooms.ts is lib/app.ts and
components/rooms.tsx is components/app.tsx.
2026-10-22 19:07:20 -07:00

58 lines
2.5 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { test, expect } from '@playwright/test'
import { charge, quote, saving, term, type SubscriptionPlan } from '@hanzo/app/lib/plans'
/**
* A PLAN'S TERM, PRICED FROM WHAT THE CATALOG STATES.
*
* The package states a year's charge (`annualTotal`) and the button quotes it.
* The live catalog states only `priceAnnual`, a year shown per month, and the button
* quotes that figure rather than a total made up from it. The saving is
* 1 − year ÷ (12 × month) either way, and a year reaches checkout as
* `interval=year` on whatever address checkout has.
*/
const row = (p: Partial<SubscriptionPlan>): SubscriptionPlan => ({
id: 'dev',
name: 'Pro',
description: '',
priceMonthly: null,
category: 'personal',
features: [],
...p,
})
test('a year the catalog states is quoted as its total, and the saving is computed from it', () => {
const plan = row({ priceMonthly: 20, priceAnnual: 16.67, annualTotal: 200 })
expect(quote(plan, 'month')).toBe('$20/month')
expect(quote(plan, 'year')).toBe('$200/year')
expect(charge(plan, 'year')).toBe(200)
expect(saving(plan)).toBe(Math.round((1 - 200 / (12 * 20)) * 100))
})
test('a year stated only per month is quoted per month, and saves what twelve of it save', () => {
const plan = row({ priceMonthly: 19, priceAnnual: 15.58 })
expect(quote(plan, 'year')).toBe('$15.58/month, billed yearly')
expect(charge(plan, 'year')).toBe(186.96)
expect(saving(plan)).toBe(Math.round((1 - 186.96 / (12 * 19)) * 100))
})
test('a plan with no year sells no year', () => {
const plan = row({ priceMonthly: 20 })
expect(quote(plan, 'year')).toBeNull()
expect(charge(plan, 'year')).toBeNull()
expect(saving(plan)).toBeNull()
expect(saving(row({ priceMonthly: 20, annualTotal: 240 })), 'a year that saves nothing is not offered').toBeNull()
})
test('a year reaches checkout as interval=year, keeping the query and the fragment', () => {
const cart = 'https://hanzo.ai/pay/?plan=dev&returnUrl=https%3A%2F%2Fhanzo.ai%2Fchat#pricing'
expect(term(cart, 'month')).toBe(cart)
const year = new URL(term(cart, 'year'))
expect(`${year.host}${year.pathname}`).toBe('hanzo.ai/pay/')
expect(year.searchParams.get('plan')).toBe('dev')
expect(year.searchParams.get('returnUrl')).toBe('https://hanzo.ai/chat')
expect(year.searchParams.get('interval')).toBe('year')
expect(year.hash).toBe('#pricing')
expect(new URL(term('/checkout?plan=dev', 'year')).host, 'a relative address is on the site the checkout is').toBe('hanzo.ai')
})