or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

assertion-modifiers.mdcontent-testing.mdcore-functions.mdfunction-testing.mdindex.mdnumeric-comparisons.mdpattern-validation.mdpromise-testing.mdsettings.mdstring-assertions.mdtype-assertions.mdvalue-assertions.md
tile.json

pattern-validation.mddocs/

Pattern and Custom Validation

Advanced validation using regular expressions, type checking, and custom validator functions.

Capabilities

instanceof() Method

Asserts that the reference value is an instance of the provided constructor function.

/**
 * Asserts that the reference value is instance of provided type
 * @param {Function} type - Constructor function to check against
 * @returns {Assertion} Assertion chain object for further chaining
 */
instanceof(type)

Alias:

instanceOf()

Usage Examples:

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

// Built-in types
expect(new Date()).to.be.an.instanceof(Date);
expect([1, 2, 3]).to.be.an.instanceof(Array);
expect(/abc/).to.be.an.instanceof(RegExp);
expect(new Error('test')).to.be.an.instanceof(Error);

// Custom classes
class User {
    constructor(name) {
        this.name = name;
    }
}

const user = new User('John');
expect(user).to.be.an.instanceof(User);
expect(user).to.be.an.instanceOf(Object); // inheritance chain

// Error classes
class CustomError extends Error {
    constructor(message) {
        super(message);
        this.name = 'CustomError';
    }
}

const err = new CustomError('Something went wrong');
expect(err).to.be.an.instanceof(CustomError);
expect(err).to.be.an.instanceof(Error); // Parent class

match() Method

Asserts that the reference value's string representation matches the provided regular expression.

/**
 * Asserts that the reference value matches the regex pattern
 * @param {RegExp} regex - Regular expression pattern to match
 * @returns {Assertion} Assertion chain object for further chaining
 */
match(regex)

Alias:

matches()

Usage Examples:

// String pattern matching
expect('hello123').to.match(/hello\d+/);
expect('user@example.com').to.match(/\w+@\w+\.\w+/);
expect('2023-12-01').to.match(/^\d{4}-\d{2}-\d{2}$/);

// Case insensitive matching
expect('Hello World').to.match(/hello world/i);

// Phone number validation
expect('(555) 123-4567').to.match(/^\(\d{3}\) \d{3}-\d{4}$/);

// Using alias
expect('abc123').to.matches(/[a-z]+\d+/);

// Non-string values (converted to string)
expect(12345).to.match(/^\d+$/);
expect(true).to.match(/^true$/);

satisfy() Method

Asserts that the reference value satisfies the provided validator function.

/**
 * Asserts that the reference value satisfies validator function
 * @param {Function} validator - Function that returns boolean
 * @returns {Assertion} Assertion chain object for further chaining
 */
satisfy(validator)

Alias:

satisfies()

Usage Examples:

// Simple validation
expect(10).to.satisfy(x => x > 5);
expect('hello').to.satisfy(str => str.length === 5);

// Complex validation
const isValidEmail = (email) => {
    return typeof email === 'string' && 
           email.includes('@') && 
           email.includes('.') &&
           email.length > 5;
};

expect('user@example.com').to.satisfy(isValidEmail);
expect('invalid-email').to.not.satisfy(isValidEmail);

// Array validation
const isNonEmptyArray = (arr) => Array.isArray(arr) && arr.length > 0;
expect([1, 2, 3]).to.satisfy(isNonEmptyArray);
expect([]).to.not.satisfy(isNonEmptyArray);

// Object structure validation
const hasRequiredFields = (obj) => {
    return obj && 
           typeof obj.name === 'string' &&
           typeof obj.age === 'number' &&
           obj.age > 0;
};

expect({name: 'John', age: 30}).to.satisfy(hasRequiredFields);
expect({name: 'John'}).to.not.satisfy(hasRequiredFields);

Advanced Usage Patterns

Combining Pattern Validations

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

