CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-hapi--code

BDD assertion library designed to work seamlessly with the hapi ecosystem

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

settings.mddocs/

Settings and Configuration

Global configuration options for customizing @hapi/code behavior.

Settings Object

The settings object provides global configuration options that affect all assertions.

/**
 * Global settings object for configuring @hapi/code behavior
 */
const settings = {
    truncateMessages: false,    // Truncate long error messages for readability
    comparePrototypes: false    // Include object prototypes in deep comparisons
};

Configuration Options

truncateMessages

Controls whether long assertion error messages are truncated for improved readability.

/**
 * Truncate long assertion error messages for readability
 * @type {boolean}
 * @default false
 */
settings.truncateMessages

Usage Examples:

const Code = require('@hapi/code');
const expect = Code.expect;

// Default behavior - full error messages
Code.settings.truncateMessages = false;

const longObject = {
    property1: 'very long string value that will appear in full',
    property2: 'another long string value',
    property3: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
    nested: {
        deep: {
            value: 'deeply nested long value'
        }
    }
};

try {
    expect(longObject).to.equal({different: 'object'});
} catch (err) {
    console.log(err.message); // Full object representation
}

// Truncated messages for readability
Code.settings.truncateMessages = true;

try {
    expect(longObject).to.equal({different: 'object'});
} catch (err) {
    console.log(err.message); // Truncated representation like "{ Object (property1, property2, ...) }"
}

Truncation Rules:

  • Strings longer than 40 characters: Show first 40 characters + "..."
  • Arrays: Show "[Array(length)]" format
  • Objects: Show "{ Object (key1, key2, ...) }" format with up to 2 keys
// Examples of truncated output
Code.settings.truncateMessages = true;

// Long string
const longStr = "This is a very long string that exceeds the 40 character limit";
// Error message shows: "This is a very long string that exceeds t..."

// Large array  
const largeArray = new Array(100).fill(0);
// Error message shows: "[Array(100)]"

// Complex object
const complexObj = {a: 1, b: 2, c: 3, d: 4, e: 5};
// Error message shows: "{ Object (a, b, ...) }"

comparePrototypes

Controls whether object prototypes are included in deep equality comparisons.

/**
 * Include object prototypes when doing deep comparisons
 * @type {boolean}
 * @default false
 */
settings.comparePrototypes

Usage Examples:

// Default behavior - ignore prototypes
Code.settings.comparePrototypes = false;

function Person(name) {
    this.name = name;
}
Person.prototype.greet = function() {
    return `Hello, ${this.name}`;
};

const person1 = new Person('Alice');
const person2 = {name: 'Alice'}; // Plain object without prototype

// This passes - prototypes ignored
expect(person1).to.equal(person2);

// Enable prototype comparison
Code.settings.comparePrototypes = true;

// This fails - person1 has Person.prototype, person2 doesn't
expect(person1).to.not.equal(person2);

// This passes - both have same prototype
const person3 = new Person('Alice');
expect(person1).to.equal(person3);

Advanced Prototype Scenarios:

// Custom prototypes
const proto1 = {type: 'custom'};
const proto2 = {type: 'custom'};

const obj1 = Object.create(proto1);
obj1.value = 42;

const obj2 = Object.create(proto2);
obj2.value = 42;

// With prototype comparison disabled
Code.settings.comparePrototypes = false;
expect(obj1).to.equal(obj2); // Passes - only comparing own properties

// With prototype comparison enabled
Code.settings.comparePrototypes = true;
expect(obj1).to.not.equal(obj2); // Fails - different prototype objects

// Same prototype reference
const obj3 = Object.create(proto1);
obj3.value = 42;
expect(obj1).to.equal(obj3); // Passes - same prototype reference

Per-Assertion Options

Some methods accept options that override global settings for specific assertions:

equal() Method Options

/**
 * Options for equal() method comparisons
 */
interface EqualOptions {
    prototype?: boolean;      // Override global comparePrototypes setting
    deepFunction?: boolean;   // Compare function implementations (default: true)
}

Usage Examples:

const Code = require('@hapi/code');
const expect = Code.expect;

// Global setting
Code.settings.comparePrototypes = false;

const person1 = new Person('Alice');
const person2 = {name: 'Alice'};

