@buddy-works/unit-tests
Version:
Universal test results collector for Jest, Jasmine, Mocha, Cypress, Playwright, and Vitest that sends results to Buddy Works API in real-time
321 lines (320 loc) • 18 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
if (kind === "m") throw new TypeError("Private method is not writable");
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
var _BuddyUnitTestSessionManager_instances, _a, _BuddyUnitTestSessionManager_context, _BuddyUnitTestSessionManager_config, _BuddyUnitTestSessionManager_apiClient, _BuddyUnitTestSessionManager_getCreateSessionPromise, _BuddyUnitTestSessionManager_getSessionFilePath, _BuddyUnitTestSessionManager_writeSessionToFile, _BuddyUnitTestSessionManager_readSessionFromFile, _BuddyUnitTestSessionManager_clearSessionFile, _BuddyUnitTestSessionManager_initialize, _BuddyUnitTestSessionManager_exitHandlersRegistered, _BuddyUnitTestSessionManager_handleExit;
Object.defineProperty(exports, "__esModule", { value: true });
const node_fs_1 = __importDefault(require("node:fs"));
const node_os_1 = __importDefault(require("node:os"));
const node_path_1 = __importDefault(require("node:path"));
const api_client_1 = __importDefault(require("../core/api-client"));
const config_1 = __importDefault(require("../core/config"));
const types_1 = require("../core/types");
const environment_1 = __importStar(require("../utils/environment"));
const logger_1 = __importDefault(require("../utils/logger"));
class BuddyUnitTestSessionManager {
get config() {
if (!__classPrivateFieldGet(this, _BuddyUnitTestSessionManager_config, "f")) {
throw new Error(`${_a.displayName} not initialized`);
}
return __classPrivateFieldGet(this, _BuddyUnitTestSessionManager_config, "f");
}
get apiClient() {
if (!__classPrivateFieldGet(this, _BuddyUnitTestSessionManager_apiClient, "f")) {
throw new Error(`API client not initialized in ${_a.displayName}`);
}
return __classPrivateFieldGet(this, _BuddyUnitTestSessionManager_apiClient, "f");
}
constructor() {
_BuddyUnitTestSessionManager_instances.add(this);
_BuddyUnitTestSessionManager_context.set(this, 'generic');
_BuddyUnitTestSessionManager_config.set(this, void 0);
_BuddyUnitTestSessionManager_apiClient.set(this, void 0);
_BuddyUnitTestSessionManager_exitHandlersRegistered.set(this, false);
this.sessionId = undefined;
__classPrivateFieldSet(this, _BuddyUnitTestSessionManager_config, undefined, "f");
__classPrivateFieldSet(this, _BuddyUnitTestSessionManager_apiClient, undefined, "f");
this.createSession = undefined;
this.initialized = false;
this.hasFrameworkErrors = false;
this.hasErrorTests = false;
this.hasFailedTests = false;
}
async getOrCreateSession(context) {
if (!this.initialized) {
if (context)
__classPrivateFieldSet(this, _BuddyUnitTestSessionManager_context, context, "f");
__classPrivateFieldGet(this, _BuddyUnitTestSessionManager_instances, "m", _BuddyUnitTestSessionManager_initialize).call(this);
}
if (this.sessionId)
return this.sessionId;
if (this.createSession) {
logger_1.default.debug('Session creation already in progress, waiting...');
}
else {
this.createSession = __classPrivateFieldGet(this, _BuddyUnitTestSessionManager_instances, "m", _BuddyUnitTestSessionManager_getCreateSessionPromise).call(this);
}
try {
await this.createSession;
return this.sessionId;
}
catch (error) {
logger_1.default.error('Session creation failed, continuing without session', error);
return;
}
finally {
this.createSession = undefined;
}
}
async submitTestCase(testCase) {
if (!this.initialized)
throw new Error(`${_a.displayName} not initialized`);
try {
const sessionId = await this.getOrCreateSession();
if (testCase.status === types_1.BUDDY_UNIT_TEST_STATUS.ERROR) {
this.hasErrorTests = true;
logger_1.default.debug(`Tracked ${types_1.BUDDY_UNIT_TEST_STATUS.ERROR} test result`);
}
else if (testCase.status === types_1.BUDDY_UNIT_TEST_STATUS.FAILED) {
this.hasFailedTests = true;
logger_1.default.debug(`Tracked ${types_1.BUDDY_UNIT_TEST_STATUS.FAILED} test result`);
}
if (!sessionId) {
throw new Error('Session ID is not available, cannot submit test case');
}
await this.apiClient.submitTestCase(sessionId, testCase);
}
catch (error) {
logger_1.default.error('Failed to submit test case', error);
(0, environment_1.setEnvironmentVariable)('BUDDY_API_FAILURE', true);
this.hasFrameworkErrors = true;
}
}
async closeSession() {
if (!this.initialized) {
__classPrivateFieldGet(this, _BuddyUnitTestSessionManager_instances, "m", _BuddyUnitTestSessionManager_initialize).call(this);
}
if (!__classPrivateFieldGet(this, _BuddyUnitTestSessionManager_config, "f")) {
return;
}
if (!this.sessionId && environment_1.default.BUDDY_SESSION_ID) {
this.sessionId = environment_1.default.BUDDY_SESSION_ID;
logger_1.default.debug(`Retrieved session ID from BUDDY_SESSION_ID environment variable: ${this.sessionId}`);
}
if (!this.sessionId) {
this.sessionId = __classPrivateFieldGet(this, _BuddyUnitTestSessionManager_instances, "m", _BuddyUnitTestSessionManager_readSessionFromFile).call(this);
if (this.sessionId) {
logger_1.default.debug(`Retrieved session ID from file: ${this.sessionId}`);
}
}
if (this.sessionId) {
const startTime = Date.now();
const sessionId = this.sessionId;
try {
let sessionStatus = types_1.BUDDY_UNIT_TEST_STATUS.PASSED;
if (this.hasFrameworkErrors || this.hasErrorTests) {
sessionStatus = types_1.BUDDY_UNIT_TEST_STATUS.ERROR;
}
else if (this.hasFailedTests) {
sessionStatus = types_1.BUDDY_UNIT_TEST_STATUS.FAILED;
}
const mem = process.memoryUsage();
logger_1.default.debug(`Memory usage at session close:`);
logger_1.default.debug(` Heap Used: ${String(Math.round(mem.heapUsed / 1024 / 1024))}MB`);
logger_1.default.debug(` Heap Total: ${String(Math.round(mem.heapTotal / 1024 / 1024))}MB`);
logger_1.default.debug(` RSS: ${String(Math.round(mem.rss / 1024 / 1024))}MB`);
const heapUsedMB = Math.round(mem.heapUsed / 1024 / 1024);
if (heapUsedMB > 500) {
logger_1.default.warn(`High memory usage detected: ${String(heapUsedMB)}MB heap used`);
}
logger_1.default.debug(`Closing session ${sessionId}`);
await this.apiClient.closeSession(sessionId, sessionStatus);
const duration = Date.now() - startTime;
logger_1.default.info(`Session ${sessionId} closed successfully with status: ${sessionStatus} (took ${String(duration)}ms)`);
}
catch (error) {
const duration = Date.now() - startTime;
logger_1.default.error(`Failed to close session ${sessionId} after ${String(duration)}ms`, error);
(0, environment_1.setEnvironmentVariable)('BUDDY_API_FAILURE', true);
logger_1.default.warn(`Cleaning up session ${sessionId} state despite close failure`);
}
finally {
this.sessionId = undefined;
this.createSession = undefined;
this.hasFrameworkErrors = false;
this.hasErrorTests = false;
this.hasFailedTests = false;
delete process.env.BUDDY_SESSION_ID;
logger_1.default.debug('Session ID and tracking flags cleared');
__classPrivateFieldGet(this, _BuddyUnitTestSessionManager_instances, "m", _BuddyUnitTestSessionManager_clearSessionFile).call(this);
}
}
else {
logger_1.default.debug('No active session to close');
}
}
markFrameworkError() {
this.hasFrameworkErrors = true;
}
setupProcessExitHandlers() {
if (__classPrivateFieldGet(this, _BuddyUnitTestSessionManager_exitHandlersRegistered, "f")) {
return;
}
__classPrivateFieldSet(this, _BuddyUnitTestSessionManager_exitHandlersRegistered, true, "f");
logger_1.default.debug('Setting up process exit handlers for session cleanup');
process.on('beforeExit', () => {
void __classPrivateFieldGet(this, _BuddyUnitTestSessionManager_instances, "m", _BuddyUnitTestSessionManager_handleExit).call(this, 'beforeExit');
});
process.on('SIGINT', () => {
void __classPrivateFieldGet(this, _BuddyUnitTestSessionManager_instances, "m", _BuddyUnitTestSessionManager_handleExit).call(this, 'SIGINT', true);
});
process.on('SIGTERM', () => {
void __classPrivateFieldGet(this, _BuddyUnitTestSessionManager_instances, "m", _BuddyUnitTestSessionManager_handleExit).call(this, 'SIGTERM', true);
});
process.on('SIGHUP', () => {
void __classPrivateFieldGet(this, _BuddyUnitTestSessionManager_instances, "m", _BuddyUnitTestSessionManager_handleExit).call(this, 'SIGHUP', true);
});
process.on('SIGQUIT', () => {
void __classPrivateFieldGet(this, _BuddyUnitTestSessionManager_instances, "m", _BuddyUnitTestSessionManager_handleExit).call(this, 'SIGQUIT', true);
});
process.on('uncaughtException', (error) => {
logger_1.default.error('Uncaught exception, closing session before exit', error);
void __classPrivateFieldGet(this, _BuddyUnitTestSessionManager_instances, "m", _BuddyUnitTestSessionManager_handleExit).call(this, 'uncaughtException', true);
});
process.on('unhandledRejection', (reason) => {
logger_1.default.error('Unhandled promise rejection, closing session before exit', reason);
void __classPrivateFieldGet(this, _BuddyUnitTestSessionManager_instances, "m", _BuddyUnitTestSessionManager_handleExit).call(this, 'unhandledRejection', true);
});
}
}
_a = BuddyUnitTestSessionManager, _BuddyUnitTestSessionManager_context = new WeakMap(), _BuddyUnitTestSessionManager_config = new WeakMap(), _BuddyUnitTestSessionManager_apiClient = new WeakMap(), _BuddyUnitTestSessionManager_exitHandlersRegistered = new WeakMap(), _BuddyUnitTestSessionManager_instances = new WeakSet(), _BuddyUnitTestSessionManager_getCreateSessionPromise = async function _BuddyUnitTestSessionManager_getCreateSessionPromise() {
if (this.sessionId)
return this.sessionId;
try {
this.sessionId = await (this.config.sessionId
? this.apiClient.reopenSession(this.config.sessionId)
: this.apiClient.createSession());
(0, environment_1.setEnvironmentVariable)('BUDDY_SESSION_ID', this.sessionId);
if (environment_1.default.BUDDY_SESSION_ID === this.sessionId) {
logger_1.default.debug(`Session ID stored in environment variable BUDDY_SESSION_ID: ${environment_1.default.BUDDY_SESSION_ID}`);
}
else {
logger_1.default.debug('BUDDY_SESSION_ID environment variable could not be updated to match current session ID');
}
__classPrivateFieldGet(this, _BuddyUnitTestSessionManager_instances, "m", _BuddyUnitTestSessionManager_writeSessionToFile).call(this, this.sessionId);
}
catch (error) {
logger_1.default.error('Failed to create/reopen session', error);
(0, environment_1.setEnvironmentVariable)('BUDDY_API_FAILURE', true);
}
return this.sessionId;
}, _BuddyUnitTestSessionManager_getSessionFilePath = function _BuddyUnitTestSessionManager_getSessionFilePath() {
return node_path_1.default.join(node_os_1.default.tmpdir(), 'buddy-session-id.txt');
}, _BuddyUnitTestSessionManager_writeSessionToFile = function _BuddyUnitTestSessionManager_writeSessionToFile(sessionId) {
try {
node_fs_1.default.writeFileSync(__classPrivateFieldGet(this, _BuddyUnitTestSessionManager_instances, "m", _BuddyUnitTestSessionManager_getSessionFilePath).call(this), sessionId, 'utf8');
logger_1.default.debug(`Session ID written to file: ${sessionId}`);
}
catch (error) {
logger_1.default.error('Failed to write session ID to file', error);
}
}, _BuddyUnitTestSessionManager_readSessionFromFile = function _BuddyUnitTestSessionManager_readSessionFromFile() {
try {
const filePath = __classPrivateFieldGet(this, _BuddyUnitTestSessionManager_instances, "m", _BuddyUnitTestSessionManager_getSessionFilePath).call(this);
if (node_fs_1.default.existsSync(filePath)) {
const sessionId = node_fs_1.default.readFileSync(filePath, 'utf8').trim();
logger_1.default.debug(`Session ID read from file: ${sessionId}`);
return sessionId;
}
}
catch (error) {
logger_1.default.error('Failed to read session ID from file', error);
}
return;
}, _BuddyUnitTestSessionManager_clearSessionFile = function _BuddyUnitTestSessionManager_clearSessionFile() {
try {
const filePath = __classPrivateFieldGet(this, _BuddyUnitTestSessionManager_instances, "m", _BuddyUnitTestSessionManager_getSessionFilePath).call(this);
if (node_fs_1.default.existsSync(filePath)) {
node_fs_1.default.unlinkSync(filePath);
logger_1.default.debug('Session file cleared');
}
}
catch (error) {
logger_1.default.error('Failed to clear session file', error);
}
}, _BuddyUnitTestSessionManager_initialize = function _BuddyUnitTestSessionManager_initialize() {
if (this.initialized)
return;
try {
__classPrivateFieldSet(this, _BuddyUnitTestSessionManager_config, new config_1.default(__classPrivateFieldGet(this, _BuddyUnitTestSessionManager_context, "f")), "f");
__classPrivateFieldSet(this, _BuddyUnitTestSessionManager_apiClient, new api_client_1.default(__classPrivateFieldGet(this, _BuddyUnitTestSessionManager_config, "f")), "f");
this.initialized = true;
logger_1.default.debug(`${_a.displayName} initialized`);
this.setupProcessExitHandlers();
}
catch (error) {
logger_1.default.error(`Failed to initialize ${_a.displayName}`, error);
throw error;
}
}, _BuddyUnitTestSessionManager_handleExit = async function _BuddyUnitTestSessionManager_handleExit(signal, shouldExit = false) {
logger_1.default.debug(`Received ${signal}, closing session`);
let exitCode = 0;
try {
await this.closeSession();
logger_1.default.debug(`Session closed successfully on ${signal}`);
}
catch (error) {
logger_1.default.error(`Error closing session on ${signal}`, error);
(0, environment_1.setEnvironmentVariable)('BUDDY_API_FAILURE', true);
exitCode = 1;
}
if (shouldExit) {
process.exit(exitCode);
}
};
BuddyUnitTestSessionManager.displayName = 'BuddyUnitTestSessionManager';
exports.default = new BuddyUnitTestSessionManager();