Agent Skills: Test Writer

|

UncategorizedID: Spectaculous-Code/raamattu-nyt/test-writer

Install this agent skill to your local

pnpm dlx add-skill https://github.com/Spectaculous-Code/raamattu-nyt/tree/HEAD/.claude/skills/test-writer

Skill Files

Browse the full folder contents for test-writer.

Download Skill

Loading file tree…

.claude/skills/test-writer/SKILL.md

Skill Metadata

Name
test-writer
Description
|

Test Writer

Write and maintain tests for the Raamattu Nyt monorepo.

Monorepo Test Architecture

Determine workspace first. Before writing or running tests, identify which workspace the code belongs to:

| Workspace | Vitest Config | Test Command | Path Aliases | |-----------|--------------|--------------|--------------| | apps/raamattu-nyt | vite.config.ts (test section) | cd apps/raamattu-nyt && npx vitest run | @/./src, @shared-auth, @ui, etc. | | packages/shared-i18n | vitest.config.ts | cd packages/shared-i18n && npx vitest run | @/integrations/supabase/client → raamattu-nyt client | | packages/* (others) | None yet | Must create vitest.config.ts first | Varies per package |

Root npm test only runs apps/raamattu-nyt tests.

Running Tests

# ALWAYS cd into the workspace directory first
cd apps/raamattu-nyt && npx vitest run src/hooks/useMyHook.test.ts

# For packages with vitest config
cd packages/shared-i18n && npx vitest run src/myUtil.test.ts

# Run all raamattu-nyt tests with coverage
cd apps/raamattu-nyt && npx vitest run --coverage

NEVER run from monorepo root with a path — include patterns are relative to config location. See references/learnings.md.

Test File Conventions

  • Place tests adjacent to source: useHook.tsuseHook.test.ts
  • Use .test.ts for pure logic, .test.tsx for React components/hooks
  • Name: describe("ComponentName") or describe("hookName")

Standard Test Structure

import { describe, expect, it, vi, beforeEach } from "vitest";

// Mocks BEFORE imports (hoisted)
vi.mock("@/integrations/supabase/client", () => ({
  supabase: { rpc: vi.fn() }
}));

// Import module under test AFTER mocks
import { myFunction } from "./myModule";

describe("myFunction", () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it("does expected behavior", () => {
    expect(myFunction()).toBe(expected);
  });
});

Hook Testing Pattern

import { renderHook, waitFor } from "@testing-library/react";

const wrapper = ({ children }) => (
  <AuthProvider>{children}</AuthProvider>
);

it("returns initial state", () => {
  const { result } = renderHook(() => useMyHook(), { wrapper });
  expect(result.current.loading).toBe(true);
});

it("updates on async action", async () => {
  const { result } = renderHook(() => useMyHook(), { wrapper });
  await waitFor(() => {
    expect(result.current.data).toBeDefined();
  });
});

Common Mocks

See references/mocks.md for reusable mock patterns:

  • Supabase client (RPC, auth, schema queries)
  • useAuth hook
  • React Query
  • localStorage

Adding Tests to a New Package

When a package (e.g. packages/shared-recording) needs tests for the first time:

  1. Create vitest.config.ts in the package root:
/// <reference types="vitest" />
import path from "node:path";
import { defineConfig } from "vitest/config";

export default defineConfig({
  test: {
    globals: true,
    environment: "jsdom",
    include: ["src/**/*.{test,spec}.{ts,tsx}"],
  },
  resolve: {
    alias: {
      // Add aliases matching the package's imports
      "@/integrations/supabase/client": path.resolve(
        __dirname, "../../apps/raamattu-nyt/src/integrations/supabase/client.ts"
      ),
    },
  },
});
  1. Add test script to package's package.json:
{ "scripts": { "test": "vitest run" } }
  1. Add test setup if using React Testing Library — create src/test/setup.ts:
import "@testing-library/jest-dom/vitest";

And add setupFiles: ["./src/test/setup.ts"] to the vitest config.

Workflow

  1. Identify workspace — determine which app/package the code belongs to
  2. Check existing testsGlob pattern: <workspace>/**/*.test.{ts,tsx}
  3. Check vitest config — ensure the workspace has one; create if not
  4. Write tests — happy path, errors, edge cases, loading states
  5. Run from workspace dircd <workspace> && npx vitest run src/path/to/file.test.ts

Test Quality Checklist

  • [ ] Tests are independent (no shared state between tests)
  • [ ] Mocks are cleared in beforeEach
  • [ ] Async operations use waitFor not arbitrary delays
  • [ ] Error scenarios are tested
  • [ ] Edge cases covered (null, empty, boundary values)
  • [ ] Tests run from correct workspace directory

IdeaMachina Evolution Tests

For IdeaMachina evolution features (sparks, cores, direction, force), write migration-safe tests that survive the Zustand→Supabase migration.

See references/idea-machina-migration-safe.md for:

  • Data Port Pattern — abstract the store behind an interface so tests swap Zustand↔Supabase with one import change
  • Test fixturesmakeSpark(), makeCore(), makeDirection() factories
  • Component tests — test rendered UI, not store internals
  • Pure logic tests — stage computation, core health, spark filtering (always migration-proof)
  • What NOT to test — avoid persist config, localStorage keys, store version migrations

Quick rule: If a test imports useProjectEvolutionStore directly, consider whether it can test through rendered UI or the data port instead.

Related Skills

| Situation | Delegate To | |-----------|-------------| | Find code to test | code-wizard | | Debug test failures | systematic-debugging | | CI test failures | ci-doctor | | Lint errors in tests | lint-fixer |