█
LastWrite
  • > Curriculum
  • > Pricing
  • > For Educators
  • > About
  • > Contact
Log InGet Started

Questions, concerns, bug reports, or suggestions? We read every message, write to us at [email protected].

More ways to reach us →
LastWrite

Structured computer science lessons for aspiring developers and security professionals.

[email protected]

(201) 785-7951

Mon–Fri, 9 AM–5 PM EST

Learn

  • Curriculum
  • Pricing

Company

  • About
  • For Educators & Schools
  • Contact Us

Legal

  • Terms of Service
  • Privacy Policy
© 2026 LastWrite. All rights reserved.
Curriculum/Software Engineering/Testing/Unit Testing in JavaScript and TypeScript
50 minIntermediate

Unit Testing in JavaScript and TypeScript

After this lesson, you will be able to: Test functions and modules with Vitest or Jest, mock modules and network calls, and use snapshot testing where it actually helps.

Now the hands-on JavaScript/TypeScript layer. Vitest and Jest have nearly identical APIs, so learning one transfers to the other. This lesson covers writing real tests, mocking modules and fetch, and the right (narrow) use for snapshot tests.

Prerequisites:Unit Testing Fundamentals

Vitest: setup and a real test file

Vitest is the modern Vite-native runner; the API matches Jest's describe/it/expect.

python
// package.json
{ "scripts": { "test": "vitest", "test:ci": "vitest run --coverage" } }
// src/discount.ts
export function applyDiscount(price: number, code: string): number {
if (code === 'HALF') return price / 2;
if (code === 'TENOFF') return Math.max(0, price - 10);
return price;
}
// src/discount.test.ts
import { describe, it, expect } from 'vitest';
import { applyDiscount } from './discount';
describe('applyDiscount', () => {
it('halves the price for HALF', () => {
expect(applyDiscount(40, 'HALF')).toBe(20);
});
it('never goes below zero', () => {
expect(applyDiscount(5, 'TENOFF')).toBe(0);
});
it('ignores unknown codes', () => {
expect(applyDiscount(40, 'NOPE')).toBe(40);
});
});

Mocking a module and a network call

Mock at the boundary: the module you import or the global fetch. Keep your own logic real.

python
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { getWeatherSummary } from './weather';
// Mock the whole module:
vi.mock('./emailClient', () => ({
sendEmail: vi.fn().mockResolvedValue({ ok: true }),
}));
beforeEach(() => vi.restoreAllMocks());
it('summarizes the API response', async () => {
// Stub global fetch so no real network call happens:
vi.stubGlobal('fetch', vi.fn().mockResolvedValue({
ok: true,
json: async () => ({ tempC: 21, condition: 'Clear' }),
}));
const summary = await getWeatherSummary('London');
expect(summary).toBe('London: 21C, Clear');
expect(fetch).toHaveBeenCalledOnce();
});

Snapshot testing: useful, but narrow

A snapshot test serializes a value (often rendered UI) and saves it; future runs compare against the saved snapshot. It is handy for catching unintended changes to complex output, like a rendered component's structure. The trap: huge snapshots that nobody reads, so reviewers rubber-stamp updates and the test guards nothing. Keep snapshots small and intentional, and review every snapshot change like real code. For most logic, explicit assertions beat a snapshot.

Quick Check

Your test calls a real third-party weather API and fails intermittently in CI. What is the fix?

Pick the best answer.

Sign in and purchase access to unlock this lesson.

Sign in to purchase
←Unit Testing Fundamentals
Back to Testing
Unit Testing in Python→