From c4aa768a033d328f41d0920c9e19fdaaa2469d1f Mon Sep 17 00:00:00 2001 From: Manas Srivastava Date: Fri, 29 May 2026 13:58:51 +0530 Subject: [PATCH] fix(pricing): drop "small/medium deployment" size adjectives from dashboard + landing tiles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BIZ-3 (QA backlog, P1). The dashboard in-app PricingGrid and the landing pricing tile both shipped copy inherited from a retired deployment_size field on POST /deploy/new: - Hobby tile: "1 small deployment" - Pro tile: "50 GB object storage · 10 medium deployments" The API 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 /pricing (PricingPage.tsx) dropped the size adjectives in the 2026-05-20 DOC-REALITY-DELTA sweep; the dashboard PricingGrid and the landing MarketingPage tile lagged. This PR matches the voice that marketing /pricing already ships: - Hobby: "1 deployment" - Pro: "50 GB object storage · 10 deployments" Regression coverage: - PricingGrid.test.tsx: 4 assertions pinning the new copy and pinning both retired strings out of the rendered DOM. - MarketingPage.test.tsx: adds the same negative assertions to the landing-tile suite. Surface checklist (CLAUDE.md rule 22): contract-aligned pricing copy already in plans.yaml + common/plans + openapi + content/llms.txt + the marketing PricingPage; this PR brings the dashboard PricingGrid and the landing MarketingPage tile in line with the rest. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/components/PricingGrid.test.tsx | 58 +++++++++++++++++++++++++++++ src/components/PricingGrid.tsx | 4 +- src/pages/MarketingPage.test.tsx | 17 +++++++++ src/pages/MarketingPage.tsx | 4 +- 4 files changed, 79 insertions(+), 4 deletions(-) create mode 100644 src/components/PricingGrid.test.tsx 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