The Cucumber.js programmatic API allows you to run tests, load configurations, and integrate Cucumber into build tools, IDEs, and custom test runners without using the command-line interface.
Execute Cucumber tests programmatically with full control over configuration and execution.
/**
* Run Cucumber tests programmatically
* @param options - Test execution options
* @param environment - Runtime environment context (optional)
* @param onMessage - Message handler for test events (optional)
* @returns Promise resolving to test execution results
*/
function runCucumber(
options: IRunOptions,
environment?: IRunEnvironment,
onMessage?: (message: Envelope) => void
): Promise<IRunResult>;Usage Examples:
import { runCucumber } from "@cucumber/cucumber/api";
// Basic test execution
const result = await runCucumber({
sources: {
paths: ['features/**/*.feature']
},
support: {
requireModules: ['ts-node/register'],
requirePaths: ['features/step_definitions/**/*.ts']
}
});
console.log(`Tests completed: ${result.success ? 'PASSED' : 'FAILED'}`);
// Advanced configuration with custom options
const advancedResult = await runCucumber({
sources: {
paths: ['features/**/*.feature'],
names: ['User login', 'Password reset'], // Run specific scenarios
tagExpression: '@smoke and not @skip' // Filter by tags
},
support: {
requireModules: ['ts-node/register'],
requirePaths: ['features/support/**/*.ts']
},
runtime: {
dryRun: false,
failFast: true,
filterStackTraces: true,
parallel: 4,
retry: 1,
retryTagFilter: '@flaky',
worldParameters: {
apiUrl: 'https://api.staging.example.com',
timeout: 30000
}
},
formats: [
{ type: 'progress' },
{ type: 'json', outputTo: 'reports/results.json' },
{ type: 'html', outputTo: 'reports/results.html' }
]
});
// Custom message handling for real-time monitoring
const monitoredResult = await runCucumber({
sources: { paths: ['features/**/*.feature'] },
support: { requirePaths: ['features/support/**/*.js'] }
}, undefined, (message) => {
// Handle test events in real-time
switch (message.type) {
case 'testCaseStarted':
console.log(`Starting: ${getScenarioName(message)}`);
break;
case 'testCaseFinished':
const status = message.testCaseFinished.result.status;
console.log(`Finished: ${status}`);
break;
case 'testStepFinished':
if (message.testStepFinished.result.status === 'FAILED') {
console.error(`Step failed: ${getStepText(message)}`);
}
break;
}
});Load and resolve Cucumber configuration from various sources.
/**
* Load and resolve Cucumber configuration
* @param options - Configuration loading options (optional)
* @param environment - Runtime environment context (optional)
* @returns Promise resolving to resolved configuration
*/
function loadConfiguration(
options?: ILoadConfigurationOptions,
environment?: IRunEnvironment
): Promise<IResolvedConfiguration>;Usage Examples:
import { loadConfiguration } from "@cucumber/cucumber/api";
// Load default configuration
const config = await loadConfiguration();
console.log('Default config:', config);
// Load with custom options
const customConfig = await loadConfiguration({
file: 'cucumber.staging.js', // Custom config file
profiles: ['staging', 'integration'], // Activate specific profiles
provided: { // Override specific settings
parallel: 2,
format: ['json:test-results.json']
}
});
// Load with environment context
const envConfig = await loadConfiguration({
profiles: ['ci']
}, {
cwd: '/path/to/project',
stdout: process.stdout,
stderr: process.stderr,
env: {
...process.env,
NODE_ENV: 'test',
API_URL: 'https://test-api.example.com'
}
});
// Validate configuration before use
if (!customConfig.sources.paths.length) {
throw new Error('No feature files specified');
}
if (customConfig.runtime.parallel > 1 && !customConfig.support.requirePaths.length) {
console.warn('Parallel execution enabled but no support files specified');
}Load and parse Gherkin feature files.
/**
* Load and parse feature files
* @param coordinates - Source file coordinates and filters
* @param environment - Runtime environment context (optional)
* @returns Promise resolving to loaded sources with parsed features
*/
function loadSources(
coordinates: ISourcesCoordinates,
environment?: IRunEnvironment
): Promise<ILoadSourcesResult>;Usage Examples:
import { loadSources } from "@cucumber/cucumber/api";
// Load all feature files
const sources = await loadSources({
paths: ['features/**/*.feature']
});
console.log(`Loaded ${sources.features.length} features`);
sources.features.forEach(feature => {
console.log(`Feature: ${feature.feature.name}`);
feature.feature.children.forEach(scenario => {
console.log(` Scenario: ${scenario.scenario?.name}`);
});
});
// Load with filters
const filteredSources = await loadSources({
paths: ['features/**/*.feature'],
names: ['Login functionality'], // Filter by scenario names
tagExpression: '@smoke', // Filter by tags
order: 'random' // Randomize execution order
});
// Load specific files
const specificSources = await loadSources({
paths: [
'features/authentication.feature',
'features/user-management.feature'
]
});
// Inspect loaded content
filteredSources.features.forEach(gherkinDocument => {
gherkinDocument.feature.children.forEach(child => {
if (child.scenario) {
console.log(`Scenario: ${child.scenario.name}`);
child.scenario.steps.forEach(step => {
console.log(` ${step.keyword}${step.text}`);
});
}
});
});Load step definitions, hooks, and other support code.
/**
* Load support code (step definitions, hooks, etc.)
* @param options - Support code loading options
* @param environment - Runtime environment context (optional)
* @returns Promise resolving to loaded support code library
*/
function loadSupport(
options: ILoadSupportOptions,
environment?: IRunEnvironment
): Promise<ISupportCodeLibrary>;Usage Examples:
import { loadSupport } from "@cucumber/cucumber/api";
// Load support code
const supportLibrary = await loadSupport({
requireModules: ['ts-node/register', '@babel/register'],
requirePaths: ['features/support/**/*.ts'],
worldParameters: {
apiUrl: 'https://api.example.com',
databaseUrl: 'postgresql://localhost/test'
}
});
console.log(`Loaded ${supportLibrary.stepDefinitions.length} step definitions`);
console.log(`Loaded ${supportLibrary.beforeTestCaseHookDefinitions.length} Before hooks`);
console.log(`Loaded ${supportLibrary.afterTestCaseHookDefinitions.length} After hooks`);
// Inspect step definitions
supportLibrary.stepDefinitions.forEach(stepDef => {
console.log(`Step: ${stepDef.pattern} (${stepDef.keyword || 'any'})`);
});
// Load with custom world constructor
const customSupportLibrary = await loadSupport({
requirePaths: ['features/support/**/*.js'],
worldParameters: { customParam: 'value' }
});
// Check for undefined steps after loading
if (customSupportLibrary.undefinedParameterTypes.length > 0) {
console.warn('Undefined parameter types:',
customSupportLibrary.undefinedParameterTypes
);
}Provide runtime environment context for API functions.
Usage Examples:
import { runCucumber, loadConfiguration } from "@cucumber/cucumber/api";
import path from 'path';
// Custom environment context
const environment = {
cwd: path.resolve(__dirname, 'my-project'),
stdout: process.stdout,
stderr: process.stderr,
env: {
...process.env,
NODE_ENV: 'test',
LOG_LEVEL: 'debug'
}
};
// Use environment with configuration loading
const config = await loadConfiguration({
file: 'cucumber.test.js'
}, environment);
// Use environment with test execution
const result = await runCucumber({
sources: { paths: ['features/**/*.feature'] },
support: { requirePaths: ['features/support/**/*.js'] }
}, environment);
// Capture output streams
let stdoutOutput = '';
let stderrOutput = '';
const captureEnvironment = {
cwd: process.cwd(),
stdout: {
write: (data) => { stdoutOutput += data; return true; }
},
stderr: {
write: (data) => { stderrOutput += data; return true; }
},
env: process.env
};
await runCucumber(options, captureEnvironment);
console.log('Captured stdout:', stdoutOutput);
console.log('Captured stderr:', stderrOutput);Complete examples for common integration scenarios.
Build Tool Integration:
// Jest integration
import { runCucumber } from "@cucumber/cucumber/api";
describe('Cucumber Integration Tests', () => {
it('should pass all cucumber scenarios', async () => {
const result = await runCucumber({
sources: { paths: ['features/**/*.feature'] },
support: { requirePaths: ['features/support/**/*.ts'] },
runtime: { failFast: true }
});
expect(result.success).toBe(true);
expect(result.support.stepDefinitions.length).toBeGreaterThan(0);
}, 60000);
});
// Webpack/Vite integration
export async function runTests() {
const config = await loadConfiguration({
file: 'cucumber.config.js'
});
const result = await runCucumber(config);
if (!result.success) {
throw new Error(`Cucumber tests failed: ${result.summary}`);
}
return result;
}CI/CD Integration:
// GitHub Actions / CI runner
import { runCucumber } from "@cucumber/cucumber/api";
import fs from 'fs/promises';
async function runCucumberCI() {
try {
const result = await runCucumber({
sources: {
paths: ['features/**/*.feature'],
tagExpression: process.env.CUCUMBER_TAGS || '@smoke'
},
support: {
requirePaths: ['features/support/**/*.ts']
},
runtime: {
parallel: parseInt(process.env.CUCUMBER_PARALLEL || '1'),
retry: parseInt(process.env.CUCUMBER_RETRY || '0')
},
formats: [
{ type: 'json', outputTo: 'test-results/cucumber-results.json' },
{ type: 'junit', outputTo: 'test-results/cucumber-results.xml' }
]
});
// Generate summary for CI
await fs.writeFile('test-results/summary.json', JSON.stringify({
success: result.success,
scenarios: result.summary,
duration: result.duration
}, null, 2));
process.exit(result.success ? 0 : 1);
} catch (error) {
console.error('Cucumber execution failed:', error);
process.exit(1);
}
}
if (require.main === module) {
runCucumberCI();
}interface IRunOptions {
/** Source file configuration */
sources: ISourcesCoordinates;
/** Support code configuration */
support: ISupportCodeCoordinatesOrLibrary;
/** Runtime execution options */
runtime: IRunOptionsRuntime;
/** Output format configuration */
formats: IRunOptionsFormats;
}
interface ISourcesCoordinates {
/** Default Gherkin dialect */
defaultDialect: string;
/** Paths and/or glob expressions to feature files */
paths: string[];
/** Regular expressions of which scenario names should match one of to be run */
names: string[];
/** Tag expression to filter which scenarios should be run */
tagExpression: string;
/** Run in the order defined, or in a random order */
order: IPickleOrder;
/** Shard tests and execute only the selected shard, format `<index>/<total>` */
shard?: string;
}
interface ISupportCodeCoordinates {
/** Names of transpilation modules to load, via require() */
requireModules: string[];
/** Paths and/or glob expressions of user code to load, via require() */
requirePaths: string[];
/** Paths and/or glob expressions of user code to load, via import() */
importPaths: string[];
/** Specifiers of loaders to register, via register() */
loaders: string[];
}
type ISupportCodeCoordinatesOrLibrary = Partial<ISupportCodeCoordinates> | ISupportCodeLibrary;
interface IRunOptionsRuntime {
/** Perform a dry run, where a test run is prepared but nothing is executed */
dryRun: boolean;
/** Stop running tests when a test fails */
failFast: boolean;
/** Filter out stack frames from Cucumber's code when formatting stack traces */
filterStacktraces: boolean;
/** Run tests in parallel with the given number of worker processes */
parallel: number;
/** Retry failing tests up to the given number of times */
retry: number;
/** Tag expression to filter which scenarios can be retried */
retryTagFilter: string;
/** Fail the test run if there are pending steps */
strict: boolean;
/** Parameters to be passed to the World */
worldParameters: JsonObject;
}
interface IRunOptionsFormats {
/** Name/path of the formatter to use for stdout output */
stdout: string;
/** Zero or more mappings of file output path (key) to name/path of the formatter to use (value) */
files: Record<string, string>;
/** Options for report publication, or false to disable publication */
publish: IPublishConfig | false;
/** Options to be provided to formatters */
options: JsonObject;
}
interface IRunResult {
/** Whether the test run was overall successful */
success: boolean;
/** The support code library that was used in the test run */
support: ISupportCodeLibrary;
}
interface IRunEnvironment {
/** Current working directory */
cwd?: string;
/** Standard output stream */
stdout?: WriteStream;
/** Standard error stream */
stderr?: WriteStream;
/** Environment variables */
env?: { [key: string]: string };
}
interface ILoadConfigurationOptions {
/** Path to load configuration file from, or false to skip */
file?: string | false;
/** Zero or more profile names from which to source configuration in the file */
profiles?: string[];
/** Ad-hoc configuration options to be merged over the top of whatever is loaded from the configuration file/profiles */
provided?: Partial<IConfiguration> | string[] | string;
}
interface IResolvedConfiguration {
/** The final flat configuration object resolved from the configuration file/profiles plus any extra provided */
useConfiguration: IConfiguration;
/** The format that can be passed into runCucumber */
runConfiguration: IRunConfiguration;
}
interface IPlannedPickle {
/** Name of the pickle (after parameter resolution) */
name: string;
uri: string;
location: {
line: number;
column?: number;
};
}
interface ISourcesError {
uri: string;
location: {
line: number;
column?: number;
};
/** Error message explaining what went wrong with the parse */
message: string;
}
interface ILoadSourcesResult {
/** Pickles that have been successfully compiled, in the order they would be run in */
plan: IPlannedPickle[];
/** Any errors encountered when parsing sources */
errors: ISourcesError[];
}
interface ILoadSupportOptions {
/** This is needed because the default support path locations are derived from feature file locations */
sources: ISourcesCoordinates;
support: Partial<ISupportCodeCoordinates>;
}
interface ISupportCodeLibrary {
readonly originalCoordinates: ISupportCodeCoordinates;
}
interface IRunConfiguration {
sources: ISourcesCoordinates;
support: Partial<ISupportCodeCoordinates>;
runtime: IRunOptionsRuntime;
formats: IRunOptionsFormats;
}