or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

build.mdcode-quality.mddocumentation.mdindex.mdmonorepo.mdrelease.mdtesting.mdutilities.md
tile.json

utilities.mddocs/

Testing Utilities

Aegir provides comprehensive testing utilities including enhanced Chai assertions, HTTP echo server, fixture loading, port management, path resolution, and environment detection.

Capabilities

Enhanced Chai Assertions

Pre-configured Chai instance with useful testing plugins for comprehensive assertion capabilities.

// Import enhanced Chai
import { expect, assert, chai } from 'aegir/chai';

// Available exports
export const expect: Chai.ExpectStatic;
export const assert: Chai.AssertStatic;
export const chai: Chai.ChaiStatic;

// Included plugins (automatically configured):
export const chaiAsPromised: any;    // Promise assertion support
export const chaiParentheses: any;   // Parentheses syntax support
export const chaiSubset: any;        // Object subset matching
export const chaiBites: any;         // Binary data assertions
export const chaiString: any;        // String assertion extensions

Usage Examples:

import { expect } from 'aegir/chai';

// Standard Chai assertions
expect(true).to.be.true();
expect('hello').to.be.a('string');
expect([1, 2, 3]).to.have.length(3);

// Promise assertions (chai-as-promised)
await expect(Promise.resolve('success')).to.eventually.equal('success');
await expect(Promise.reject('error')).to.be.rejected;

// String assertions (chai-string)
expect('hello world').to.startWith('hello');
expect('test@example.com').to.be.an.email();

// Object subset matching (chai-subset)
expect({ a: 1, b: 2, c: 3 }).to.containSubset({ a: 1, b: 2 });

// Binary data assertions (chai-bites)
const buffer = Buffer.from('hello');
expect(buffer).to.have.bytes([104, 101, 108, 108, 111]);

HTTP Echo Server

HTTP server for testing HTTP requests with configurable endpoints and responses.

/**
 * HTTP echo server for testing purposes
 */
export default class EchoServer {
  /**
   * Create echo server instance
   * @param options - Server configuration options
   */
  constructor(options?: {
    port?: number;      // Server port (default: 3000)
    host?: string;      // Server host (default: '127.0.0.1')
    findPort?: boolean; // Auto-find available port (default: true)
  });

  /** Start the server */
  start(): Promise<EchoServer>;

  /** Stop the server */
  stop(): Promise<EchoServer>;

  /** Server port (available after start()) */
  port: number;

  /** Server host */
  host: string;

  /** Server started status */
  started: boolean;
}

Usage Examples:

import EchoServer from 'aegir/echo-server';

// Basic usage
const server = new EchoServer();
await server.start();
console.log(`Server running on http://${server.host}:${server.port}`);

// Test endpoints
const response = await fetch(`http://${server.host}:${server.port}/echo`, {
  method: 'POST',
  body: JSON.stringify({ test: 'data' }),
  headers: { 'Content-Type': 'application/json' }
});
const echoed = await response.json();

await server.stop();

Available Endpoints:

# Echo request body
POST/GET /echo
# Returns: complete request object

# Echo query parameters  
GET /echo/query?key=value
# Returns: { key: "value" }

# Echo request headers
GET /echo/headers
# Returns: request headers object

# Redirect endpoint
GET /redirect?to=<url>
# Returns: 302 redirect to specified URL

# Download endpoint
GET /download?data=<string>
# Returns: binary data as download

Fixture Loading

Cross-platform fixture file loading for tests (works in Node.js and browsers).

/**
 * Load fixture files for testing
 * @param filePath - Path to fixture file relative to module root
 * @param module - Optional module name for cross-module fixtures
 * @returns File contents as Uint8Array
 */
export default function loadFixtures(filePath: string, module?: string): Uint8Array;

Usage Examples:

import loadFixtures from 'aegir/fixtures';

// Load fixture from current module
const fixture = loadFixtures('test/fixtures/sample.json');
const data = JSON.parse(new TextDecoder().decode(fixture));

// Load fixture from different module (for shared test suites)
const sharedFixture = loadFixtures('test/fixtures/data.json', 'shared-test-module');

// Convert to string
const textFixture = loadFixtures('test/fixtures/text-file.txt');
const content = new TextDecoder().decode(textFixture);

The loader searches for files in multiple locations:

  • Current working directory + filePath
  • node_modules + filePath
  • require.resolve() resolution
  • Module-specific node_modules traversal

