Building Your Learning Module...
Getting things ready for you!
Find videos you like?
Save to resource drawer for future reference!
Good tests are readable, maintainable, and reliable. Following best practices ensures your test suite provides value and doesn't become a burden.
test('test1', () => { ... });
test('it works', () => { ... });
test('user', () => { ... });
test('edge case', () => { ... });❌ Vague, unclear what's being tested
test('adds two numbers correctly', () => { ... });
test('returns error for invalid email', () => { ... });
test('user can login with valid credentials', () => { ... });
test('handles empty array input', () => { ... });✅ Clear, describes behavior being tested
// Pattern 1: "should" pattern
test('should return sum of two numbers', () => {
expect(add(2, 3)).toBe(5);
});
// Pattern 2: Behavioral description
test('returns user data when ID exists', () => {
const user = findUser(1);
expect(user).toBeDefined();
});
// Pattern 3: Given-When-Then format
test('given valid email, when user signs up, then account is created', () => {
const result = signup('test@example.com', 'password');
expect(result.success).toBe(true);
});
// Pattern 4: Error scenarios
test('throws error when dividing by zero', () => {
expect(() => divide(10, 0)).toThrow('Division by zero');
});
// Pattern 5: Edge cases
test('returns empty array when input is null', () => {
expect(filterItems(null)).toEqual([]);
});test('calculates total price with discount', () => {
// Arrange - Setup
const cart = {
items: [
{ name: 'Book', price: 20 },
{ name: 'Pen', price: 5 }
]
};
const discountCode = 'SAVE10';
// Act - Execute
const total = calculateTotal(cart, discountCode);
// Assert - Verify
expect(total).toBe(22.5); // 25 - 10% = 22.5
});test('user operations', () => {
// Testing multiple things!
const user = createUser('Alice');
expect(user.name).toBe('Alice');
updateUser(user, { age: 25 });
expect(user.age).toBe(25);
deleteUser(user.id);
expect(findUser(user.id)).toBeNull();
});
// ❌ Tests 3 different operationstest('creates user with name', () => {
const user = createUser('Alice');
expect(user.name).toBe('Alice');
});
test('updates user age', () => {
const user = createUser('Alice');
updateUser(user, { age: 25 });
expect(user.age).toBe(25);
});
test('deletes user by id', () => {
const user = createUser('Alice');
deleteUser(user.id);
expect(findUser(user.id)).toBeNull();
});
// ✅ Each test focuses on one operation// ❌ BAD: Tests depend on execution order
let user;
test('creates user', () => {
user = createUser('Alice'); // Sets global variable
expect(user).toBeDefined();
});
test('updates user', () => {
updateUser(user, { age: 25 }); // Depends on previous test!
expect(user.age).toBe(25);
});
// ✅ GOOD: Each test is independent
test('creates user with correct data', () => {
const user = createUser('Alice');
expect(user.name).toBe('Alice');
expect(user.id).toBeDefined();
});
test('updates user age successfully', () => {
const user = createUser('Bob'); // Create fresh user
updateUser(user, { age: 30 });
expect(user.age).toBe(30);
});
// ✅ BETTER: Use beforeEach for common setup
describe('User operations', () => {
let user;
beforeEach(() => {
user = createUser('Alice'); // Fresh user for each test
});
test('has correct name', () => {
expect(user.name).toBe('Alice');
});
test('can update age', () => {
updateUser(user, { age: 25 });
expect(user.age).toBe(25);
});
});test('test', () => {
const a = foo('x', 1);
expect(a).toBe(2);
});
// ❌ What is 'x'? Why 1? Why expect 2?test('calculates sales tax', () => {
const price = 100;
const taxRate = 0.1; // 10%
const expectedTotal = 110;
const total = addTax(price, taxRate);
expect(total).toBe(expectedTotal);
});
// ✅ Clear what's being tested and why// test-helpers.js - Shared test utilities
export const createTestUser = (overrides = {}) => ({
id: 1,
name: 'Test User',
email: 'test@example.com',
role: 'user',
...overrides
});
export const createTestProduct = (overrides = {}) => ({
id: 1,
name: 'Test Product',
price: 99.99,
stock: 10,
...overrides
});
// Using in tests
import { createTestUser, createTestProduct } from './test-helpers';
test('applies employee discount', () => {
const employee = createTestUser({ role: 'employee' });
const product = createTestProduct({ price: 100 });
const discountedPrice = calculatePrice(product, employee);
expect(discountedPrice).toBe(80); // 20% employee discount
});
test('regular users pay full price', () => {
const regularUser = createTestUser(); // Default role: 'user'
const product = createTestProduct({ price: 100 });
const price = calculatePrice(product, regularUser);
expect(price).toBe(100); // No discount
});Group related tests together with shared setup
Run common setup before each test automatically
Extract repeated logic into reusable functions
describe('Shopping Cart', () => {
let cart;
beforeEach(() => {
cart = new ShoppingCart(); // Fresh cart for each test
});
describe('adding items', () => {
test('adds item to cart', () => {
cart.add({ id: 1, name: 'Book', price: 20 });
expect(cart.items).toHaveLength(1);
});
test('increases quantity for duplicate items', () => {
const item = { id: 1, name: 'Book', price: 20 };
cart.add(item);
cart.add(item);
expect(cart.items).toHaveLength(1);
expect(cart.items[0].quantity).toBe(2);
});
});
describe('calculating total', () => {
beforeEach(() => {
cart.add({ id: 1, name: 'Book', price: 20 });
cart.add({ id: 2, name: 'Pen', price: 5 });
});
test('calculates total without discount', () => {
expect(cart.getTotal()).toBe(25);
});
test('applies discount code', () => {
cart.applyDiscount('SAVE10'); // 10% off
expect(cart.getTotal()).toBe(22.5);
});
});
afterEach(() => {
cart.clear(); // Cleanup
});
});Describe what you're testing
Tests are documentation
One assertion per test
Focused and isolated
Arrange → Act → Assert
Clear test structure
Mock external dependencies
Run tests frequently