ember-try uses task classes to handle scenario execution, dependency management, and cleanup operations. These tasks coordinate between commands, scenario managers, and dependency adapters.
The core task class that executes test scenarios and manages the testing lifecycle.
/**
* Main task class for executing scenarios
*/
class TryEachTask {
/**
* Create a new TryEachTask instance
* @param options - Task configuration options
*/
constructor(options: {
/** ember-try configuration */
config: EmberTryConfig;
/** Current working directory */
cwd: string;
/** Command arguments to run (overrides config/scenario commands) */
commandArgs?: string[];
/** Command execution options */
commandOptions?: any;
/** Pre-configured dependency manager adapters */
dependencyManagerAdapters?: DependencyManagerAdapter[];
});
/**
* Execute scenarios and return exit code
* @param scenarios - Array of scenarios to execute
* @param options - Execution options
* @returns Promise resolving to exit code (0 = success, 1 = failure)
*/
async run(
scenarios: Scenario[],
options?: { skipCleanup?: boolean }
): Promise<number>;
}Usage Examples:
// Basic task execution
const tryEachTask = new TryEachTask({
config: await getConfig({ cwd: process.cwd() }),
cwd: process.cwd()
});
const exitCode = await tryEachTask.run(config.scenarios);
// Task execution with custom command
const tryEachTask = new TryEachTask({
config,
cwd: process.cwd(),
commandArgs: ['ember', 'test', '--reporter', 'xunit']
});
const exitCode = await tryEachTask.run([scenario], { skipCleanup: true });Internal methods used by the task execution system.
/**
* Execute command for a specific scenario
* @param scenario - Scenario to execute
* @returns Promise resolving to execution results
*/
async _runCommandForThisScenario(scenario: Scenario): Promise<{
scenario: string;
allowedToFail: boolean;
dependencyState: any[];
envState?: Record<string, string>;
command: string;
result: boolean;
}>;
/**
* Determine which command to run for a scenario
* @param scenario - Current scenario
* @returns Array of command arguments
*/
_determineCommandFor(scenario: Scenario): string[];
/**
* Execute a command with specified options
* @param options - Command execution options
* @returns Promise resolving to command success
*/
_runCommand(options: {
commandArgs: string[];
commandOptions?: any;
}): Promise<boolean>;
/**
* Build command options including environment variables
* @param env - Environment variables from scenario
* @returns Command execution options
*/
_commandOptions(env?: Record<string, string>): any;
/**
* Get default command arguments when none specified
* @returns Default command array
*/
_defaultCommandArgs(): string[];
/**
* Print formatted results summary
* @param results - Array of scenario execution results
*/
_printResults(results: any[]): void;
/**
* Determine appropriate exit code based on results
* @param results - Array of scenario execution results
* @returns Exit code (0 = success, 1 = failure)
*/
_exitAsAppropriate(results: any[]): number;
/**
* Optionally cleanup dependencies based on options
* @param options - Cleanup options
*/
async _optionallyCleanup(options?: { skipCleanup?: boolean }): Promise<void>;
/**
* Write formatted header for scenario execution
* @param text - Header text
*/
_writeHeader(text: string): void;
/**
* Write formatted footer after scenario execution
* @param text - Footer text
*/
_writeFooter(text: string): void;Task class for resetting dependencies to their original state.
/**
* Task for resetting dependencies to committed state
*/
class ResetTask {
/**
* Create a new ResetTask instance
* @param options - Task configuration options
*/
constructor(options: {
/** ember-try configuration */
config: EmberTryConfig;
/** Current working directory */
cwd: string;
});
/**
* Execute dependency reset
* @returns Promise that resolves when reset is complete
*/
run(): Promise<void>;
}Usage Examples:
// Reset dependencies to original state
const resetTask = new ResetTask({
config: await getConfig({ cwd: process.cwd() }),
cwd: process.cwd()
});
await resetTask.run();The task execution lifecycle follows these phases:
/**
* Task execution lifecycle phases
*/
interface TaskLifecycle {
/** 1. Setup phase - initialize dependency managers */
setup(): Promise<void>;
/** 2. Scenario execution phase - for each scenario */
executeScenario(scenario: Scenario): Promise<{
/** Change to scenario dependencies */
changeDependencies(): Promise<any[]>;
/** Set environment variables */
setEnvironment(): void;
/** Execute test command */
runCommand(): Promise<boolean>;
/** Collect results */
collectResults(): any;
}>;
/** 3. Cleanup phase - restore original state */
cleanup(options?: { skipCleanup?: boolean }): Promise<void>;
/** 4. Reporting phase - display results */
reportResults(results: any[]): void;
}TryEachTask handles graceful shutdown on interruption signals.
/**
* Signal handling for graceful shutdown
* @param signal - Signal name (e.g., 'SIGINT')
* @param fn - Handler function
*/
_on(signal: string, fn: () => Promise<void>): void;
/**
* Exit with specified code
* @param code - Exit code
*/
_exit(code: number): void;
/**
* Determine exit code based on condition
* @param condition - True if should exit with error
* @returns Exit code
*/
_exitBasedOnCondition(condition: boolean): number;Signal Handling Example:
// TryEachTask sets up SIGINT handler for graceful shutdown
this._on('SIGINT', () => {
this._canceling = true;
console.log('\nGracefully shutting down from SIGINT (Ctrl-C)');
return this.ScenarioManager.cleanup();
});Task execution results follow a standardized format.
/**
* Individual scenario execution result
*/
interface ScenarioResult {
/** Scenario name */
scenario: string;
/** Whether scenario is allowed to fail */
allowedToFail: boolean;
/** Dependency state changes applied */
dependencyState: any[];
/** Environment variables that were set */
envState?: Record<string, string>;
/** Command that was executed */
command: string;
/** Execution result (true = success, false = failure) */
result: boolean;
}
/**
* Overall task execution results
*/
interface TaskResults {
/** Individual scenario results */
results: ScenarioResult[];
/** Overall exit code */
exitCode: number;
/** Summary statistics */
summary: {
total: number;
passed: number;
failed: number;
allowedFailures: number;
};
}Tasks implement comprehensive error handling and recovery.
/**
* Task error handling patterns
*/
interface TaskErrorHandling {
/** Handle command execution failures */
handleCommandFailure(error: Error, scenario: Scenario): boolean;
/** Handle dependency installation failures */
handleDependencyFailure(error: Error, scenario: Scenario): Promise<void>;
/** Handle cleanup failures */
handleCleanupFailure(error: Error): Promise<void>;
/** Handle graceful shutdown */
handleShutdown(): Promise<void>;
}Tasks catch and handle various error conditions:
Tasks set and manage environment variables during execution: