mocha-multiple-sessions-detailed-runner
Version:
High-level API for multi-session Mocha tests with detailed reporting
212 lines (177 loc) • 6.72 kB
text/typescript
import type { IMultiSessionDetailedRunner } from '../interfaces/core/IMultiSessionDetailedRunner';
import type { SessionState, SessionResult, DetailedReport, CombinedReport, MultiSessionConfig } from '../interfaces/core/types';
import type { RunnerEventType, RunnerEvent } from '../interfaces/events/runner-events';
import type { SessionEventType, SessionEvent } from '../interfaces/events/session-events';
import type { BatchExecutionOptions } from '../interfaces/core/batch-execution';
// Implementation imports
import { SessionMetaRepository } from './repositories/session-meta-repository';
import { ReportRepository } from './repositories/report-repository';
import { UnifiedEventBus } from './events/unified-event-bus';
import { MochaIntegration } from './infrastructure/mocha-integration';
import { ReportService } from './services/report-service';
// Use case imports
import {
InitializeRunnerUseCase,
DefineSessionUseCase,
RunSingleSessionUseCase,
RunAllSessionsUseCase,
ClearAllSessionsUseCase,
DestroyRunnerUseCase
} from './use-cases/runner-use-cases';
export class MultiSessionDetailedRunner implements IMultiSessionDetailedRunner {
// Dependencies
private sessionRepository: SessionMetaRepository;
private reportRepository: ReportRepository;
private eventBus: UnifiedEventBus;
private mochaIntegration: MochaIntegration;
private reportService: ReportService;
// Use cases
private initializeUseCase: InitializeRunnerUseCase;
private defineSessionUseCase: DefineSessionUseCase;
private runSingleSessionUseCase: RunSingleSessionUseCase;
private runAllSessionsUseCase: RunAllSessionsUseCase;
private clearAllSessionsUseCase: ClearAllSessionsUseCase;
private destroyRunnerUseCase: DestroyRunnerUseCase;
// State
private initialized = false;
private destroyed = false;
constructor() {
// Initialize dependencies
this.sessionRepository = new SessionMetaRepository();
this.reportRepository = new ReportRepository();
this.eventBus = new UnifiedEventBus();
this.mochaIntegration = new MochaIntegration();
this.reportService = new ReportService(
this.reportRepository,
this.sessionRepository,
this.eventBus
);
// Initialize use cases
this.initializeUseCase = new InitializeRunnerUseCase(
this.mochaIntegration,
this.eventBus
);
this.defineSessionUseCase = new DefineSessionUseCase(
this.sessionRepository,
this.reportRepository,
this.eventBus
);
this.runSingleSessionUseCase = new RunSingleSessionUseCase(
this.sessionRepository,
this.reportRepository,
this.eventBus
);
this.runAllSessionsUseCase = new RunAllSessionsUseCase(
this.sessionRepository,
this.runSingleSessionUseCase,
this.eventBus
);
this.clearAllSessionsUseCase = new ClearAllSessionsUseCase(
this.sessionRepository,
this.reportRepository,
this.eventBus
);
this.destroyRunnerUseCase = new DestroyRunnerUseCase(
this.clearAllSessionsUseCase,
this.eventBus
);
// Bridge session events from the existing library
this.bridgeExistingSessionEvents();
}
// Core Management
init(config?: Partial<MultiSessionConfig>): void {
if (this.destroyed) {
throw new Error('Runner has been destroyed');
}
// Set initialized flag before calling use case to avoid timing issues
this.initialized = true;
try {
this.initializeUseCase.execute(config);
} catch (error) {
// Reset initialized flag on error
this.initialized = false;
throw error;
}
}
define(label: string, setupFn: () => void): void {
this.ensureInitialized();
this.defineSessionUseCase.execute(label, setupFn);
}
async run(label: string): Promise<SessionResult> {
this.ensureInitialized();
return this.runSingleSessionUseCase.execute(label);
}
async runAll(options?: BatchExecutionOptions): Promise<Record<string, SessionResult>> {
this.ensureInitialized();
return this.runAllSessionsUseCase.execute(options);
}
// Report Access
getReport(label: string): DetailedReport | null {
this.ensureInitialized();
return this.reportService.getSessionReport(label);
}
getSessionStates(): Record<string, SessionState> {
this.ensureInitialized();
return this.sessionRepository.getStates();
}
getCombinedReport(): CombinedReport {
this.ensureInitialized();
return this.reportService.generateCombinedReport();
}
// Event System
onRunnerEvent(eventType: RunnerEventType, callback: (event: RunnerEvent) => void): () => void {
return this.eventBus.onRunnerEvent(eventType, callback);
}
onSessionEvent(eventType: SessionEventType, callback: (event: SessionEvent) => void): () => void {
return this.eventBus.onSessionEvent(eventType, callback);
}
onAnyEvent(callback: (event: RunnerEvent | SessionEvent) => void): () => void {
return this.eventBus.onAnyEvent(callback);
}
// State Queries
isInitialized(): boolean {
return this.initialized && !this.destroyed;
}
hasSession(label: string): boolean {
return this.sessionRepository.exists(label);
}
getSessionCount(): number {
return this.sessionRepository.findAll().length;
}
// Utility
async clear(): Promise<void> {
this.ensureInitialized();
await this.clearAllSessionsUseCase.execute();
}
async destroy(): Promise<void> {
if (this.destroyed) return;
await this.destroyRunnerUseCase.execute();
this.destroyed = true;
this.initialized = false;
}
// Private helper methods
private ensureInitialized(): void {
if (this.destroyed) {
throw new Error('Runner has been destroyed');
}
if (!this.initialized) {
throw new Error('Runner not initialized. Call init() first.');
}
}
private bridgeExistingSessionEvents(): void {
// Bridge events from the existing mocha-multiple-sessions library
if (typeof window !== 'undefined' && window.MochaMultipleSessions?.onAnySessionEvent) {
window.MochaMultipleSessions.onAnySessionEvent((event: any) => {
// Convert and forward the event
const sessionEvent: SessionEvent = {
type: event.type,
sessionLabel: event.sessionLabel,
timestamp: event.timestamp || new Date(),
data: event.data,
source: 'mocha-multiple-sessions'
};
this.eventBus.emitSessionEvent(sessionEvent);
});
}
}
}