Internal utility functions for type detection, property manipulation, flag management, and deep equality comparison. These utilities power Chai's assertion system and are available for plugin development.
Complete interface of utility functions available to plugins and internal Chai operations.
interface ChaiUtils {
// Core utilities
flag(assertion: Assertion, key: string, value?: any): any;
test(assertion: Assertion, expression: boolean): void;
type(obj: any): string;
getMessage(assertion: Assertion, args: any[]): string;
getActual(assertion: Assertion, args: any[]): any;
inspect(obj: any, showHidden?: boolean, depth?: number, colors?: boolean): string;
objDisplay(obj: any): string;
// Equality and comparison
eql(a: any, b: any): boolean;
compareByInspect(a: any, b: any): number;
// Property and path utilities
getPathInfo(path: string, obj: any): PathInfo;
hasProperty(obj: any, name: string | number | symbol): boolean;
getOwnEnumerableProperties(obj: any): Array<string | symbol>;
getOwnEnumerablePropertySymbols(obj: any): symbol[];
// Flag management
transferFlags(assertion: Assertion, target: Assertion, includeAll?: boolean): void;
// Function utilities
getName(fn: Function): string;
// Type checking utilities
expectTypes(obj: any, types: string[]): void;
isRegExp(obj: any): boolean;
isNumeric(obj: any): boolean;
isNaN(obj: any): boolean;
// Assertion building utilities
addProperty(proto: any, name: string, fn: Function): void;
addMethod(proto: any, name: string, fn: Function): void;
addChainableMethod(proto: any, name: string, method: Function, chainingBehavior?: Function): void;
overwriteProperty(proto: any, name: string, fn: Function): void;
overwriteMethod(proto: any, name: string, fn: Function): void;
overwriteChainableMethod(proto: any, name: string, method: Function, chainingBehavior?: Function): void;
// Additional utility functions
getName(fn: Function): string;
isRegExp(obj: any): boolean;
isNumeric(obj: any): boolean;
proxify(assertion: Assertion): Assertion;
addLengthGuard(fn: Function, assertionName: string, isChainable: boolean): Function;
isProxyEnabled(): boolean;
getOperator(assertion: Assertion, args: any[]): string;
checkError: CheckErrorStatic;
}Get or set flags on assertion instances for state management.
/**
* Get or set flags on assertion instance
* @param assertion - Assertion instance
* @param key - Flag key name
* @param value - Flag value to set (optional)
* @returns Current flag value when getting, assertion instance when setting
*/
flag(assertion: Assertion, key: string, value?: any): any;Usage Examples:
import { use } from "chai";
use(function(chai, utils) {
const { Assertion } = chai;
Assertion.addProperty('negative', function() {
const obj = utils.flag(this, 'object'); // Get the target value
const negate = utils.flag(this, 'negate'); // Check if negated
utils.flag(this, 'customFlag', true); // Set custom flag
this.assert(
obj < 0,
'expected #{this} to be negative',
'expected #{this} to not be negative'
);
});
});Execute an assertion with proper error handling and message generation.
/**
* Execute an assertion with proper error handling
* @param assertion - Assertion instance
* @param expression - Boolean expression to test
*/
test(assertion: Assertion, expression: boolean): void;Get the type of a value as a string using enhanced type detection.
/**
* Get the type of a value as a string
* @param obj - Value to get type of
* @returns Type name (e.g., 'string', 'array', 'object', 'null')
*/
type(obj: any): string;Usage Examples:
utils.type("hello"); // 'string'
utils.type(42); // 'number'
utils.type([1, 2, 3]); // 'array'
utils.type({ a: 1 }); // 'object'
utils.type(null); // 'null'
utils.type(undefined); // 'undefined'
utils.type(new Date()); // 'date'
utils.type(/regex/); // 'regexp'
utils.type(Symbol('s')); // 'symbol'
utils.type(BigInt(123)); // 'bigint'Generate formatted error messages for assertion failures.
/**
* Generate error message for assertion
* @param assertion - Assertion instance
* @param args - Message template arguments [positiveMsg, negativeMsg, expected, actual, showDiff]
* @returns Formatted error message
*/
getMessage(assertion: Assertion, args: any[]): string;Extract the actual value being asserted against, with support for custom getters.
/**
* Get the actual value being asserted against
* @param assertion - Assertion instance
* @param args - Additional arguments for context
* @returns The actual value for comparison
*/
getActual(assertion: Assertion, args: any[]): any;Stringify/inspect values for display in error messages and debugging.
/**
* Inspect/stringify a value for display
* @param obj - Value to inspect
* @param showHidden - Show hidden properties (default: false)
* @param depth - Inspection depth (default: 2)
* @param colors - Use colors in output (default: false)
* @returns String representation of the value
*/
inspect(obj: any, showHidden?: boolean, depth?: number, colors?: boolean): string;Usage Examples:
utils.inspect({ a: 1, b: { c: 2 } });
// '{ a: 1, b: { c: 2 } }'
utils.inspect([1, 2, 3]);
// '[ 1, 2, 3 ]'
utils.inspect("hello world");
// "'hello world'"
utils.inspect(function test() {}, false, 0);
// '[Function: test]'Deep equality comparison using the deep-eql library.
/**
* Deep equality comparison
* @param a - First value
* @param b - Second value
* @returns True if deeply equal, false otherwise
*/
eql(a: any, b: any): boolean;Usage Examples:
utils.eql({ a: 1 }, { a: 1 }); // true
utils.eql([1, 2, 3], [1, 2, 3]); // true
utils.eql({ a: { b: 1 } }, { a: { b: 1 } }); // true
utils.eql({ a: 1 }, { a: 2 }); // false
utils.eql(new Date('2023-01-01'), new Date('2023-01-01')); // trueCompare values by their string representation for sorting.
/**
* Compare values by their inspect output for sorting
* @param a - First value
* @param b - Second value
* @returns Comparison result (-1, 0, 1)
*/
compareByInspect(a: any, b: any): number;Validate that a value matches one of the expected types.
/**
* Validate that a value matches expected types
* @param obj - Value to check
* @param types - Array of acceptable type names
* @throws TypeError if value doesn't match any expected type
*/
expectTypes(obj: any, types: string[]): void;Usage Examples:
utils.expectTypes("hello", ["string"]); // OK
utils.expectTypes(42, ["string", "number"]); // OK
utils.expectTypes([], ["string"]); // Throws TypeErrorCheck if a value is a regular expression.
/**
* Check if a value is a RegExp
* @param obj - Value to test
* @returns True if value is a RegExp
*/
isRegExp(obj: any): boolean;Check if a value is numeric (number or BigInt).
/**
* Check if a value is numeric (number or BigInt)
* @param obj - Value to test
* @returns True if value is numeric
*/
isNumeric(obj: any): boolean;Enhanced NaN checking that works correctly across different contexts.
/**
* Check if a value is NaN
* @param obj - Value to test
* @returns True if value is NaN
*/
isNaN(obj: any): boolean;Get information about a property path in an object.
/**
* Get information about a property path
* @param path - Property path (e.g., 'user.name', 'items[0].id')
* @param obj - Object to traverse
* @returns Path information object
*/
getPathInfo(path: string, obj: any): PathInfo;
interface PathInfo {
parent: any;
name: string | number;
value: any;
exists: boolean;
}Check if an object has a specific property.
/**
* Check if an object has a property
* @param obj - Object to check
* @param name - Property name
* @returns True if property exists
*/
hasProperty(obj: any, name: string | number | symbol): boolean;Get all own enumerable properties of an object.
/**
* Get own enumerable properties of an object
* @param obj - Object to inspect
* @returns Array of property names and symbols
*/
getOwnEnumerableProperties(obj: any): Array<string | symbol>;Get own enumerable symbol properties of an object.
/**
* Get own enumerable symbol properties
* @param obj - Object to inspect
* @returns Array of symbol properties
*/
getOwnEnumerablePropertySymbols(obj: any): symbol[];Add a chainable property to a prototype.
/**
* Add a chainable property to a prototype
* @param proto - Prototype to extend
* @param name - Property name
* @param fn - Property function
*/
addProperty(proto: any, name: string, fn: Function): void;Add a chainable method to a prototype.
/**
* Add a chainable method to a prototype
* @param proto - Prototype to extend
* @param name - Method name
* @param fn - Method function
*/
addMethod(proto: any, name: string, fn: Function): void;Add a method that can function as both property and method.
/**
* Add a chainable method (property + method behavior)
* @param proto - Prototype to extend
* @param name - Method/property name
* @param method - Method function
* @param chainingBehavior - Property behavior function (optional)
*/
addChainableMethod(
proto: any,
name: string,
method: Function,
chainingBehavior?: Function
): void;Replace existing assertion methods while preserving access to original.
/**
* Overwrite an existing property
* @param proto - Prototype to modify
* @param name - Property name
* @param fn - New property function (receives original as _super)
*/
overwriteProperty(proto: any, name: string, fn: Function): void;
/**
* Overwrite an existing method
* @param proto - Prototype to modify
* @param name - Method name
* @param fn - New method function (receives original as _super)
*/
overwriteMethod(proto: any, name: string, fn: Function): void;
/**
* Overwrite an existing chainable method
* @param proto - Prototype to modify
* @param name - Method name
* @param method - New method function
* @param chainingBehavior - New chaining behavior function (optional)
*/
overwriteChainableMethod(
proto: any,
name: string,
method: Function,
chainingBehavior?: Function
): void;Copy flags from one assertion to another.
/**
* Transfer flags from source to target assertion
* @param assertion - Source assertion
* @param target - Target assertion
* @param includeAll - Include all flags or just transferable ones
*/
transferFlags(assertion: Assertion, target: Assertion, includeAll?: boolean): void;Wrap an assertion with a Proxy for typo detection.
/**
* Wrap assertion with Proxy for property access validation
* @param assertion - Assertion to wrap
* @returns Proxified assertion
*/
proxify(assertion: Assertion): Assertion;Check if Proxy support is available and enabled.
/**
* Check if Proxy support is available and enabled
* @returns True if Proxy can be used
*/
isProxyEnabled(): boolean;Extract the name of a function.
/**
* Get the name of a function
* @param fn - Function to get name of
* @returns Function name or empty string
*/
getName(fn: Function): string;Usage Examples:
function myFunction() {}
const arrow = () => {};
const anonymous = function() {};
utils.getName(myFunction); // 'myFunction'
utils.getName(arrow); // 'arrow'
utils.getName(anonymous); // 'anonymous' or ''Add length guard to functions to prevent incorrect usage.
/**
* Add length guard to a function for proper argument validation
* @param fn - Function to guard
* @param assertionName - Name of the assertion for error messages
* @param isChainable - Whether the assertion is chainable
* @returns Guarded function
*/
addLengthGuard(fn: Function, assertionName: string, isChainable: boolean): Function;Extract the operator from assertion arguments for error reporting.
/**
* Get the operator from assertion arguments
* @param assertion - Assertion instance
* @param args - Assertion arguments
* @returns Operator string for error messages
*/
getOperator(assertion: Assertion, args: any[]): string;Error checking utilities from the check-error package.
interface CheckErrorStatic {
/**
* Check if an error matches criteria
* @param error - Error to check
* @param errorLike - Expected error type or instance
* @param errMsgMatcher - Expected message pattern
* @returns True if error matches
*/
compatibleInstance(error: Error, errorLike: any): boolean;
compatibleConstructor(error: Error, errorLike: any): boolean;
compatibleMessage(error: Error, errMsgMatcher: string | RegExp): boolean;
getConstructorName(errorLike: any): string;
getMessage(error: Error): string;
}use(function(chai, utils) {
const { Assertion } = chai;
Assertion.addMethod('sorted', function(direction = 'asc') {
const obj = utils.flag(this, 'object');
// Type validation
utils.expectTypes(obj, ['array']);
// Check if array is sorted
const isSorted = obj.every((item, index) => {
if (index === 0) return true;
const comparison = utils.compareByInspect(obj[index - 1], item);
return direction === 'asc' ? comparison <= 0 : comparison >= 0;
});
this.assert(
isSorted,
`expected array to be sorted in ${direction}ending order`,
`expected array to not be sorted in ${direction}ending order`
);
});
});
// Usage
expect([1, 2, 3, 4]).to.be.sorted();
expect([4, 3, 2, 1]).to.be.sorted('desc');use(function(chai, utils) {
const { Assertion } = chai;
// Modifier property
Assertion.addProperty('eventually', function() {
utils.flag(this, 'eventually', true);
});
// Method that uses the flag
Assertion.addMethod('equal', function(expected) {
const obj = utils.flag(this, 'object');
const eventually = utils.flag(this, 'eventually');
if (eventually && typeof obj === 'function') {
// Handle async assertions
return obj().then(result => {
new Assertion(result).to.equal(expected);
});
} else {
// Standard synchronous assertion
return new Assertion(obj).to.equal(expected);
}
});
});
// Usage
expect(asyncFunction).to.eventually.equal('result');