Files
supabase/apps/studio/components/interfaces/Organization/BillingSettings/Subscription/plan-presentation.test.ts
kemal.earth 839c7a9cbb feat(studio): full-screen pricing panel variants (#49640)
## I have read the
[CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md)
file.

YES

## What kind of change does this PR introduce?

Incorporating the parent PR.

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-31 11:53:16 +02:00

107 lines
3.9 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import {
FREE_PLAN_GAPS,
hasPlanGaps,
isFullScreenPresentation,
isParityPresentation,
isPlanChangeEligible,
parsePlanPresentationVariant,
PLAN_PRESENTATION_VARIANTS,
PRO_PLAN_GAPS,
} from './plan-presentation'
import { MANAGED_BY } from '@/lib/constants/infrastructure'
describe('isPlanChangeEligible', () => {
const baseArgs = {
managedBy: 'supabase' as const,
billingPartner: null as string | null | undefined,
currentPlanId: 'free',
canUpdateSubscription: true,
}
it('returns true for a standard free-plan org with billing permissions', () => {
expect(isPlanChangeEligible(baseArgs)).toBe(true)
})
it('returns false for Stripe-managed orgs', () => {
expect(isPlanChangeEligible({ ...baseArgs, managedBy: MANAGED_BY.STRIPE_PROJECTS })).toBe(false)
})
it('returns false for AWS Marketplace orgs', () => {
expect(isPlanChangeEligible({ ...baseArgs, managedBy: MANAGED_BY.AWS_MARKETPLACE })).toBe(false)
})
it('returns false for partner-billed orgs', () => {
expect(isPlanChangeEligible({ ...baseArgs, billingPartner: 'aws_marketplace' })).toBe(false)
})
it('returns false for enterprise plan', () => {
expect(isPlanChangeEligible({ ...baseArgs, currentPlanId: 'enterprise' })).toBe(false)
})
it('returns false for platform plan', () => {
expect(isPlanChangeEligible({ ...baseArgs, currentPlanId: 'platform' })).toBe(false)
})
it('returns false when user cannot update subscription', () => {
expect(isPlanChangeEligible({ ...baseArgs, canUpdateSubscription: false })).toBe(false)
})
it('returns true for pro-plan org with billing permissions', () => {
expect(isPlanChangeEligible({ ...baseArgs, currentPlanId: 'pro' })).toBe(true)
})
})
describe('parsePlanPresentationVariant', () => {
it.each(PLAN_PRESENTATION_VARIANTS)('accepts %s', (variant) => {
expect(parsePlanPresentationVariant(variant)).toBe(variant)
})
it.each([undefined, false, '', 'Fullscreen', 'full-screen', 'fullscreen_gaps'])(
'rejects %o as not in the experiment',
(flag) => {
expect(parsePlanPresentationVariant(flag)).toBeUndefined()
}
)
})
describe('presentation matrix', () => {
// cards, shell, gaps — the three things a variant decides
it.each([
{ variant: 'control', isParity: false, isFullScreen: false, showsGaps: false },
{ variant: 'parity', isParity: true, isFullScreen: false, showsGaps: false },
{ variant: 'gaps', isParity: true, isFullScreen: false, showsGaps: true },
{ variant: 'fullscreen', isParity: true, isFullScreen: true, showsGaps: false },
{ variant: 'fullscreen-gaps', isParity: true, isFullScreen: true, showsGaps: true },
] as const)('$variant', ({ variant, isParity, isFullScreen, showsGaps }) => {
expect(isParityPresentation(variant)).toBe(isParity)
expect(isFullScreenPresentation(variant)).toBe(isFullScreen)
expect(hasPlanGaps(variant)).toBe(showsGaps)
})
it('covers every variant in the experiment', () => {
expect(PLAN_PRESENTATION_VARIANTS).toHaveLength(5)
})
})
describe('gap lists', () => {
it('FREE_PLAN_GAPS includes backups and email support as missing', () => {
const missing = FREE_PLAN_GAPS.filter((g) => g.type === 'missing')
expect(missing.map((g) => g.label)).toContain('Daily backups')
expect(missing.map((g) => g.label)).toContain('Email support')
})
it('FREE_PLAN_GAPS shows log retention as lesser, not missing', () => {
const logRetention = FREE_PLAN_GAPS.find((g) => g.label.includes('log retention'))
expect(logRetention).toBeDefined()
expect(logRetention!.type).toBe('lesser')
})
it('PRO_PLAN_GAPS includes SOC2 and SSO as missing', () => {
const missing = PRO_PLAN_GAPS.filter((g) => g.type === 'missing')
expect(missing.map((g) => g.label)).toContain('SOC2 & ISO 27001')
expect(missing.map((g) => g.label)).toContain('SSO for Supabase Dashboard')
})
})