diff --git a/src/components/PricingGrid.test.tsx b/src/components/PricingGrid.test.tsx new file mode 100644 index 0000000..4864942 --- /dev/null +++ b/src/components/PricingGrid.test.tsx @@ -0,0 +1,58 @@ +/* PricingGrid.test.tsx — pricing copy regression guards. + * + * BIZ-3 (2026-05-29): the dashboard in-app pricing tile shipped with copy + * inherited from a retired "deployment_size" field on /deploy/new: + * - Hobby tile: "1 small deployment" + * - Pro tile: "50 GB object storage · 10 medium deployments" + * + * The backend handler (api/internal/handlers/deploy.go) has no + * deployment_size field — there are no small/medium/large pod sizes. + * Numbers come from plans.yaml deployments_apps. Marketing PricingPage + * (src/pages/PricingPage.tsx) dropped the size adjectives in the + * 2026-05-20 DOC-REALITY-DELTA sweep; the dashboard surface lagged. + * + * This test pins both strings out of the in-app pricing surface so any + * future copy edit that re-introduces them fails CI before it ships. + */ + +import { describe, it, expect, afterEach } from 'vitest' +import { render, cleanup } from '@testing-library/react' +import { MemoryRouter } from 'react-router-dom' +import { PricingGrid } from './PricingGrid' + +afterEach(() => cleanup()) + +function renderGrid() { + return render( + + {}} + onSelectTier={() => {}} + /> + , + ) +} + +describe('PricingGrid — BIZ-3 deployment copy regression', () => { + it('does not render "small deployment" copy anywhere', () => { + renderGrid() + expect(document.body.textContent ?? '').not.toMatch(/small deployment/i) + }) + + it('does not render "medium deployments" copy anywhere', () => { + renderGrid() + expect(document.body.textContent ?? '').not.toMatch(/medium deployments/i) + }) + + it('Hobby tile says "1 deployment" (matches plans.yaml deployments_apps=1)', () => { + renderGrid() + expect(document.body.textContent ?? '').toContain('1 deployment') + }) + + it('Pro tile says "10 deployments" (matches plans.yaml deployments_apps=10)', () => { + renderGrid() + expect(document.body.textContent ?? '').toContain('10 deployments') + }) +}) diff --git a/src/components/PricingGrid.tsx b/src/components/PricingGrid.tsx index 320296d..30fc552 100644 --- a/src/components/PricingGrid.tsx +++ b/src/components/PricingGrid.tsx @@ -109,7 +109,7 @@ export const PRICING_GRID_TIERS: TierDefinition[] = [ { text: '1 GB Postgres · 8 conn' }, { text: '50 MB Redis' }, { text: '100 MB MongoDB · 5 conn' }, - { text: '1 small deployment' }, + { text: '1 deployment' }, { text: '20 vault entries · production env' }, { text: '1,000 stored webhooks' }, ], @@ -161,7 +161,7 @@ export const PRICING_GRID_TIERS: TierDefinition[] = [ { text: '10 GB Postgres · 20 conn' }, { text: '512 MB Redis' }, { text: '5 GB MongoDB · 20 conn' }, - { text: '50 GB object storage · 10 medium deployments' }, + { text: '50 GB object storage · 10 deployments' }, { text: '200 vault entries · multi-env' }, { text: 'custom domain · 10k stored webhooks' }, ], diff --git a/src/pages/MarketingPage.test.tsx b/src/pages/MarketingPage.test.tsx index 6082df4..d147ba6 100644 --- a/src/pages/MarketingPage.test.tsx +++ b/src/pages/MarketingPage.test.tsx @@ -116,4 +116,21 @@ describe('MarketingPage — claim consistency (T18 P1-4 / P1-6)', () => { expect(text).not.toMatch(/<10s/) expect(text).toMatch(/~60s/) }) + + // BIZ-3 (2026-05-29): the landing pricing tile shipped "1 small deployment" + // and "10 medium deployments" copy from the days when /deploy/new had a + // deployment_size field. The backend dropped that field; marketing + // /pricing dropped the size adjectives in the 2026-05-20 sweep; the + // landing tile lagged. Pin both strings out so a future copy edit can't + // silently re-introduce a contract claim the API doesn't honor. + it('landing pricing tile no longer claims "small / medium" deployment sizes', () => { + const { container } = render( + + + , + ) + const text = container.textContent ?? '' + expect(text).not.toMatch(/small deployment/i) + expect(text).not.toMatch(/medium deployments/i) + }) }) diff --git a/src/pages/MarketingPage.tsx b/src/pages/MarketingPage.tsx index 216aecc..05673ff 100644 --- a/src/pages/MarketingPage.tsx +++ b/src/pages/MarketingPage.tsx @@ -164,7 +164,7 @@ const PLANS: Plan[] = [ features: [ '1 GB Postgres · 8 conn', '50 MB Redis · 100 MB Mongo · 5 conn', - '1 small deployment · *.deployment.instanode.dev', + '1 deployment · *.deployment.instanode.dev', '20 vault entries · production env', ], cta: { label: 'Start hobby →', href: ROUTES.signin, variant: 'secondary' }, @@ -186,7 +186,7 @@ const PLANS: Plan[] = [ features: [ '10 GB Postgres · 20 conn', '512 MB Redis · 5 GB Mongo · 20 conn', - '50 GB object storage · 10 medium deployments · custom domain', + '50 GB object storage · 10 deployments · custom domain', // BugBash P3-08: kept in sync with PricingPage's "Vault envs" row // and the multi-env FAQ — Pro's multi-env is dev/staging/prod. The // earlier "+ custom" claim implied arbitrary named environments the