Back to Blog
Node.jsTestingAssertDebugging

Node.js Assert Module Guide

Master the Node.js assert module for testing. From basic assertions to custom messages to strict mode.

B
Bootspring Team
Engineering
April 27, 2020
6 min read

The assert module provides assertion functions for testing. Here's how to use it effectively.

Basic Assertions#

1const assert = require('assert'); 2 3// Basic equality 4assert.equal(1, 1); // Passes (loose equality) 5assert.equal(1, '1'); // Passes (loose equality) 6assert.strictEqual(1, 1); // Passes (strict equality) 7// assert.strictEqual(1, '1'); // Throws! 8 9// Not equal 10assert.notEqual(1, 2); // Passes 11assert.notStrictEqual(1, '1'); // Passes 12 13// Truthy/Falsy 14assert.ok(true); // Passes 15assert.ok(1); // Passes 16assert.ok('string'); // Passes 17// assert.ok(false); // Throws! 18// assert.ok(0); // Throws! 19 20// Direct assertions 21assert(true); // Same as assert.ok() 22assert(1 === 1);

Strict Mode#

1const assert = require('assert').strict; 2// Or: const assert = require('assert/strict'); 3 4// In strict mode, equal uses strict equality 5assert.equal(1, 1); // Passes 6// assert.equal(1, '1'); // Throws in strict mode! 7 8// Deep equality is also strict 9assert.deepEqual({ a: 1 }, { a: 1 }); // Passes 10// assert.deepEqual({ a: 1 }, { a: '1' }); // Throws! 11 12// Recommended: always use strict mode 13const { strict: assert } = require('assert');

Deep Equality#

1const assert = require('assert').strict; 2 3// Deep object comparison 4assert.deepStrictEqual( 5 { a: 1, b: { c: 2 } }, 6 { a: 1, b: { c: 2 } } 7); // Passes 8 9assert.deepStrictEqual( 10 [1, 2, [3, 4]], 11 [1, 2, [3, 4]] 12); // Passes 13 14// Not deep equal 15assert.notDeepStrictEqual( 16 { a: 1 }, 17 { a: 2 } 18); // Passes 19 20// Works with various types 21assert.deepStrictEqual( 22 new Date('2021-01-01'), 23 new Date('2021-01-01') 24); 25 26assert.deepStrictEqual( 27 new Map([['a', 1]]), 28 new Map([['a', 1]]) 29); 30 31assert.deepStrictEqual( 32 new Set([1, 2, 3]), 33 new Set([1, 2, 3]) 34); 35 36// Prototype checking 37const obj1 = Object.create({ proto: true }); 38const obj2 = Object.create(null); 39// assert.deepStrictEqual(obj1, obj2); // Throws - different prototypes

Error Assertions#

1const assert = require('assert').strict; 2 3// Assert throws 4assert.throws( 5 () => { throw new Error('Wrong'); }, 6 Error 7); 8 9// With specific error 10assert.throws( 11 () => { throw new TypeError('Invalid'); }, 12 TypeError 13); 14 15// With error message 16assert.throws( 17 () => { throw new Error('Specific error'); }, 18 { message: 'Specific error' } 19); 20 21// With regex 22assert.throws( 23 () => { throw new Error('File not found'); }, 24 /not found/ 25); 26 27// With validation function 28assert.throws( 29 () => { throw new Error('Custom error'); }, 30 (err) => { 31 return err instanceof Error && err.message.includes('Custom'); 32 } 33); 34 35// Does not throw 36assert.doesNotThrow( 37 () => { return 42; } 38); 39 40// Async assertions 41async function failingAsync() { 42 throw new Error('Async error'); 43} 44 45await assert.rejects(failingAsync, Error); 46 47await assert.rejects( 48 failingAsync, 49 { message: 'Async error' } 50); 51 52// Does not reject 53await assert.doesNotReject( 54 async () => { return 42; } 55);

Custom Messages#

1const assert = require('assert').strict; 2 3// Add context to failures 4assert.equal(result, expected, 'Result should match expected value'); 5 6assert.ok(user.isActive, `User ${user.id} should be active`); 7 8assert.strictEqual( 9 response.status, 10 200, 11 `Expected status 200, got ${response.status}` 12); 13 14// With Error object 15assert.fail(new Error('This test should not reach here')); 16 17// Fail with message 18assert.fail('Unreachable code executed'); 19 20// AssertionError details 21try { 22 assert.strictEqual(1, 2, 'Numbers should match'); 23} catch (err) { 24 console.log(err.message); // 'Numbers should match' 25 console.log(err.actual); // 1 26 console.log(err.expected); // 2 27 console.log(err.operator); // 'strictEqual' 28}

Match and ifError#