// Override global setting for this assertion
expect(person1).to.equal(person2, {prototype: true}); // Fails - overrides global setting

// Function comparison options
const func1 = function(x) { return x * 2; };
const func2 = function(x) { return x * 2; };
const func3 = func1;

expect({fn: func1}).to.equal({fn: func2}, {deepFunction: true}); // Compare implementations
expect({fn: func1}).to.equal({fn: func3}, {deepFunction: false}); // Reference comparison only

Configuration Best Practices

Test Suite Configuration

// Configure at test suite start
const Code = require('@hapi/code');

// Set global configuration for all tests
Code.settings.truncateMessages = true;  // Cleaner error output
Code.settings.comparePrototypes = false; // Typical for most use cases

// Example test configuration
describe('API Tests', () => {
    before(() => {
        // Override settings for specific test suites
        Code.settings.truncateMessages = false; // Full details for debugging
    });
    
    after(() => {
        // Restore settings
        Code.settings.truncateMessages = true;
    });
});

Environment-Based Configuration

// Configure based on environment
const Code = require('@hapi/code');

if (process.env.NODE_ENV === 'development') {
    Code.settings.truncateMessages = false; // Full error details for debugging
} else {
    Code.settings.truncateMessages = true;  // Cleaner output for CI/production
}

// Always customize for specific needs
if (process.env.DETAILED_ERRORS === 'true') {
    Code.settings.truncateMessages = false;
}

Temporary Setting Changes

// Save and restore settings
const Code = require('@hapi/code');
const expect = Code.expect;

function withSettings(newSettings, testFn) {
    const originalSettings = {...Code.settings};
    
    try {
        Object.assign(Code.settings, newSettings);
        return testFn();
    } finally {
        Object.assign(Code.settings, originalSettings);
    }
}

// Usage
withSettings({truncateMessages: false}, () => {
    // Tests that need full error messages
    expect(complexObject).to.equal(otherComplexObject);
});

// Settings automatically restored after test

Integration with Test Runners

@hapi/lab Integration

const Lab = require('@hapi/lab');
const Code = require('@hapi/code');
const lab = exports.lab = Lab.script();
const expect = Code.expect;

// Configure for lab integration
lab.before(() => {
    // Optimal settings for lab test runner
    Code.settings.truncateMessages = true;
    Code.settings.comparePrototypes = false;
});

lab.test('assertion count tracking', () => {
    const initialCount = Code.count();
    
    expect(1 + 1).to.equal(2);
    expect('hello').to.be.a.string();
    
    const finalCount = Code.count();
    expect(finalCount - initialCount).to.equal(2);
});

Other Test Runners

// Jest configuration
beforeAll(() => {
    const Code = require('@hapi/code');
    Code.settings.truncateMessages = true;
});

// Mocha configuration  
before(() => {
    const Code = require('@hapi/code');
    Code.settings.truncateMessages = process.env.NODE_ENV !== 'development';
});

// Ava configuration
import test from 'ava';
import * as Code from '@hapi/code';

test.before(() => {
    Code.settings.truncateMessages = true;
});

Settings Validation

// Validate settings values
const Code = require('@hapi/code');

// Type checking
if (typeof Code.settings.truncateMessages !== 'boolean') {
    throw new Error('truncateMessages must be boolean');
}

if (typeof Code.settings.comparePrototypes !== 'boolean') {
    throw new Error('comparePrototypes must be boolean');
}

// Helper function for safe configuration
function configureCode(options = {}) {
    const validOptions = ['truncateMessages', 'comparePrototypes'];
    
    for (const key of Object.keys(options)) {
        if (!validOptions.includes(key)) {
            throw new Error(`Invalid setting: ${key}`);
        }
        if (typeof options[key] !== 'boolean') {
            throw new Error(`Setting ${key} must be boolean`);
        }
    }
    
    Object.assign(Code.settings, options);
}

// Usage
configureCode({
    truncateMessages: true,
    comparePrototypes: false
});

docs

assertion-modifiers.md

content-testing.md

core-functions.md

function-testing.md

index.md

numeric-comparisons.md

pattern-validation.md

promise-testing.md

settings.md

string-assertions.md

type-assertions.md

value-assertions.md

tile.json