--- phase: 21-chat-foundation plan: 00 type: execute wave: 0 depends_on: [] files_modified: - server/src/__tests__/chat-service.test.ts - server/src/__tests__/chat-routes.test.ts - ui/src/components/ChatMarkdownMessage.test.tsx - ui/src/components/ChatInput.test.tsx autonomous: true requirements: [HIST-01, CHAT-02, CHAT-03, CHAT-04, CHAT-05, CHAT-06, INPUT-07] must_haves: truths: - "Test stubs exist and can be executed by vitest without errors" - "Each stub has describe blocks with placeholder tests that skip or pass trivially" artifacts: - path: "server/src/__tests__/chat-service.test.ts" provides: "Test scaffold for chat service (HIST-01, CHAT-04, CHAT-05, CHAT-06)" contains: "describe.*chatService" - path: "server/src/__tests__/chat-routes.test.ts" provides: "Test scaffold for chat routes (POST conversation, GET list, POST message)" contains: "describe.*chatRoutes" - path: "ui/src/components/ChatMarkdownMessage.test.tsx" provides: "Test scaffold for markdown rendering (CHAT-02, CHAT-03)" contains: "describe.*ChatMarkdownMessage" - path: "ui/src/components/ChatInput.test.tsx" provides: "Test scaffold for keyboard shortcuts (INPUT-07)" contains: "describe.*ChatInput" key_links: [] --- Create Wave 0 test stubs for the four key test files needed by Plans 01-05. Purpose: Satisfy the Nyquist rule — every implementation task must have a pre-existing test file with describe blocks and placeholder expectations. Plans 01 and 02 depend on these stubs existing before they execute. Output: Four test files with describe/it blocks that vitest can discover and run. @$HOME/.claude/get-shit-done/workflows/execute-plan.md @$HOME/.claude/get-shit-done/templates/summary.md @.planning/PROJECT.md @.planning/ROADMAP.md @.planning/phases/21-chat-foundation/21-RESEARCH.md From server/src/__tests__/activity-routes.test.ts (reference pattern for server tests): ```typescript import express from "express"; import request from "supertest"; import { beforeEach, describe, expect, it, vi } from "vitest"; import { errorHandler } from "../middleware/index.js"; const mockService = vi.hoisted(() => ({ list: vi.fn(), create: vi.fn() })); vi.mock("../services/activity.js", () => ({ activityService: () => mockService })); function createApp() { const app = express(); app.use(express.json()); // ... mock actor middleware } ``` From ui/src/components/MarkdownBody.test.tsx (reference pattern for UI component tests): ```typescript // @vitest-environment node import { describe, expect, it } from "vitest"; import { renderToStaticMarkup } from "react-dom/server"; import { ThemeProvider } from "../context/ThemeContext"; ``` Task 1: Create server-side test stubs (chat-service + chat-routes) server/src/__tests__/chat-service.test.ts, server/src/__tests__/chat-routes.test.ts - server/src/__tests__/activity-routes.test.ts (full file — reference for mock pattern, createApp, supertest usage) Create `server/src/__tests__/chat-service.test.ts`: ```typescript import { describe, it, expect } from "vitest"; describe("chatService", () => { describe("createConversation", () => { it.todo("creates a conversation row with companyId"); it.todo("returns the created conversation with id and timestamps"); }); describe("listConversations", () => { it.todo("returns conversations sorted by updatedAt DESC"); it.todo("excludes soft-deleted conversations"); it.todo("supports cursor-based pagination with hasMore"); it.todo("limits results to max 100"); }); describe("getConversation", () => { it.todo("returns conversation by id"); it.todo("throws notFound for non-existent conversation"); it.todo("throws notFound for soft-deleted conversation"); }); describe("updateConversation", () => { it.todo("updates title"); it.todo("sets pinnedAt timestamp"); it.todo("clears pinnedAt when set to null"); it.todo("sets archivedAt timestamp"); it.todo("bumps updatedAt on every update"); }); describe("softDeleteConversation", () => { it.todo("sets deletedAt timestamp"); it.todo("throws notFound if already deleted"); }); describe("addMessage", () => { it.todo("inserts a message row with conversationId and role"); it.todo("bumps conversation updatedAt after insert"); it.todo("auto-sets title from first user message when title is null"); it.todo("does not overwrite existing title on subsequent messages"); }); describe("listMessages", () => { it.todo("returns messages for conversation sorted by createdAt DESC"); it.todo("supports cursor-based pagination"); }); }); ``` Create `server/src/__tests__/chat-routes.test.ts`: ```typescript import { describe, it, expect } from "vitest"; describe("chatRoutes", () => { describe("POST /companies/:companyId/conversations", () => { it.todo("creates a conversation and returns 201"); it.todo("accepts optional title and agentId"); }); describe("GET /companies/:companyId/conversations", () => { it.todo("returns paginated conversation list"); it.todo("supports cursor query param"); }); describe("GET /conversations/:id", () => { it.todo("returns conversation by id"); it.todo("returns 404 for non-existent conversation"); }); describe("PATCH /conversations/:id", () => { it.todo("updates conversation fields"); }); describe("DELETE /conversations/:id", () => { it.todo("soft-deletes and returns 204"); }); describe("POST /conversations/:id/messages", () => { it.todo("creates a message and returns 201"); it.todo("rejects invalid role"); }); describe("GET /conversations/:id/messages", () => { it.todo("returns paginated message list"); }); }); ``` Both files use `it.todo()` which vitest marks as skipped — they run without error and serve as scaffolds for implementation tasks to fill in. cd /opt/nexus && pnpm vitest run server/src/__tests__/chat-service.test.ts server/src/__tests__/chat-routes.test.ts --reporter=verbose 2>&1 | tail -5 Server test stubs exist with describe/it.todo blocks covering all chatService methods and chatRoutes endpoints. Vitest runs them without error. Task 2: Create UI test stubs (ChatMarkdownMessage + ChatInput) ui/src/components/ChatMarkdownMessage.test.tsx, ui/src/components/ChatInput.test.tsx - ui/src/components/MarkdownBody.test.tsx (reference for UI component test pattern — renderToStaticMarkup, ThemeProvider wrapper) - ui/src/components/IssueRow.test.tsx (reference for component test with RTL if used) Create `ui/src/components/ChatMarkdownMessage.test.tsx`: ```tsx // @vitest-environment node import { describe, it, expect } from "vitest"; describe("ChatMarkdownMessage", () => { describe("markdown rendering (CHAT-02)", () => { it.todo("renders plain text as paragraph"); it.todo("renders code blocks with hljs classes for syntax highlighting"); it.todo("renders GFM tables"); it.todo("renders headings, lists, and links"); }); describe("code block features (CHAT-03)", () => { it.todo("renders language label from code fence"); it.todo("renders copy button with aria-label"); it.todo("extracts code text content for clipboard"); }); }); ``` Create `ui/src/components/ChatInput.test.tsx`: ```tsx // @vitest-environment node import { describe, it, expect } from "vitest"; describe("ChatInput", () => { describe("keyboard shortcuts (INPUT-07)", () => { it.todo("calls onSend when Enter is pressed without Shift"); it.todo("inserts newline when Shift+Enter is pressed"); it.todo("clears input when Escape is pressed"); it.todo("does not send when input is empty"); }); describe("auto-resize (INPUT-01)", () => { it.todo("textarea has max-height constraint"); }); describe("submit state", () => { it.todo("disables send button when isSubmitting is true"); }); }); ``` Both files use `it.todo()` for the same reason as the server stubs. cd /opt/nexus && pnpm vitest run ui/src/components/ChatMarkdownMessage.test.tsx ui/src/components/ChatInput.test.tsx --reporter=verbose 2>&1 | tail -5 UI test stubs exist with describe/it.todo blocks covering ChatMarkdownMessage rendering and ChatInput keyboard shortcuts. Vitest runs them without error. - All four test files exist and vitest discovers them - `pnpm vitest run server/src/__tests__/chat-service.test.ts` exits 0 - `pnpm vitest run server/src/__tests__/chat-routes.test.ts` exits 0 - `pnpm vitest run ui/src/components/ChatMarkdownMessage.test.tsx` exits 0 - `pnpm vitest run ui/src/components/ChatInput.test.tsx` exits 0 - Four test stub files created with describe blocks matching the requirements they cover - Vitest runs all four files without errors (todo tests are skipped, not failed) - Implementation plans (01-05) can reference these files in their verify commands After completion, create `.planning/phases/21-chat-foundation/21-00-SUMMARY.md`