CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-testem

Test-framework agnostic JavaScript testing runner that supports TDD workflows and CI integration across multiple browsers and environments.

Pending
Overview
Eval results
Files

programmatic-api.mddocs/

Programmatic API

Testem provides a JavaScript API for integrating into build tools, custom workflows, and automated systems.

Capabilities

Api Class

Main programmatic interface for controlling testem execution modes.

/**
 * Main API class for programmatic testem control
 */
class Api {
  /**
   * Start development mode with file watching and interactive UI
   * @param options - Configuration options for development mode
   * @param finalizer - Optional callback when development session ends
   */
  startDev(options: TestemOptions, finalizer?: (exitCode: number, error?: Error) => void): void;
  
  /**
   * Start CI mode for automated test execution
   * @param options - Configuration options for CI mode  
   * @param finalizer - Callback when tests complete with exit code and error
   */
  startCI(options: TestemOptions, finalizer?: (exitCode: number, error?: Error) => void): void;
  
  /**
   * Start server-only mode without launching browsers
   * @param options - Configuration options for server mode
   */
  startServer(options: TestemOptions): void;
  
  /**
   * Restart the current test run (development mode only)
   */
  restart(): void;
  
  /**
   * Set default options that will be merged with runtime options
   * @param defaultOptions - Default configuration options
   */
  setDefaultOptions(defaultOptions: TestemOptions): void;
}

Usage Examples:

const Api = require('testem/lib/api');

// Development mode
const api = new Api();
api.startDev({
  port: 7357,
  launch: ['Chrome', 'Firefox'],
  src_files: ['src/**/*.js', 'test/**/*.js']
});

// CI mode with callback
api.startCI({
  reporter: 'tap',
  parallel: 3,
  launch_in_ci: ['Chrome', 'Firefox']
}, (exitCode, error) => {
  if (exitCode === 0) {
    console.log('All tests passed!');
  } else {
    console.error('Tests failed:', error);
  }
  process.exit(exitCode);
});

// Server-only mode
api.startServer({
  port: 8080,
  serve_files: ['dist/bundle.js']
});

Config Class

Configuration management with file parsing and option merging.

/**
 * Configuration management class
 */
class Config {
  /**
   * Create a new configuration instance
   * @param appMode - Application mode (dev, ci, server)
   * @param progOptions - Programmatic options
   * @param config - Direct configuration object
   */
  constructor(appMode: 'dev' | 'ci' | 'server', progOptions?: TestemOptions, config?: ConfigOptions);
  
  /**
   * Read configuration from file system
   * @param callback - Called when configuration is loaded
   */
  read(callback: () => void): void;
  
  /**
   * Get a configuration value
   * @param key - Configuration key
   * @returns Configuration value
   */
  get(key: string): any;
  
  /**
   * Set a configuration value
   * @param key - Configuration key  
   * @param value - Value to set
   */
  set(key: string, value: any): void;
  
  /**
   * Resolve a file path relative to working directory
   * @param filepath - File path to resolve
   * @returns Absolute file path
   */
  resolvePath(filepath: string): string;
  
  /**
   * Get client-side configuration
   * @returns Configuration object for browser clients
   */
  client(): object;
  
  /**
   * Print information about available launchers
   */
  printLauncherInfo(): void;
  
  /**
   * Set default configuration options
   * @param defaultOptions - Default options to merge
   */
  setDefaultOptions(defaultOptions: TestemOptions): void;
}

Usage Examples:

const Config = require('testem/lib/config');

// Create configuration
const config = new Config('ci', {
  port: 7357,
  reporter: 'tap'
});

// Read from file
config.read(() => {
  console.log('Framework:', config.get('framework'));
  console.log('Source files:', config.get('src_files'));
  
  // Modify configuration
  config.set('parallel', 5);
  
  // Resolve paths
  const testFile = config.resolvePath('test/runner.js');
});

Server Class

Express-based server for serving test files and managing client connections.

/**
 * Web server for serving tests and managing browser connections
 */
class Server extends EventEmitter {
  /**
   * Create a new server instance
   * @param config - Configuration instance
   */
  constructor(config: Config);
  
  /**
   * Start the server
   * @param callback - Optional callback when server starts
   * @returns Promise that resolves when server is listening
   */
  start(callback?: () => void): Promise<void>;
  
  /**
   * Stop the server and close all connections
   * @param callback - Optional callback when server stops
   * @returns Promise that resolves when server is closed  
   */
  stop(callback?: () => void): Promise<void>;
  
  // Events emitted:
  // 'server-start' - Server has started listening
  // 'server-error' - Server encountered an error
}

