๐Ÿงช

How to Write Tests in JavaScript

JavaScriptIntermediate

Unit testing and test-driven development.

Code Example

JavaScript
// Simple test framework
function describe(name, fn) {
  console.group(name);
  fn();
  console.groupEnd();
}

function it(name, fn) {
  try {
    fn();
    console.log('โœ“', name);
  } catch (error) {
    console.error('โœ—', name);
    console.error('  ', error.message);
  }
}

function assert(condition, message) {
  if (!condition) {
    throw new Error(message || 'Assertion failed');
  }
}

function assertEqual(actual, expected, message) {
  if (actual !== expected) {
    throw new Error(
      message || `Expected ${expected}, got ${actual}`
    );
  }
}

// Example tests
describe('Math operations', () => {
  it('should add two numbers', () => {
    const result = 2 + 3;
    assertEqual(result, 5);
  });
  
  it('should multiply two numbers', () => {
    const result = 4 * 5;
    assertEqual(result, 20);
  });
});

// Testing functions
function add(a, b) {
  return a + b;
}

describe('add function', () => {
  it('should return sum of two positive numbers', () => {
    assertEqual(add(2, 3), 5);
  });
  
  it('should handle negative numbers', () => {
    assertEqual(add(-1, 1), 0);
  });
  
  it('should handle zero', () => {
    assertEqual(add(0, 5), 5);
  });
});

// Testing async code
async function fetchUser(id) {
  return { id, name: 'User ' + id };
}

describe('fetchUser', () => {
  it('should return user object', async () => {
    const user = await fetchUser(1);
    assertEqual(user.id, 1);
    assertEqual(user.name, 'User 1');
  });
});

// Mock functions
function createMock() {
  const calls = [];
  const mock = function(...args) {
    calls.push(args);
    return mock.returnValue;
  };
  mock.calls = calls;
  mock.returnValue = undefined;
  mock.mockReturnValue = (value) => {
    mock.returnValue = value;
    return mock;
  };
  return mock;
}

describe('Mock functions', () => {
  it('should track calls', () => {
    const mock = createMock();
    mock(1, 2);
    mock(3, 4);
    assertEqual(mock.calls.length, 2);
    assertEqual(mock.calls[0][0], 1);
  });
});

// Test coverage concept
function divide(a, b) {
  if (b === 0) throw new Error('Division by zero');
  return a / b;
}

describe('divide function', () => {
  it('should divide two numbers', () => {
    assertEqual(divide(10, 2), 5);
  });
  
  it('should throw error for division by zero', () => {
    try {
      divide(10, 0);
      assert(false, 'Should have thrown');
    } catch (error) {
      assertEqual(error.message, 'Division by zero');
    }
  });
});

// Test organization
// describe - test suite
// it/test - individual test case
// before/after - setup/teardown
// beforeEach/afterEach - run before/after each test

Explanation

Write tests with describe/it blocks. Use assertions to verify behavior. Test edge cases and error conditions. Mock dependencies. Aim for high test coverage.

Related Tutorials