Q18 of 38 · TypeScript
What is module augmentation in TypeScript, and when do you use it in a test project?
Short answer
Short answer: Module augmentation extends the types of an existing module without modifying its source. Use it in test projects to add types to Playwright's `test` object for custom fixtures, extend `expect` matchers, add properties to `Window`, or add types for third-party libraries that ship without `.d.ts` files.
Detail
Module augmentation is a TypeScript feature that allows you to add to or modify the type declarations of an existing module via a declare module '...' { ... } block.
How it works: In a .d.ts file or a file with no imports/exports (ambient module), you write declare module 'some-module' { export interface Foo { newProp: string } } and TypeScript merges it with the module's existing types.
Common use cases in test automation:
Custom Playwright fixtures: The recommended pattern — extend
testwithtest.extend<MyFixtures>()and the TypeScript types automatically reflect your fixtures through declaration merging.Custom Jest matchers:
expect.extend({ myMatcher() {} })at runtime, plus a declaration:declare global { namespace jest { interface Matchers<R> { myMatcher(): R; } } }.Extending Window: Add properties injected by the browser under test:
declare global { interface Window { analytics: Analytics; } }.Stub types for untyped packages: When a third-party package has no
@types, create a.d.tsstub:declare module 'legacy-sdk' { export function init(key: string): void; }.
// EXAMPLE
// 1. Extending Playwright test fixtures (via test.extend)
import { test as base } from "@playwright/test";
import { ApiClient } from "./ApiClient";
export const test = base.extend<{ apiClient: ApiClient }>({
apiClient: async ({}, use) => {
await use(new ApiClient());
},
});
// TypeScript automatically types test({ apiClient }) correctly
// 2. Custom Jest matcher augmentation
// matchers.d.ts
declare global {
namespace jest {
interface Matchers<R> {
toBeWithinRange(floor: number, ceiling: number): R;
}
}
}
// 3. Window augmentation for browser globals under test
// window.d.ts
declare global {
interface Window {
_analytics: { track(event: string): void };
}
}
// Now page.evaluate(() => window._analytics.track("login")) is typed