/** * Component tests for PlanGate — the client half of the plan-gating feature * (the server half, requirePlan middleware, is covered from the root repo's * template suite). No template page uses it — it exists for template users — * so this test is also what keeps it from registering as dead code. */ import { render, screen } from '@testing-library/react'; import { describe, expect, it, vi } from 'vitest'; import { PlanGate } from '@/components/PlanGate'; const useSubscriptionMock = vi.hoisted(() => vi.fn()); vi.mock('@/hooks/api', () => ({ useSubscription: useSubscriptionMock })); function stubPlan(planId: 'free' | 'starter' | 'pro', isActive: boolean) { useSubscriptionMock.mockReturnValue({ planId, isActive }); } describe('PlanGate', () => { it('renders children when the active plan meets the requirement', () => { stubPlan('pro', true); render( secret feature ); expect(screen.getByText('secret feature')).toBeDefined(); }); it('renders the fallback when the active plan is below the requirement', () => { stubPlan('starter', true); render( upgrade prompt}> secret feature ); expect(screen.queryByText('secret feature')).toBeNull(); expect(screen.getByText('upgrade prompt')).toBeDefined(); }); it('renders nothing (null fallback) when gated with no fallback provided', () => { stubPlan('free', true); const { container } = render( secret feature ); expect(container.textContent).toBe(''); }); it('treats an inactive subscription as free tier: gates paid, allows free', () => { stubPlan('pro', false); // stale plan id, subscription lapsed render( gated}> paid ); expect(screen.getByText('gated')).toBeDefined(); stubPlan('pro', false); render( free content ); expect(screen.getByText('free content')).toBeDefined(); }); });