@testomatio/reporter 2.0.1-beta.8 → 2.0.1-beta.9

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.
@@ -14,6 +14,7 @@ const client_js_1 = __importDefault(require("../client.js"));
14
14
  const utils_js_1 = require("../utils/utils.js");
15
15
  const index_js_1 = require("../services/index.js");
16
16
  const data_storage_js_1 = require("../data-storage.js");
17
+ const constants_js_2 = require("../utils/constants.js");
17
18
  const reportTestPromises = [];
18
19
  class PlaywrightReporter {
19
20
  constructor(config = {}) {
@@ -123,9 +124,12 @@ class PlaywrightReporter {
123
124
  }
124
125
  if (artifact.body) {
125
126
  let filePath = generateTmpFilepath(artifact.name);
126
- const extension = artifact.contentType?.split('/')[1]?.replace('jpeg', 'jpg');
127
- if (extension)
128
- filePath += `.${extension}`;
127
+ const hasExtension = artifact.name && path_1.default.extname(artifact.name);
128
+ if (!hasExtension && artifact.contentType) {
129
+ const extension = constants_js_2.extensionMap[artifact.contentType] || artifact.contentType.split('/')[1];
130
+ if (extension)
131
+ filePath += `.${extension}`;
132
+ }
129
133
  fs_1.default.writeFileSync(filePath, artifact.body);
130
134
  return filePath;
131
135
  }
@@ -11,6 +11,7 @@ export class DebugPipe {
11
11
  batchIndex: number;
12
12
  };
13
13
  logFilePath: string;
14
+ latestFilePath: string;
14
15
  testomatioEnvVars: {};
15
16
  batchUpload(): Promise<void>;
16
17
  /**
package/lib/pipe/debug.js CHANGED
@@ -27,19 +27,20 @@ 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 symlink to ensure consistent path to latest debug file
31
- const symlinkPath = path_1.default.join(os_1.default.tmpdir(), 'testomatio.debug.latest.json');
30
+ // Create latest debug file reference (Windows compatible)
31
+ this.latestFilePath = path_1.default.join(os_1.default.tmpdir(), 'testomatio.debug.latest.json');
32
32
  try {
33
- // Remove existing symlink if it exists
34
- if (fs_1.default.existsSync(symlinkPath)) {
35
- fs_1.default.unlinkSync(symlinkPath);
33
+ // Remove existing latest file if it exists
34
+ if (fs_1.default.existsSync(this.latestFilePath)) {
35
+ fs_1.default.rmSync(this.latestFilePath);
36
36
  }
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);
37
+ // Initialize latest file
38
+ fs_1.default.writeFileSync(this.latestFilePath, '');
39
+ debug('Created latest debug file:', this.latestFilePath);
40
40
  }
41
41
  catch (err) {
42
- debug('Failed to create symlink:', err.message);
42
+ debug('Failed to create latest debug file:', err.message);
43
+ this.latestFilePath = null; // Disable latest file if creation fails
43
44
  }
44
45
  console.log(constants_js_1.APP_PREFIX, '🪲 Debug file created');
45
46
  this.testomatioEnvVars = Object.keys(process.env)
@@ -67,7 +68,18 @@ class DebugPipe {
67
68
  const timePassedFromLastAction = Date.now() - (this.lastActionTimestamp || Date.now());
68
69
  this.lastActionTimestamp = Date.now();
69
70
  const logLine = JSON.stringify({ t: `+${(0, pretty_ms_1.default)(timePassedFromLastAction)}`, ...logData });
70
- fs_1.default.appendFileSync(this.logFilePath, `${logLine}\n`);
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
+ }
71
83
  }
72
84
  async prepareRun(opts) {
73
85
  if (!this.isEnabled)
@@ -119,6 +131,9 @@ class DebugPipe {
119
131
  clearInterval(this.batch.intervalFunction);
120
132
  this.logToFile({ action: 'finishRun', params });
121
133
  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
+ }
122
137
  }
123
138
  toString() {
124
139
  return 'Debug Reporter';
package/lib/replay.d.ts CHANGED
@@ -10,6 +10,19 @@ 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[];
13
26
  /**
14
27
  * Parse a debug file and extract test data
15
28
  * @param {string} debugFile - Path to the debug file
package/lib/replay.js CHANGED
@@ -10,6 +10,7 @@ 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;
13
14
  class Replay {
14
15
  constructor(options = {}) {
15
16
  this.apiKey = options.apiKey || config_js_1.config.TESTOMATIO || undefined;
@@ -25,6 +26,93 @@ class Replay {
25
26
  getDefaultDebugFile() {
26
27
  return path_1.default.join(os_1.default.tmpdir(), 'testomatio.debug.latest.json');
27
28
  }
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
+ }
28
116
  /**
29
117
  * Parse a debug file and extract test data
30
118
  * @param {string} debugFile - Path to the debug file
@@ -35,7 +123,10 @@ class Replay {
35
123
  throw new Error(`Debug file not found: ${debugFile}`);
36
124
  }
37
125
  const fileContent = fs_1.default.readFileSync(debugFile, 'utf-8');
38
- const lines = fileContent.trim().split('\n').filter(line => line.trim() !== '');
126
+ const lines = fileContent
127
+ .trim()
128
+ .split('\n')
129
+ .filter(line => line.trim() !== '');
39
130
  if (lines.length === 0) {
40
131
  throw new Error('Debug file is empty');
41
132
  }
@@ -72,14 +163,24 @@ class Replay {
72
163
  Object.keys(test).forEach(key => {
73
164
  if (test[key] !== null && test[key] !== undefined) {
74
165
  if (key === 'files' && Array.isArray(test[key]) && test[key].length > 0) {
75
- // Merge files arrays
76
- mergedTest.files = [...(existingTest.files || []), ...test[key]];
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
+ });
77
177
  }
78
178
  else if (key === 'artifacts' && Array.isArray(test[key]) && test[key].length > 0) {
79
- // Merge artifacts arrays
80
- mergedTest.artifacts = [...(existingTest.artifacts || []), ...test[key]];
179
+ // Keep the most recent artifacts array (don't merge to avoid duplicates)
180
+ mergedTest.artifacts = test[key];
81
181
  }
82
- else if (existingTest[key] === null || existingTest[key] === undefined ||
182
+ else if (existingTest[key] === null ||
183
+ existingTest[key] === undefined ||
83
184
  (Array.isArray(existingTest[key]) && existingTest[key].length === 0)) {
84
185
  // Use new value if existing is null/undefined/empty array
85
186
  mergedTest[key] = test[key];
@@ -108,8 +209,33 @@ class Replay {
108
209
  // Handle tests with rid (deduplicate)
109
210
  const existingTest = testsMap.get(test.rid);
110
211
  if (existingTest) {
111
- // Merge with existing test
112
- const mergedTest = { ...existingTest, ...test };
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
+ });
113
239
  testsMap.set(test.rid, mergedTest);
114
240
  }
115
241
  else {
@@ -145,7 +271,7 @@ class Replay {
145
271
  envVars,
146
272
  parseErrors,
147
273
  totalLines: lines.length,
148
- runId
274
+ runId,
149
275
  };
150
276
  }
151
277
  /**
@@ -175,14 +301,132 @@ class Replay {
175
301
  this.onLog(`Replaying data from debug file: ${debugFile}`);
176
302
  // Parse the debug file
177
303
  const debugData = this.parseDebugFile(debugFile);
178
- const { runParams, finishParams, tests, envVars, runId } = debugData;
304
+ const { runParams, finishParams, envVars, runId } = debugData;
305
+ let tests = debugData.tests;
179
306
  this.onLog(`Found ${tests.length} tests to replay`);
180
307
  if (tests.length === 0) {
181
308
  throw new Error('No test data found in debug file');
182
309
  }
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
+ }
183
319
  // Restore environment variables
184
320
  this.restoreEnvironmentVariables(envVars);
185
321
  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');
186
430
  return {
187
431
  success: true,
188
432
  testsCount: tests.length,
@@ -190,51 +434,175 @@ class Replay {
190
434
  finishParams,
191
435
  envVars,
192
436
  runId,
193
- dryRun: true
437
+ dryRun: true,
194
438
  };
195
439
  }
196
440
  // Create client and restore the run
197
441
  const client = new client_js_1.default({
198
442
  apiKey: this.apiKey,
199
- isBatchEnabled: true,
443
+ // isBatchEnabled: true,
200
444
  ...runParams,
201
445
  });
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
+ }
202
462
  // Use the stored runId if available, otherwise create a new run
203
463
  if (runId) {
204
464
  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));
205
469
  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`);
206
476
  }
207
477
  else {
208
478
  this.onLog('Publishing to run...');
479
+ if (isEnabled)
480
+ console.log(`šŸ†• Creating new run with params:`, JSON.stringify(runParams, null, 2));
209
481
  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));
210
509
  }
211
510
  // Send each test result
212
511
  let successCount = 0;
213
512
  let failureCount = 0;
214
513
  for (const [index, test] of tests.entries()) {
215
514
  try {
216
- await client.addTestRun(test.status, test);
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);
217
557
  successCount++;
218
558
  this.onProgress({
219
559
  current: index + 1,
220
560
  total: tests.length,
221
561
  test,
222
- success: true
562
+ success: true,
223
563
  });
224
564
  }
225
565
  catch (err) {
226
566
  failureCount++;
567
+ if (isEnabled) {
568
+ console.log(` āŒ Failed to send: ${err.message}`);
569
+ console.log(` šŸ” Error details:`, err);
570
+ }
227
571
  this.onError(`Failed to send test ${index + 1}: ${err.message}`);
228
572
  this.onProgress({
229
573
  current: index + 1,
230
574
  total: tests.length,
231
575
  test,
232
576
  success: false,
233
- error: err.message
577
+ error: err.message,
234
578
  });
235
579
  }
236
580
  }
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
+ }
237
586
  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
+ }
238
606
  const result = {
239
607
  success: true,
240
608
  testsCount: tests.length,
@@ -243,8 +611,28 @@ class Replay {
243
611
  runParams,
244
612
  finishParams,
245
613
  envVars,
246
- runId: runId || client.runId
614
+ runId: runId || client.runId,
247
615
  };
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
+ }
248
636
  this.onLog(`Successfully replayed ${successCount}/${tests.length} tests from debug file`);
249
637
  return result;
250
638
  }
@@ -0,0 +1,12 @@
1
+ export const extensionMap: {
2
+ 'application/json': string;
3
+ 'text/plain': string;
4
+ 'image/jpeg': string;
5
+ 'image/png': string;
6
+ 'text/html': string;
7
+ 'text/css': string;
8
+ 'text/javascript': string;
9
+ 'application/pdf': string;
10
+ 'application/xml': string;
11
+ 'text/xml': string;
12
+ };