一键导入
add-unit-tests
Add unit tests for domain logic, database adapters, API endpoints, or frontend components using Vitest patterns.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Add unit tests for domain logic, database adapters, API endpoints, or frontend components using Vitest patterns.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Implement a backlog story following the layer order (Domain, Database, API, Frontend, E2E) with TDD.
Review the backlog to determine what to work on next by checking epic and story statuses in docs/backlog/.
Automates pre-commit workflow: lint, test, review changes, then commit with conventional commit format.
Verify a story is complete by checking acceptance criteria, running all tests, and updating status.
Add end-to-end Playwright tests for a feature using data-testid selectors, with API and UI test patterns.
Create a new user story in the backlog with technical tasks, test scenarios, and epic integration.
| name | add-unit-tests |
| description | Add unit tests for domain logic, database adapters, API endpoints, or frontend components using Vitest patterns. |
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { MyUseCase } from '../MyUseCase';
import type { MyRepository } from '../../ports/MyRepository';
describe('MyUseCase', () => {
let repo: MyRepository;
let useCase: MyUseCase;
beforeEach(() => {
repo = {
create: vi.fn().mockResolvedValue({ id: '1', name: 'test' }),
findById: vi.fn(),
// ... mock all methods
};
useCase = new MyUseCase(repo);
});
it('should create successfully', async () => {
const result = await useCase.execute({ name: 'test' });
expect(result.id).toBe('1');
});
});
import { describe, it, expect, beforeEach } from 'vitest';
import { sql } from 'drizzle-orm';
import { createTestConnection } from '../../connection';
import { MyAdapter } from '../MyAdapter';
describe('MyAdapter', () => {
let db: DatabaseConnection;
let adapter: MyAdapter;
beforeEach(() => {
db = createTestConnection();
db.run(sql`CREATE TABLE IF NOT EXISTS ...`);
adapter = new MyAdapter(db);
});
});
import { describe, it, expect, vi } from 'vitest';
import { render, screen, fireEvent } from '@testing-library/react';
import { MyWidget } from './MyWidget';
describe('MyWidget', () => {
const defaultProps = {
title: 'Test',
onClick: vi.fn(),
};
it('renders with props', () => {
render(<MyWidget {...defaultProps} />);
expect(screen.getByTestId('my-widget')).toBeDefined();
});
it('calls onClick when clicked', () => {
render(<MyWidget {...defaultProps} />);
fireEvent.click(screen.getByTestId('my-widget-btn'));
expect(defaultProps.onClick).toHaveBeenCalled();
});
});
import { describe, it, expect, vi } from 'vitest';
import { renderHook, waitFor } from '@testing-library/react';
import React from 'react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { useMyHook } from './useMyHook';
vi.mock('../api', () => ({
myApi: { list: vi.fn().mockResolvedValue([]) },
}));
function createWrapper() {
const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } });
return ({ children }: { children: React.ReactNode }) =>
React.createElement(QueryClientProvider, { client: queryClient }, children);
}
describe('useMyHook', () => {
it('fetches data', async () => {
const { result } = renderHook(() => useMyHook(), { wrapper: createWrapper() });
await waitFor(() => expect(result.current.isSuccess).toBe(true));
});
});
// @vitest-environment jsdom
vi.mock('expo-router', () => ({ useRouter: vi.fn() }));
vi.mock('expo-secure-store', () => ({
getItemAsync: vi.fn(), setItemAsync: vi.fn(), deleteItemAsync: vi.fn(),
}));
vi.mock('../api', () => ({
myApi: { list: vi.fn(), create: vi.fn() },
}));
import { renderHook, waitFor } from '@testing-library/react';
import React from 'react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { useMyHook } from './useMyHook';
function createWrapper() {
const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } });
return ({ children }: { children: React.ReactNode }) =>
React.createElement(QueryClientProvider, { client: queryClient }, children);
}
describe('useMyHook', () => {
it('fetches data', async () => {
const { result } = renderHook(() => useMyHook(), { wrapper: createWrapper() });
await waitFor(() => expect(result.current.isSuccess).toBe(true));
});
});
// @vitest-environment jsdom
vi.mock('react-native', () => {
const React = require('react');
return {
View: (props: any) => React.createElement('div', props),
Text: (props: any) => React.createElement('span', props),
Pressable: ({ testID, onPress, children, ...props }: any) =>
React.createElement('div', { 'data-testid': testID, onClick: onPress, ...props }, children),
};
});
vi.mock('@acme/design-system-mobile', () => {
const React = require('react');
return {
Card: ({ children, ...props }: any) => React.createElement('div', props, children),
// ... mock other components
};
});
import { describe, it, expect, vi } from 'vitest';
import { render, screen } from '@testing-library/react';
import React from 'react';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { MyFeature } from './MyFeature';
vi.mock('../api', () => ({
myApi: { list: vi.fn().mockResolvedValue([{ id: '1', name: 'Test' }]) },
}));
function createWrapper() {
const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } });
return ({ children }: { children: React.ReactNode }) =>
React.createElement(QueryClientProvider, { client: queryClient }, children);
}
describe('MyFeature', () => {
it('renders complete feature with real hooks and widgets', () => {
render(<MyFeature />, { wrapper: createWrapper() });
expect(screen.getByTestId('my-feature')).toBeDefined();
});
});