Usage Examples:

const Server = require('testem/lib/server');
const Config = require('testem/lib/config');

// Create and start server
const config = new Config('server', { port: 8080 });
config.read(() => {
  const server = new Server(config);
  
  server.on('server-start', () => {
    console.log('Server started on port', config.get('port'));
  });
  
  server.on('server-error', (error) => {
    console.error('Server error:', error);
  });
  
  server.start().then(() => {
    console.log('Server is ready');
  });
});

App Class

Main application orchestrator that coordinates all testem components.

/**
 * Main application class that orchestrates test execution
 */
class App extends EventEmitter {
  /**
   * Create a new application instance
   * @param config - Configuration instance
   * @param finalizer - Function called when app exits
   */
  constructor(config: Config, finalizer?: (exitCode: number, error?: Error) => void);
  
  /**
   * Start the application
   * @param callback - Optional callback when app starts
   * @returns Promise that resolves when app is running
   */
  start(callback?: () => void): Promise<void>;
  
  /**
   * Exit the application
   * @param error - Optional error that caused exit
   */
  exit(error?: Error): void;
  
  /**
   * Trigger a new test run (development mode)
   * @param reason - Reason for triggering run
   */
  triggerRun(reason: string): void;
  
  // Events emitted:
  // 'tests-finish' - All tests completed successfully
  // 'tests-error' - Tests completed with errors
}

Usage Examples:

const App = require('testem/lib/app');
const Config = require('testem/lib/config');

// Create application
const config = new Config('dev', { port: 7357 });
config.read(() => {
  const app = new App(config, (exitCode, error) => {
    console.log('App exited with code:', exitCode);
    if (error) console.error('Error:', error);
  });
  
  app.on('tests-finish', () => {
    console.log('Tests completed successfully');
  });
  
  app.on('tests-error', () => {
    console.log('Tests completed with errors');
  });
  
  app.start();
});

Integration Examples

Build Tool Integration

// Example: Gulp integration
const gulp = require('gulp');
const Api = require('testem/lib/api');

gulp.task('test', (done) => {
  const api = new Api();
  api.startCI({
    launch_in_ci: ['Chrome', 'Firefox'],
    reporter: 'tap'
  }, (exitCode, error) => {
    if (exitCode !== 0) {
      done(new Error('Tests failed'));
    } else {
      done();
    }
  });
});

// Example: Webpack plugin
class TestemPlugin {
  apply(compiler) {
    compiler.hooks.afterEmit.tapAsync('TestemPlugin', (compilation, callback) => {
      const api = new Api();
      api.startCI({
        src_files: ['dist/bundle.js', 'test/**/*.js']
      }, (exitCode) => {
        callback();
      });
    });
  }
}

Custom Test Runner

// Custom test runner with programmatic control
const Api = require('testem/lib/api');
const Config = require('testem/lib/config');

class CustomTestRunner {
  constructor(options) {
    this.api = new Api();
    this.config = new Config('ci', options);
  }
  
  async run() {
    return new Promise((resolve, reject) => {
      this.config.read(() => {
        this.api.startCI(this.config, (exitCode, error) => {
          if (exitCode === 0) {
            resolve({ success: true, exitCode });
          } else {
            reject({ success: false, exitCode, error });
          }
        });
      });
    });
  }
}

// Usage
const runner = new CustomTestRunner({
  framework: 'jasmine',
  src_files: ['src/**/*.js', 'test/**/*.js'],
  launch_in_ci: ['Chrome', 'Firefox']
});

runner.run()
  .then(result => console.log('Tests passed'))
  .catch(result => console.error('Tests failed:', result.error));

Development Server Integration

// Example: Express middleware integration
const express = require('express');
const Server = require('testem/lib/server');
const Config = require('testem/lib/config');

const app = express();

// Regular routes
app.get('/api/*', handleApiRequests);

// Testem integration for testing
const config = new Config('server', {
  port: 0, // Use random port for testem
  src_files: ['public/js/**/*.js', 'test/**/*.js']
});

config.read(() => {
  const testemServer = new Server(config);
  testemServer.start().then(() => {
    const testemPort = config.get('port');
    
    // Proxy test requests to testem
    app.use('/testem', proxy(`http://localhost:${testemPort}`));
    
    app.listen(3000, () => {
      console.log('Development server with testem integration ready');
    });
  });
});

Install with Tessl CLI

npx tessl i tessl/npm-testem

docs

cli.md

configuration.md

index.md

launchers.md

programmatic-api.md

reporters.md

tile.json