CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-web-component-tester

A comprehensive testing framework specifically designed for web components with browser-based testing environment, Mocha/Chai/Sinon integration, and support for both local and remote testing via Sauce Labs.

Pending
Overview
Eval results
Files

test-runner.mddocs/

Test Runner

The Web Component Tester programmatic API provides full control over test execution with event-based progress tracking and comprehensive configuration options.

Capabilities

Main Test Function

Runs a suite of web component tests with lifecycle events and comprehensive error handling.

/**
 * Runs a suite of web component tests
 * @param options - Configuration object or Context instance
 * @returns Promise that resolves when all tests complete
 */
function test(options: Config | Context): Promise<void>;

Usage Examples:

const wct = require('web-component-tester');

// Basic test run
await wct.test({
  suites: ['test/**/*.html'],
  verbose: true
});

// Advanced configuration
await wct.test({
  suites: ['test/unit/*.html', 'test/integration/*.js'],
  root: './app',
  testTimeout: 30000,
  persistent: false,
  plugins: {
    local: {
      browsers: ['chrome', 'firefox']
    }
  }
});

// Using Context for advanced control
const { Context } = wct;
const context = new Context({
  verbose: true,
  suites: ['test/*.html']
});

context.on('test-end', (browser, test, stats) => {
  console.log(`Test "${test.title}" ${test.state}`);
});

await wct.test(context);

Configuration Interface

Main configuration object for controlling test execution behavior.

interface Config {
  /** Array of test file patterns to run */
  suites?: string[];
  /** Output stream for test results */
  output?: NodeJS.WritableStream;
  /** Enable TTY-specific output formatting */
  ttyOutput?: boolean;
  /** Enable verbose logging */
  verbose?: boolean;
  /** Suppress output */
  quiet?: boolean;
  /** Show expanded test results */
  expanded?: boolean;
  /** Root directory for test files */
  root?: string;
  /** Test timeout in milliseconds */
  testTimeout?: number;
  /** Keep browsers open after tests complete */
  persistent?: boolean;
  /** Additional scripts to load in browser */
  extraScripts?: string[];
  /** Package name for client-side WCT code */
  wctPackageName?: string;
  /** Browser-side configuration options */
  clientOptions?: {
    root?: string;
    verbose?: boolean;
    environmentScripts?: string[];
  };
  /** Active browser configurations */
  activeBrowsers?: BrowserDef[];
  /** Plugin configurations */
  plugins?: {[key: string]: any};
  /** Browser-specific options */
  browserOptions?: any;
  /** Skip cleanup after tests */
  skipCleanup?: boolean;
}

Browser Definition

Configuration for individual browser instances.

interface BrowserDef {
  /** Browser name (chrome, firefox, safari, etc.) */
  browserName?: string;
  /** Platform/OS name */
  platform?: string;
  /** Browser version */
  version?: string;
  /** Unique browser ID (assigned automatically) */
  id?: number;
  /** Variant name for dependency testing */
  variant?: string;
  /** Additional browser-specific capabilities */
  [key: string]: any;
}

type Browser = string | BrowserDef;

Test Lifecycle Events

The test runner emits comprehensive lifecycle events for monitoring test progress:

Event Types

// Lifecycle Events
interface TestEvents {
  'run-start': (options: Config) => void;
  'browser-init': (browser: BrowserDef, stats: TestStats) => void;
  'browser-start': (browser: BrowserDef, metadata: any, stats: TestStats) => void;
  'sub-suite-start': (browser: BrowserDef, sharedState: any, stats: TestStats) => void;
  'test-start': (browser: BrowserDef, test: TestCase, stats: TestStats) => void;
  'test-end': (browser: BrowserDef, test: TestCase, stats: TestStats) => void;
  'sub-suite-end': (browser: BrowserDef, sharedState: any, stats: TestStats) => void;
  'browser-end': (browser: BrowserDef, error: any, stats: TestStats) => void;
  'run-end': (error: any) => void;
  
