用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
直接命令不会经过审查 Prompt;运行前请先检查来源。
npx skills add https://github.com/mkaraivanov/invoice-processor --skill write-tests命令会保持在同一行。复制前请横向滚动并检查完整内容。
想先保存到本地?可下载 SkillsMP 当前能够提供的文件。
Implement a numbered testing strategy phase from docs/testing_strategy_phases/phase_$ARGUMENTS_*.md step by step
Implement a numbered phase from docs/phases/phase-$ARGUMENTS.md step by step
Review changed code for correctness, security, and project conventions. Invoke this skill automatically whenever a complete unit of work is done — a full implementation phase, a complete feature (repository + service + route + component all connected), or just before creating a PR. Do NOT invoke after editing a single file or mid-way through a feature. If the user says "done", "finished", "phase complete", "ready to commit", or similar, trigger this review immediately.
正在显示 SKILL.md
基于 SOC 职业分类
| name | write-tests |
| description | Write Vitest tests for a specified file following the project's 3-project config |
| disable-model-invocation | true |
| argument-hint | [file-path] |
Write Vitest tests for $ARGUMENTS. Read the target file first.
| Source file location | Tier | Test file location | Env |
|---|---|---|---|
src/repositories/** | unit | tests/unit/repositories/ | node |
src/services/** | unit | tests/unit/services/ | node |
src/utils/** | unit | tests/unit/utils/ | node |
src/app/api/** | integration | tests/integration/api/ | node |
src/components/** | components | tests/components/ | jsdom |
src/app/**/page.tsx (Client Components) | components | tests/components/ | jsdom |
Test filename mirrors source: invoice.service.ts → invoice.service.spec.ts
import { describe, it, expect, beforeEach } from 'vitest'
import { invoiceRepository } from '@/repositories/invoice.repository'
import { prisma } from '@/lib/prisma'
import { InvoiceStatus } from '@/app/generated/prisma/client' // ← custom path, not @prisma/client
describe('invoiceRepository', () => {
const testUserId = 'test-user-' + Math.random().toString(36).slice(2)
beforeEach(async () => {
await prisma.invoice.deleteMany({ where: { userId: testUserId } })
})
it('creates and retrieves an invoice', async () => { ... })
it('returns null for a missing id', async () => { ... })
})
Key rules:
DATABASE_URL from .env.test)prisma in repository testsimport { describe, it, expect, vi, beforeEach } from 'vitest'
import { invoiceService } from '@/services/invoice.service'
import { invoiceRepository } from '@/repositories/invoice.repository'
vi.mock('@/repositories/invoice.repository')
describe('invoiceService', () => {
beforeEach(() => vi.clearAllMocks())
it('throws Unauthorized when userId does not match', async () => {
vi.mocked(invoiceRepository.findById).mockResolvedValue({
id: '1', userId: 'owner', ...
})
await expect(
invoiceService.getById('1', 'other-user')
).rejects.toThrow('Unauthorized')
})
})
Key rules:
'Unauthorized'import { GET } from '@/app/api/invoices/route'
import { NextRequest } from 'next/server'
import * as authSvc from '@/services/auth.service'
import * as invoiceSvc from '@/services/invoice.service'
vi.mock('@/services/auth.service')
vi.mock('@/services/invoice.service')
it('returns 401 when unauthenticated', async () => {
vi.mocked(authSvc.authService.getUser).mockResolvedValue(null)
const req = new NextRequest('http://localhost/api/invoices')
const res = await GET(req)
expect(res.status).toBe(401)
})
import { render, screen } from '@testing-library/react'
import { vi } from 'vitest'
import InvoiceList from '@/components/InvoiceList'
vi.mock('next/navigation', () => ({
useRouter: () => ({ push: vi.fn() }),
useParams: () => ({}),
}))
For every method, cover:
Do not write tests that only assert a mock was called — assert observable behavior (return values, thrown errors, rendered text).
npx vitest run <test-file-path>
Fix any failures before marking done.