javascript-testing-patterns

JavaScript Testing Patterns

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "javascript-testing-patterns" with this command: npx skills add thapaliyabikendra/ai-artifacts/thapaliyabikendra-ai-artifacts-javascript-testing-patterns

JavaScript Testing Patterns

Comprehensive testing strategies for JavaScript/TypeScript applications.

Framework Setup

Jest Configuration

// jest.config.ts import type { Config } from 'jest';

const config: Config = { preset: 'ts-jest', testEnvironment: 'node', roots: ['<rootDir>/src'], testMatch: ['/tests//.ts', '**/?(.)+(spec|test).ts'], collectCoverageFrom: ['src//*.ts', '!src//*.d.ts'], coverageThreshold: { global: { branches: 80, functions: 80, lines: 80, statements: 80 }, }, setupFilesAfterEnv: ['<rootDir>/src/test/setup.ts'], };

export default config;

Vitest Configuration

// vitest.config.ts import { defineConfig } from 'vitest/config';

export default defineConfig({ test: { globals: true, environment: 'node', coverage: { provider: 'v8', reporter: ['text', 'json', 'html'], }, setupFiles: ['./src/test/setup.ts'], }, });

Unit Testing Patterns

Testing Pure Functions

import { describe, it, expect } from 'vitest';

describe('Calculator', () => { describe('add', () => { it('should add two positive numbers', () => { expect(add(2, 3)).toBe(5); });

it('should handle zero', () => {
  expect(add(0, 5)).toBe(5);
});

});

describe('divide', () => { it('should throw error when dividing by zero', () => { expect(() => divide(10, 0)).toThrow('Division by zero'); }); }); });

Testing Classes

describe('UserService', () => { let service: UserService;

beforeEach(() => { service = new UserService(); });

describe('create', () => { it('should create a new user', () => { const user = { id: '1', name: 'John', email: 'john@example.com' }; const created = service.create(user);

  expect(created).toEqual(user);
  expect(service.findById('1')).toEqual(user);
});

it('should throw error if user already exists', () => {
  const user = { id: '1', name: 'John', email: 'john@example.com' };
  service.create(user);
  expect(() => service.create(user)).toThrow('User already exists');
});

}); });

Testing Async Functions

describe('ApiService', () => { beforeEach(() => { vi.clearAllMocks(); });

it('should fetch user successfully', async () => { const mockUser = { id: '1', name: 'John' }; global.fetch = vi.fn().mockResolvedValueOnce({ ok: true, json: async () => mockUser, });

const user = await service.fetchUser('1');

expect(user).toEqual(mockUser);
expect(fetch).toHaveBeenCalledWith('https://api.example.com/users/1');

});

it('should throw error if user not found', async () => { global.fetch = vi.fn().mockResolvedValueOnce({ ok: false }); await expect(service.fetchUser('999')).rejects.toThrow('User not found'); }); });

Mocking Patterns

Mocking Modules

vi.mock('nodemailer', () => ({ default: { createTransport: vi.fn(() => ({ sendMail: vi.fn().mockResolvedValue({ messageId: '123' }), })), }, }));

Dependency Injection

describe('UserService', () => { let service: UserService; let mockRepository: IUserRepository;

beforeEach(() => { mockRepository = { findById: vi.fn(), create: vi.fn(), }; service = new UserService(mockRepository); });

it('should return user if found', async () => { const mockUser = { id: '1', name: 'John' }; vi.mocked(mockRepository.findById).mockResolvedValue(mockUser);

const user = await service.getUser('1');

expect(user).toEqual(mockUser);
expect(mockRepository.findById).toHaveBeenCalledWith('1');

}); });

Spying on Functions

let loggerSpy: any;

beforeEach(() => { loggerSpy = vi.spyOn(logger, 'info'); });

afterEach(() => { loggerSpy.mockRestore(); });

it('should log order processing', async () => { await service.processOrder('123'); expect(loggerSpy).toHaveBeenCalledWith('Processing order 123'); });

React Component Testing

import { render, screen, fireEvent } from '@testing-library/react';

describe('UserForm', () => { it('should render form inputs', () => { render(<UserForm onSubmit={vi.fn()} />);

expect(screen.getByPlaceholderText('Name')).toBeInTheDocument();
expect(screen.getByRole('button', { name: 'Submit' })).toBeInTheDocument();

});

it('should call onSubmit with form data', () => { const onSubmit = vi.fn(); render(<UserForm onSubmit={onSubmit} />);

fireEvent.change(screen.getByTestId('name-input'), {
  target: { value: 'John Doe' },
});
fireEvent.click(screen.getByRole('button', { name: 'Submit' }));

expect(onSubmit).toHaveBeenCalledWith({ name: 'John Doe' });

}); });

Testing Hooks

import { renderHook, act } from '@testing-library/react';

describe('useCounter', () => { it('should increment count', () => { const { result } = renderHook(() => useCounter());

act(() => {
  result.current.increment();
});

expect(result.current.count).toBe(1);

}); });

Test Fixtures

import { faker } from '@faker-js/faker';

export function createUserFixture(overrides?: Partial<User>): User { return { id: faker.string.uuid(), name: faker.person.fullName(), email: faker.internet.email(), ...overrides, }; }

Best Practices

  • AAA Pattern - Arrange, Act, Assert

  • One assertion per test - Or logically related assertions

  • Descriptive test names - Describe what is being tested

  • Use beforeEach/afterEach - For setup and teardown

  • Mock external dependencies - Keep tests isolated

  • Test edge cases - Not just happy paths

  • Avoid implementation details - Test behavior

  • Keep tests fast - Mock slow operations

  • Maintain 80%+ coverage - Aim high

  • Clean up after tests - Prevent pollution

Common Patterns

// Testing promises await expect(service.fetchUser('invalid')).rejects.toThrow('Not found');

// Testing timers vi.useFakeTimers(); vi.advanceTimersByTime(1000); vi.useRealTimers();

// Snapshot testing expect(container.firstChild).toMatchSnapshot();

Detailed References

For comprehensive patterns, see:

  • references/integration-testing.md

  • references/react-testing-patterns.md

  • references/mocking-strategies.md

Resources

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

abp-infrastructure-patterns

No summary provided by upstream source.

Repository SourceNeeds Review
General

abp-entity-patterns

No summary provided by upstream source.

Repository SourceNeeds Review
General

abp-api-implementation

No summary provided by upstream source.

Repository SourceNeeds Review