js-tests-results-collector
Version:
Universal test results collector for Jest, Jasmine, Mocha, Cypress, and Playwright that sends results to Buddy Works API
118 lines (100 loc) • 4.2 kB
JavaScript
const sessionManager = require('../../core/session-manager');
const TestResultMapper = require('../../utils/test-result-mapper');
const Logger = require('../../utils/logger');
class MochaReporter {
constructor(runner, options) {
this.runner = runner;
this.options = options;
this.logger = new Logger('MochaReporter');
this.pendingSubmissions = new Set();
// Hook into Mocha's specific test result events for more accurate state capture
this.runner.on('start', this.onStart.bind(this));
this.runner.on('pass', this.onTestPass.bind(this));
this.runner.on('fail', this.onTestFail.bind(this));
this.runner.on('pending', this.onTestPending.bind(this));
this.runner.on('end', this.onEnd.bind(this));
}
onStart() {
this.logger.debug('Mocha test run started');
}
async onTestPass(test) {
const submissionPromise = this.submitTestWithTracking(test, () => {
// Explicitly set state to ensure correct mapping
test.state = 'passed';
return TestResultMapper.mapMochaResult(test);
});
// Don't await here - let it run async but track it
submissionPromise.catch(error => {
this.logger.error('Error processing Mocha test pass result', error);
});
}
async onTestFail(test, err) {
const submissionPromise = this.submitTestWithTracking(test, () => {
// Explicitly set state and error to ensure correct mapping
test.state = 'failed';
test.err = err;
return TestResultMapper.mapMochaResult(test);
});
// Don't await here - let it run async but track it
submissionPromise.catch(error => {
this.logger.error('Error processing Mocha test fail result', error);
});
}
async onTestPending(test) {
const submissionPromise = this.submitTestWithTracking(test, () => {
// Explicitly set state to ensure correct mapping
test.state = 'pending';
test.pending = true;
return TestResultMapper.mapMochaResult(test);
});
// Don't await here - let it run async but track it
submissionPromise.catch(error => {
this.logger.error('Error processing Mocha test pending result', error);
});
}
async submitTestWithTracking(test, resultMapperFn) {
const submissionId = Symbol();
this.pendingSubmissions.add(submissionId);
try {
const testResult = resultMapperFn();
await sessionManager.submitTestCase(testResult);
this.logger.debug(`Successfully submitted: ${testResult.name}`);
} catch (error) {
this.logger.error('Error processing Mocha test result', error);
// Mark this as a framework error since we failed to process test results
sessionManager.markFrameworkError();
} finally {
this.pendingSubmissions.delete(submissionId);
}
}
async onEnd() {
this.logger.debug('Mocha test run completed');
// Wait for all pending submissions to complete
if (this.pendingSubmissions.size > 0) {
this.logger.debug(`Waiting for ${this.pendingSubmissions.size} pending test submissions to complete`);
// Poll until all submissions are done (with timeout)
const maxWaitTime = 10000; // 10 seconds
const startTime = Date.now();
while (this.pendingSubmissions.size > 0 && (Date.now() - startTime) < maxWaitTime) {
await new Promise(resolve => setTimeout(resolve, 100)); // Wait 100ms
}
if (this.pendingSubmissions.size > 0) {
this.logger.warn(`Timed out waiting for ${this.pendingSubmissions.size} test submissions`);
// Mark this as a framework error since we couldn't complete all submissions
sessionManager.markFrameworkError();
} else {
this.logger.debug('All test submissions completed');
}
}
try {
// Close the session when all tests are finished
await sessionManager.closeSession();
this.logger.debug('Session closed after Mocha test completion');
} catch (error) {
this.logger.error('Error closing session after Mocha test completion', error);
// Mark this as a framework error
sessionManager.markFrameworkError();
}
}
}
module.exports = MochaReporter;