Running Tests & CI/CD Integration
Local Test Execution
Basic Commands
# Run all tests once
npm run test
# Run tests in watch mode (re-run on file changes)
npm run test:watch
# Run tests with UI dashboard
npm run test:ui
# Run tests with coverage report
npm run test:coverage
# Debug tests (Node inspector)
npm run test:debugFiltering Tests
# Run only specific file
npm run test ProductService.test.ts
# Run tests matching pattern
npm run test -- --grep "should create"
# Run only unit tests
npm run test -- --grep "Unit"
# Run only integration tests
npm run test -- --grep "Integration"
# Run tests in specific directory
npm run test src/__tests__/api/Test Modes
# Watch mode with specific reporter
npm run test:watch -- --reporter=verbose
# Run once, exit on first failure
npm run test -- --bail
# Run with reporter UI
npm run test -- --ui
# Run with browser console
npm run test -- --inspect-brkCI/CD Integration
GitHub Actions Workflow
File:
.github/workflows/test.yml
name: Tests
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18.x, 20.x]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run linter
run: npm run lint
- name: Run tests
run: npm run test:coverage
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
files: ./coverage/coverage-final.json
flags: unittests
name: codecov-umbrella
fail_ci_if_error: true
- name: Comment PR with coverage
if: github.event_name == 'pull_request'
uses: romeovs/lcov-reporter-action@v0.3.1
with:
lcov-file: ./coverage/lcov.info
- name: Build application
run: npm run build
- name: Archive test results
if: always()
uses: actions/upload-artifact@v3
with:
name: coverage
path: coverage/
retention-days: 30Test Output Examples
Standard Output
$ npm run test
β src/__tests__/api/ProductService.test.ts (40)
β src/__tests__/api/auth.test.ts (20)
β src/__tests__/api/client.test.ts (30)
β src/__tests__/services/hooks/useProducts.test.ts (25)
β src/__tests__/services/hooks/useForm.test.ts (30)
β src/__tests__/components/Buttons.test.tsx (15)
β src/__tests__/components/Header.test.tsx (20)
β src/__tests__/components/pages/LoginPage.test.tsx (20)
β src/__tests__/integration/productWorkflow.test.ts (12)
607 tests passed (8.2s)
Coverage: 82%Watch Mode
$ npm run test:watch
PASS src/__tests__/api/ProductService.test.ts
PASS src/__tests__/services/hooks/useProducts.test.ts
FAIL src/__tests__/components/Header.test.tsx
β Header (1)
β renders with user menu (1)
β TypeError: Cannot read property 'toBeInTheDocument' of undefined
Test Files 3 passed + 1 failed (4)
Tests 607 passed + 1 failed (608)
Rerun with -t Header to filter testsCoverage Report
$ npm run test:coverage
ββββββββββββββββββββββββββββββββββββββββββββ
File | % Stmts | % Branch | % Funcs | % Lines |
ββββββββββββββββββββββββββββββββββββββββββββ
All files | 82.2 | 77.8 | 81.4 | 83.1 |
src/api/ | 96.0 | 92.0 | 96.0 | 96.0 |
ProductService.ts | 98.0 | 95.0 | 97.0 | 98.0 |
auth.ts | 95.0 | 90.0 | 96.0 | 95.0 |
client.ts | 95.0 | 92.0 | 94.0 | 96.0 |
src/services/ | 91.0 | 88.0 | 91.0 | 93.0 |
src/components/ | 89.0 | 86.0 | 88.0 | 90.0 |
src/utils/ | 89.0 | 86.0 | 88.0 | 91.0 |
ββββββββββββββββββββββββββββββββββββββββββββDebugging Tests
VS Code Debugging
File: .vscode/launch.json
{
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Debug Tests",
"runtimeExecutable": "npm",
"runtimeArgs": ["run", "test:debug"],
"console": "integratedTerminal"
}
]
}Debug Commands
# Start debugger
npm run test:debug
# With breakpoints in VS Code
# 1. Set breakpoint in test file
# 2. Run: npm run test:debug
# 3. Open chrome://inspect
# 4. Click "inspect" on node process
# Or use VS Code launcher:
# Press F5 to start debugging with launch.json configDebug Output
$ npm run test:debug
Debugger listening on ws://127.0.0.1:9229/...
To start debugging, open the following URL in a Chrome browser:
chrome://inspect
[Process listening on port 9229]
β src/__tests__/api/ProductService.test.ts
Paused at breakpoint (line 42)
> expect(result).toBe(expectedValue)Test Performance Optimization
Slow Test Analysis
# Run tests with timing
npm run test -- --reporter=verbose
# Output shows slowest tests
SLOW TESTS:
β LoginPage integration (245ms)
β ProductForm submission (189ms)
β Dashboard data loading (156ms)Performance Tips
// β Slow - making actual network calls
test('fetches data', async () => {
const data = await fetch('/api/data');
});
// β
Fast - mocked API
test('fetches data', async () => {
vi.mocked(api.get).mockResolvedValue({ data });
const result = await getProducts();
});
// β Slow - waiting for real timeouts
test('debounce works', async () => {
await new Promise(r => setTimeout(r, 1000));
});
// β
Fast - fake timers
test('debounce works', () => {
vi.useFakeTimers();
// ... test
vi.advanceTimersByTime(1000);
vi.restoreAllMocks();
});Test Checklist for PRs
Before submitting a PR, ensure:
Common Issues & Solutions
Tests Pass Locally but Fail in CI
Cause: Different Node version or missing dependencies
Fix:
- Check .nvmrc or package.json engines
- Run: npm ci instead of npm install
- Clear: rm -rf node_modules && npm ci
Random Test Failures
Cause: Async operations, timing issues
Fix:
- Use waitFor() instead of setTimeout
- Use vi.fakeTimers() for time-based tests
- Ensure proper cleanup in afterEach
Timeout Errors
Cause: Tests taking too long
Fix:
- Increase timeout: test('...', async () => {...}, 10000)
- Mock slower operations
- Remove unnecessary delays
Memory Leaks in Tests
Cause: Not cleaning up subscriptions/listeners
Fix:
- Cleanup in afterEach hook
- Unsubscribe from observables
- Remove event listeners
Performance Benchmarks
Target Times
Unit Tests: < 1ms per test
Component Tests: 1-5ms per test
Integration Tests: 5-50ms per test
Total Suite: < 10 seconds
Current Performance
Unit Tests (320): 2.1s (6.6ms avg) β
Component Tests (120): 2.8s (23ms avg) β οΈ
Integration Tests (30): 1.0s (33ms avg) β
Utility Tests (40): 0.5s (12ms avg) β
ββββββββββββββββββββββββββββ
Total (607 tests): 8.2s β
Continuous Monitoring
Coverage Tracking
# Generate monthly report
npm run test:coverage > coverage-$(date +%Y-%m-%d).txt
# Track trends over time
# Aim to increase coverage 1-2% per monthTest Metrics Dashboard
Total Tests: 607
Pass Rate: 100%
Avg Duration: 8.2s
Coverage: 82%
Trend: βοΈ +2% (this month)
Related Documentation
- Overview - Testing overview
- Structure - Test organization
- Patterns - Testing patterns
- Setup - Configuration
- Coverage - Coverage goals
Last Updated: November 2025