Docker image: zchencow/innozverse-ts:latest (Node 20 built-in test runner)
Lab Instructions
Step 1: Node.js Built-in Test Runner
import{test,describe,it,before,after,beforeEach,afterEach}from"node:test";importassertfrom"node:assert/strict";// Simple testtest("add numbers",()=>{assert.equal(2+2,4);assert.equal(10-3,7);});// Describe blockdescribe("Math utilities",()=>{functionclamp(n:number,min:number,max:number):number{returnMath.min(Math.max(n,min),max);}it("clamps above max",()=>assert.equal(clamp(100,0,10),10));it("clamps below min",()=>assert.equal(clamp(-5,0,10),0));it("keeps value in range",()=>assert.equal(clamp(5,0,10),5));});// Async testtest("async operation",async()=>{constresult=awaitPromise.resolve(42);assert.equal(result,42);});// Test with error assertiontest("throws on invalid input",()=>{functionparsePositive(n:number):number{if (n<=0) thrownewRangeError("Must be positive");returnn;}assert.throws(()=>parsePositive(-1),RangeError);assert.equal(parsePositive(5),5);});
💡 Node.js 18+ has a built-in test runner (node:test) — no Jest or Mocha needed for simple test suites. It supports describe/it/test, async tests, subtests, mocking, and --test CLI flag. For TypeScript, run with ts-node --test or compile first.
📸 Verified Output:
Step 2: Type-Safe Assertions & Custom Matchers
💡 asserts val is T return type makes custom assertion functions narrow types. After assertDefined(user), TypeScript removes null | undefined from user's type. Without this return type, TypeScript doesn't know the assertion changed the type — you'd still need ! or ?. afterward.
📸 Verified Output:
Steps 3–8: Mocks, Stubs, Spies, Test Utilities, Integration Tests, Capstone
📸 Verified Output:
Summary
TypeScript testing is expressive and type-safe. You've written typed assertions with asserts type predicates, created mock factories, implemented spy functions, built test data with builders, done property-based testing, and ran a complete OrderService test suite — all with zero external testing frameworks.