@testomatio/reporter 2.0.1-beta.9 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -11,7 +11,6 @@ export class DebugPipe {
11
11
  batchIndex: number;
12
12
  };
13
13
  logFilePath: string;
14
- latestFilePath: string;
15
14
  testomatioEnvVars: {};
16
15
  batchUpload(): Promise<void>;
17
16
  /**
package/lib/pipe/debug.js CHANGED
@@ -27,20 +27,19 @@ class DebugPipe {
27
27
  this.logFilePath = path_1.default.join(os_1.default.tmpdir(), `testomatio.debug.${Date.now()}.json`);
28
28
  debug('Creating debug file:', this.logFilePath);
29
29
  fs_1.default.writeFileSync(this.logFilePath, '');
30
- // Create latest debug file reference (Windows compatible)
31
- this.latestFilePath = path_1.default.join(os_1.default.tmpdir(), 'testomatio.debug.latest.json');
30
+ // Create symlink to ensure consistent path to latest debug file
31
+ const symlinkPath = path_1.default.join(os_1.default.tmpdir(), 'testomatio.debug.latest.json');
32
32
  try {
33
- // Remove existing latest file if it exists
34
- if (fs_1.default.existsSync(this.latestFilePath)) {
35
- fs_1.default.rmSync(this.latestFilePath);
33
+ // Remove existing symlink if it exists
34
+ if (fs_1.default.existsSync(symlinkPath)) {
35
+ fs_1.default.unlinkSync(symlinkPath);
36
36
  }
37
- // Initialize latest file
38
- fs_1.default.writeFileSync(this.latestFilePath, '');
39
- debug('Created latest debug file:', this.latestFilePath);
37
+ // Create new symlink pointing to the timestamped debug file
38
+ fs_1.default.symlinkSync(this.logFilePath, symlinkPath);
39
+ debug('Created symlink:', symlinkPath, '->', this.logFilePath);
40
40
  }
41
41
  catch (err) {
42
- debug('Failed to create latest debug file:', err.message);
43
- this.latestFilePath = null; // Disable latest file if creation fails
42
+ debug('Failed to create symlink:', err.message);
44
43
  }
45
44
  console.log(constants_js_1.APP_PREFIX, '🪲 Debug file created');
46
45
  this.testomatioEnvVars = Object.keys(process.env)
@@ -68,18 +67,7 @@ class DebugPipe {
68
67
  const timePassedFromLastAction = Date.now() - (this.lastActionTimestamp || Date.now());
69
68
  this.lastActionTimestamp = Date.now();
70
69
  const logLine = JSON.stringify({ t: `+${(0, pretty_ms_1.default)(timePassedFromLastAction)}`, ...logData });
71
- const logLineWithNewline = `${logLine}\n`;
72
- // Write to timestamped debug file
73
- fs_1.default.appendFileSync(this.logFilePath, logLineWithNewline);
74
- // Also write to latest debug file for Windows compatibility
75
- if (this.latestFilePath) {
76
- try {
77
- fs_1.default.appendFileSync(this.latestFilePath, logLineWithNewline);
78
- }
79
- catch (err) {
80
- debug('Failed to write to latest debug file:', err.message);
81
- }
82
- }
70
+ fs_1.default.appendFileSync(this.logFilePath, `${logLine}\n`);
83
71
  }
84
72
  async prepareRun(opts) {
85
73
  if (!this.isEnabled)
@@ -131,9 +119,6 @@ class DebugPipe {
131
119
  clearInterval(this.batch.intervalFunction);
132
120
  this.logToFile({ action: 'finishRun', params });
133
121
  console.log(constants_js_1.APP_PREFIX, '🪲 Debug Saved to', this.logFilePath);
134
- if (this.latestFilePath) {
135
- console.log(constants_js_1.APP_PREFIX, '🪲 Latest Debug file:', this.latestFilePath);
136
- }
137
122
  }
138
123
  toString() {
139
124
  return 'Debug Reporter';
package/lib/replay.d.ts CHANGED
@@ -10,19 +10,6 @@ export class Replay {
10
10
  * @returns {string} Path to the latest debug file
11
11
  */
12
12
  getDefaultDebugFile(): string;