1const assert = require('assert').strict; 2 3// Match - check if string matches regex 4assert.match('hello world', /world/); 5assert.match('test@example.com', /^\S+@\S+\.\S+$/); 6 7// Does not match 8assert.doesNotMatch('hello', /world/); 9 10// ifError - throws if value is truthy (for callbacks) 11assert.ifError(null); // Passes 12assert.ifError(undefined); // Passes 13// assert.ifError(new Error('fail')); // Throws the error 14 15// Common callback pattern 16function callback(err, result) { 17 assert.ifError(err); // Throws if error exists 18 assert.ok(result); 19}

Testing Patterns#

1const assert = require('assert').strict; 2 3// Test function 4function add(a, b) { 5 return a + b; 6} 7 8// Basic test 9function testAdd() { 10 assert.strictEqual(add(1, 2), 3); 11 assert.strictEqual(add(-1, 1), 0); 12 assert.strictEqual(add(0, 0), 0); 13 console.log('✓ add tests passed'); 14} 15 16// Test with setup/teardown 17function testDatabase() { 18 // Setup 19 const db = new Database(); 20 db.connect(); 21 22 try { 23 // Test 24 const user = db.createUser({ name: 'Alice' }); 25 assert.ok(user.id); 26 assert.strictEqual(user.name, 'Alice'); 27 28 const found = db.findUser(user.id); 29 assert.deepStrictEqual(found, user); 30 31 console.log('✓ database tests passed'); 32 } finally { 33 // Teardown 34 db.disconnect(); 35 } 36} 37 38// Async test 39async function testAsyncFunction() { 40 const result = await fetchData(); 41 assert.ok(Array.isArray(result)); 42 assert.ok(result.length > 0); 43 console.log('✓ async tests passed'); 44} 45 46// Run tests 47async function runTests() { 48 testAdd(); 49 testDatabase(); 50 await testAsyncFunction(); 51 console.log('All tests passed!'); 52} 53 54runTests().catch(console.error);

Custom Assertions#

1const assert = require('assert').strict; 2const { AssertionError } = assert; 3 4// Custom assertion function 5function assertInRange(value, min, max, message) { 6 if (value < min || value > max) { 7 throw new AssertionError({ 8 message: message || `Expected ${value} to be between ${min} and ${max}`, 9 actual: value, 10 expected: `${min} - ${max}`, 11 operator: 'inRange', 12 }); 13 } 14} 15 16// Usage 17assertInRange(5, 1, 10); // Passes 18// assertInRange(15, 1, 10); // Throws 19 20// Assert array contains 21function assertContains(array, item, message) { 22 if (!array.includes(item)) { 23 throw new AssertionError({ 24 message: message || `Expected array to contain ${item}`, 25 actual: array, 26 expected: item, 27 operator: 'contains', 28 }); 29 } 30} 31 32// Assert object has property 33function assertHasProperty(obj, prop, message) { 34 if (!(prop in obj)) { 35 throw new AssertionError({ 36 message: message || `Expected object to have property "${prop}"`, 37 actual: Object.keys(obj), 38 expected: prop, 39 operator: 'hasProperty', 40 }); 41 } 42} 43 44// Assert type 45function assertType(value, type, message) { 46 const actualType = typeof value; 47 if (actualType !== type) { 48 throw new AssertionError({ 49 message: message || `Expected type ${type}`, 50 actual: actualType, 51 expected: type, 52 operator: 'typeOf', 53 }); 54 } 55}

Integration with Test Runners#

1// Works with Node.js test runner (v18+) 2const { describe, it } = require('node:test'); 3const assert = require('assert').strict; 4 5describe('Calculator', () => { 6 it('should add numbers', () => { 7 assert.strictEqual(add(1, 2), 3); 8 }); 9 10 it('should subtract numbers', () => { 11 assert.strictEqual(subtract(5, 3), 2); 12 }); 13 14 it('should throw on division by zero', () => { 15 assert.throws( 16 () => divide(1, 0), 17 { message: 'Division by zero' } 18 ); 19 }); 20}); 21 22// With Mocha 23describe('User Service', function() { 24 it('should create user', async function() { 25 const user = await createUser({ name: 'Test' }); 26 assert.ok(user.id); 27 assert.strictEqual(user.name, 'Test'); 28 }); 29});

Best Practices#

Usage: ✓ Use strict mode ✓ Provide descriptive messages ✓ Use deepStrictEqual for objects ✓ Test edge cases Organization: ✓ Group related assertions ✓ Use setup/teardown patterns ✓ Test one thing per test ✓ Name tests descriptively Error Handling: ✓ Test both success and failure ✓ Use assert.throws for errors ✓ Use assert.rejects for promises ✓ Include error messages Avoid: ✗ Loose equality (==) ✗ Missing error messages ✗ Testing implementation details ✗ Ignoring async errors

Conclusion#

The Node.js assert module provides essential testing primitives. Use strict mode for reliable comparisons, provide clear error messages, and leverage deepStrictEqual for object comparisons. For larger projects, consider using it with a test runner like Node.js's built-in test runner or Mocha.

Share this article

Help spread the word about Bootspring