Back to KB
Difficulty
Intermediate
Read Time
6 min

How I Test My Node.js Apps: A Practical Guide (2026)

By Codcompass TeamΒ·Β·6 min read

Testing doesn't have to be complicated. Here's the minimal setup that catches real bugs.

The Truth About Testing

Most developers know they should test.
Few actually do it consistently.

Why?
β†’ "I don't have time"
β†’ "My code is too simple to test"
β†’ "Setting up tests is annoying"
β†’ "Tests break when I refactor"

Here's my counter-argument:
β†’ Tests catch bugs before users do
β†’ Tests document how your code works
β†’ Tests give you confidence to refactor
β†’ The "minimal" setup takes 15 minutes

Enter fullscreen mode Exit fullscreen mode

My Testing Stack

Layer

Tool

Why

Unit tests

Node.js built-in test runner

Zero dependencies

HTTP APIs

node:test + undici dispatch

Built into Node.js 18+

Integration

Custom scripts with supertest

Simple, predictable

E2E

Playwright

Reliable, fast, free

Total cost: $0. Everything here is free and open source.

Step 1: Unit Testing with Node.js Built-in Runner

No need for Jest or Mocha anymore. Node.js has its own test runner since v18:

# No installation needed β€” it's built in
node --test

Enter fullscreen mode Exit fullscreen mode

Basic Example

// math.js
export function add(a, b) {
  return a + b;
}

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

Enter fullscreen mode Exit fullscreen mode

// math.test.js
import { describe, it } from 'node:test';
import assert from 'node:assert/strict';
import { add, divide } from './math.js';

describe('Math utilities', () => {
  it('should add two numbers', () => {
    assert.equal(add(2, 3), 5);
  });

  it('should handle negative numbers', () => {
    assert.equal(add(-1, 1), 0);
  });

  it('should throw on division by zero', () => {
    assert.throws(() => divide(10, 0), {
      message: 'Division by zero'
    });
  });
});

Enter fullscreen mode Exit fullscreen mode

$ node --test
βœ“ Math utilities (4.8ms)
βœ“ should add two numbers
βœ“ should handle negative numbers
βœ“ should throw on division by zero

β„Ή tests 3
β„Ή pass 3
β„Ή fail 0
β„Ή duration 15ms

Enter fullscreen mode Exit fullscreen mode

Async Code Testing

import { describe, it } from 'node:test';
import assert from 'node:assert/strict';

describe('API calls', () => {
  it('should fetch data successfully', async () => {
    const response = await fetch('https://api.example.com/data');
    const data = await response.json();

    assert.ok(data.items);
    assert(Array.isArray(data.items));
  });

  it('should timeout after 5 seconds', async () => {
    const controller = new AbortController();
    setTimeout(() => controller.abort(), 5000);

    await assert.rejects(
      async () => fetch('h

πŸŽ‰ Mid-Year Sale β€” Unlock Full Article

Base plan from just $4.99/mo or $49/yr

Sign in to read the full article and unlock all 635+ tutorials.

Sign In / Register β€” Start Free Trial

7-day free trial Β· Cancel anytime Β· 30-day money-back