or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

code-coverage.mdcommand-line-interface.mdindex.mdmemory-leak-detection.mdtest-execution.mdtest-organization.mdtypescript-integration.md
tile.json

typescript-integration.mddocs/

TypeScript Integration

Comprehensive TypeScript support including type validation and test execution. Provides seamless integration for TypeScript projects with full type safety and validation capabilities.

Capabilities

TypeScript Test Execution

Run TypeScript test files directly without manual compilation, with full type checking integration.

CLI Usage:

# Run TypeScript tests
lab --typescript

# Run with custom tsconfig
lab --typescript --require 'tsconfig-paths/register'

# Validate types during execution
lab --typescript --types

Programmatic Usage:

const result = await Lab.report(script, {
    typescript: true,
    types: true,
    'types-test': './test/types.ts'
});

Type Validation

Validates TypeScript type definitions to ensure API correctness and catch type-related issues.

/**
 * Validates TypeScript types and definitions
 * @param options - Type validation configuration
 * @returns Promise resolving to type validation report
 */
types.validate(options?: TypeOptions): Promise<TypesReport>;

Usage Examples:

const Lab = require('@hapi/lab');

// Basic type validation
const typeReport = await Lab.types.validate();

// Validation with specific test file
const report = await Lab.types.validate({
    'types-test': './test/api-types.ts'
});

Type Assertion Utilities

Provides utilities for asserting types in tests, ensuring compile-time and runtime type safety.

interface TypeExpect {
    /**
     * Assert the type of a value matches expected type T
     * @param value - Value to type-check
     */
    type<T>(value: T): void;
    
    /**
     * Assert that a value should produce a type error
     * @param value - Value that should cause type error
     */
    error<T = any>(value: T): void;
}

// Available as Lab.types.expect
const expect: TypeExpect;

Usage Examples:

import * as Lab from '@hapi/lab';
import { expect as codeExpect } from '@hapi/code';

const lab = Lab.script();
const { describe, it } = lab;
export { lab };

describe('Type assertions', () => {

    it('validates correct types', () => {
        const name: string = 'test';
        const age: number = 25;
        
        // Assert types are correct
        Lab.types.expect.type<string>(name);
        Lab.types.expect.type<number>(age);
    });

    it('detects type errors', () => {
        // This should produce a type error
        Lab.types.expect.error<string>(123);
        
        // This should also produce a type error
        Lab.types.expect.error<number>('not a number');
    });
});

TypeScript Configuration

Type Validation Options

Configuration options for TypeScript type validation and testing.

interface TypeOptions {
    /** Enable TypeScript type validation */
    types?: boolean;
    
    /** Path to TypeScript definitions test file */
    'types-test'?: string;
    
    /** TypeScript compiler options */
    typescript?: boolean;
    
    /** Custom TypeScript configuration file path */
    tsconfig?: string;
}

TypeScript Support Features

Comprehensive TypeScript integration features:

  • Direct .ts file execution: No manual compilation required
  • Type checking integration: Compile-time type validation
  • Source map support: Accurate error reporting and debugging
  • Custom path mapping: Support for TypeScript path configuration
  • Definition file testing: Validate .d.ts files for correctness
  • Generic type preservation: Full type safety in test assertions

Type Validation Results

Types Report

Detailed results from TypeScript type validation and compilation.

interface TypesReport {
    /** Whether type validation passed */
    passed: boolean;
    
    /** Array of type errors found */
    errors: TypeValidationError[];
    
    /** Number of files validated */
    filesValidated: number;
    
    /** Validation execution time in milliseconds */
    duration: number;
    
    /** TypeScript compiler version used */
    compilerVersion: string;
    
    /** Configuration file used */
    configFile?: string;
}

interface TypeValidationError {
    /** Error message from TypeScript compiler */
    message: string;
    
    /** File where error occurred */
    file: string;
    
    /** Line number of error */
    line: number;
    
    /** Column number of error */
    column: number;
    
    /** Error code from TypeScript */
    code: number;
    
    /** Severity level of error */
    severity: 'error' | 'warning';
    
    /** Source code context around error */
    context?: string;
}

TypeScript Test Examples

Basic TypeScript Test Structure

Standard TypeScript test file structure with full type safety:

import * as Lab from '@hapi/lab';
import { expect } from '@hapi/code';

// API being tested
import { UserService, User, CreateUserRequest } from '../src/user-service';

const lab = Lab.script();
const { describe, it, beforeEach, afterEach } = lab;
export { lab };

describe('UserService', () => {
    let userService: UserService;

    beforeEach(() => {
        userService = new UserService();
    });

    it('creates user with correct types', async () => {
        const request: CreateUserRequest = {
            name: 'John Doe',
            email: 'john@example.com',
            age: 30
        };

        const user: User = await userService.createUser(request);
        
        expect(user.id).to.be.a.string();
        expect(user.name).to.equal(request.name);
        expect(user.email).to.equal(request.email);
        expect(user.age).to.equal(request.age);
        expect(user.createdAt).to.be.a.date();

        // Type assertions
        Lab.types.expect.type<User>(user);
        Lab.types.expect.type<string>(user.id);
        Lab.types.expect.type<Date>(user.createdAt);
    });

    it('handles type errors correctly', () => {
        // This should cause a type error
        Lab.types.expect.error<CreateUserRequest>({
            name: 'John',
            email: 'invalid',
            age: 'not a number'  // Type error: age should be number
        });
    });
});

