mocha-multiple-sessions-detailed-runner
Version:
High-level API for multi-session Mocha tests with detailed reporting
184 lines (154 loc) • 5.92 kB
text/typescript
import type { IUnifiedEventBus, EventFilter } from '../../interfaces/events/unified-event-bus';
import type { RunnerEvent, RunnerEventType } from '../../interfaces/events/runner-events';
import type { SessionEvent, SessionEventType } from '../../interfaces/events/session-events';
export class UnifiedEventBus implements IUnifiedEventBus {
private runnerListeners = new Map<RunnerEventType, Set<(event: RunnerEvent) => void>>();
private sessionListeners = new Map<SessionEventType, Set<(event: SessionEvent) => void>>();
private anyEventListeners = new Set<(event: RunnerEvent | SessionEvent) => void>();
private eventHistory: (RunnerEvent | SessionEvent)[] = [];
private readonly maxHistorySize = 1000;
emitRunnerEvent(event: RunnerEvent): void {
// Add to history
this.addToHistory(event);
// Emit to specific listeners
const listeners = this.runnerListeners.get(event.type);
if (listeners) {
listeners.forEach(callback => {
try {
callback(event);
} catch (error) {
console.error('Error in runner event listener:', error);
}
});
}
// Emit to universal listeners
this.anyEventListeners.forEach(callback => {
try {
callback(event);
} catch (error) {
console.error('Error in universal event listener:', error);
}
});
}
onRunnerEvent(eventType: RunnerEventType, callback: (event: RunnerEvent) => void): () => void {
if (!this.runnerListeners.has(eventType)) {
this.runnerListeners.set(eventType, new Set());
}
this.runnerListeners.get(eventType)!.add(callback);
// Return unsubscribe function
return () => {
const listeners = this.runnerListeners.get(eventType);
if (listeners) {
listeners.delete(callback);
if (listeners.size === 0) {
this.runnerListeners.delete(eventType);
}
}
};
}
emitSessionEvent(event: SessionEvent): void {
// Add to history
this.addToHistory(event);
// Emit to specific listeners
const listeners = this.sessionListeners.get(event.type);
if (listeners) {
listeners.forEach(callback => {
try {
callback(event);
} catch (error) {
console.error('Error in session event listener:', error);
}
});
}
// Emit to universal listeners
this.anyEventListeners.forEach(callback => {
try {
callback(event);
} catch (error) {
console.error('Error in universal event listener:', error);
}
});
}
onSessionEvent(eventType: SessionEventType, callback: (event: SessionEvent) => void): () => void {
if (!this.sessionListeners.has(eventType)) {
this.sessionListeners.set(eventType, new Set());
}
this.sessionListeners.get(eventType)!.add(callback);
// Return unsubscribe function
return () => {
const listeners = this.sessionListeners.get(eventType);
if (listeners) {
listeners.delete(callback);
if (listeners.size === 0) {
this.sessionListeners.delete(eventType);
}
}
};
}
onAnyEvent(callback: (event: RunnerEvent | SessionEvent) => void): () => void {
this.anyEventListeners.add(callback);
// Return unsubscribe function
return () => {
this.anyEventListeners.delete(callback);
};
}
getEventHistory(filter?: EventFilter): (RunnerEvent | SessionEvent)[] {
let filtered = [...this.eventHistory];
if (filter) {
if (filter.eventTypes) {
filtered = filtered.filter(event => filter.eventTypes!.includes(event.type as any));
}
if (filter.sessionLabel) {
filtered = filtered.filter(event =>
'sessionLabel' in event && event.sessionLabel === filter.sessionLabel
);
}
if (filter.timeRange) {
filtered = filtered.filter(event => {
const eventTime = new Date(event.timestamp);
return eventTime >= filter.timeRange!.start && eventTime <= filter.timeRange!.end;
});
}
if (filter.maxEvents) {
filtered = filtered.slice(-filter.maxEvents);
}
}
return filtered;
}
clearEventHistory(): void {
this.eventHistory = [];
}
hasListeners(eventType?: RunnerEventType | SessionEventType): boolean {
if (!eventType) {
return this.runnerListeners.size > 0 ||
this.sessionListeners.size > 0 ||
this.anyEventListeners.size > 0;
}
return (this.runnerListeners.get(eventType as RunnerEventType)?.size || 0) > 0 ||
(this.sessionListeners.get(eventType as SessionEventType)?.size || 0) > 0;
}
getListenerCount(eventType?: RunnerEventType | SessionEventType): number {
if (!eventType) {
let total = this.anyEventListeners.size;
this.runnerListeners.forEach(listeners => total += listeners.size);
this.sessionListeners.forEach(listeners => total += listeners.size);
return total;
}
const runnerCount = this.runnerListeners.get(eventType as RunnerEventType)?.size || 0;
const sessionCount = this.sessionListeners.get(eventType as SessionEventType)?.size || 0;
return runnerCount + sessionCount;
}
destroy(): void {
this.runnerListeners.clear();
this.sessionListeners.clear();
this.anyEventListeners.clear();
this.eventHistory = [];
}
private addToHistory(event: RunnerEvent | SessionEvent): void {
this.eventHistory.push(event);
// Trim history if it gets too large
if (this.eventHistory.length > this.maxHistorySize) {
this.eventHistory = this.eventHistory.slice(-this.maxHistorySize);
}
}
}