Skip to main content
Back to Blog
Series Playlist

TypeScript Quality Engineering

Eight guides to runtime validation, Vitest layers, browser mode, typed contracts, module isolation, and agent-safe TypeScript test generation.

Series Chapters (8)

Part 1 · Automation Tutorials

Type Safety Stops at Runtime: Test the TypeScript Boundary

A type assertion compiles away, and JSON.parse and Response.json() are typed any, so a payload missing a required role or carrying an unlisted status reaches your domain code unchecked. This guide covers why hand-written type predicates repeat the problem, parsing unknown through a Zod 4 schema into a separate domain type, when to strip or reject undeclared keys, why a missing enum field and an unknown enum value report the same issue code, and a Vitest suite that asserts path, code and a sanitised received value without leaking personal data into failures or test names.

Oct 4, 202620 min read
Part 2 · Automation Tutorials

Choose Vitest, Browser Mode, or Playwright by Risk

Each test layer can observe different things: Node sees pure logic and Blobs, jsdom sees DOM structure but no layout, Vitest browser mode sees real geometry, input and object URLs, and only Playwright sees what the browser does outside the page. This guide splits one file-download component across all four, gives a capability-to-layer decision table, shows the vacuous jsdom layout test and its fix, and prices each layer in feedback time, CI browser installs and diagnostic artefacts on Vitest 5 and Playwright 1.63.

Oct 5, 202617 min read
Part 3 · Automation Tutorials

Debug Vitest Module Mocking and Cache Leaks

When a Vitest test passes with -t and fails in the full file, a module cached by an earlier test usually holds the state. This guide reproduces the failure with a fixed shuffle seed, shows what per-file isolation covers in each pool (including process.env surviving between files in the vm pools), fixes an import-time environment read with vi.stubEnv, a scoped vi.resetModules and onTestFinished, and separates late mocks, module singletons and leaked fake timers by their symptoms. It also shows why clearMocks, mockReset, restoreMocks and unstubEnvs leave the module cache alone.

Oct 6, 202616 min read
Part 4 · Automation Tutorials

Test TypeScript Discriminated Unions as State Machines

A discriminated union rules out impossible shapes, but not illegal moves between legal ones or unknown statuses from the server. Using a payment flow, this guide covers deriving the union from a Zod discriminated-union schema, the exact issue Zod reports for an unknown discriminant, why a default branch absorbs a new variant and what assertNever and switch-exhaustiveness-check do instead, a transition table typed with satisfies, generated tests for all sixteen pairs, and why rejected events should return the same object.

Oct 7, 202618 min read
Part 5 · Automation Tutorials

Test React Server and Client Boundaries in Next.js

An admin page that redirects editors can still let them import data, because its Server Action is a separate POST endpoint. Using a Next.js 16 page with a client CSV import form, this guide covers testing the access decision and the action as plain functions, why server-only throws under Vitest and how to alias it, checking props for React's serialization rules, testing the form in Vitest browser mode with the action passed as a prop, and a Playwright contract that replays the admin's action request with an editor's session.

Oct 8, 202622 min read
Part 6 · Automation Tutorials

Test TypeScript Error Handling Without Losing Causes

Rethrowing new Error(e.message) turns a refused connection into two words and a stack that starts in your own catch block. This guide covers what the cause option actually installs, the subclass field that silently resets cause to undefined, an invoice client that classifies validation, unauthorized, timeout and unknown failures with fixed user copy and retry flags, a single redacting log boundary, and Vitest tests that assert each classification, including why toThrow with an error instance cannot see a lost cause.

Oct 9, 202622 min read
Part 7 · Automation Tutorials

Make TypeScript Type-Level Tests Earn Their Place

A type-level test earns its place when a type-only change could break a caller you cannot see. Using a typed API client whose endpoint map infers params from the path, this guide covers expectTypeOf and *.test-d.ts files under vitest --typecheck, why a plain vitest run skips them, an @ts-expect-error that stays green after the contract breaks, how a leaked any passes assertType and toExtend but not toEqualTypeOf, the type test that mirrors its implementation, and when not to write type tests at all.

Oct 10, 202616 min read
Part 8 · AI in Testing

Validate AI Agent Tool Calls in TypeScript: Schema, Authorization, Approval

Strict tool use and MCP SDK validation check the shape of a model's arguments; neither knows who is asking. This guide builds a draft-only MCP tool with the TypeScript SDK v2 and Zod 4: strict schemas with no identity fields, the user taken from the verified request, per-call ownership checks on model-supplied ids, publication turned into a human-approved request, and results and errors bounded so nothing secret reaches the model. It covers why tool annotations are untrusted hints, why z.object silently drops a forged authorId, how a thrown exception's message becomes model-visible text, and a Vitest suite that asserts every denial by state as well as response.

Oct 11, 202621 min read