CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-qunit

The powerful, easy-to-use testing framework for JavaScript applications

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

events.mddocs/

Events

Event-driven architecture enabling monitoring of test lifecycle, capturing results, building custom reporting solutions, and integrating with external tools.

Capabilities

Event Registration

Register callbacks to listen for test lifecycle events.

/**
 * Register event listener for test lifecycle events
 * @param {string} eventName - Name of the event to listen for
 * @param {Function} callback - Function to call when event occurs
 */
QUnit.on(eventName, callback)

Usage Examples:

import QUnit from "qunit";

// Listen for test start events
QUnit.on("testStart", function(details) {
  console.log(`Starting test: ${details.name}`);
});

// Listen for assertion events
QUnit.on("assertion", function(details) {
  if (!details.result) {
    console.error(`Assertion failed: ${details.message}`);
  }
});

// Listen for test completion
QUnit.on("testEnd", function(details) {
  console.log(`Test completed: ${details.name} (${details.status})`);
});

Test Run Events

Events related to overall test run lifecycle.

/**
 * Fired when test run begins
 * @typedef {Object} RunStartEvent
 * @property {number} totalTests - Total number of tests to run
 * @property {Array} modules - Array of modules (for legacy callbacks)
 */
QUnit.on('runStart', function(runSuite) {
  // runSuite contains test run information
  console.log('Test run started');
});

/**
 * Fired when test run completes
 * @typedef {Object} RunEndEvent  
 * @property {string} status - 'passed' or 'failed'
 * @property {Object} testCounts - Test result counts
 * @property {number} runtime - Total runtime in milliseconds
 */
QUnit.on('runEnd', function(runSuite) {
  // runSuite contains final test results
  console.log('Test run completed');
});

Usage Examples:

QUnit.on('runStart', function(runSuite) {
  console.log('Test run started');
  console.log(`Total tests: ${QUnit.config.stats.testCount}`);
});

QUnit.on('runEnd', function(runSuite) {
  console.log('Test run completed');
  console.log(`Results: ${runSuite.testCounts.passed} passed, ${runSuite.testCounts.failed} failed`);
  console.log(`Runtime: ${runSuite.runtime}ms`);
});

Module Events

Events related to test module execution.

/**
 * Fired when module execution begins
 * @typedef {Object} SuiteStartEvent
 * @property {string} name - Module name
 * @property {string} moduleId - Module ID
 */
QUnit.on('suiteStart', function(suite) {
  console.log(`Starting module: ${suite.name}`);
});

/**
 * Fired when module execution completes  
 * @typedef {Object} SuiteEndEvent
 * @property {string} name - Module name
 * @property {string} moduleId - Module ID
 * @property {string} status - 'passed' or 'failed'
 * @property {Object} testCounts - Test counts within module
 * @property {number} runtime - Module runtime in milliseconds
 */
QUnit.on('suiteEnd', function(suite) {
  console.log(`Module completed: ${suite.name}`);
});

Usage Examples:

QUnit.on('suiteStart', function(suite) {
  console.log(`Starting module: ${suite.name}`);
  console.log(`Tests in module: ${suite.testCounts.total}`);
});

QUnit.on('suiteEnd', function(suite) {
  console.log(`Module ${suite.name} completed`);
  console.log(`Status: ${suite.status}`);
  console.log(`Runtime: ${suite.runtime}ms`);
});

Test Events

Events related to individual test execution.

/**
 * Fired when individual test begins
 * @typedef {Object} TestStartEvent
 * @property {string} name - Test name
 * @property {string} testId - Test ID
 * @property {string} module - Module name
 * @property {boolean} [previousFailure] - Whether test failed in previous run
 */
QUnit.on('testStart', function(test) {
  console.log(`Starting test: ${test.name}`);
});

/**
 * Fired when individual test completes
 * @typedef {Object} TestEndEvent
 * @property {string} name - Test name
 * @property {string} testId - Test ID  
 * @property {string} module - Module name
 * @property {boolean} skipped - Whether test was skipped
 * @property {boolean} todo - Whether test is a todo test
 * @property {number} failed - Number of failed assertions
 * @property {number} passed - Number of passed assertions
 * @property {number} total - Total number of assertions
 * @property {number} runtime - Test runtime in milliseconds
 * @property {Array} assertions - Array of assertion objects (HTML Reporter use)
 * @property {string} source - Test source location (getter)
 */
QUnit.on('testEnd', function(test) {
  const status = test.failed > 0 ? 'failed' : 'passed';
  console.log(`Test ${status}: ${test.name}`);
});

Usage Examples:

QUnit.on('testStart', function(test) {
  console.log(`Starting test: ${test.name}`);
  console.log(`Module: ${test.module}`);
  console.log(`Test ID: ${test.testId}`);
});

QUnit.on('testEnd', function(test) {
  const status = test.failed > 0 ? 'FAILED' : 'PASSED';
  console.log(`${status}: ${test.name}`);
  console.log(`  Passed: ${test.passed}, Failed: ${test.failed}, Total: ${test.total}`);
  console.log(`  Runtime: ${test.runtime}ms`);
  
  if (test.skipped) {
    console.log('  Status: SKIPPED');
  } else if (test.todo) {
    console.log('  Status: TODO');
  }
});

