9.3 KiB
| phase | plan | type | wave | depends_on | files_modified | autonomous | requirements | must_haves | |||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 21-chat-foundation | 00 | execute | 0 |
|
true |
|
|
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.
<execution_context> @$HOME/.claude/get-shit-done/workflows/execute-plan.md @$HOME/.claude/get-shit-done/templates/summary.md </execution_context>
@.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`:
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:
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.
// @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:
// @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.
<success_criteria>
- 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 </success_criteria>