diff --git a/__tests__/components/build/JourneyBar-title-fallback.test.tsx b/__tests__/components/build/JourneyBar-title-fallback.test.tsx new file mode 100644 index 00000000..14a0c0b6 --- /dev/null +++ b/__tests__/components/build/JourneyBar-title-fallback.test.tsx @@ -0,0 +1,52 @@ +// @vitest-environment jsdom +import { describe, it, expect, vi, beforeAll, afterEach } from 'vitest' +import React from 'react' +import { createRoot, type Root } from 'react-dom/client' +import { act } from 'react' + +beforeAll(() => { + ;(globalThis as any).React = React + ;(globalThis as any).IS_REACT_ACT_ENVIRONMENT = true +}) + +vi.mock('next-auth/react', () => ({ useSession: () => ({ data: null }) })) +vi.mock('@/contexts/build-context', () => ({ + useBuild: () => ({ + state: { track: 'company', view: 'thesis', done: {}, auto: false }, + views: ['thesis', 'unmappedFutureView'], + dispatch: vi.fn(), + goView: vi.fn(), + woven: 0, + totalPrimitives: 10, + }), +})) +vi.mock('@/components/build/WorkspaceShell', () => ({ currentActIndex: () => 0 })) + +import { JourneyBar } from '@/components/build/JourneyBar' + +let host: HTMLElement +let root: Root +function render(node: React.ReactElement) { + host = document.createElement('div') + document.body.appendChild(host) + root = createRoot(host) + act(() => { root.render(node) }) +} +afterEach(() => { + act(() => { root?.unmount() }) + host?.remove() + vi.clearAllMocks() +}) + +describe('JourneyBar chip labels (#BLD-08)', () => { + it('shows the plain ARTIFACT_TITLES label, not the raw view id, for a mapped view', () => { + render(React.createElement(JourneyBar)) + expect(host.textContent).toContain('Your business thesis') + expect(host.textContent).not.toContain('>thesis<') + }) + + it('falls back to the raw view id for an unmapped view rather than rendering blank', () => { + render(React.createElement(JourneyBar)) + expect(host.textContent).toContain('unmappedFutureView') + }) +}) diff --git a/__tests__/components/build/JourneyBar.test.tsx b/__tests__/components/build/JourneyBar.test.tsx index f0593381..8baf42c0 100644 --- a/__tests__/components/build/JourneyBar.test.tsx +++ b/__tests__/components/build/JourneyBar.test.tsx @@ -64,16 +64,19 @@ describe('JourneyBar (#BLD-06.1)', () => { }) it('marks a done artifact chip as done, the current one as current', () => { + // #BLD-08 — chips now show the plain ARTIFACT_TITLES label ("Product + // Brief"/"Design System"), not the raw view id, so these lookups match + // the plain text instead of the id. render(React.createElement(JourneyBar)) - const briefChip = Array.from(host.querySelectorAll('.m-crumb')).find((el) => el.textContent === 'brief') as HTMLButtonElement + const briefChip = Array.from(host.querySelectorAll('.m-crumb')).find((el) => el.textContent === 'Product Brief') as HTMLButtonElement expect(briefChip.className).toContain('is-current') - const designChip = Array.from(host.querySelectorAll('.m-crumb')).find((el) => el.textContent === 'design') as HTMLButtonElement + const designChip = Array.from(host.querySelectorAll('.m-crumb')).find((el) => el.textContent === 'Design System') as HTMLButtonElement expect(designChip.className).toContain('is-done') }) it('clicking a done, non-current chip calls goView', () => { render(React.createElement(JourneyBar)) - const designChip = Array.from(host.querySelectorAll('.m-crumb')).find((el) => el.textContent === 'design') as HTMLButtonElement + const designChip = Array.from(host.querySelectorAll('.m-crumb')).find((el) => el.textContent === 'Design System') as HTMLButtonElement act(() => { designChip.click() }) expect(goViewMock).toHaveBeenCalledWith('design') }) diff --git a/__tests__/components/build/no-jargon-strings.test.ts b/__tests__/components/build/no-jargon-strings.test.ts new file mode 100644 index 00000000..fc49f434 --- /dev/null +++ b/__tests__/components/build/no-jargon-strings.test.ts @@ -0,0 +1,43 @@ +import { describe, it, expect } from 'vitest' +import { readFileSync } from 'fs' + +describe('no internal jargon in user-facing copy (#BLD-08)', () => { + it('Pricing.tsx feature list and tagline do not say "agent swarm" / "autonomous loop"', () => { + const content = readFileSync('components/build/screens/Pricing.tsx', 'utf-8') + expect(content).not.toContain('The nightly autonomous loop + real agent swarm') + expect(content).not.toContain('Full agent-swarm autonomy.') + }) + + it('Account.tsx billing copy does not say "swarm" in display strings', () => { + const content = readFileSync('components/build/screens/Account.tsx', 'utf-8') + expect(content).not.toContain('Custom domain, nightly loop & swarm on paid plans.') + expect(content).not.toContain("'agent swarm'") + expect(content).not.toContain('Upgrade to unlock custom domain, nightly loop, and the swarm.') + }) + + it('BuildOverlays.tsx headline/sub-copy do not say "swarm" or the internal "provision everything" phrasing', () => { + const content = readFileSync('components/build/BuildOverlays.tsx', 'utf-8') + expect(content).not.toContain("Cody's swarm is building the MVP") + expect(content).not.toContain('Provision everything, ask nothing') + }) + + it('AutoModePanel.tsx activity line does not say "swarm"', () => { + const content = readFileSync('components/build/AutoModePanel.tsx', 'utf-8') + expect(content).not.toContain('Cody is dispatching the swarm on') + }) + + it('DocumentsPanel.tsx empty-state copy does not say "swarm"', () => { + const content = readFileSync('components/build/DocumentsPanel.tsx', 'utf-8') + expect(content).not.toContain('what the swarm did, metrics, and next actions') + }) + + it('OnboardingVideo.tsx fallback copy does not say "swarm"', () => { + const content = readFileSync('components/build/OnboardingVideo.tsx', 'utf-8') + expect(content).not.toContain("Cody and the swarm.") + }) + + it('LiveTicker.tsx ticker line does not say "swarm"', () => { + const content = readFileSync('components/build/LiveTicker.tsx', 'utf-8') + expect(content).not.toContain('swarm ▸ composing artifacts') + }) +}) diff --git a/__tests__/lib/build/titles-plain-language.test.ts b/__tests__/lib/build/titles-plain-language.test.ts new file mode 100644 index 00000000..1bfb8106 --- /dev/null +++ b/__tests__/lib/build/titles-plain-language.test.ts @@ -0,0 +1,12 @@ +import { describe, it, expect } from 'vitest' +import { ARTIFACT_TITLES } from '@/lib/build/titles' + +describe('ARTIFACT_TITLES — plain language (#BLD-08)', () => { + it('dataModel, memoryPolicy, thesis, wedge no longer use internal jargon', () => { + expect(ARTIFACT_TITLES.dataModel).not.toBe('Data Model') + expect(ARTIFACT_TITLES.memoryPolicy).not.toBe('Memory Policy') + expect(ARTIFACT_TITLES.thesis).not.toBe('Venture Thesis') + expect(ARTIFACT_TITLES.wedge).not.toBe('Initial Wedge') + expect(ARTIFACT_TITLES.dataModel).toMatch(/your|the/i) + }) +}) diff --git a/components/build/AutoModePanel.tsx b/components/build/AutoModePanel.tsx index b76fae33..3a2601dc 100644 --- a/components/build/AutoModePanel.tsx +++ b/components/build/AutoModePanel.tsx @@ -173,7 +173,7 @@ export function AutoModePanel({ companyId, companyName, track = 'company', unloc {progress.dispatchesSoFar} task{progress.dispatchesSoFar === 1 ? '' : 's'} dispatched this run
- Current activity: Cody is dispatching the swarm on {companyName} — briefing → highest-leverage task → ship. + Current activity: Cody's team is working on {companyName} — briefing → highest-leverage task → ship.