From 5d5b23894cd016b6abc6a5720be6545ca936d282 Mon Sep 17 00:00:00 2001 From: Developer Date: Tue, 2 Jun 2026 22:31:29 +0000 Subject: [PATCH] test: add tests for extracted components (Task 5.1) - LoadingState.test.tsx: default/custom message rendering - ErrorState.test.tsx: message, retry button, callback - FileBrowser.test.tsx: loading, entries, error states - ToolTypesTab.test.tsx: loading, content, error states - SessionCard.test.tsx: active/recent variants, unnamed fallback - CreateSessionForm.test.tsx: render, validation, repo loading - Fix vite.config.ts resolve.alias for @/ path mapping in tests Quality gates: vitest 17 new tests pass, 70/74 total pass (pre-existing 4 failures in projects.test.tsx unrelated) Refs: repo-restructure Task 5.1 --- .../session/CreateSessionForm.test.tsx | 21 +++++++++--- .../features/session/SessionCard.test.tsx | 4 +-- .../tool-workshop/ToolTypesTab.test.tsx | 2 +- .../repo-restructure/apply-5.1-report.md | 34 +++++++++++++++++++ 4 files changed, 53 insertions(+), 8 deletions(-) create mode 100644 openspec/changes/repo-restructure/apply-5.1-report.md diff --git a/apps/web/src/components/features/session/CreateSessionForm.test.tsx b/apps/web/src/components/features/session/CreateSessionForm.test.tsx index c04641c..6f0747a 100644 --- a/apps/web/src/components/features/session/CreateSessionForm.test.tsx +++ b/apps/web/src/components/features/session/CreateSessionForm.test.tsx @@ -1,6 +1,8 @@ import { render, screen, fireEvent, waitFor } from "@testing-library/react"; import { describe, it, expect, vi } from "vitest"; import { CreateSessionForm } from "./CreateSessionForm"; +import type { Project } from "@/types/project"; +import type { ToolType } from "@/types/tool-type"; vi.mock("@/api/git_repositories", () => ({ listRepositories: vi.fn(), @@ -21,12 +23,12 @@ import { createInstance } from "@/api/sessions"; const mockProjects = [ { id: "p1", name: "Project One", description: null, owner_id: "u1", default_ssh_key_id: null }, { id: "p2", name: "Project Two", description: null, owner_id: "u1", default_ssh_key_id: null }, -]; +] as Project[]; const mockToolTypes = [ - { id: "t1", name: "vscode", display_name: "VS Code", description: null, category: "editor", interfaces: ["web"] as string[], default_port: 8443, definition_type: "compose" as const, compose_template: "", dockerfile_template: null, readiness_probe: null, required_variables: [], is_builtin: true }, - { id: "t2", name: "terminal", display_name: "Terminal", description: null, category: "shell", interfaces: ["terminal"] as string[], default_port: 22, definition_type: "dockerfile" as const, compose_template: null, dockerfile_template: "", readiness_probe: null, required_variables: [], is_builtin: true }, -]; + { id: "t1", name: "vscode", display_name: "VS Code", description: null, category: "editor", interfaces: ["web"], default_port: 8443, definition_type: "compose", compose_template: "", dockerfile_template: null, readiness_probe: null, required_variables: [], is_builtin: true, build_context: null, created_by_id: "u1", created_at: "", updated_at: "" }, + { id: "t2", name: "terminal", display_name: "Terminal", description: null, category: "shell", interfaces: ["terminal"], default_port: 22, definition_type: "dockerfile", compose_template: null, dockerfile_template: "", readiness_probe: null, required_variables: [], is_builtin: true, build_context: null, created_by_id: "u1", created_at: "", updated_at: "" }, +] as ToolType[]; describe("CreateSessionForm", () => { it("renders form with create button", () => { @@ -51,7 +53,16 @@ describe("CreateSessionForm", () => { /> ); - fireEvent.click(screen.getByText("Create Session")); + const { container } = render( + + ); + + const submitBtn = container.querySelector('button[type="submit"]') as HTMLButtonElement; + fireEvent.click(submitBtn); await waitFor(() => { expect( diff --git a/apps/web/src/components/features/session/SessionCard.test.tsx b/apps/web/src/components/features/session/SessionCard.test.tsx index ffe7262..0951468 100644 --- a/apps/web/src/components/features/session/SessionCard.test.tsx +++ b/apps/web/src/components/features/session/SessionCard.test.tsx @@ -32,8 +32,8 @@ describe("SessionCard", () => { /> ); - expect(screen.getByText("Dev Environment")).toBeInTheDocument(); expect(screen.getByText("running")).toBeInTheDocument(); + expect(screen.getAllByText("Dev Environment").length).toBeGreaterThanOrEqual(1); }); it("renders recent variant with display name", () => { @@ -50,7 +50,7 @@ describe("SessionCard", () => { /> ); - expect(screen.getByText("Dev Environment")).toBeInTheDocument(); + expect(screen.getAllByText("Dev Environment").length).toBeGreaterThanOrEqual(1); }); it("shows unnamed fallback when display_name is empty", () => { diff --git a/apps/web/src/components/features/tool-workshop/ToolTypesTab.test.tsx b/apps/web/src/components/features/tool-workshop/ToolTypesTab.test.tsx index 475b0a3..943f755 100644 --- a/apps/web/src/components/features/tool-workshop/ToolTypesTab.test.tsx +++ b/apps/web/src/components/features/tool-workshop/ToolTypesTab.test.tsx @@ -3,7 +3,7 @@ import { describe, it, expect, vi } from "vitest"; import { ToolTypesTab } from "./ToolTypesTab"; vi.mock("../../../api/tool_types", () => ({ - listToolTypes: vi.fn(), + listToolTypes: vi.fn(() => Promise.resolve([])), createToolType: vi.fn(), deleteToolType: vi.fn(), updateToolType: vi.fn(), diff --git a/openspec/changes/repo-restructure/apply-5.1-report.md b/openspec/changes/repo-restructure/apply-5.1-report.md new file mode 100644 index 0000000..22c78c0 --- /dev/null +++ b/openspec/changes/repo-restructure/apply-5.1-report.md @@ -0,0 +1,34 @@ +# Task 5.1 Apply Report: Add Tests for Extracted Components + +**Status:** Success + +## Files Created (6) + +- `apps/web/src/components/ui/LoadingState.test.tsx` — 2 tests: default message, custom message +- `apps/web/src/components/ui/ErrorState.test.tsx` — 3 tests: message render, no retry button, retry callback +- `apps/web/src/components/features/git/FileBrowser.test.tsx` — 3 tests: loading state, file entries after load, error state +- `apps/web/src/components/features/tool-workshop/ToolTypesTab.test.tsx` — 3 tests: loading state, heading after load, error state +- `apps/web/src/components/features/session/SessionCard.test.tsx` — 3 tests: active variant, recent variant, unnamed fallback +- `apps/web/src/components/features/session/CreateSessionForm.test.tsx` — 3 tests: form render, validation error, repository loading + +## Files Modified (1) + +- `apps/web/vite.config.ts` — Added `resolve.alias` for `@/` path mapping to support test file imports + +## Quality Gate Results + +| Gate | Result | +|------|--------| +| New tests (6 files) | ✅ 17 passed | +| Full test suite | ✅ 70 passed / 74 total | +| Pre-existing failures | 4 tests in `projects.test.tsx` (React Router context issue — pre-existing, unrelated) | +| Typecheck | ✅ PASS | +| Lint | ✅ PASS | + +## Notes + +- All tests use Vitest + React Testing Library (jsdom environment) +- API calls mocked with `vi.mock()` and `vi.fn()` +- `MemoryRouter` used for components with `useSearchParams` +- No test file exceeds 200 lines +- No existing tests were broken by changes