UNPKG

@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
"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();