Port Management

Utility for finding available ports for test servers and development tools.

/**
 * Find available port for server binding
 * @param port - Preferred port number (default: 3000)
 * @param host - Host address (default: '127.0.0.1')
 * @returns Promise resolving to available port number
 */
export default function getPort(port?: number, host?: string): Promise<number>;

Usage Examples:

import getPort from 'aegir/get-port';

// Find available port starting from 3000
const port = await getPort(3000);
console.log(`Using port: ${port}`);

// Find any available port
const anyPort = await getPort();

// Specific host
const port = await getPort(8080, '0.0.0.0');

// Use in test setup
const testPort = await getPort(9000, '127.0.0.1');
const server = createServer().listen(testPort);

Path Resolution

Cross-context path resolution utility for loading resources across different module contexts.

/**
 * Resolve file paths across different module contexts
 * @param filePath - File path to resolve
 * @param module - Optional module context for resolution
 * @returns Absolute path to the resolved file
 * @throws Error if file cannot be found
 */
export default function resolve(filePath: string, module?: string): string;

Usage Examples:

import resolve from 'aegir/resolve';

// Resolve file in current project
const configPath = resolve('config/test.json');

// Resolve file in specific module context
const sharedPath = resolve('templates/base.html', 'shared-templates');

// Use resolved path
import fs from 'fs';
const config = JSON.parse(fs.readFileSync(resolve('config/app.json'), 'utf8'));

// Browser version available as 'aegir/resolve' (different implementation)

Resolution Strategy:

  1. Current working directory + filePath
  2. node_modules + filePath
  3. require.resolve() fallback
  4. Module-specific node_modules traversal (if module specified)

Environment Detection

Environment detection utilities for cross-platform test code using wherearewe package.

// Re-exports all from 'wherearewe' package
export * from 'wherearewe';

// Common environment detection constants:
export const isNode: boolean;           // Node.js environment
export const isBrowser: boolean;        // Browser environment  
export const isWebWorker: boolean;      // Web Worker environment
export const isElectron: boolean;       // Electron environment
export const isElectronMain: boolean;   // Electron main process
export const isElectronRenderer: boolean; // Electron renderer process
export const isReactNative: boolean;    // React Native environment
// ... and other environment flags from wherearewe

Usage Examples:

import { isNode, isBrowser, isWebWorker, isElectron } from 'aegir/env';

// Platform-specific code
if (isNode) {
  // Use Node.js APIs
  const fs = await import('fs');
  const data = fs.readFileSync('config.json');
}

if (isBrowser) {
  // Use browser APIs
  const data = localStorage.getItem('config');
}

if (isWebWorker) {
  // Web Worker specific code
  self.addEventListener('message', handler);
}

if (isElectron) {
  // Electron-specific functionality
  const { ipcRenderer } = await import('electron');
}

// Test environment setup
describe('Cross-platform tests', () => {
  it('should work in Node.js', function() {
    if (!isNode) this.skip();
    // Node.js specific test
  });

  it('should work in browsers', function() {
    if (!isBrowser) this.skip();
    // Browser specific test
  });
});

Common Testing Patterns

Combining utilities for comprehensive test setups:

import { expect } from 'aegir/chai';
import EchoServer from 'aegir/echo-server';
import loadFixtures from 'aegir/fixtures';
import getPort from 'aegir/get-port';
import { isNode, isBrowser } from 'aegir/env';

describe('HTTP Client Tests', () => {
  let server;
  let serverUrl;

  before(async () => {
    // Setup test server
    const port = await getPort(9000);
    server = new EchoServer({ port, findPort: false });
    await server.start();
    serverUrl = `http://127.0.0.1:${port}`;
  });

  after(async () => {
    // Cleanup
    if (server) {
      await server.stop();
    }
  });

  it('should echo request data', async () => {
    const testData = { message: 'hello' };
    
    const response = await fetch(`${serverUrl}/echo`, {
      method: 'POST',
      body: JSON.stringify(testData),
      headers: { 'Content-Type': 'application/json' }
    });
    
    const result = await response.json();
    expect(result.body).to.deep.equal(testData);
  });

  it('should load fixture data', () => {
    if (!isNode) return; // Node.js only test
    
    const fixture = loadFixtures('test/fixtures/sample.json');
    const data = JSON.parse(new TextDecoder().decode(fixture));
    
    expect(data).to.be.an('object');
    expect(data).to.have.property('version');
  });
});