const fs = require('fs'); const path = require('path'); const { spawnSync } = require('child_process'); function runPython(args, inputObj) { const result = spawnSync('python3', ['scripts/sqlite_db.py', ...args], { cwd: process.cwd(), input: inputObj ? JSON.stringify(inputObj) : undefined, encoding: 'utf8', env: process.env, maxBuffer: 1024 * 1024 * 10, }); if (result.status !== 0) { const msg = result.stderr || result.stdout || 'Unknown sqlite_db.py error'; throw new Error(msg); } const out = (result.stdout || '').trim(); return out ? JSON.parse(out) : {}; } class SqliteReporter { constructor(options = {}) { this.dbPath = options.dbPath || process.env.SQLITE_RESULTS_DB || 'results/uat_vapt_results.sqlite'; this.runName = options.runName || process.env.TEST_RUN_NAME || `Run ${new Date().toISOString()}`; this.runId = null; } onBegin(config, suite) { fs.mkdirSync(path.dirname(this.dbPath), { recursive: true }); runPython(['--db', this.dbPath, 'init']); const matrixPath = process.env.TEST_MATRIX_JSON || 'data/generated-test-matrix.json'; if (fs.existsSync(matrixPath)) { runPython(['--db', this.dbPath, '--matrix', matrixPath, 'import-cases']); } const started = runPython(['--db', this.dbPath, '--run-name', this.runName, '--base-url', process.env.BASE_URL || '', 'begin-run']); this.runId = started.run_id; console.log(`SQLite reporter writing to ${this.dbPath}; run_id=${this.runId}`); } extractVariantId(test) { const titlePath = test.titlePath ? test.titlePath() : [test.title]; const fullTitle = titlePath.join(' '); const bracket = fullTitle.match(/\[([^\]]+)\]/); if (bracket) return bracket[1]; const fallback = fullTitle.match(/((?:V25-)?[A-Z][A-Z0-9]*(?:-[A-Z0-9]+)+)/); return fallback ? fallback[1] : ''; } onTestEnd(test, result) { const location = test.location || {}; const attachments = (result.attachments || []).map(a => ({ name: a.name || '', contentType: a.contentType || '', path: a.path || '', })); const record = { run_id: this.runId, variant_id: this.extractVariantId(test), title: test.title, title_path: test.titlePath ? test.titlePath() : [test.title], project_name: test.parent && test.parent.project ? (test.parent.project()?.name || '') : '', location, status: result.status, expected_status: test.expectedStatus, duration_ms: result.duration || 0, retry: result.retry || 0, error: result.error ? { message: result.error.message || '', stack: result.error.stack || '' } : null, stdout: (result.stdout || []).map(x => Buffer.isBuffer(x) ? x.toString('utf8') : String(x)).join('\n'), stderr: (result.stderr || []).map(x => Buffer.isBuffer(x) ? x.toString('utf8') : String(x)).join('\n'), attachments, started_at: result.startTime ? result.startTime.toISOString() : null, finished_at: new Date().toISOString(), }; try { runPython(['--db', this.dbPath, 'record-result'], record); } catch (e) { console.error('Failed to record SQLite test result:', e.message); } } onEnd(result) { if (!this.runId) return; try { runPython(['--db', this.dbPath, '--run-id', String(this.runId), '--status', result.status || 'completed', 'finish-run']); runPython(['--db', this.dbPath, '--run-id', String(this.runId), '--output', 'results/merged-results.json', 'export-json']); runPython(['--db', this.dbPath, '--run-id', String(this.runId), '--output', 'results/UAT_VAPT_SQLite_Export.xlsx', 'export-xlsx']); console.log(`SQLite run ${this.runId} finished and exported.`); } catch (e) { console.error('Failed to finish/export SQLite run:', e.message); } } } module.exports = SqliteReporter;