Test-framework agnostic JavaScript testing runner that supports TDD workflows and CI integration across multiple browsers and environments.
—
Testem's launcher system provides pluggable browser and process execution with built-in support for major browsers and custom launcher definitions.
Testem includes built-in support for major browsers and runtime environments.
// Built-in browser launchers
const builtInBrowsers = [
'Chrome', // Google Chrome
'Firefox', // Mozilla Firefox
'Safari', // Safari (macOS)
'Edge', // Microsoft Edge
'IE', // Internet Explorer
'Opera', // Opera browser
'PhantomJS' // Headless PhantomJS
];
// Built-in process launchers
const builtInProcesses = [
'Node', // Node.js execution
'Mocha' // Mocha TAP runner
];Usage Examples:
// Launch specific browsers
{
"launch_in_dev": ["Chrome", "Firefox"],
"launch_in_ci": ["Chrome", "Firefox", "Safari"]
}
// Cross-platform browser launching
{
"launch_in_ci": ["Chrome", "Firefox", "IE"] // IE only works on Windows
}Find available launchers on the current system.
testem launchersExample Output:
Have 7 launchers available; auto-launch info displayed on the right.
Launcher Type CI Dev
------------ ------------ -- ---
Chrome browser ✔
Firefox browser ✔
Safari browser ✔
IE browser ✔
Node process ✔
PhantomJS browser ✔
Mocha process(TAP) ✔Customize browser behavior with arguments, paths, and executables.
interface BrowserCustomization {
// Browser Arguments
browser_args?: {
[browser: string]: string[] | string | BrowserArgsByMode;
};
// Custom Browser Paths
browser_paths?: {
[browser: string]: string;
};
// Custom Browser Executables
browser_exes?: {
[browser: string]: string;
};
}
interface BrowserArgsByMode {
dev?: string[]; // Arguments for development mode
ci?: string[]; // Arguments for CI mode
}Usage Examples:
// Browser arguments
{
"browser_args": {
"Chrome": [
"--no-sandbox",
"--disable-gpu",
"--disable-web-security"
],
"Firefox": ["--headless"],
"Chrome": {
"dev": ["--auto-open-devtools-for-tabs"],
"ci": ["--headless", "--no-sandbox"]
}
}
}
// Custom browser paths
{
"browser_paths": {
"Chrome": "/opt/google/chrome/chrome",
"Firefox": "/usr/local/firefox/firefox"
}
}
// Custom browser executables
{
"browser_exes": {
"Chromium": "chromium-browser",
"Chrome": "google-chrome-stable"
}
}Define custom launchers for specialized execution environments.
interface CustomLauncher {
// Command Execution
command?: string; // Full command to execute
exe?: string; // Executable path
args?: string[]; // Command arguments
// Launcher Behavior
protocol?: 'browser' | 'tap' | 'process'; // Communication protocol
cwd?: string; // Working directory
env?: Record<string, string>; // Environment variables
// Display Options
hide_stdout?: boolean; // Hide standard output
}Usage Examples:
// Custom Node.js launcher
{
"launchers": {
"Node": {
"command": "node test/runner.js",
"protocol": "tap"
}
}
}
// Custom browser launcher
{
"launchers": {
"CustomChrome": {
"exe": "/path/to/chrome",
"args": [
"--user-data-dir=/tmp/chrome-test",
"--disable-extensions",
"<url>"
],
"protocol": "browser"
}
}
}
// Custom process launcher
{
"launchers": {
"Jest": {
"command": "npm run test:jest",
"protocol": "tap",
"cwd": "frontend/",
"env": {
"NODE_ENV": "test"
}
}
}
}Programmatic launcher control for advanced integrations.
/**
* Base launcher class for controlling browser and process execution
*/
class Launcher {
/**
* Create a new launcher instance
* @param name - Launcher name
* @param settings - Launcher configuration
* @param config - Global configuration
*/
constructor(name: string, settings: CustomLauncher, config: Config);
/**
* Start the launcher
* @returns Promise that resolves when launcher starts
*/
start(): Promise<void>;
/**
* Kill the launcher process
* @returns Promise that resolves when launcher stops
*/
kill(): Promise<void>;
/**
* Check if this is a process launcher (not browser)
* @returns True if process launcher
*/
isProcess(): boolean;
/**
* Get the launcher protocol
* @returns Communication protocol
*/
protocol(): 'browser' | 'tap' | 'process';
/**
* Get the command line for this launcher
* @returns Command line string
*/
commandLine(): string;
}Factory for creating launcher instances with configuration.
/**
* Factory for creating configured launcher instances
*/
class LauncherFactory {
/**
* Create a launcher factory
* @param name - Launcher name
* @param settings - Base launcher settings
* @param config - Global configuration
*/
constructor(name: string, settings: CustomLauncher, config: Config);
/**
* Create a launcher instance with additional options
* @param options - Additional launcher options
* @returns Configured launcher instance
*/
create(options?: Partial<CustomLauncher>): Launcher;
}Usage Examples:
const LauncherFactory = require('testem/lib/launcher-factory');
const Config = require('testem/lib/config');
// Create launcher factory
const config = new Config('dev');
const factory = new LauncherFactory('Chrome', {
exe: 'google-chrome',
protocol: 'browser'
}, config);
// Create launcher instances
const launcher1 = factory.create({
args: ['--incognito']
});
const launcher2 = factory.create({
args: ['--disable-plugins']
});
// Start launchers
launcher1.start().then(() => {
console.log('Chrome launcher 1 started');
});{
"browser_args": {
"Chrome": [
"--no-sandbox", // Disable sandbox (CI environments)
"--disable-gpu", // Disable GPU acceleration
"--disable-web-security", // Disable CORS (testing only)
"--disable-features=VizDisplayCompositor", // Disable compositor
"--auto-open-devtools-for-tabs", // Auto-open DevTools
"--incognito", // Incognito mode
"--headless" // Headless mode
]
}
}{
"browser_args": {
"Firefox": [
"--headless", // Headless mode
"--safe-mode", // Safe mode
"--devtools" // Open DevTools
]
}
}{
"browser_args": {
"Safari": [
"--develop-menu", // Enable develop menu
"--javascript-enabled" // Ensure JavaScript is enabled
]
}
}{
"browser_args": {
"IE": [
"-extoff", // Disable extensions
"-private" // Private browsing
]
}
}{
"launchers": {
"Node": {
"command": "node test/node-runner.js",
"protocol": "tap"
}
}
}{
"launchers": {
"Mocha": {
"command": "mocha test/**/*.js --reporter tap",
"protocol": "tap",
"hide_stdout": true
}
}
}{
"launchers": {
"Jest": {
"command": "jest --testResultsProcessor=jest-tap-reporter",
"protocol": "tap"
}
}
}// testem.js - Dynamic launcher configuration
module.exports = {
launch_in_ci: function() {
const launchers = ['Chrome', 'Firefox'];
// Add Safari on macOS
if (process.platform === 'darwin') {
launchers.push('Safari');
}
// Add IE on Windows
if (process.platform === 'win32') {
launchers.push('IE');
}
return launchers;
}
};{
"launchers": {
"TestNode": {
"command": "node --inspect test/runner.js",
"protocol": "tap",
"env": {
"NODE_ENV": "test",
"DEBUG": "app:*"
}
}
}
}{
"launchers": {
"DockerChrome": {
"command": "docker run --rm -v $(pwd):/workspace selenium/standalone-chrome:latest",
"protocol": "browser"
}
}
}Install with Tessl CLI
npx tessl i tessl/npm-testem