13
- /**
14
- * Read artifacts file for a specific run
15
- * @param {string} runId - Run ID to find artifacts for
16
- * @returns {Array} Array of artifact records with rid and file paths
17
- */
18
- readArtifactsFile(runId: string): any[];
19
- /**
20
- * Merge artifacts data with test data
21
- * @param {Array} tests - Array of test objects
22
- * @param {Array} artifacts - Array of artifact records
23
- * @returns {Array} Tests with merged artifact data
24
- */
25
- mergeArtifactsWithTests(tests: any[], artifacts: any[]): any[];
26
13
  /**
27
14
  * Parse a debug file and extract test data
28
15
  * @param {string} debugFile - Path to the debug file
package/lib/replay.js CHANGED
@@ -10,7 +10,6 @@ const os_1 = __importDefault(require("os"));
10
10
  const client_js_1 = __importDefault(require("./client.js"));
11
11
  const constants_js_1 = require("./constants.js");
12
12
  const config_js_1 = require("./config.js");
13
- const isEnabled = !!process.env.TESTOMATIO_DEBUG || !!process.env.DEBUG;
14
13
  class Replay {
15
14
  constructor(options = {}) {
16
15
  this.apiKey = options.apiKey || config_js_1.config.TESTOMATIO || undefined;
@@ -26,93 +25,6 @@ class Replay {
26
25
  getDefaultDebugFile() {
27
26
  return path_1.default.join(os_1.default.tmpdir(), 'testomatio.debug.latest.json');
28
27
  }
29
- /**
30
- * Read artifacts file for a specific run
31
- * @param {string} runId - Run ID to find artifacts for
32
- * @returns {Array} Array of artifact records with rid and file paths
33
- */
34
- readArtifactsFile(runId) {
35
- if (!runId)
36
- return [];
37
- const artifactsFile = path_1.default.join(os_1.default.tmpdir(), `testomatio.run.${runId}.json`);
38
- if (!fs_1.default.existsSync(artifactsFile)) {
39
- if (isEnabled)
40
- console.log(`No artifacts file found: ${artifactsFile}`);
41
- return [];
42
- }
43
- try {
44
- const data = fs_1.default.readFileSync(artifactsFile, 'utf-8');
45
- const lines = data.split('\n').filter(Boolean);
46
- const artifacts = lines.map(line => JSON.parse(line));
47
- if (isEnabled)
48
- console.log(`Found ${artifacts.length} artifact records in ${artifactsFile}`);
49
- return artifacts;
50
- }
51
- catch (err) {
52
- if (isEnabled)
53
- console.log(`Error reading artifacts file: ${err.message}`);
54
- return [];
55
- }
56
- }
57
- /**
58
- * Merge artifacts data with test data
59
- * @param {Array} tests - Array of test objects
60
- * @param {Array} artifacts - Array of artifact records
61
- * @returns {Array} Tests with merged artifact data
62
- */
63
- mergeArtifactsWithTests(tests, artifacts) {
64
- if (!artifacts.length)
65
- return tests;
66
- // Extract runId prefix from first test
67
- const runIdPrefix = tests[0]?.rid ? tests[0].rid.split('-')[0] + '-' : '';
68
- // Group artifacts by RID
69
- const artifactsByRid = artifacts.reduce((acc, artifact) => {
70
- const fullRid = runIdPrefix && !artifact.rid.startsWith(runIdPrefix) ? runIdPrefix + artifact.rid : artifact.rid;
71
- if (!acc[fullRid])
72
- acc[fullRid] = [];
73
- acc[fullRid].push(artifact);
74
- return acc;
75
- }, {});
76
- // Merge artifacts into tests
77
- let mergedCount = 0;
78
- const result = tests.map(test => {
79
- if (!test.rid || !artifactsByRid[test.rid])
80
- return test;
81
- const testArtifacts = artifactsByRid[test.rid];
82
- mergedCount++;
83
- if (isEnabled && test.title) {
84
- console.log(`🔄 Adding artifact info for test: ${test.title}`);
85
- console.log(` 📎 Existing files: ${(test.files || []).length} | Artifact records: ${testArtifacts.length}`);
86
- }
87
- // Deduplicate artifacts by filename
88
- const seenFiles = new Set();
89
- const deduplicatedArtifacts = testArtifacts.filter(artifact => {
90
- if (!artifact.file)
91
- return true;
92
- const fileName = path_1.default.basename(artifact.file);
93
- if (seenFiles.has(fileName)) {
94
- if (isEnabled && test.title) {
95
- console.log(` ⚠️ Removed duplicate artifact: ${fileName}`);
96
- }
97
- return false;
98
- }
99
- seenFiles.add(fileName);
100
- return true;
101
- });
102
- if (isEnabled && test.title && deduplicatedArtifacts.length !== testArtifacts.length) {
103
- console.log(` 🧹 Deduplicated: ${testArtifacts.length} → ${deduplicatedArtifacts.length} artifacts`);
104
- }
105
- return {
106
- ...test,
107
- files: test.files || [],
108
- artifactRecords: deduplicatedArtifacts,
109
- };
110
- });
111
- if (isEnabled) {
112
- console.log(`🔄 Added artifact info to ${mergedCount} tests (no file duplication)`);
113
- }
114
- return result;
115
- }
116
28
  /**
117
29
  * Parse a debug file and extract test data
118
30
  * @param {string} debugFile - Path to the debug file
@@ -123,10 +35,7 @@ class Replay {
123
35
  throw new Error(`Debug file not found: ${debugFile}`);
124
36
  }
125
37
  const fileContent = fs_1.default.readFileSync(debugFile, 'utf-8');
126
- const lines = fileContent
127
- .trim()
128
- .split('\n')
129
- .filter(line => line.trim() !== '');
38
+ const lines = fileContent.trim().split('\n').filter(line => line.trim() !== '');
130
39
  if (lines.length === 0) {
131
40
  throw new Error('Debug file is empty');
132
41
  }
@@ -163,24 +72,14 @@ class Replay {
163
72
  Object.keys(test).forEach(key => {
164
73
  if (test[key] !== null && test[key] !== undefined) {
165
74
  if (key === 'files' && Array.isArray(test[key]) && test[key].length > 0) {
166
- // Deduplicate files within the array itself
167
- const seen = new Set();
168
- mergedTest.files = test[key].filter(file => {
169
- const fileName = typeof file === 'string'
170
- ? path_1.default.basename(file)
171
- : path_1.default.basename(file?.path || file?.file || '');
172
- if (seen.has(fileName))
173
- return false;
174
- seen.add(fileName);
175
- return true;
176
- });
75
+ // Merge files arrays
76
+ mergedTest.files = [...(existingTest.files || []), ...test[key]];
177
77
  }
178
78
  else if (key === 'artifacts' && Array.isArray(test[key]) && test[key].length > 0) {
179
- // Keep the most recent artifacts array (don't merge to avoid duplicates)
180
- mergedTest.artifacts = test[key];
79
+ // Merge artifacts arrays
80
+ mergedTest.artifacts = [...(existingTest.artifacts || []), ...test[key]];
181
81
  }
182
- else if (existingTest[key] === null ||
183
- existingTest[key] === undefined ||
82
+ else if (existingTest[key] === null || existingTest[key] === undefined ||
184
83
  (Array.isArray(existingTest[key]) && existingTest[key].length === 0)) {
185
84
  // Use new value if existing is null/undefined/empty array
186
85
  mergedTest[key] = test[key];
@@ -209,33 +108,8 @@ class Replay {
209
108
  // Handle tests with rid (deduplicate)
210
109
  const existingTest = testsMap.get(test.rid);
211
110
  if (existingTest) {
212
- // Merge test data - prioritize non-null/non-empty values (same logic as addTestsBatch)
213
- const mergedTest = { ...existingTest };
214
- Object.keys(test).forEach(key => {
215
- if (test[key] !== null && test[key] !== undefined) {
216
- if (key === 'files' && Array.isArray(test[key]) && test[key].length > 0) {
217
- // Deduplicate files within the array itself
218
- const seen = new Set();
219
- mergedTest.files = test[key].filter(file => {
220
- const fileName = typeof file === 'string' ? path_1.default.basename(file) : path_1.default.basename(file?.path || file?.file || '');
221
- if (seen.has(fileName))
222
- return false;
223
- seen.add(fileName);
224
- return true;
225
- });
226
- }
227
- else if (key === 'artifacts' && Array.isArray(test[key]) && test[key].length > 0) {
228
- // Keep the most recent artifacts array (don't merge to avoid duplicates)
229
- mergedTest.artifacts = test[key];
230
- }
231
- else if (existingTest[key] === null ||
232
- existingTest[key] === undefined ||
233
- (Array.isArray(existingTest[key]) && existingTest[key].length === 0)) {
234
- // Use new value if existing is null/undefined/empty array
235
- mergedTest[key] = test[key];
236
- }
237
- }
238
- });
111
+ // Merge with existing test
112
+ const mergedTest = { ...existingTest, ...test };
239
113
  testsMap.set(test.rid, mergedTest);
240
114
  }
241
115
  else {
@@ -271,7 +145,7 @@ class Replay {
271
145
  envVars,
272
146
  parseErrors,
273
147
  totalLines: lines.length,
274
- runId,
148
+ runId
275
149
  };
276
150
  }
277
151
  /**
@@ -301,132 +175,14 @@ class Replay {
301
175
  this.onLog(`Replaying data from debug file: ${debugFile}`);
302
176
  // Parse the debug file
303
177
  const debugData = this.parseDebugFile(debugFile);
304
- const { runParams, finishParams, envVars, runId } = debugData;
305
- let tests = debugData.tests;
178
+ const { runParams, finishParams, tests, envVars, runId } = debugData;
306
179
  this.onLog(`Found ${tests.length} tests to replay`);
307
180
  if (tests.length === 0) {
308
181
  throw new Error('No test data found in debug file');
309
182
  }
310
- // Read and merge artifacts if runId is available
311
- if (runId) {
312
- const artifacts = this.readArtifactsFile(runId);
313
- if (artifacts.length > 0) {
314
- if (isEnabled)
315
- console.log(`Found ${artifacts.length} artifact records in testomatio.run.${runId}.json`);
316
- tests = this.mergeArtifactsWithTests(tests, artifacts);
317
- }
318
- }
319
183
  // Restore environment variables
320
184
  this.restoreEnvironmentVariables(envVars);
321
185
  if (this.dryRun) {
322
- if (isEnabled)
323
- console.log('🔍 DRY RUN - Tests to be sent:');
324
- if (isEnabled)
325
- console.log('='.repeat(60));
326
- let totalArtifacts = 0;
327
- let totalFiles = 0;
328
- let uploadedArtifacts = 0;
329
- let notUploadedArtifacts = 0;
330
- tests.forEach((test, index) => {
331
- const status = test.status === 'passed' ? '✅' : test.status === 'failed' ? '❌' : '⏭️';
332
- if (isEnabled)
333
- console.log(`${index + 1}. ${status} ${test.title || test.id}`);
334
- if (isEnabled)
335
- console.log(` 📁 File: ${test.file || 'Unknown'}`);
336
- if (isEnabled)
337
- console.log(` 📊 Status: ${test.status}`);
338
- if (isEnabled)
339
- console.log(` 🔑 RID: ${test.rid || 'No RID'}`);
340
- if (test.steps && test.steps.length > 0) {
341
- if (isEnabled)
342
- console.log(` 🔄 Steps: ${test.steps.length}`);
343
- test.steps.slice(0, 3).forEach((step, stepIndex) => {
344
- const stepStatus = step.status === 'passed' ? '✅' : step.status === 'failed' ? '❌' : '⚪';
345
- if (isEnabled)
346
- console.log(` ${stepIndex + 1}. ${stepStatus} ${step.title || step.name || 'Step'}`);
347
- });
348
- if (test.steps.length > 3) {
349
- if (isEnabled)
350
- console.log(` ... also ${test.steps.length - 3} steps`);
351
- }
352
- }
353
- // Show either artifact records (if available) or files
354
- if (test.artifactRecords && test.artifactRecords.length > 0) {
355
- totalArtifacts += test.artifactRecords.length;
356
- if (isEnabled)
357
- console.log(` 📎 Artifacts: ${test.artifactRecords.length}`);
358
- test.artifactRecords.forEach((artifact, artIndex) => {
359
- const uploaded = artifact.uploaded === true
360
- ? '✅ Uploaded'
361
- : artifact.uploaded === false
362
- ? '📤 Not Uploaded'
363
- : '⏳ Unknown';
364
- const fileName = artifact.file ? path_1.default.basename(artifact.file) : 'Unknown';
365
- if (isEnabled)
366
- console.log(` ${artIndex + 1}. ${uploaded}: ${fileName}`);
367
- // Count artifact upload status
368
- if (artifact.uploaded === true) {
369
- uploadedArtifacts++;
370
- }
371
- else if (artifact.uploaded === false) {
372
- notUploadedArtifacts++;
373
- }
374
- });
375
- }
376
- else if (test.files && test.files.length > 0) {
377
- totalFiles += test.files.length;
378
- if (isEnabled)
379
- console.log(` 📎 Files: ${test.files.length}`);
380
- test.files.slice(0, 3).forEach((file, fileIndex) => {
381
- // Handle both string paths and object formats
382
- let fileName;
383
- if (typeof file === 'string') {
384
- fileName = path_1.default.basename(file);
385
- }
386
- else if (file && typeof file === 'object') {
387
- const filePath = file.path || file.file || JSON.stringify(file);
388
- fileName = file.name || (typeof filePath === 'string' ? path_1.default.basename(filePath) : 'Unknown');
389
- }
390
- else {
391
- fileName = 'Unknown';
392
- }
393
- if (isEnabled)
394
- console.log(` ${fileIndex + 1}. ${fileName}`);
395
- });
396
- if (test.files.length > 3) {
397
- if (isEnabled)
398
- console.log(` ... also ${test.files.length - 3} files`);
399
- }
400
- }
401
- if (isEnabled)
402
- console.log('');
403
- });
404
- if (isEnabled)
405
- console.log('='.repeat(60));
406
- if (isEnabled)
407
- console.log('📊 SUMMARY:');
408
- if (isEnabled)
409
- console.log(` 📋 Total tests: ${tests.length}`);
410
- if (isEnabled)
411
- console.log(` 📎 Total files: ${totalFiles}`);
412
- if (isEnabled)
413
- console.log(` 📎 Total artifact records: ${totalArtifacts}`);
414
- if (totalArtifacts > 0) {
415
- if (isEnabled)
416
- console.log(` ✅ Uploaded: ${uploadedArtifacts}`);
417
- if (isEnabled)
418
- console.log(` 📤 Not Uploaded: ${notUploadedArtifacts}`);
419
- }
420
- if (isEnabled)
421
- console.log(` 🆔 Run ID: ${runId || 'Will create new'}`);
422
- if (isEnabled)
423
- console.log(` 🌍 Environment: ${envVars.TESTOMATIO_ENV || 'Unknown'}`);
424
- if (isEnabled)
425
- console.log(` 🔗 API URL: ${envVars.TESTOMATIO_URL || 'Default'}`);
426
- if (isEnabled)
427
- console.log('');
428
- if (isEnabled)
429
- console.log('✅ Use without --dry-run to send this data to Testomat.io');
430
186
  return {
431
187
  success: true,
432
188
  testsCount: tests.length,
@@ -434,175 +190,51 @@ class Replay {
434
190
  finishParams,
435
191
  envVars,
436
192
  runId,
437
- dryRun: true,
193
+ dryRun: true
438
194
  };
439
195
  }
440
196
  // Create client and restore the run
441
197
  const client = new client_js_1.default({
442
198
  apiKey: this.apiKey,
443
- // isBatchEnabled: true,
199
+ isBatchEnabled: true,
444
200
  ...runParams,
445
201
  });
446
- if (isEnabled) {
447
- console.log('🔧 CLIENT CONFIGURATION:');
448
- console.log(` 🔑 API Key: ${this.apiKey ? `${this.apiKey.slice(0, 10)}...` : 'NOT SET'}`);
449
- console.log(` 🏪 Batch enabled: ${runParams.isBatchEnabled || 'unknown'}`);
450
- console.log(` 📡 Pipes count: ${client.pipes ? client.pipes.length : 0}`);
451
- if (client.pipes && client.pipes.length > 0) {
452
- client.pipes.forEach((pipe, index) => {
453
- console.log(` ${index + 1}. ${pipe.toString()} - enabled: ${pipe.isEnabled}`);
454
- });
455
- }
456
- else {
457
- console.log(` ⚠️ WARNING: No pipes configured!`);
458
- }
459
- console.log(` 📤 Uploader enabled: ${client.uploader ? client.uploader.isEnabled : 'unknown'}`);
460
- console.log('');
461
- }
462
202
  // Use the stored runId if available, otherwise create a new run
463
203
  if (runId) {
464
204
  this.onLog(`Using existing run ID: ${runId}`);
465
- if (isEnabled)
466
- console.log(`🔄 Restoring run with ID: ${runId}`);
467
- if (isEnabled)
468
- console.log(`📊 Run params:`, JSON.stringify(runParams, null, 2));
469
205
  client.runId = runId;
470
- // Always call createRun to initialize batch system and update run params
471
- if (isEnabled)
472
- console.log(`🔄 Initializing batch system for existing run...`);
473
- // await client.createRun({ ...runParams, isBatchEnabled: true });
474
- await client.createRun(runParams);
475
- this.onLog(`Create new run`);
476
206
  }
477
207
  else {
478
208
  this.onLog('Publishing to run...');
479
- if (isEnabled)
480
- console.log(`🆕 Creating new run with params:`, JSON.stringify(runParams, null, 2));
481
209
  await client.createRun(runParams);
482
- if (isEnabled)
483
- console.log(`✅ New run created with ID: ${client.runId}`);
484
- }
485
- if (isEnabled) {
486
- console.log('🔧 POST-INITIALIZATION STATUS:');
487
- console.log(` 🆔 Final Run ID: ${client.runId}`);
488
- // Check each pipe status
489
- if (!client.pipes?.length) {
490
- console.log(' ⚠️ No pipes found!');
491
- }
492
- else {
493
- client.pipes.forEach((pipe, index) => {
494
- console.log(` 📡 Pipe ${index + 1}: ${pipe.toString()}`);
495
- console.log(` ✅ Enabled: ${pipe.isEnabled}`);
496
- console.log(` 🆔 Run ID: ${pipe.runId || 'NOT SET'}`);
497
- if (!pipe.toString().includes('Testomatio') || !pipe.batch)
498
- return;
499
- console.log(` 🔄 Batch enabled: ${pipe.batch.isEnabled}`);
500
- console.log(` ⏱️ Batch interval: ${pipe.batch.intervalFunction ? 'RUNNING' : 'NOT RUNNING'}`);
501
- console.log(` 📦 Tests in queue: ${pipe.batch.tests?.length || 0}`);
502
- });
503
- }
504
- console.log('');
505
- }
506
- if (isEnabled) {
507
- console.log('🚀 SENDING TESTS TO TESTOMAT.IO');
508
- console.log('='.repeat(60));
509
210
  }
510
211
  // Send each test result
511
212
  let successCount = 0;
512
213
  let failureCount = 0;
513
214
  for (const [index, test] of tests.entries()) {
514
215
  try {
515
- if (isEnabled) {
516
- const status = test.status === 'passed' ? '✅' : test.status === 'failed' ? '❌' : '⏭️';
517
- console.log(`\n📤 Sending test ${index + 1}/${tests.length}: ${status} ${test.title || test.id}`);
518
- console.log(` 📁 File: ${test.file || 'Unknown'}`);
519
- console.log(` 🔑 RID: ${test.rid || 'No RID'}`);
520
- console.log(` 📊 Status: ${test.status}${test.steps?.length > 0 ? ` | steps: ${test.steps.length}` : ''}`);
521
- // Show artifacts info
522
- if (test.artifactRecords?.length) {
523
- console.log(` 📎 Artifacts: ${test.artifactRecords.length}`);
524
- test.artifactRecords.forEach((artifact, i) => {
525
- const status = artifact.uploaded ? '✅ Uploaded' : '📤 Not Uploaded';
526
- const name = artifact.file ? path_1.default.basename(artifact.file) : 'Unknown';
527
- console.log(` ${i + 1}. ${status}: ${name}`);
528
- });
529
- }
530
- else if (test.files?.length) {
531
- console.log(` 📎 Files: ${test.files.length}`);
532
- test.files.slice(0, 3).forEach((file, i) => {
533
- const name = typeof file === 'string' ? path_1.default.basename(file) : path_1.default.basename(file?.path || file?.file || 'Unknown');
534
- console.log(` ${i + 1}. ${name}`);
535
- });
536
- if (test.files.length > 3) {
537
- console.log(` ... also ${test.files.length - 3} more files`);
538
- }
539
- }
540
- // Show the actual data payload being sent
541
- const uniqueFiles = test.files
542
- ? [
543
- ...new Set(test.files.map(f => typeof f === 'string' ? path_1.default.basename(f) : path_1.default.basename(f?.path || f?.file || ''))),
544
- ].length
545
- : 0;
546
- console.log(` 📦 Payload preview:`, JSON.stringify({
547
- status: test.status,
548
- title: test.title,
549
- id: test.id,
550
- rid: test.rid,
551
- uniqueFiles,
552
- steps: test.steps ? test.steps.length : 0,
553
- artifactRecords: test.artifactRecords ? test.artifactRecords.length : 0,
554
- }, null, 2));
555
- }
556
- const addTestRunResult = await client.addTestRun(test.status, test);
216
+ await client.addTestRun(test.status, test);
557
217
  successCount++;
558
218
  this.onProgress({
559
219
  current: index + 1,
560
220
  total: tests.length,
561
221
  test,
562
- success: true,
222
+ success: true
563
223
  });
564
224
  }
565
225
  catch (err) {
566
226
  failureCount++;
567
- if (isEnabled) {
568
- console.log(` ❌ Failed to send: ${err.message}`);
569
- console.log(` 🔍 Error details:`, err);
570
- }
571
227
  this.onError(`Failed to send test ${index + 1}: ${err.message}`);
572
228
  this.onProgress({
573
229
  current: index + 1,
574
230
  total: tests.length,
575
231
  test,
576
232
  success: false,
577
- error: err.message,
233
+ error: err.message
578
234
  });
579
235
  }
580
236
  }
581
- if (isEnabled) {
582
- console.log('\n' + '='.repeat(60));
583
- console.log('🏁 FINISHING RUN');
584
- console.log(`📊 Finish params:`, JSON.stringify(finishParams, null, 2));
585
- }
586
237
  await client.updateRunStatus(finishParams.status || constants_js_1.STATUS.FINISHED, finishParams.parallel || false);
587
- if (isEnabled) {
588
- console.log(`✅ Run finished with status: ${finishParams.status || constants_js_1.STATUS.FINISHED}`);
589
- // Wait a bit for batch system to finish sending remaining tests
590
- const testomatioPipe = client.pipes && client.pipes.find(p => p.toString().includes('Testomatio'));
591
- if (testomatioPipe &&
592
- testomatioPipe.batch &&
593
- testomatioPipe.batch.tests &&
594
- testomatioPipe.batch.tests.length > 0) {
595
- console.log(`⏳ Waiting for batch system to send ${testomatioPipe.batch.tests.length} remaining tests...`);
596
- await new Promise(resolve => setTimeout(resolve, 6000)); // Wait 6 seconds for batch upload
597
- const remainingAfterWait = testomatioPipe.batch.tests ? testomatioPipe.batch.tests.length : 0;
598
- if (remainingAfterWait > 0) {
599
- console.log(`⚠️ ${remainingAfterWait} tests still in batch queue after waiting`);
600
- }
601
- else {
602
- console.log(`✅ All tests successfully sent via batch system`);
603
- }
604
- }
605
- }
606
238
  const result = {
607
239
  success: true,
608
240
  testsCount: tests.length,
@@ -611,28 +243,8 @@ class Replay {
611
243
  runParams,
612
244
  finishParams,
613
245
  envVars,
614
- runId: runId || client.runId,
246
+ runId: runId || client.runId
615
247
  };
616
- if (isEnabled) {
617
- console.log('\n' + '='.repeat(60));
618
- console.log('📊 FINAL SUMMARY:');
619
- console.log(` 📋 Total tests: ${tests.length}`);
620
- console.log(` ✅ Successfully sent: ${successCount}`);
621
- console.log(` ❌ Failed to send: ${failureCount}`);
622
- console.log(` 🆔 Run ID: ${runId || client.runId}`);
623
- console.log(` 🌍 Environment: ${envVars.TESTOMATIO_ENV || 'Unknown'}`);
624
- console.log(` 🔗 API URL: ${envVars.TESTOMATIO_URL || 'Default'}`);
625
- // Check final batch status
626
- if (client.pipes && client.pipes.length > 0) {
627
- const testomatioPipe = client.pipes.find(p => p.toString().includes('Testomatio'));
628
- if (testomatioPipe && testomatioPipe.batch) {
629
- const remainingTests = testomatioPipe.batch.tests ? testomatioPipe.batch.tests.length : 0;
630
- console.log(` 🔄 Final batch queue: ${remainingTests} tests remaining`);
631
- console.log(` ⏱️ Batch interval: ${testomatioPipe.batch.intervalFunction ? 'STILL RUNNING' : 'STOPPED'}`);
632
- }
633
- }
634
- console.log('='.repeat(60));
635
- }
636
248
  this.onLog(`Successfully replayed ${successCount}/${tests.length} tests from debug file`);
637
249
  return result;
638
250
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@testomatio/reporter",
3
- "version": "2.0.1-beta.9",
3
+ "version": "2.0.2",
4
4
  "description": "Testomatio Reporter Client",
5
5
  "engines": {
6
6
  "node": ">=18"
package/src/pipe/debug.js CHANGED
@@ -26,19 +26,18 @@ export class DebugPipe {
26
26
  debug('Creating debug file:', this.logFilePath);
27
27
  fs.writeFileSync(this.logFilePath, '');
28
28
 
29
- // Create latest debug file reference (Windows compatible)
30
- this.latestFilePath = path.join(os.tmpdir(), 'testomatio.debug.latest.json');
29
+ // Create symlink to ensure consistent path to latest debug file
30
+ const symlinkPath = path.join(os.tmpdir(), 'testomatio.debug.latest.json');
31
31
  try {
32
- // Remove existing latest file if it exists
33
- if (fs.existsSync(this.latestFilePath)) {
34
- fs.rmSync(this.latestFilePath);
32
+ // Remove existing symlink if it exists
33
+ if (fs.existsSync(symlinkPath)) {
34
+ fs.unlinkSync(symlinkPath);
35
35
  }
36
- // Initialize latest file
37
- fs.writeFileSync(this.latestFilePath, '');
38
- debug('Created latest debug file:', this.latestFilePath);
36
+ // Create new symlink pointing to the timestamped debug file
37
+ fs.symlinkSync(this.logFilePath, symlinkPath);
38
+ debug('Created symlink:', symlinkPath, '->', this.logFilePath);
39
39
  } catch (err) {
40
- debug('Failed to create latest debug file:', err.message);
41
- this.latestFilePath = null; // Disable latest file if creation fails
40
+ debug('Failed to create symlink:', err.message);
42
41
  }
43
42
 
44
43
  console.log(APP_PREFIX, '🪲 Debug file created');
@@ -68,19 +67,7 @@ export class DebugPipe {
68
67
  this.lastActionTimestamp = Date.now();
69
68
 
70
69
  const logLine = JSON.stringify({ t: `+${prettyMs(timePassedFromLastAction)}`, ...logData });
71
- const logLineWithNewline = `${logLine}\n`;
72
-
73
- // Write to timestamped debug file
74
- fs.appendFileSync(this.logFilePath, logLineWithNewline);
75
-
76
- // Also write to latest debug file for Windows compatibility
77
- if (this.latestFilePath) {
78
- try {
79
- fs.appendFileSync(this.latestFilePath, logLineWithNewline);
80
- } catch (err) {
81
- debug('Failed to write to latest debug file:', err.message);
82
- }
83
- }
70
+ fs.appendFileSync(this.logFilePath, `${logLine}\n`);
84
71
  }
85
72
 
86
73
  async prepareRun(opts) {
@@ -106,7 +93,8 @@ export class DebugPipe {
106
93
  const logData = { action: 'addTest', testId: data };
107
94
  if (this.store.runId) logData.runId = this.store.runId;
108
95
  this.logToFile(logData);
109
- } else this.batch.tests.push(data);
96
+ }
97
+ else this.batch.tests.push(data);
110
98
 
111
99
  if (!this.batch.intervalFunction) await this.batchUpload();
112
100
  }
@@ -129,9 +117,6 @@ export class DebugPipe {
129
117
  if (this.batch.intervalFunction) clearInterval(this.batch.intervalFunction);
130
118
  this.logToFile({ action: 'finishRun', params });
131
119
  console.log(APP_PREFIX, '🪲 Debug Saved to', this.logFilePath);
132
- if (this.latestFilePath) {
133
- console.log(APP_PREFIX, '🪲 Latest Debug file:', this.latestFilePath);
134
- }
135
120
  }
136
121
 
137
122
  toString() {
package/src/replay.js CHANGED
@@ -5,8 +5,6 @@ import TestomatClient from './client.js';
5
5
  import { STATUS } from './constants.js';
6
6
  import { config } from './config.js';
7
7
 
8
- const isEnabled = !!process.env.TESTOMATIO_DEBUG || !!process.env.DEBUG;
9
-
10
8
  export class Replay {
11
9
  constructor(options = {}) {
12
10
  this.apiKey = options.apiKey || config.TESTOMATIO || undefined;
@@ -24,100 +22,6 @@ export class Replay {
24
22
  return path.join(os.tmpdir(), 'testomatio.debug.latest.json');
25
23
  }
26
24
 
27
- /**
28
- * Read artifacts file for a specific run
29
- * @param {string} runId - Run ID to find artifacts for
30
- * @returns {Array} Array of artifact records with rid and file paths
31
- */
32
- readArtifactsFile(runId) {
33
- if (!runId) return [];
34
-
35
- const artifactsFile = path.join(os.tmpdir(), `testomatio.run.${runId}.json`);
36
-
37
- if (!fs.existsSync(artifactsFile)) {
38
- if (isEnabled) console.log(`No artifacts file found: ${artifactsFile}`);
39
- return [];
40
- }
41
-
42
- try {
43
- const data = fs.readFileSync(artifactsFile, 'utf-8');
44
- const lines = data.split('\n').filter(Boolean);
45
- const artifacts = lines.map(line => JSON.parse(line));
46
- if (isEnabled) console.log(`Found ${artifacts.length} artifact records in ${artifactsFile}`);
47
- return artifacts;
48
- } catch (err) {
49
- if (isEnabled) console.log(`Error reading artifacts file: ${err.message}`);
50
- return [];
51
- }
52
- }
53
-
54
- /**
55
- * Merge artifacts data with test data
56
- * @param {Array} tests - Array of test objects
57
- * @param {Array} artifacts - Array of artifact records
58
- * @returns {Array} Tests with merged artifact data
59
- */
60
- mergeArtifactsWithTests(tests, artifacts) {
61
- if (!artifacts.length) return tests;
62
-
63
- // Extract runId prefix from first test
64
- const runIdPrefix = tests[0]?.rid ? tests[0].rid.split('-')[0] + '-' : '';
65
-
66
- // Group artifacts by RID
67
- const artifactsByRid = artifacts.reduce((acc, artifact) => {
68
- const fullRid = runIdPrefix && !artifact.rid.startsWith(runIdPrefix) ? runIdPrefix + artifact.rid : artifact.rid;
69
-
70
- if (!acc[fullRid]) acc[fullRid] = [];
71
- acc[fullRid].push(artifact);
72
- return acc;
73
- }, {});
74
-
75
- // Merge artifacts into tests
76
- let mergedCount = 0;
77
- const result = tests.map(test => {
78
- if (!test.rid || !artifactsByRid[test.rid]) return test;
79
-
80
- const testArtifacts = artifactsByRid[test.rid];
81
- mergedCount++;
82
-
83
- if (isEnabled && test.title) {
84
- console.log(`🔄 Adding artifact info for test: ${test.title}`);
85
- console.log(` 📎 Existing files: ${(test.files || []).length} | Artifact records: ${testArtifacts.length}`);
86
- }
87
-
88
- // Deduplicate artifacts by filename
89
- const seenFiles = new Set();
90
- const deduplicatedArtifacts = testArtifacts.filter(artifact => {
91
- if (!artifact.file) return true;
92
- const fileName = path.basename(artifact.file);
93
- if (seenFiles.has(fileName)) {
94
- if (isEnabled && test.title) {
95
- console.log(` ⚠️ Removed duplicate artifact: ${fileName}`);
96
- }
97
- return false;
98
- }
99
- seenFiles.add(fileName);
100
- return true;
101
- });
102
-
103
- if (isEnabled && test.title && deduplicatedArtifacts.length !== testArtifacts.length) {
104
- console.log(` 🧹 Deduplicated: ${testArtifacts.length} → ${deduplicatedArtifacts.length} artifacts`);
105
- }
106
-
107
- return {
108
- ...test,
109
- files: test.files || [],
110
- artifactRecords: deduplicatedArtifacts,
111
- };
112
- });
113
-
114
- if (isEnabled) {
115
- console.log(`🔄 Added artifact info to ${mergedCount} tests (no file duplication)`);
116
- }
117
-
118
- return result;
119
- }
120
-
121
25
  /**
122
26
  * Parse a debug file and extract test data
123
27
  * @param {string} debugFile - Path to the debug file
@@ -129,10 +33,7 @@ export class Replay {
129
33
  }
130
34
 
131
35
  const fileContent = fs.readFileSync(debugFile, 'utf-8');
132
- const lines = fileContent
133
- .trim()
134
- .split('\n')
135
- .filter(line => line.trim() !== '');
36
+ const lines = fileContent.trim().split('\n').filter(line => line.trim() !== '');
136
37
 
137
38
  if (lines.length === 0) {
138
39
  throw new Error('Debug file is empty');
@@ -171,25 +72,13 @@ export class Replay {
171
72
  Object.keys(test).forEach(key => {
172
73
  if (test[key] !== null && test[key] !== undefined) {
173
74
  if (key === 'files' && Array.isArray(test[key]) && test[key].length > 0) {
174
- // Deduplicate files within the array itself
175
- const seen = new Set();
176
- mergedTest.files = test[key].filter(file => {
177
- const fileName =
178
- typeof file === 'string'
179
- ? path.basename(file)
180
- : path.basename(file?.path || file?.file || '');
181
- if (seen.has(fileName)) return false;
182
- seen.add(fileName);
183
- return true;
184
- });
75
+ // Merge files arrays
76
+ mergedTest.files = [...(existingTest.files || []), ...test[key]];
185
77
  } else if (key === 'artifacts' && Array.isArray(test[key]) && test[key].length > 0) {
186
- // Keep the most recent artifacts array (don't merge to avoid duplicates)
187
- mergedTest.artifacts = test[key];
188
- } else if (
189
- existingTest[key] === null ||
190
- existingTest[key] === undefined ||
191
- (Array.isArray(existingTest[key]) && existingTest[key].length === 0)
192
- ) {
78
+ // Merge artifacts arrays
79
+ mergedTest.artifacts = [...(existingTest.artifacts || []), ...test[key]];
80
+ } else if (existingTest[key] === null || existingTest[key] === undefined ||
81
+ (Array.isArray(existingTest[key]) && existingTest[key].length === 0)) {
193
82
  // Use new value if existing is null/undefined/empty array
194
83
  mergedTest[key] = test[key];
195
84
  }
@@ -214,33 +103,8 @@ export class Replay {
214
103
  // Handle tests with rid (deduplicate)
215
104
  const existingTest = testsMap.get(test.rid);
216
105
  if (existingTest) {
217
- // Merge test data - prioritize non-null/non-empty values (same logic as addTestsBatch)
218
- const mergedTest = { ...existingTest };
219
- Object.keys(test).forEach(key => {
220
- if (test[key] !== null && test[key] !== undefined) {
221
- if (key === 'files' && Array.isArray(test[key]) && test[key].length > 0) {
222
- // Deduplicate files within the array itself
223
- const seen = new Set();
224
- mergedTest.files = test[key].filter(file => {
225
- const fileName =
226
- typeof file === 'string' ? path.basename(file) : path.basename(file?.path || file?.file || '');
227
- if (seen.has(fileName)) return false;
228
- seen.add(fileName);
229
- return true;
230
- });
231
- } else if (key === 'artifacts' && Array.isArray(test[key]) && test[key].length > 0) {
232
- // Keep the most recent artifacts array (don't merge to avoid duplicates)
233
- mergedTest.artifacts = test[key];
234
- } else if (
235
- existingTest[key] === null ||
236
- existingTest[key] === undefined ||
237
- (Array.isArray(existingTest[key]) && existingTest[key].length === 0)
238
- ) {
239
- // Use new value if existing is null/undefined/empty array
240
- mergedTest[key] = test[key];
241
- }
242
- }
243
- });
106
+ // Merge with existing test
107
+ const mergedTest = { ...existingTest, ...test };
244
108
  testsMap.set(test.rid, mergedTest);
245
109
  } else {
246
110
  testsMap.set(test.rid, { ...test });
@@ -275,7 +139,7 @@ export class Replay {
275
139
  envVars,
276
140
  parseErrors,
277
141
  totalLines: lines.length,
278
- runId,
142
+ runId
279
143
  };
280
144
  }
281
145
 
@@ -310,8 +174,7 @@ export class Replay {
310
174
 
311
175
  // Parse the debug file
312
176
  const debugData = this.parseDebugFile(debugFile);
313
- const { runParams, finishParams, envVars, runId } = debugData;
314
- let tests = debugData.tests;
177
+ const { runParams, finishParams, tests, envVars, runId } = debugData;
315
178
 
316
179
  this.onLog(`Found ${tests.length} tests to replay`);
317
180
 
@@ -319,104 +182,10 @@ export class Replay {
319
182
  throw new Error('No test data found in debug file');
320
183
  }
321
184
 
322
- // Read and merge artifacts if runId is available
323
- if (runId) {
324
- const artifacts = this.readArtifactsFile(runId);
325
- if (artifacts.length > 0) {
326
- if (isEnabled) console.log(`Found ${artifacts.length} artifact records in testomatio.run.${runId}.json`);
327
- tests = this.mergeArtifactsWithTests(tests, artifacts);
328
- }
329
- }
330
-
331
185
  // Restore environment variables
332
186
  this.restoreEnvironmentVariables(envVars);
333
187
 
334
188
  if (this.dryRun) {
335
- if (isEnabled) console.log('🔍 DRY RUN - Tests to be sent:');
336
- if (isEnabled) console.log('='.repeat(60));
337
-
338
- let totalArtifacts = 0;
339
- let totalFiles = 0;
340
- let uploadedArtifacts = 0;
341
- let notUploadedArtifacts = 0;
342
-
343
- tests.forEach((test, index) => {
344
- const status = test.status === 'passed' ? '✅' : test.status === 'failed' ? '❌' : '⏭️';
345
- if (isEnabled) console.log(`${index + 1}. ${status} ${test.title || test.id}`);
346
- if (isEnabled) console.log(` 📁 File: ${test.file || 'Unknown'}`);
347
- if (isEnabled) console.log(` 📊 Status: ${test.status}`);
348
- if (isEnabled) console.log(` 🔑 RID: ${test.rid || 'No RID'}`);
349
-
350
- if (test.steps && test.steps.length > 0) {
351
- if (isEnabled) console.log(` 🔄 Steps: ${test.steps.length}`);
352
- test.steps.slice(0, 3).forEach((step, stepIndex) => {
353
- const stepStatus = step.status === 'passed' ? '✅' : step.status === 'failed' ? '❌' : '⚪';
354
- if (isEnabled) console.log(` ${stepIndex + 1}. ${stepStatus} ${step.title || step.name || 'Step'}`);
355
- });
356
- if (test.steps.length > 3) {
357
- if (isEnabled) console.log(` ... also ${test.steps.length - 3} steps`);
358
- }
359
- }
360
-
361
- // Show either artifact records (if available) or files
362
- if (test.artifactRecords && test.artifactRecords.length > 0) {
363
- totalArtifacts += test.artifactRecords.length;
364
- if (isEnabled) console.log(` 📎 Artifacts: ${test.artifactRecords.length}`);
365
- test.artifactRecords.forEach((artifact, artIndex) => {
366
- const uploaded =
367
- artifact.uploaded === true
368
- ? '✅ Uploaded'
369
- : artifact.uploaded === false
370
- ? '📤 Not Uploaded'
371
- : '⏳ Unknown';
372
- const fileName = artifact.file ? path.basename(artifact.file) : 'Unknown';
373
- if (isEnabled) console.log(` ${artIndex + 1}. ${uploaded}: ${fileName}`);
374
-
375
- // Count artifact upload status
376
- if (artifact.uploaded === true) {
377
- uploadedArtifacts++;
378
- } else if (artifact.uploaded === false) {
379
- notUploadedArtifacts++;
380
- }
381
- });
382
- } else if (test.files && test.files.length > 0) {
383
- totalFiles += test.files.length;
384
- if (isEnabled) console.log(` 📎 Files: ${test.files.length}`);
385
- test.files.slice(0, 3).forEach((file, fileIndex) => {
386
- // Handle both string paths and object formats
387
- let fileName;
388
- if (typeof file === 'string') {
389
- fileName = path.basename(file);
390
- } else if (file && typeof file === 'object') {
391
- const filePath = file.path || file.file || JSON.stringify(file);
392
- fileName = file.name || (typeof filePath === 'string' ? path.basename(filePath) : 'Unknown');
393
- } else {
394
- fileName = 'Unknown';
395
- }
396
- if (isEnabled) console.log(` ${fileIndex + 1}. ${fileName}`);
397
- });
398
- if (test.files.length > 3) {
399
- if (isEnabled) console.log(` ... also ${test.files.length - 3} files`);
400
- }
401
- }
402
-
403
- if (isEnabled) console.log('');
404
- });
405
-
406
- if (isEnabled) console.log('='.repeat(60));
407
- if (isEnabled) console.log('📊 SUMMARY:');
408
- if (isEnabled) console.log(` 📋 Total tests: ${tests.length}`);
409
- if (isEnabled) console.log(` 📎 Total files: ${totalFiles}`);
410
- if (isEnabled) console.log(` 📎 Total artifact records: ${totalArtifacts}`);
411
- if (totalArtifacts > 0) {
412
- if (isEnabled) console.log(` ✅ Uploaded: ${uploadedArtifacts}`);
413
- if (isEnabled) console.log(` 📤 Not Uploaded: ${notUploadedArtifacts}`);
414
- }
415
- if (isEnabled) console.log(` 🆔 Run ID: ${runId || 'Will create new'}`);
416
- if (isEnabled) console.log(` 🌍 Environment: ${envVars.TESTOMATIO_ENV || 'Unknown'}`);
417
- if (isEnabled) console.log(` 🔗 API URL: ${envVars.TESTOMATIO_URL || 'Default'}`);
418
- if (isEnabled) console.log('');
419
- if (isEnabled) console.log('✅ Use without --dry-run to send this data to Testomat.io');
420
189
  return {
421
190
  success: true,
422
191
  testsCount: tests.length,
@@ -424,77 +193,24 @@ export class Replay {
424
193
  finishParams,
425
194
  envVars,
426
195
  runId,
427
- dryRun: true,
196
+ dryRun: true
428
197
  };
429
198
  }
430
199
 
431
200
  // Create client and restore the run
432
201
  const client = new TestomatClient({
433
202
  apiKey: this.apiKey,
434
- // isBatchEnabled: true,
203
+ isBatchEnabled: true,
435
204
  ...runParams,
436
205
  });
437
206
 
438
- if (isEnabled) {
439
- console.log('🔧 CLIENT CONFIGURATION:');
440
- console.log(` 🔑 API Key: ${this.apiKey ? `${this.apiKey.slice(0, 10)}...` : 'NOT SET'}`);
441
- console.log(` 🏪 Batch enabled: ${runParams.isBatchEnabled || 'unknown'}`);
442
- console.log(` 📡 Pipes count: ${client.pipes ? client.pipes.length : 0}`);
443
- if (client.pipes && client.pipes.length > 0) {
444
- client.pipes.forEach((pipe, index) => {
445
- console.log(` ${index + 1}. ${pipe.toString()} - enabled: ${pipe.isEnabled}`);
446
- });
447
- } else {
448
- console.log(` ⚠️ WARNING: No pipes configured!`);
449
- }
450
- console.log(` 📤 Uploader enabled: ${client.uploader ? client.uploader.isEnabled : 'unknown'}`);
451
- console.log('');
452
- }
453
-
454
207
  // Use the stored runId if available, otherwise create a new run
455
208
  if (runId) {
456
209
  this.onLog(`Using existing run ID: ${runId}`);
457
- if (isEnabled) console.log(`🔄 Restoring run with ID: ${runId}`);
458
- if (isEnabled) console.log(`📊 Run params:`, JSON.stringify(runParams, null, 2));
459
210
  client.runId = runId;
460
- // Always call createRun to initialize batch system and update run params
461
- if (isEnabled) console.log(`🔄 Initializing batch system for existing run...`);
462
- // await client.createRun({ ...runParams, isBatchEnabled: true });
463
- await client.createRun(runParams);
464
- this.onLog(`Create new run`);
465
211
  } else {
466
212
  this.onLog('Publishing to run...');
467
- if (isEnabled) console.log(`🆕 Creating new run with params:`, JSON.stringify(runParams, null, 2));
468
213
  await client.createRun(runParams);
469
- if (isEnabled) console.log(`✅ New run created with ID: ${client.runId}`);
470
- }
471
-
472
- if (isEnabled) {
473
- console.log('🔧 POST-INITIALIZATION STATUS:');
474
- console.log(` 🆔 Final Run ID: ${client.runId}`);
475
-
476
- // Check each pipe status
477
- if (!client.pipes?.length) {
478
- console.log(' ⚠️ No pipes found!');
479
- } else {
480
- client.pipes.forEach((pipe, index) => {
481
- console.log(` 📡 Pipe ${index + 1}: ${pipe.toString()}`);
482
- console.log(` ✅ Enabled: ${pipe.isEnabled}`);
483
- console.log(` 🆔 Run ID: ${pipe.runId || 'NOT SET'}`);
484
-
485
- if (!pipe.toString().includes('Testomatio') || !pipe.batch) return;
486
-
487
- console.log(` 🔄 Batch enabled: ${pipe.batch.isEnabled}`);
488
- console.log(` ⏱️ Batch interval: ${pipe.batch.intervalFunction ? 'RUNNING' : 'NOT RUNNING'}`);
489
- console.log(` 📦 Tests in queue: ${pipe.batch.tests?.length || 0}`);
490
- });
491
- }
492
- console.log('');
493
- }
494
-
495
- if (isEnabled) {
496
- console.log('🚀 SENDING TESTS TO TESTOMAT.IO');
497
- console.log('='.repeat(60));
498
214
  }
499
215
 
500
216
  // Send each test result
@@ -503,119 +219,29 @@ export class Replay {
503
219
 
504
220
  for (const [index, test] of tests.entries()) {
505
221
  try {
506
- if (isEnabled) {
507
- const status = test.status === 'passed' ? '✅' : test.status === 'failed' ? '❌' : '⏭️';
508
- console.log(`\n📤 Sending test ${index + 1}/${tests.length}: ${status} ${test.title || test.id}`);
509
- console.log(` 📁 File: ${test.file || 'Unknown'}`);
510
- console.log(` 🔑 RID: ${test.rid || 'No RID'}`);
511
- console.log(` 📊 Status: ${test.status}${test.steps?.length > 0 ? ` | steps: ${test.steps.length}` : ''}`);
512
-
513
- // Show artifacts info
514
- if (test.artifactRecords?.length) {
515
- console.log(` 📎 Artifacts: ${test.artifactRecords.length}`);
516
- test.artifactRecords.forEach((artifact, i) => {
517
- const status = artifact.uploaded ? '✅ Uploaded' : '📤 Not Uploaded';
518
- const name = artifact.file ? path.basename(artifact.file) : 'Unknown';
519
- console.log(` ${i + 1}. ${status}: ${name}`);
520
- });
521
- } else if (test.files?.length) {
522
- console.log(` 📎 Files: ${test.files.length}`);
523
- test.files.slice(0, 3).forEach((file, i) => {
524
- const name =
525
- typeof file === 'string' ? path.basename(file) : path.basename(file?.path || file?.file || 'Unknown');
526
- console.log(` ${i + 1}. ${name}`);
527
- });
528
- if (test.files.length > 3) {
529
- console.log(` ... also ${test.files.length - 3} more files`);
530
- }
531
- }
532
-
533
- // Show the actual data payload being sent
534
- const uniqueFiles = test.files
535
- ? [
536
- ...new Set(
537
- test.files.map(f =>
538
- typeof f === 'string' ? path.basename(f) : path.basename(f?.path || f?.file || ''),
539
- ),
540
- ),
541
- ].length
542
- : 0;
543
-
544
- console.log(
545
- ` 📦 Payload preview:`,
546
- JSON.stringify(
547
- {
548
- status: test.status,
549
- title: test.title,
550
- id: test.id,
551
- rid: test.rid,
552
- uniqueFiles,
553
- steps: test.steps ? test.steps.length : 0,
554
- artifactRecords: test.artifactRecords ? test.artifactRecords.length : 0,
555
- },
556
- null,
557
- 2,
558
- ),
559
- );
560
- }
561
-
562
- const addTestRunResult = await client.addTestRun(test.status, test);
222
+ await client.addTestRun(test.status, test);
563
223
  successCount++;
564
-
565
224
  this.onProgress({
566
225
  current: index + 1,
567
226
  total: tests.length,
568
227
  test,
569
- success: true,
228
+ success: true
570
229
  });
571
230
  } catch (err) {
572
231
  failureCount++;
573
- if (isEnabled) {
574
- console.log(` ❌ Failed to send: ${err.message}`);
575
- console.log(` 🔍 Error details:`, err);
576
- }
577
232
  this.onError(`Failed to send test ${index + 1}: ${err.message}`);
578
233
  this.onProgress({
579
234
  current: index + 1,
580
235
  total: tests.length,
581
236
  test,
582
237
  success: false,
583
- error: err.message,
238
+ error: err.message
584
239
  });
585
240
  }
586
241
  }
587
242
 
588
- if (isEnabled) {
589
- console.log('\n' + '='.repeat(60));
590
- console.log('🏁 FINISHING RUN');
591
- console.log(`📊 Finish params:`, JSON.stringify(finishParams, null, 2));
592
- }
593
-
594
243
  await client.updateRunStatus(finishParams.status || STATUS.FINISHED, finishParams.parallel || false);
595
244
 
596
- if (isEnabled) {
597
- console.log(`✅ Run finished with status: ${finishParams.status || STATUS.FINISHED}`);
598
-
599
- // Wait a bit for batch system to finish sending remaining tests
600
- const testomatioPipe = client.pipes && client.pipes.find(p => p.toString().includes('Testomatio'));
601
- if (
602
- testomatioPipe &&
603
- testomatioPipe.batch &&
604
- testomatioPipe.batch.tests &&
605
- testomatioPipe.batch.tests.length > 0
606
- ) {
607
- console.log(`⏳ Waiting for batch system to send ${testomatioPipe.batch.tests.length} remaining tests...`);
608
- await new Promise(resolve => setTimeout(resolve, 6000)); // Wait 6 seconds for batch upload
609
-
610
- const remainingAfterWait = testomatioPipe.batch.tests ? testomatioPipe.batch.tests.length : 0;
611
- if (remainingAfterWait > 0) {
612
- console.log(`⚠️ ${remainingAfterWait} tests still in batch queue after waiting`);
613
- } else {
614
- console.log(`✅ All tests successfully sent via batch system`);
615
- }
616
- }
617
- }
618
-
619
245
  const result = {
620
246
  success: true,
621
247
  testsCount: tests.length,
@@ -624,36 +250,13 @@ export class Replay {
624
250
  runParams,
625
251
  finishParams,
626
252
  envVars,
627
- runId: runId || client.runId,
253
+ runId: runId || client.runId
628
254
  };
629
255
 
630
- if (isEnabled) {
631
- console.log('\n' + '='.repeat(60));
632
- console.log('📊 FINAL SUMMARY:');
633
- console.log(` 📋 Total tests: ${tests.length}`);
634
- console.log(` ✅ Successfully sent: ${successCount}`);
635
- console.log(` ❌ Failed to send: ${failureCount}`);
636
- console.log(` 🆔 Run ID: ${runId || client.runId}`);
637
- console.log(` 🌍 Environment: ${envVars.TESTOMATIO_ENV || 'Unknown'}`);
638
- console.log(` 🔗 API URL: ${envVars.TESTOMATIO_URL || 'Default'}`);
639
-
640
- // Check final batch status
641
- if (client.pipes && client.pipes.length > 0) {
642
- const testomatioPipe = client.pipes.find(p => p.toString().includes('Testomatio'));
643
- if (testomatioPipe && testomatioPipe.batch) {
644
- const remainingTests = testomatioPipe.batch.tests ? testomatioPipe.batch.tests.length : 0;
645
- console.log(` 🔄 Final batch queue: ${remainingTests} tests remaining`);
646
- console.log(` ⏱️ Batch interval: ${testomatioPipe.batch.intervalFunction ? 'STILL RUNNING' : 'STOPPED'}`);
647
- }
648
- }
649
-
650
- console.log('='.repeat(60));
651
- }
652
-
653
256
  this.onLog(`Successfully replayed ${successCount}/${tests.length} tests from debug file`);
654
257
 
655
258
  return result;
656
259
  }
657
260
  }
658
261
 
659
- export default Replay;
262
+ export default Replay;