Generic Type Testing

Testing functions with generic types while preserving type information:

import * as Lab from '@hapi/lab';
import { expect } from '@hapi/code';
import { Repository } from '../src/repository';

const lab = Lab.script();
const { describe, it } = lab;
export { lab };

interface TestEntity {
    id: string;
    name: string;
}

describe('Generic Repository', () => {

    it('preserves generic types', async () => {
        const repo = new Repository<TestEntity>();
        
        const entity: TestEntity = {
            id: '123',
            name: 'Test Entity'
        };

        const saved = await repo.save(entity);
        const found = await repo.findById('123');

        // Type assertions verify generic type preservation
        Lab.types.expect.type<TestEntity>(saved);
        Lab.types.expect.type<TestEntity | null>(found);
        
        if (found) {
            Lab.types.expect.type<TestEntity>(found);
            expect(found.id).to.equal(entity.id);
            expect(found.name).to.equal(entity.name);
        }
    });
});

API Definition Testing

Testing TypeScript definition files to ensure API correctness:

// test/api-types.ts - Type definition tests
import * as Lab from '@hapi/lab';

// Import types being tested
import { 
    UserService, 
    User, 
    CreateUserRequest, 
    UpdateUserRequest,
    UserRepository 
} from '../src/index';

const { expect } = Lab.types;

// Test interface structure
expect.type<{
    id: string;
    name: string;
    email: string;
    age: number;
    createdAt: Date;
    updatedAt: Date;
}>(undefined as any as User);

// Test request interfaces
expect.type<{
    name: string;
    email: string;
    age: number;
}>(undefined as any as CreateUserRequest);

expect.type<{
    name?: string;
    email?: string;
    age?: number;
}>(undefined as any as UpdateUserRequest);

// Test service interface
expect.type<{
    createUser(request: CreateUserRequest): Promise<User>;
    updateUser(id: string, request: UpdateUserRequest): Promise<User>;
    deleteUser(id: string): Promise<void>;
    findById(id: string): Promise<User | null>;
    findAll(): Promise<User[]>;
}>(undefined as any as UserService);

// Test error cases
expect.error<CreateUserRequest>({
    name: 'John',
    email: 'john@example.com'
    // Missing required 'age' property
});

expect.error<User>({
    id: '123',
    name: 'John',
    email: 'john@example.com',
    age: 30,
    createdAt: new Date()
    // Missing required 'updatedAt' property
});

Advanced TypeScript Features

Path Mapping Support

Support for TypeScript path mapping and module resolution:

# Install path resolution support
npm install --save-dev tsconfig-paths

# Run tests with path mapping
lab --typescript --require 'tsconfig-paths/register'
// tsconfig.json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/models/*": ["src/models/*"],
      "@/services/*": ["src/services/*"],
      "@/utils/*": ["src/utils/*"]
    }
  }
}
// Use path mapping in tests
import { User } from '@/models/user';
import { UserService } from '@/services/user-service';
import { validateEmail } from '@/utils/validation';

Source Map Integration

Accurate stack traces and debugging with source map support:

// Enable source maps for better debugging
const result = await Lab.report(script, {
    typescript: true,
    sourcemaps: true
});

Custom Compiler Options

Override TypeScript compiler options for specific test scenarios:

// Custom compiler configuration for tests
const compilerOptions = {
    strict: true,
    noImplicitAny: true,
    noImplicitReturns: true,
    noUnusedLocals: true,
    noUnusedParameters: true
};

Integration Examples

Complete TypeScript Test Setup

Full example of a TypeScript project test configuration:

// test/setup.ts
import * as Lab from '@hapi/lab';
import { expect } from '@hapi/code';

// Global test configuration
const lab = Lab.script();
export { lab };

// Export commonly used test utilities
export { expect };
export const { describe, it, before, after, beforeEach, afterEach } = lab;

// Type assertion helpers
export const expectType = Lab.types.expect.type;
export const expectError = Lab.types.expect.error;
// test/user-service.test.ts
import { lab, describe, it, expect, expectType } from './setup';
import { UserService, User } from '../src/user-service';

describe('UserService with full TypeScript support', () => {

    it('creates users with type safety', async () => {
        const service = new UserService();
        
        const user = await service.createUser({
            name: 'John Doe',
            email: 'john@example.com',
            age: 30
        });

        // Runtime assertions
        expect(user.id).to.be.a.string();
        expect(user.name).to.equal('John Doe');

        // Type assertions
        expectType<User>(user);
        expectType<string>(user.id);
        expectType<Date>(user.createdAt);
    });
});

export { lab };

CI/CD TypeScript Integration

Complete CI/CD setup with TypeScript validation:

// scripts/test-typescript.js
const Lab = require('@hapi/lab');

const runTypeScriptTests = async () => {
    const result = await Lab.run({
        typescript: true,
        types: true,
        'types-test': './test/api-types.ts',
        coverage: true,
        threshold: 90,
        reporter: ['console', 'json'],
        output: ['', 'test-results.json']
    });

    if (result.types && !result.types.passed) {
        console.error('TypeScript validation failed:');
        result.types.errors.forEach(error => {
            console.error(`  ${error.file}:${error.line}:${error.column} - ${error.message}`);
        });
        process.exit(1);
    }

    if (result.failures > 0) {
        console.error(`${result.failures} test failures`);
        process.exit(1);
    }

    console.log('All TypeScript tests passed!');
};

runTypeScriptTests();