or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

assert-interface.mdconfiguration.mdcore-assertions.mdexpect-interface.mdindex.mdplugin-system.mdshould-interface.mdutilities.md
tile.json

utilities.mddocs/

Utilities

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.

Capabilities

ChaiUtils Interface

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;
}

Core Utilities

flag

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'
    );
  });
});

test

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;

type

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'

getMessage

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;

getActual

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;

inspect

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]'

Equality and Comparison

eql

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')); // true

compareByInspect

Compare 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;

Type Checking

expectTypes

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 TypeError

isRegExp

Check 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;

isNumeric

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;

isNaN

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;

Property and Path Utilities

getPathInfo

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;
}

hasProperty

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;

getOwnEnumerableProperties

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>;

getOwnEnumerablePropertySymbols

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[];

Assertion Building

addProperty

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;

addMethod

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;

addChainableMethod

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;

Overwrite Methods

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;

Advanced Utilities

transferFlags

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;

proxify

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;

isProxyEnabled

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;

getName

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 ''

addLengthGuard

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;

getOperator

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;

External Library Integration

checkError

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;
}

Utility Usage Examples

Building Custom Assertions

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');

Working with Flags

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');