askill
testing

testingSafety 90Repository

Testing patterns, strategies, and best practices for comprehensive test coverage.

0 stars
1.2k downloads
Updated 1/2/2026

Package Files

Loading files...
SKILL.md

Testing Skill

Overview

This skill defines testing patterns, strategies, and best practices for achieving comprehensive test coverage across the project.

Test Types

TypePurposeLocationSpeed
UnitTest isolated functionstests/unit/Fast
IntegrationTest component interactionstests/integration/Medium
E2ETest full user flowstests/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', () => {
    // Setup
    beforeEach(() => {
      // Reset state before each test
    });

    afterEach(() => {
      // Cleanup after each test
    });

    // Happy path tests
    describe('when given valid input', () => {
      test('returns expected result', () => {
        const result = functionToTest('valid');
        expect(result).toBe('expected');
      });
    });

    // Edge cases
    describe('edge cases', () => {
      test('handles empty input', () => {
        expect(functionToTest('')).toBe('default');
      });

      test('handles null input', () => {
        expect(functionToTest(null)).toBeNull();
      });
    });

    // Error cases
    describe('error handling', () => {
      test('throws on invalid input', () => {
        expect(() => functionToTest(undefined)).toThrow();
      });
    });
  });
});

AAA Pattern

test('calculateTotal returns correct sum with discount', () => {
  // Arrange - Setup test data
  const items = [{ price: 100 }, { price: 50 }];
  const discount = 0.1;

  // Act - Execute the code
  const result = calculateTotal(items, discount);

  // Assert - Verify the result
  expect(result).toBe(135); // (100 + 50) * 0.9
});

Common Assertions

// Equality
expect(value).toBe(expected);           // Strict equality
expect(value).toEqual(expected);        // Deep equality
expect(value).not.toBe(unexpected);     // Negation

// Truthiness
expect(value).toBeTruthy();
expect(value).toBeFalsy();
expect(value).toBeNull();
expect(value).toBeUndefined();
expect(value).toBeDefined();

// Numbers
expect(value).toBeGreaterThan(3);
expect(value).toBeLessThan(5);
expect(value).toBeCloseTo(0.3, 5);      // For floating point

// Strings
expect(string).toMatch(/pattern/);
expect(string).toContain('substring');

// Arrays
expect(array).toContain(item);
expect(array).toHaveLength(3);

// Objects
expect(object).toHaveProperty('key');
expect(object).toHaveProperty('key', 'value');
expect(object).toMatchObject({ partial: 'match' });

// Errors
expect(() => fn()).toThrow();
expect(() => fn()).toThrow(Error);
expect(() => fn()).toThrow('message');

// Async
await expect(asyncFn()).resolves.toBe(expected);
await expect(asyncFn()).rejects.toThrow();

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();

// Set return value
mockFn.mockReturnValue('value');
mockFn.mockResolvedValue('async value');
mockFn.mockRejectedValue(new Error('error'));

// Verify calls
expect(mockFn).toHaveBeenCalled();
expect(mockFn).toHaveBeenCalledWith('arg1', 'arg2');
expect(mockFn).toHaveBeenCalledTimes(2);

Mock Modules

// Mock entire module
jest.mock('../path/to/module');

// Mock with implementation
jest.mock('../path/to/module', () => ({
  functionA: jest.fn().mockReturnValue('mocked'),
  functionB: jest.fn()
}));

// Clear mocks between tests
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

// tests/fixtures/testData.js
module.exports = {
  validUser: {
    id: 1,
    name: 'Test User',
    email: 'test@example.com'
  },
  invalidUser: {
    id: null,
    name: '',
    email: 'invalid-email'
  }
};

// Usage in tests
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('GET /users/:id returns user', async () => {
    const user = await db.insert('users', { name: 'Test' });

    const response = await request(app)
      .get(`/users/${user.id}`)
      .expect(200);

    expect(response.body.name).toBe('Test');
  });
});

Coverage Goals

CategoryTarget
Critical paths100%
Business logic90%+
Error handling80%+
Edge cases70%+
Utilities50%+

Running Tests

# Run all tests
npm test

# Run specific file
npm test -- tests/unit/utils.test.js

# Run with coverage
npm test -- --coverage

# Watch mode
npm test -- --watch

# Run only changed tests
npm test -- --onlyChanged

Test Quality Checklist

  • Tests are independent (no shared state)
  • Tests are deterministic (same result every run)
  • Tests are fast (< 100ms for unit tests)
  • Tests are readable (clear what's being tested)
  • Tests cover happy path
  • Tests cover edge cases
  • Tests cover error cases
  • Mocks are appropriate (not over-mocking)
  • No console.log in tests
  • No skipped tests without explanation

Install

Download ZIP
Requires askill CLI v1.0+

AI Quality Score

96/100Analyzed 2/10/2026

An exceptionally well-structured and comprehensive guide to testing in a JavaScript/Jest environment. It covers everything from basic unit tests to complex integration tests, mocking strategies, and coverage goals.

90
100
90
95
95

Metadata

Licenseunknown
Version-
Updated1/2/2026
Publisheraz9713

Tags

apidatabasetesting