agents-standards
Standards for authoring SDD plugin agents — frontmatter, self-containment, skill references, and no-user-interaction rules.
Unit testing patterns with Vitest - mocking, fixtures, isolation, and fast feedback.
Claude Code
$ npx -y skills add LiorCohen/sdd --skill unit-testing --agent claude-code
Codex
$ npx skills add LiorCohen/sdd --skill unit-testing -a codex -y
Cursor
$ npx skills add LiorCohen/sdd --skill unit-testing -a cursor -y
Gemini CLI
$ npx skills add LiorCohen/sdd --skill unit-testing -a gemini-cli -y
GitHub Copilot
$ npx skills add LiorCohen/sdd --skill unit-testing -a github-copilot -y
OpenCode
$ npx skills add LiorCohen/sdd --skill unit-testing -a opencode -y
Windsurf
$ npx skills add LiorCohen/sdd --skill unit-testing -a windsurf -y
name: unit-testing description: Unit testing patterns with Vitest - mocking, fixtures, isolation, and fast feedback. user-invocable: false
Fast, isolated tests that verify individual functions and modules. Unit tests run in the CI runner (not Kubernetes) for rapid feedback.
---
| Aspect | Details | |--------|---------| | Location | `components/*/src/**/*.test.ts` | | Framework | Vitest | | Runs In | CI runner (fast feedback) | | Written By | Implementors (alongside their code) |
---
Place test files next to the code they test:
src/model/use-cases/ ├── create_user.ts ├── create_user.test.ts # Unit test for create_user ├── update_user.ts └── update_user.test.ts
// src/model/use-cases/create_user.test.ts
import { describe, it, expect } from 'vitest';
import { createUser } from './create_user';
import type { Dependencies } from '../dependencies';
/**
* @spec changes/user-management/SPEC.md
* @issue PROJ-123
*/
describe('createUser', () => {
describe('AC1: Valid user creation', () => {
it('creates user when email is unique', async () => {
// Arrange (Given)
const mockDeps = createMockDependencies();
const args = { email: 'test@example.com', name: 'Test User' };
// Act (When)
const result = await createUser(mockDeps, args);
// Assert (Then)
expect(result.success).toBe(true);
if (result.success) {
expect(result.user.email).toBe('test@example.com');
}
});
});
});---
For functions that receive dependencies as the first argument (CMDO pattern):
import type { Dependencies } from '../dependencies';
const createMockDependencies = (overrides?: Partial<Dependencies>): Dependencies => ({
findUserByEmail: async () => null,
findUserById: async () => null,
insertUser: async (data) => ({ id: 'mock-id', ...data, createdAt: new Date() }),
updateUser: async (id, data) => ({ id, ...data, updatedAt: new Date() }),
...overrides,
});
// Usage in tests
it('returns error when email exists', async () => {
const deps = createMockDependencies({
findUserByEmail: async () => ({ id: '123', email: 'exists@test.com', name: 'Existing' }),
});
const result = await createUser(deps, { email: 'exists@test.com', name: 'New' });
expect(result.success).toBe(false);
});For tracking calls and controlling return values:
import { describe, it, expect, vi } from 'vitest';
it('calls insertUser with correct data', async () => {
const insertUser = vi.fn().mockResolvedValue({ id: '123', email: 'test@example.com' });
const deps = createMockDependencies({ insertUser });
await createUser(deps, { email: 'test@example.com', name: 'Test' });
expect(insertUser).toHaveBeenCalledOnce();
expect(insertUser).toHaveBeenCalledWith(
expect.objectContaining({ email: 'test@example.com' })
);
});For mocking entire modules (use sparingly):
import { vi } from 'vitest';
vi.mock('../services/email', () => ({
sendEmail: vi.fn().mockResolvedValue({ sent: true }),
}));
import { sendEmail } from '../services/email';
it('sends welcome email after user creation', async () => {
await createUserWithWelcomeEmail(deps, { email: 'new@test.com' });
expect(sendEmail).toHaveBeenCalledWith(
expect.objectContaining({ to: 'new@test.com', template: 'welcome' })
);
});---
Create reusable factories for test data:
// src/__tests__/fixtures/user.ts
import type { User } from '../../types/generated';
export const createTestUser = (overrides?: Partial<User>): User => ({
id: 'test-user-id',
email: 'test@example.com',
name: 'Test User',
role: 'planner',
clientId: 'test-client',
createdAt: new Date('2026-01-01'),
updatedAt: new Date('2026-01-01'),
...overrides,
});
// Usage
it('formats user display name', () => {
const user = createTestUser({ name: 'John Doe' });
expect(formatDisplayName(user)).toBe('John Doe');
});
it('uses email when name is empty', () => {
const user = createTestUser({ name: '', email: 'john@example.com' });
expect(formatDisplayName(user)).toBe('john');
});// src/__tests__/fixtures/constants.ts
export const TEST_USER_ID = 'test-user-123';
export const TEST_CLIENT_ID = 'test-client-456';
export const TEST_EMAIL = 'test@example.com';
export const VALID_CREDENTIALS = {
email: TEST_EMAIL,
password: 'ValidPass123!',
};
export const INVALID_CREDENTIALS = {
email: TEST_EMAIL,
password: 'wrong',
};---
import { describe, it, beforeEach, afterEach, vi } from 'vitest';
describe('userService', () => {
beforeEach(() => {
vi.clearAllMocks();
});
afterEach(() => {
vi.restoreAllMocks();
});
// Tests run in isolation
});// BAD: Shared mutable state
let testUser = { id: '1', name: 'Test' };
it('test 1', () => {
testUser.name = 'Modified'; // Affects other tests!
});
// GOOD: Create fresh data per test
it('test 1', () => {
const testUser = createTestUser();
// Modifications don't affect other tests
});import { vi, beforeEach, afterEach } from 'vitest';
describe('time-dependent tests', () => {
beforeEach(() => {
vi.useFakeTimers();
vi.setSystemTime(new Date('2026-01-15T10:00:00Z'));
});
afterEach(() => {
vi.useRealTimers();
});
it('calculates expiration correctly', () => {
const token = createToken({ expiresIn: '1h' });
expect(token.expiresAt).toEqual(new Date('2026-01-15T11:00:00Z'));
});
});---
it('handles async operaStructure for AI-assisted development AI coding assistants are powerful but chaotic. You prompt, you get code, but then what?
Standards for authoring SDD plugin agents — frontmatter, self-containment, skill references, and no-user-interaction rules.
Standards for authoring SDD plugin commands — frontmatter, user interaction, skill/agent invocation, CLI integration, and output…
Create a commit following repository guidelines with proper versioning and changelog updates.
Two-step self-review at every task lifecycle phase. Step 1 (this skill) runs in-context to gather session signals — files read vs…
D2 diagramming language reference for architecture diagrams, sequence diagrams, grid layouts, SQL tables, and class diagrams.…
Writes and maintains user-facing documentation for the SDD plugin. Proactively detects when docs are out of sync with plugin…
You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…
Ask which skill or flow fits your situation. A router over the skills in this repo.