Assertion Events

Events fired for each individual assertion.

/**
 * Fired for each assertion
 * @typedef {Object} AssertionEvent
 * @property {boolean} passed - Whether assertion passed
 * @property {any} [actual] - Actual value
 * @property {any} [expected] - Expected value
 * @property {string} message - Assertion message
 * @property {string} [stack] - Stack trace for failed assertions
 * @property {boolean} todo - Whether assertion is in a todo test
 */
QUnit.on('assertion', function(assertion) {
  if (assertion.passed) {
    console.log(`✓ ${assertion.message}`);
  } else {
    console.error(`✗ ${assertion.message}`);
    if (assertion.stack) {
      console.error(assertion.stack);
    }
  }
});

Usage Examples:

QUnit.on('assertion', function(assertion) {
  if (assertion.passed) {
    console.log(`✓ ${assertion.message}`);
  } else {
    console.error(`✗ ${assertion.message}`);
    
    if (assertion.actual !== undefined) {
      console.error(`  Expected: ${assertion.expected}`);
      console.error(`  Actual: ${assertion.actual}`);
    }
    
    if (assertion.stack) {
      console.error(`  ${assertion.stack}`);
    }
  }
});

Error Events

Events fired for uncaught errors and exceptions.

/**
 * Fired for uncaught errors during test execution
 * @typedef {Object} ErrorEvent
 * @property {string} message - Error message
 * @property {string} [source] - Error source location
 * @property {string} [testName] - Test name when error occurred
 * @property {string} [module] - Module name when error occurred
 */
QUnit.on('error', function(error) {
  console.error('Uncaught error:', error.message);
  if (error.source) {
    console.error('Source:', error.source);
  }
});

Usage Examples:

QUnit.on("error", function(details) {
  console.error("Uncaught error during test execution:");
  console.error(`Message: ${details.message}`);
  console.error(`Source: ${details.source}`);
  
  if (details.testName) {
    console.error(`Test: ${details.testName}`);
  }
  
  if (details.module) {
    console.error(`Module: ${details.module}`);
  }
});

Custom Reporter Implementation

Build custom reporters using the event system.

Usage Examples:

// Custom JSON reporter
class JSONReporter {
  constructor() {
    this.results = {
      tests: [],
      modules: [],
      summary: null
    };
    
    this.bindEvents();
  }
  
  bindEvents() {
    QUnit.on("testEnd", (details) => {
      this.results.tests.push({
        name: details.name,
        module: details.module,
        status: details.status,
        assertions: details.assertions.total,
        runtime: details.runtime,
        errors: details.errors
      });
    });
    
    QUnit.on("suiteEnd", (details) => {
      this.results.modules.push({
        name: details.name,
        status: details.status,
        testCounts: details.testCounts,
        runtime: details.runtime
      });
    });
    
    QUnit.on("runEnd", (details) => {
      this.results.summary = {
        status: details.status,
        testCounts: details.testCounts,
        runtime: details.runtime
      };
      
      this.output();
    });
  }
  
  output() {
    console.log(JSON.stringify(this.results, null, 2));
  }
}

// Initialize custom reporter
new JSONReporter();

Event-based Test Monitoring

Monitor test progress and performance.

Usage Examples:

// Performance monitoring
const performanceMonitor = {
  slowTests: [],
  threshold: 1000, // 1 second
  
  init() {
    QUnit.on("testEnd", (details) => {
      if (details.runtime > this.threshold) {
        this.slowTests.push({
          name: details.name,
          module: details.module,
          runtime: details.runtime
        });
      }
    });
    
    QUnit.on("runEnd", () => {
      if (this.slowTests.length > 0) {
        console.warn("Slow tests detected:");
        this.slowTests.forEach(test => {
          console.warn(`  ${test.module} > ${test.name}: ${test.runtime}ms`);
        });
      }
    });
  }
};

performanceMonitor.init();

Supported Events

QUnit supports the following events (defined in src/events.js):

/**
 * Available event names:
 * - 'error' - Uncaught errors (memory event)
 * - 'runStart' - Test run begins
 * - 'suiteStart' - Module execution begins  
 * - 'testStart' - Individual test begins
 * - 'assertion' - Each assertion result
 * - 'testEnd' - Individual test completes
 * - 'suiteEnd' - Module execution completes
 * - 'runEnd' - Test run completes (memory event)
 */

/**
 * Memory events are replayed for late-registered listeners
 * Events: 'error', 'runEnd'
 */

Legacy Callback API

QUnit also supports legacy callbacks for backwards compatibility:

/**
 * Legacy callback functions (still supported but events preferred)
 */
QUnit.begin(callback)      // Called before tests start
QUnit.testStart(callback)  // Called when test starts
QUnit.log(callback)        // Called for each assertion
QUnit.testDone(callback)   // Called when test completes
QUnit.moduleStart(callback)// Called when module starts
QUnit.moduleDone(callback) // Called when module completes
QUnit.done(callback)       // Called when all tests complete

Install with Tessl CLI

npx tessl i tessl/npm-qunit

docs

assertions.md

cli.md

configuration.md

error-handling.md

events.md

hooks.md

index.md

test-definition.md

test-flavors.md

utilities.md

tile.json