// "Apply code quality standards for testing, coverage, CI/CD, and automation: Vitest, coverage philosophy, git hooks, GitHub Actions, quality gates. Use when setting up testing, configuring CI, discussing quality practices, or reviewing automation."
| name | code-quality-standards |
| description | Apply code quality standards for testing, coverage, CI/CD, and automation: Vitest, coverage philosophy, git hooks, GitHub Actions, quality gates. Use when setting up testing, configuring CI, discussing quality practices, or reviewing automation. |
Standards and practices for maintaining high code quality through testing, automation, and continuous integration.
Default test runner for all projects.
Why Vitest:
Setup:
pnpm add -D vitest @testing-library/react @testing-library/jest-dom
Basic test structure:
import { describe, it, expect } from 'vitest'
describe('Module Name', () => {
it('should do something', () => {
expect(result).toBe(expected)
})
})
Don't chase arbitrary percentage targets.
โ "We need 80% coverage" โ "This file has low coverage, add more tests" โ Testing implementation details to hit coverage goals โ Writing tests just to make coverage numbers green
โ Test module boundaries (inputs โ outputs)
โ Test critical paths and edge cases
โ Skip testing implementation details
โ Coverage as diagnostic, not goal
Focus on new code, not absolute project coverage.
GitHub Actions Setup (zero external services):
# .github/workflows/test.yml
- uses: davelosert/vitest-coverage-report-action@v2
with:
file-coverage-mode: changes # Only show changed files
Standards:
PR Comments: Automatic via GitHub Action, no Codecov needed
Why Codecov:
Configuration:
# .codecov.yml
coverage:
status:
project:
default:
target: auto # Maintain current coverage
threshold: 5% # Allow 5% decrease
What to test:
Example:
// โ
Good unit test
it('should format currency correctly', () => {
expect(formatCurrency(1234.56)).toBe('$1,234.56')
})
What to test:
Example:
// โ
Good integration test
it('should submit form and show success message', async () => {
render(<ContactForm />)
await userEvent.type(screen.getByLabelText('Email'), 'test@example.com')
await userEvent.click(screen.getByRole('button', { name: 'Submit' }))
expect(await screen.findByText('Success!')).toBeInTheDocument()
})
What to test:
NOT every feature needs E2E.
Example:
// โ
Good E2E test
test('user can sign up and create first project', async ({ page }) => {
await page.goto('/signup')
await page.fill('input[name="email"]', 'user@example.com')
await page.click('button:has-text("Sign Up")')
await page.waitForURL('/projects')
await page.click('button:has-text("New Project")')
await expect(page.locator('h1')).toContainText('New Project')
})
Purpose: Fast feedback before committing/pushing code.
Run on every commit (fast checks only):
{
"simple-git-hooks": {
"pre-commit": "pnpm lint-staged"
}
}
{
"lint-staged": {
"*.{ts,tsx}": [
"eslint --fix",
"prettier --write"
],
"*.{ts,tsx}": "tsc-files --noEmit"
}
}
What it does:
Why staged files only:
Run before pushing (comprehensive checks):
{
"simple-git-hooks": {
"pre-push": "pnpm test:ci"
}
}
{
"scripts": {
"test:ci": "vitest run --coverage"
}
}
What it does:
Why pre-push:
git push --no-verify)Option 1: simple-git-hooks
Option 2: Husky
Either is fine โ consistency matters more than choice.
Every PR must pass these checks:
# .github/workflows/ci.yml
name: CI
on: [pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
- uses: actions/setup-node@v4
with:
node-version: 22
cache: 'pnpm'
- run: pnpm install --frozen-lockfile
- run: pnpm lint
- run: pnpm type-check
- run: pnpm test:ci
- run: pnpm build
- uses: codecov/codecov-action@v3
with:
files: ./coverage/coverage-final.json
Checks:
PR can only merge when:
โ All CI checks pass โ Coverage not significantly decreased (Codecov check) โ No new TypeScript errors introduced โ At least 1 approval (for team projects) โ No merge conflicts
Enforce via GitHub branch protection rules:
pnpm add -D vitest @testing-library/react @testing-library/jest-dom
pnpm add -D @vitest/coverage-v8 # For coverage
// vitest.config.ts
import { defineConfig } from 'vitest/config'
export default defineConfig({
test: {
globals: true,
environment: 'jsdom',
setupFiles: './test/setup.ts',
coverage: {
provider: 'v8',
reporter: ['text', 'json', 'html'],
},
},
})
pnpm add -D simple-git-hooks lint-staged
// package.json
{
"simple-git-hooks": {
"pre-commit": "pnpm lint-staged",
"pre-push": "pnpm test:ci"
},
"lint-staged": {
"*.{ts,tsx}": ["eslint --fix", "prettier --write", "tsc-files --noEmit"]
}
}
# Initialize hooks
pnpm simple-git-hooks
{
"scripts": {
"test": "vitest",
"test:ci": "vitest run --coverage",
"lint": "eslint .",
"type-check": "tsc --noEmit"
}
}
Create .github/workflows/ci.yml with required checks (see above).
Create .codecov.yml with coverage thresholds (see above).
Quality is not a checklist โ it's a habit.
Automation ensures baseline quality, but doesn't replace:
Tests verify the code does what you intended. They don't verify you intended the right thing.
Use these tools to catch regressions and maintain standards. Use your judgment to build the right thing.