// Multiple validation approaches
const email = 'user@example.com';
expect(email)
    .to.be.a.string()
    .and.match(/^[^@]+@[^@]+\.[^@]+$/)
    .and.satisfy(e => e.length > 5)
    .and.include('@');

// Complex object validation
class Product {
    constructor(name, price) {
        this.name = name;
        this.price = price;
    }
}

const product = new Product('Laptop', 999);
expect(product)
    .to.be.an.instanceof(Product)
    .and.satisfy(p => p.price > 0)
    .and.satisfy(p => typeof p.name === 'string');

Custom Validators

// Reusable validators
const validators = {
    isValidUrl: (url) => {
        try {
            new URL(url);
            return true;
        } catch {
            return false;
        }
    },
    
    isPositiveInteger: (num) => {
        return Number.isInteger(num) && num > 0;
    },
    
    isValidDate: (dateStr) => {
        const date = new Date(dateStr);
        return date instanceof Date && !isNaN(date);
    },
    
    hasMinLength: (minLen) => (str) => {
        return typeof str === 'string' && str.length >= minLen;
    }
};

// Usage
expect('https://example.com').to.satisfy(validators.isValidUrl);
expect(42).to.satisfy(validators.isPositiveInteger);
expect('2023-12-01').to.satisfy(validators.isValidDate);
expect('hello world').to.satisfy(validators.hasMinLength(5));

Regular Expression Patterns

// Common regex patterns
const patterns = {
    email: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
    phone: /^\(?([0-9]{3})\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$/,
    url: /^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)$/,
    uuid: /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i,
    ipv4: /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/,
    creditCard: /^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|3[47][0-9]{13}|3[0-9]{13}|6(?:011|5[0-9]{2})[0-9]{12})$/
};

// Validation usage
expect('user@domain.com').to.match(patterns.email);
expect('555-123-4567').to.match(patterns.phone);
expect('https://www.example.com').to.match(patterns.url);
expect('550e8400-e29b-41d4-a716-446655440000').to.match(patterns.uuid);

Error Handling and Edge Cases

// Graceful error handling in validators
const safeValidator = (value) => {
    try {
        // Some complex validation logic
        return value && value.toString().length > 0;
    } catch (err) {
        return false; // Return false instead of throwing
    }
};

expect('test').to.satisfy(safeValidator);
expect(null).to.not.satisfy(safeValidator);

// Type checking in validators
const typeAwareValidator = (value) => {
    if (typeof value !== 'string') return false;
    return value.startsWith('prefix_');
};

expect('prefix_test').to.satisfy(typeAwareValidator);
expect(123).to.not.satisfy(typeAwareValidator);

// Multiple condition validators
const complexValidator = (obj) => {
    return obj &&
           typeof obj === 'object' &&
           Array.isArray(obj.items) &&
           obj.items.length > 0 &&
           obj.items.every(item => typeof item === 'string');
};

expect({items: ['a', 'b', 'c']}).to.satisfy(complexValidator);
expect({items: []}).to.not.satisfy(complexValidator);
expect({items: [1, 2, 3]}).to.not.satisfy(complexValidator);

Integration with Business Logic

// Domain-specific validation
class UserAccount {
    constructor(username, email, age) {
        this.username = username;
        this.email = email;
        this.age = age;
    }
}

const isValidUserAccount = (account) => {
    return account instanceof UserAccount &&
           typeof account.username === 'string' &&
           account.username.length >= 3 &&
           /^[^@]+@[^@]+\.[^@]+$/.test(account.email) &&
           typeof account.age === 'number' &&
           account.age >= 13;
};

const user = new UserAccount('john_doe', 'john@example.com', 25);
expect(user)
    .to.be.an.instanceof(UserAccount)
    .and.satisfy(isValidUserAccount);

// API response validation
const isValidApiResponse = (response) => {
    return response &&
           typeof response.status === 'number' &&
           response.status >= 200 &&
           response.status < 300 &&
           response.data !== undefined;
};

const apiResponse = {status: 200, data: {id: 1, name: 'Test'}};
expect(apiResponse).to.satisfy(isValidApiResponse);