The built-in matchers cover general-purpose assertions, but real-world ExtendScript projects often need domain-specific checks—validating sign, parity, layer type, or any property unique to your codebase. TheDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/Octopodo/kt-testing-suite-core/llms.txt
Use this file to discover all available pages before exploring further.
extendMatchers() function lets you define a Matcher<any> object with custom assertion methods and compose it into a new expect function that has your matchers alongside all built-in ones. No monkeypatching, no global state: each custom expect is a clean factory.
The Matcher<T> Interface
A Matcher<T> is a plain object where every key is a function that performs an assertion and returns this. TypeScript’s interface for it looks like this:
Expect<T> class through this:
| Member | Description |
|---|---|
this.actual | The raw value passed to expect() |
this.assert(condition, message) | Throws if condition is falsy (respects .not() inversion) |
this.getSafeActual(type) | Returns this.actual coerced to 'array', 'string', 'number', or 'any'; returns a safe default on null/undefined/type mismatch |
this.toSafeString(value) | Converts any value to a readable string, handling null and undefined safely |
this.expect(value) | Creates a new expect instance scoped to the same matcher set, for calling sibling matchers |
The extendMatchers() Function
extendMatchers is the factory that combines your matchers with the built-in jsMatchers and returns a fully typed Expect<T> & Matcher<T> instance:
expect function so the signature stays familiar:
Built-in matchers (
jsMatchers) are always included. You never need to pass them explicitly—extendMatchers prepends them automatically even when you supply your own matcher array.Step-by-Step: Writing a Custom Matcher
Define a Matcher<any> object
Create a plain object typed as
Matcher<any>. Each key is your matcher name; the value is a regular function (not an arrow function—this binding is required).Implement assertion logic with this.assert()
Call
this.assert(condition, message) with a boolean condition and a descriptive failure message. assert automatically handles .not() inversion—you always write the positive condition.Use this.getSafeActual(type) for safe access
Always call
getSafeActual('number') (or 'string', 'array', 'any') instead of reading this.actual directly for type-sensitive checks. It returns a safe fallback when the value is null, undefined, or the wrong type—preventing runtime errors in ExtendScript’s strict environment.Return this for chaining
Every matcher must
return this so assertions can be chained: expect(5).toBePositive().toBeNumber().Full Example: toBePositive / toBeNegative
The following is taken directly from the test suite (src/tests/extend.test.ts) and shows a complete custom matcher definition, including a toPassAny usage that mixes custom and built-in matcher names.
toBeEven / toBeOdd Example
Here is another pair of matchers illustrating the same pattern with modular arithmetic:
Using this.expect to Call Sibling Matchers
When one matcher needs to reuse the logic of another in the same custom set, use this.expect(this.actual). This property is injected by extendMatchers and creates a new instance that carries your full custom matcher set—not just the built-ins.
This pattern is especially useful for layered validation: check that a value is structurally valid before asserting domain-specific properties.