  // Log Events
  'log:debug': (message: string, ...args: any[]) => void;
  'log:info': (message: string, ...args: any[]) => void;
  'log:warn': (message: string, ...args: any[]) => void;
  'log:error': (message: string, ...args: any[]) => void;
}

Event Usage Examples

const wct = require('web-component-tester');
const { Context } = wct;

const context = new Context({
  suites: ['test/*.html'],
  verbose: true
});

// Track test progress
context.on('run-start', (options) => {
  console.log('Starting test run with', options.activeBrowsers.length, 'browsers');
});

context.on('browser-start', (browser, metadata, stats) => {
  console.log(`Browser ${browser.browserName} started`);
});

context.on('test-end', (browser, test, stats) => {
  const status = test.state === 'passed' ? '✓' : '✗';
  console.log(`${status} ${test.title} (${browser.browserName})`);
});

context.on('browser-end', (browser, error, stats) => {
  if (error) {
    console.error(`Browser ${browser.browserName} failed:`, error);
  } else {
    console.log(`Browser ${browser.browserName} completed: ${stats.passed}/${stats.total} passed`);
  }
});

context.on('run-end', (error) => {
  if (error) {
    console.error('Test run failed:', error);
  } else {
    console.log('All tests completed successfully');
  }
});

await wct.test(context);

Advanced Usage

Custom Reporting

const wct = require('web-component-tester');
const fs = require('fs');

class CustomReporter {
  constructor() {
    this.results = [];
  }
  
  onTestEnd(browser, test, stats) {
    this.results.push({
      browser: browser.browserName,
      test: test.title,
      state: test.state,
      duration: test.duration,
      timestamp: new Date().toISOString()
    });
  }
  
  onRunEnd() {
    fs.writeFileSync('test-results.json', JSON.stringify(this.results, null, 2));
  }
}

const context = new wct.Context({ suites: ['test/*.html'] });
const reporter = new CustomReporter();

context.on('test-end', reporter.onTestEnd.bind(reporter));
context.on('run-end', reporter.onRunEnd.bind(reporter));

await wct.test(context);

Error Handling

const wct = require('web-component-tester');

try {
  await wct.test({
    suites: ['test/*.html'],
    testTimeout: 10000
  });
  console.log('All tests passed!');
} catch (error) {
  console.error('Test run failed:', error.message);
  
  // Check if it's a test failure vs system error
  if (error.message.includes('failed')) {
    process.exit(1); // Test failures
  } else {
    console.error('System error occurred');
    process.exit(2); // System errors
  }
}

Plugin Integration

const wct = require('web-component-tester');

await wct.test({
  suites: ['test/*.html'],
  plugins: {
    // Local browser testing
    local: {
      browsers: ['chrome', 'firefox'],
      browserOptions: {
        chrome: ['--headless', '--disable-gpu'],
        firefox: ['-headless']
      }
    },
    // Sauce Labs testing
    sauce: {
      username: process.env.SAUCE_USERNAME,
      accessKey: process.env.SAUCE_ACCESS_KEY,
      browsers: [
        { browserName: 'chrome', platform: 'Windows 10' },
        { browserName: 'firefox', platform: 'macOS 10.15' }
      ]
    }
  }
});

Types

interface TestCase {
  title: string;
  state: 'passed' | 'failed' | 'pending';
  duration?: number;
  error?: Error;
}

interface TestStats {
  passed: number;
  pending: number;
  failed: number;
  total: number;
}

interface Context extends EventEmitter {
  options: Config;
  emitHook(name: string): Promise<void>;
  plugins(): Promise<Plugin[]>;
}

Install with Tessl CLI

npx tessl i tessl/npm-web-component-tester

docs

browser-environment.md

build-tools.md

cli.md

configuration.md

index.md

plugin-system.md

test-runner.md

tile.json