Vitest · Unit / component test runner (Vite-native) · MIT
Vitest is a fast test runner for JavaScript and TypeScript. Its API matches Jest (describe, it, expect, vi.fn), so teams can move between the two with little rewrite. It runs in Vite’s transform pipeline, which keeps ESM and modern syntax cheap.
A runner process loads each test file, executes describe/it blocks, and reports pass/fail. Assertions come from expect(). The SUT is imported as a normal module — no HTTP server, no browser. Mocks live on vi (vi.fn, vi.mock).
Testing architecture
Unit tests call one function (or a small graph of functions) in the same process. They avoid I/O so failures point at logic, not the environment. The SUT is imported; the runner never starts Express or a browser.
priceWithTax() asks a collaborator for a tax rate. The test replaces that collaborator with a fake that returns 0.1, then checks both the computed price and that the fake was called with the region code. Isolation is the point: we do not hit a real tax API.
SUT: js-counter / python-calc · samples/js-counter/src/index.js · run npm test in examples/unit/mock-dependency/vitest
Code under test · samples/js-counter/src/index.js
/** Tiny shared system under test for unit/UX demos. */
/**
* Add two numbers and return their sum.
* @param {number} a - First operand
* @param {number} b - Second operand
*/
export function add(a, b) {
// Pure arithmetic — no I/O, no side effects
return a + b;
}
/**
* Keep n inside the inclusive range [min, max].
* @param {number} n - Value to clamp
* @param {number} min - Lower bound
* @param {number} max - Upper bound
*/
export function clamp(n, min, max) {
// Guard: a flipped range is a caller bug, not a silent no-op
if (min > max) {
throw new Error("min must be <= max");
}
// Raise floor first, then lower the ceiling
return Math.min(max, Math.max(min, n));
}
/**
* Apply a region tax rate from an injected service.
* @param {{ getTaxRate: (code: string) => number }} taxService - Collaborator that owns tax rates
* @param {number} amount - Pre-tax amount
* @param {string} region - Region code passed to the tax service
*/
export function priceWithTax(taxService, amount, region) {
// Ask the dependency for the rate (easy to mock in unit tests)
const rate = taxService.getTaxRate(region);
// Gross = net × (1 + rate), e.g. 100 at 10% → 110
return amount * (1 + rate);
}
/**
* Apply a published checkout coupon to a subtotal.
* Grown via TDD in unit.tdd-red-green (this scenario only — BDD uses reserveRoom).
* @param {number} subtotal - Cart total before the coupon
* @param {string} [coupon] - Published code, or empty / unknown
*/
export function applyCoupon(subtotal, coupon) {
if (typeof subtotal !== "number" || subtotal < 0) {
throw new Error("subtotal must be a non-negative number");
}
// SAVE10: always 10% off
if (coupon === "SAVE10") {
return subtotal * 0.9;
}
// SAVE20: 20% off only when the cart is at least 50
if (coupon === "SAVE20" && subtotal >= 50) {
return subtotal * 0.8;
}
// Missing, unknown, or SAVE20-below-minimum → pay the original subtotal
return subtotal;
}
/**
* Reserve seats in a meeting room.
* Specified in Gherkin in unit.bdd-given-when-then (this scenario only — TDD uses applyCoupon).
* @param {number} partySize - Guests who want the room
* @param {number} seatsFree - Seats still open
* @returns {{ confirmed: boolean, seatsFree: number }}
*/
export function reserveRoom(partySize, seatsFree) {
if (typeof partySize !== "number" || partySize < 1) {
throw new Error("partySize must be at least 1");
}
if (typeof seatsFree !== "number" || seatsFree < 0) {
throw new Error("seatsFree must be a non-negative number");
}
if (partySize > seatsFree) {
return { confirmed: false, seatsFree };
}
return { confirmed: true, seatsFree: seatsFree - partySize };
}
Test · examples/unit/mock-dependency/vitest/price.test.js · MIT
· run in examples/unit/mock-dependency/vitest: npm test
// Vitest: vi.fn builds a mock function we can spy on
import { describe, it, expect, vi } from "vitest";
// Function that depends on an injected taxService
import { priceWithTax } from "../../../../samples/js-counter/src/index.js";
describe("priceWithTax", () => {
it("applies the rate from the tax service", () => {
// Stub collaborator: always return 10% for any region
const taxService = {
getTaxRate: vi.fn().mockReturnValue(0.1),
};
// 100 + 10% tax → 110 (floating compare)
expect(priceWithTax(taxService, 100, "US-CA")).toBeCloseTo(110);
// Prove the SUT asked the mock with the region we passed
expect(taxService.getTaxRate).toHaveBeenCalledWith("US-CA");
});
});
Jest is the long-standing default runner in many Node and React codebases. It bundles a runner, assertion library, mocking (jest.fn), and snapshot testing. This repo uses ESM via NODE_OPTIONS=--experimental-vm-modules.
Jest discovers test files, wraps them in a VM, and provides describe/it/expect as globals (or via @jest/globals in ESM). The SUT is imported in-process. Isolation is per-file by default, not a real network hop.
Testing architecture
Unit tests call one function (or a small graph of functions) in the same process. They avoid I/O so failures point at logic, not the environment. The SUT is imported; the runner never starts Express or a browser.
priceWithTax() asks a collaborator for a tax rate. The test replaces that collaborator with a fake that returns 0.1, then checks both the computed price and that the fake was called with the region code. Isolation is the point: we do not hit a real tax API.
SUT: js-counter / python-calc · samples/js-counter/src/index.js · run npm test in examples/unit/mock-dependency/jest
Code under test · samples/js-counter/src/index.js
/** Tiny shared system under test for unit/UX demos. */
/**
* Add two numbers and return their sum.
* @param {number} a - First operand
* @param {number} b - Second operand
*/
export function add(a, b) {
// Pure arithmetic — no I/O, no side effects
return a + b;
}
/**
* Keep n inside the inclusive range [min, max].
* @param {number} n - Value to clamp
* @param {number} min - Lower bound
* @param {number} max - Upper bound
*/
export function clamp(n, min, max) {
// Guard: a flipped range is a caller bug, not a silent no-op
if (min > max) {
throw new Error("min must be <= max");
}
// Raise floor first, then lower the ceiling
return Math.min(max, Math.max(min, n));
}
/**
* Apply a region tax rate from an injected service.
* @param {{ getTaxRate: (code: string) => number }} taxService - Collaborator that owns tax rates
* @param {number} amount - Pre-tax amount
* @param {string} region - Region code passed to the tax service
*/
export function priceWithTax(taxService, amount, region) {
// Ask the dependency for the rate (easy to mock in unit tests)
const rate = taxService.getTaxRate(region);
// Gross = net × (1 + rate), e.g. 100 at 10% → 110
return amount * (1 + rate);
}
/**
* Apply a published checkout coupon to a subtotal.
* Grown via TDD in unit.tdd-red-green (this scenario only — BDD uses reserveRoom).
* @param {number} subtotal - Cart total before the coupon
* @param {string} [coupon] - Published code, or empty / unknown
*/
export function applyCoupon(subtotal, coupon) {
if (typeof subtotal !== "number" || subtotal < 0) {
throw new Error("subtotal must be a non-negative number");
}
// SAVE10: always 10% off
if (coupon === "SAVE10") {
return subtotal * 0.9;
}
// SAVE20: 20% off only when the cart is at least 50
if (coupon === "SAVE20" && subtotal >= 50) {
return subtotal * 0.8;
}
// Missing, unknown, or SAVE20-below-minimum → pay the original subtotal
return subtotal;
}
/**
* Reserve seats in a meeting room.
* Specified in Gherkin in unit.bdd-given-when-then (this scenario only — TDD uses applyCoupon).
* @param {number} partySize - Guests who want the room
* @param {number} seatsFree - Seats still open
* @returns {{ confirmed: boolean, seatsFree: number }}
*/
export function reserveRoom(partySize, seatsFree) {
if (typeof partySize !== "number" || partySize < 1) {
throw new Error("partySize must be at least 1");
}
if (typeof seatsFree !== "number" || seatsFree < 0) {
throw new Error("seatsFree must be a non-negative number");
}
if (partySize > seatsFree) {
return { confirmed: false, seatsFree };
}
return { confirmed: true, seatsFree: seatsFree - partySize };
}
Test · examples/unit/mock-dependency/jest/price.test.js · MIT
· run in examples/unit/mock-dependency/jest: npm test
// Explicit Jest ESM mock helper
import { jest } from "@jest/globals";
// Function that depends on an injected taxService
import { priceWithTax } from "../../../../samples/js-counter/src/index.js";
describe("priceWithTax", () => {
it("applies the rate from the tax service", () => {
// Stub collaborator: always return 10% for any region
const taxService = {
getTaxRate: jest.fn().mockReturnValue(0.1),
};
// 100 + 10% tax → 110 (floating compare)
expect(priceWithTax(taxService, 100, "US-CA")).toBeCloseTo(110);
// Prove the SUT asked the mock with the region we passed
expect(taxService.getTaxRate).toHaveBeenCalledWith("US-CA");
});
});
pytest is the usual Python runner: files named test_*.py, functions named test_*, rich fixtures, and first-class parametrize. Assertions are plain assert statements that pytest rewrites with better diffs.
pytest collects test functions, optionally injects fixtures, and reports failures with the rewritten assertion. For unit examples here, the SUT is imported from samples/python-calc after sys.path is adjusted. No HTTP is involved.
Testing architecture
Unit tests call one function (or a small graph of functions) in the same process. They avoid I/O so failures point at logic, not the environment. The SUT is imported; the runner never starts Express or a browser.
priceWithTax() asks a collaborator for a tax rate. The test replaces that collaborator with a fake that returns 0.1, then checks both the computed price and that the fake was called with the region code. Isolation is the point: we do not hit a real tax API.
SUT: js-counter / python-calc · samples/python-calc/calc.py · run pytest in examples/unit/mock-dependency/pytest
Code under test · samples/python-calc/calc.py
"""Tiny Python twin of the JS counter SUT."""
from typing import Optional
def add(a: float, b: float) -> float:
# Pure arithmetic — no I/O, no side effects
return a + b
def clamp(n: float, min_value: float, max_value: float) -> float:
# Guard: a flipped range is a caller bug, not a silent no-op
if min_value > max_value:
raise ValueError("min must be <= max")
# Raise floor first, then lower the ceiling
return min(max_value, max(min_value, n))
def price_with_tax(tax_service, amount: float, region: str) -> float:
# Ask the dependency for the rate (easy to mock in unit tests)
rate = tax_service.get_tax_rate(region)
# Gross = net × (1 + rate), e.g. 100 at 10% → 110
return amount * (1 + rate)
def apply_coupon(subtotal: float, coupon: Optional[str] = None) -> float:
"""Apply a published checkout coupon. Twin of JS applyCoupon()."""
if subtotal < 0:
raise ValueError("subtotal must be a non-negative number")
# SAVE10: always 10% off
if coupon == "SAVE10":
return subtotal * 0.9
# SAVE20: 20% off only when the cart is at least 50
if coupon == "SAVE20" and subtotal >= 50:
return subtotal * 0.8
# Missing, unknown, or SAVE20-below-minimum → pay the original subtotal
return subtotal
def reserve_room(party_size: int, seats_free: int) -> dict:
"""Reserve seats. Twin of JS reserveRoom() — used only by the BDD scenario."""
if party_size < 1:
raise ValueError("partySize must be at least 1")
if seats_free < 0:
raise ValueError("seatsFree must be a non-negative number")
if party_size > seats_free:
return {"confirmed": False, "seats_free": seats_free}
return {"confirmed": True, "seats_free": seats_free - party_size}
Test · examples/unit/mock-dependency/pytest/test_price.py · MIT
· run in examples/unit/mock-dependency/pytest: pytest
# Make the shared Python sample importable from this example folder
import sys
from pathlib import Path
# unittest.mock.Mock is the pytest-world twin of vi.fn / jest.fn
from unittest.mock import Mock
import pytest
# Walk up to the repo root (parents[4] from this file)
ROOT = Path(__file__).resolve().parents[4]
# Put samples/python-calc on sys.path so `import calc` works
sys.path.insert(0, str(ROOT / "samples" / "python-calc"))
from calc import price_with_tax
def test_price_with_tax_uses_service_rate():
# Stub collaborator and configure the rate it should return
tax_service = Mock()
tax_service.get_tax_rate.return_value = 0.1
# 100 + 10% tax → 110 (approx for floats)
assert price_with_tax(tax_service, 100, "US-CA") == pytest.approx(110)
# Prove the SUT asked the mock with the region we passed
tax_service.get_tax_rate.assert_called_once_with("US-CA")
Uses unittest.mock.Mock — the same idea as vi.fn() / jest.fn().