| name | testing |
| description | Testing patterns, strategies, and best practices for comprehensive test coverage. |
| triggers | ["test","tests","testing","coverage","unit test","integration test"] |
Testing Skill
Overview
This skill defines testing patterns, strategies, and best practices for achieving comprehensive test coverage across the project.
Test Types
| Type | Purpose | Location | Speed |
|---|
| Unit | Test isolated functions | tests/unit/ | Fast |
| Integration | Test component interactions | tests/integration/ | Medium |
| E2E | Test full user flows | tests/e2e/ | Slow |
Directory Structure
tests/
โโโ unit/
โ โโโ utils/
โ โ โโโ helpers.test.js
โ โโโ services/
โ โโโ userService.test.js
โโโ integration/
โ โโโ api/
โ โ โโโ userRoutes.test.js
โ โโโ database/
โ โโโ userRepository.test.js
โโโ e2e/
โ โโโ userFlow.test.js
โโโ fixtures/
โ โโโ testData.js
โโโ helpers/
โ โโโ testUtils.js
โโโ run.js
Test File Naming
// Unit tests
[module].test.js
[module].spec.js
// Integration tests
[feature].integration.test.js
// E2E tests
[flow].e2e.test.js
Writing Tests
Basic Test Structure
const { functionToTest } = require('../../app/module');
describe('ModuleName', () => {
describe('functionToTest', () => {
beforeEach(() => {
});
afterEach(() => {
});
describe('when given valid input', () => {
test('returns expected result', () => {
const result = functionToTest('valid');
expect(result).toBe('expected');
});
});
describe('edge cases', () => {
test('handles empty input', () => {
expect(functionToTest('')).toBe('default');
});
test('handles null input', () => {
expect(functionToTest(null)).toBeNull();
});
});
describe('error handling', () => {
test('throws on invalid input', () => {
expect(() => functionToTest(undefined)).toThrow();
});
});
});
});
AAA Pattern
test('calculateTotal returns correct sum with discount', () => {
const items = [{ price: 100 }, { price: 50 }];
const discount = 0.1;
const result = calculateTotal(items, discount);
expect(result).toBe(135);
});
Common Assertions
expect(value).toBe(expected);
expect(value).toEqual(expected);
expect(value).not.toBe(unexpected);
expect(value).toBeTruthy();
expect(value).toBeFalsy();
expect(value).toBeNull();
expect(value).toBeUndefined();
expect(value).toBeDefined();
expect(value).toBeGreaterThan(3);
expect(value).toBeLessThan(5);
expect(value).toBeCloseTo(0.3, 5);
expect(string).toMatch(/pattern/);
expect(string).toContain('substring');
expect(array).toContain(item);
expect(array).toHaveLength(3);
(object).();
(object).(, );
(object).({ : });
( ()).();
( ()).();
( ()).();
(())..(expected);
(())..();
Testing Async Code
Promises
test('async function resolves correctly', async () => {
const result = await asyncFunction();
expect(result).toBe('expected');
});
test('async function rejects on error', async () => {
await expect(asyncFunction('bad')).rejects.toThrow('Error');
});
Callbacks
test('callback is called with result', (done) => {
callbackFunction((result) => {
expect(result).toBe('expected');
done();
});
});
Mocking
Mock Functions
const mockFn = jest.fn();
mockFn.mockReturnValue('value');
mockFn.mockResolvedValue('async value');
mockFn.mockRejectedValue(new Error('error'));
expect(mockFn).toHaveBeenCalled();
expect(mockFn).toHaveBeenCalledWith('arg1', 'arg2');
expect(mockFn).toHaveBeenCalledTimes(2);
Mock Modules
jest.mock('../path/to/module');
jest.mock('../path/to/module', () => ({
functionA: jest.fn().mockReturnValue('mocked'),
functionB: jest.fn()
}));
beforeEach(() => {
jest.clearAllMocks();
});
Mock Time
beforeEach(() => {
jest.useFakeTimers();
});
afterEach(() => {
jest.useRealTimers();
});
test('timeout behavior', () => {
const callback = jest.fn();
setTimeout(callback, 1000);
jest.advanceTimersByTime(1000);
expect(callback).toHaveBeenCalled();
});
Test Fixtures
module.exports = {
validUser: {
id: 1,
name: 'Test User',
email: 'test@example.com'
},
invalidUser: {
id: null,
name: '',
email: 'invalid-email'
}
};
const { validUser, invalidUser } = require('../fixtures/testData');
test('validates user correctly', () => {
expect(validateUser(validUser)).toBe(true);
expect(validateUser(invalidUser)).toBe(false);
});
Integration Tests
const request = require('supertest');
const app = require('../../app');
const db = require('../../app/database');
describe('User API', () => {
beforeAll(async () => {
await db.connect();
});
afterAll(async () => {
await db.close();
});
beforeEach(async () => {
await db.clear('users');
});
test('POST /users creates new user', async () => {
const response = await request(app)
.post('/users')
.send({ name: 'Test', email: 'test@example.com' })
.expect(201);
expect(response.body).toHaveProperty('id');
expect(response.body.name).toBe('Test');
});
test(, () => {
user = db.(, { : });
response = (app)
.()
.();
(response..).();
});
});
Coverage Goals
| Category | Target |
|---|
| Critical paths | 100% |
| Business logic | 90%+ |
| Error handling | 80%+ |
| Edge cases | 70%+ |
| Utilities | 50%+ |
Running Tests
npm test
npm test -- tests/unit/utils.test.js
npm test -- --coverage
npm test -- --watch
npm test -- --onlyChanged
Test Quality Checklist