@testomatio/reporter 2.0.1-beta.4 → 2.0.1-beta.6
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.
- package/README.md +1 -0
- package/lib/client.js +6 -1
- package/lib/pipe/debug.js +10 -3
- package/lib/replay.js +23 -5
- package/package.json +1 -1
- package/src/client.js +7 -0
- package/src/pipe/debug.js +8 -2
- package/src/replay.js +22 -5
package/README.md
CHANGED
|
@@ -133,6 +133,7 @@ Bring this reporter on CI and never lose test results again!
|
|
|
133
133
|
- 🗄️ [Artifacts](./docs/artifacts.md)
|
|
134
134
|
- 🔂 [Workflows](./docs/workflows.md)
|
|
135
135
|
- 🖊️ [Logger](./docs/logger.md)
|
|
136
|
+
- 🪲 [Debug File Format](./docs/debug-file-format.md)
|
|
136
137
|
|
|
137
138
|
## Development
|
|
138
139
|
|
package/lib/client.js
CHANGED
|
@@ -172,10 +172,14 @@ class Client {
|
|
|
172
172
|
title: 'Unknown test',
|
|
173
173
|
suite_title: 'Unknown suite',
|
|
174
174
|
};
|
|
175
|
+
// Add timestamp if not already present (microseconds since Unix epoch)
|
|
176
|
+
if (!testData.timestamp && !process.env.TESTOMATIO_NO_TIMESTAMP) {
|
|
177
|
+
testData.timestamp = Math.floor((performance.timeOrigin + performance.now()) * 1000);
|
|
178
|
+
}
|
|
175
179
|
/**
|
|
176
180
|
* @type {TestData}
|
|
177
181
|
*/
|
|
178
|
-
const { rid, error = null, time = 0, example = null, files = [], filesBuffers = [], steps, code = null, title, file, suite_title, suite_id, test_id, manuallyAttachedArtifacts, } = testData;
|
|
182
|
+
const { rid, error = null, time = 0, example = null, files = [], filesBuffers = [], steps, code = null, title, file, suite_title, suite_id, test_id, timestamp, manuallyAttachedArtifacts, } = testData;
|
|
179
183
|
let { message = '', meta = {} } = testData;
|
|
180
184
|
// stringify meta values and limit keys and values length to 255
|
|
181
185
|
meta = Object.entries(meta)
|
|
@@ -258,6 +262,7 @@ class Client {
|
|
|
258
262
|
test_id,
|
|
259
263
|
message,
|
|
260
264
|
run_time: typeof time === 'number' ? time : parseFloat(time),
|
|
265
|
+
timestamp,
|
|
261
266
|
artifacts,
|
|
262
267
|
meta,
|
|
263
268
|
...(rootSuiteId && { root_suite_id: rootSuiteId }),
|
package/lib/pipe/debug.js
CHANGED
|
@@ -88,8 +88,12 @@ class DebugPipe {
|
|
|
88
88
|
async addTest(data) {
|
|
89
89
|
if (!this.isEnabled)
|
|
90
90
|
return;
|
|
91
|
-
if (!this.batch.isEnabled)
|
|
92
|
-
|
|
91
|
+
if (!this.batch.isEnabled) {
|
|
92
|
+
const logData = { action: 'addTest', testId: data };
|
|
93
|
+
if (this.store.runId)
|
|
94
|
+
logData.runId = this.store.runId;
|
|
95
|
+
this.logToFile(logData);
|
|
96
|
+
}
|
|
93
97
|
else
|
|
94
98
|
this.batch.tests.push(data);
|
|
95
99
|
if (!this.batch.intervalFunction)
|
|
@@ -102,7 +106,10 @@ class DebugPipe {
|
|
|
102
106
|
if (!this.batch.tests.length)
|
|
103
107
|
return;
|
|
104
108
|
const testsToSend = this.batch.tests.splice(0);
|
|
105
|
-
|
|
109
|
+
const logData = { action: 'addTestsBatch', tests: testsToSend };
|
|
110
|
+
if (this.store.runId)
|
|
111
|
+
logData.runId = this.store.runId;
|
|
112
|
+
this.logToFile(logData);
|
|
106
113
|
}
|
|
107
114
|
async finishRun(params) {
|
|
108
115
|
if (!this.isEnabled)
|
package/lib/replay.js
CHANGED
|
@@ -45,6 +45,7 @@ class Replay {
|
|
|
45
45
|
const testsMap = new Map(); // Use Map to deduplicate by rid
|
|
46
46
|
const testsWithoutRid = []; // For tests without rid (backward compatibility)
|
|
47
47
|
const envVars = {};
|
|
48
|
+
let runId = null;
|
|
48
49
|
// Parse debug file line by line
|
|
49
50
|
for (const [lineIndex, line] of lines.entries()) {
|
|
50
51
|
try {
|
|
@@ -56,6 +57,10 @@ class Replay {
|
|
|
56
57
|
runParams = logEntry.params || {};
|
|
57
58
|
}
|
|
58
59
|
else if (logEntry.action === 'addTestsBatch' && logEntry.tests) {
|
|
60
|
+
// Extract runId if available
|
|
61
|
+
if (logEntry.runId && !runId) {
|
|
62
|
+
runId = logEntry.runId;
|
|
63
|
+
}
|
|
59
64
|
// Process each test in the batch
|
|
60
65
|
for (const test of logEntry.tests) {
|
|
61
66
|
if (test.rid) {
|
|
@@ -94,6 +99,10 @@ class Replay {
|
|
|
94
99
|
}
|
|
95
100
|
}
|
|
96
101
|
else if (logEntry.action === 'addTest' && logEntry.testId) {
|
|
102
|
+
// Extract runId if available
|
|
103
|
+
if (logEntry.runId && !runId) {
|
|
104
|
+
runId = logEntry.runId;
|
|
105
|
+
}
|
|
97
106
|
const test = logEntry.testId;
|
|
98
107
|
if (test.rid) {
|
|
99
108
|
// Handle tests with rid (deduplicate)
|
|
@@ -135,7 +144,8 @@ class Replay {
|
|
|
135
144
|
tests: allTests,
|
|
136
145
|
envVars,
|
|
137
146
|
parseErrors,
|
|
138
|
-
totalLines: lines.length
|
|
147
|
+
totalLines: lines.length,
|
|
148
|
+
runId
|
|
139
149
|
};
|
|
140
150
|
}
|
|
141
151
|
/**
|
|
@@ -165,7 +175,7 @@ class Replay {
|
|
|
165
175
|
this.onLog(`Replaying data from debug file: ${debugFile}`);
|
|
166
176
|
// Parse the debug file
|
|
167
177
|
const debugData = this.parseDebugFile(debugFile);
|
|
168
|
-
const { runParams, finishParams, tests, envVars } = debugData;
|
|
178
|
+
const { runParams, finishParams, tests, envVars, runId } = debugData;
|
|
169
179
|
this.onLog(`Found ${tests.length} tests to replay`);
|
|
170
180
|
if (tests.length === 0) {
|
|
171
181
|
throw new Error('No test data found in debug file');
|
|
@@ -179,6 +189,7 @@ class Replay {
|
|
|
179
189
|
runParams,
|
|
180
190
|
finishParams,
|
|
181
191
|
envVars,
|
|
192
|
+
runId,
|
|
182
193
|
dryRun: true
|
|
183
194
|
};
|
|
184
195
|
}
|
|
@@ -188,8 +199,15 @@ class Replay {
|
|
|
188
199
|
isBatchEnabled: true,
|
|
189
200
|
...runParams,
|
|
190
201
|
});
|
|
191
|
-
|
|
192
|
-
|
|
202
|
+
// Use the stored runId if available, otherwise create a new run
|
|
203
|
+
if (runId) {
|
|
204
|
+
this.onLog(`Using existing run ID: ${runId}`);
|
|
205
|
+
client.runId = runId;
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
this.onLog('Publishing to run...');
|
|
209
|
+
await client.createRun(runParams);
|
|
210
|
+
}
|
|
193
211
|
// Send each test result
|
|
194
212
|
let successCount = 0;
|
|
195
213
|
let failureCount = 0;
|
|
@@ -225,7 +243,7 @@ class Replay {
|
|
|
225
243
|
runParams,
|
|
226
244
|
finishParams,
|
|
227
245
|
envVars,
|
|
228
|
-
runId: client.runId
|
|
246
|
+
runId: runId || client.runId
|
|
229
247
|
};
|
|
230
248
|
this.onLog(`Successfully replayed ${successCount}/${tests.length} tests from debug file`);
|
|
231
249
|
return result;
|
package/package.json
CHANGED
package/src/client.js
CHANGED
|
@@ -155,6 +155,11 @@ class Client {
|
|
|
155
155
|
suite_title: 'Unknown suite',
|
|
156
156
|
};
|
|
157
157
|
|
|
158
|
+
// Add timestamp if not already present (microseconds since Unix epoch)
|
|
159
|
+
if (!testData.timestamp && !process.env.TESTOMATIO_NO_TIMESTAMP) {
|
|
160
|
+
testData.timestamp = Math.floor((performance.timeOrigin + performance.now()) * 1000);
|
|
161
|
+
}
|
|
162
|
+
|
|
158
163
|
/**
|
|
159
164
|
* @type {TestData}
|
|
160
165
|
*/
|
|
@@ -172,6 +177,7 @@ class Client {
|
|
|
172
177
|
suite_title,
|
|
173
178
|
suite_id,
|
|
174
179
|
test_id,
|
|
180
|
+
timestamp,
|
|
175
181
|
manuallyAttachedArtifacts,
|
|
176
182
|
} = testData;
|
|
177
183
|
let { message = '', meta = {} } = testData;
|
|
@@ -264,6 +270,7 @@ class Client {
|
|
|
264
270
|
test_id,
|
|
265
271
|
message,
|
|
266
272
|
run_time: typeof time === 'number' ? time : parseFloat(time),
|
|
273
|
+
timestamp,
|
|
267
274
|
artifacts,
|
|
268
275
|
meta,
|
|
269
276
|
...(rootSuiteId && { root_suite_id: rootSuiteId }),
|
package/src/pipe/debug.js
CHANGED
|
@@ -89,7 +89,11 @@ export class DebugPipe {
|
|
|
89
89
|
async addTest(data) {
|
|
90
90
|
if (!this.isEnabled) return;
|
|
91
91
|
|
|
92
|
-
if (!this.batch.isEnabled)
|
|
92
|
+
if (!this.batch.isEnabled) {
|
|
93
|
+
const logData = { action: 'addTest', testId: data };
|
|
94
|
+
if (this.store.runId) logData.runId = this.store.runId;
|
|
95
|
+
this.logToFile(logData);
|
|
96
|
+
}
|
|
93
97
|
else this.batch.tests.push(data);
|
|
94
98
|
|
|
95
99
|
if (!this.batch.intervalFunction) await this.batchUpload();
|
|
@@ -102,7 +106,9 @@ export class DebugPipe {
|
|
|
102
106
|
|
|
103
107
|
const testsToSend = this.batch.tests.splice(0);
|
|
104
108
|
|
|
105
|
-
|
|
109
|
+
const logData = { action: 'addTestsBatch', tests: testsToSend };
|
|
110
|
+
if (this.store.runId) logData.runId = this.store.runId;
|
|
111
|
+
this.logToFile(logData);
|
|
106
112
|
}
|
|
107
113
|
|
|
108
114
|
async finishRun(params) {
|
package/src/replay.js
CHANGED
|
@@ -45,6 +45,7 @@ export class Replay {
|
|
|
45
45
|
const testsMap = new Map(); // Use Map to deduplicate by rid
|
|
46
46
|
const testsWithoutRid = []; // For tests without rid (backward compatibility)
|
|
47
47
|
const envVars = {};
|
|
48
|
+
let runId = null;
|
|
48
49
|
|
|
49
50
|
// Parse debug file line by line
|
|
50
51
|
for (const [lineIndex, line] of lines.entries()) {
|
|
@@ -56,6 +57,10 @@ export class Replay {
|
|
|
56
57
|
} else if (logEntry.action === 'createRun') {
|
|
57
58
|
runParams = logEntry.params || {};
|
|
58
59
|
} else if (logEntry.action === 'addTestsBatch' && logEntry.tests) {
|
|
60
|
+
// Extract runId if available
|
|
61
|
+
if (logEntry.runId && !runId) {
|
|
62
|
+
runId = logEntry.runId;
|
|
63
|
+
}
|
|
59
64
|
// Process each test in the batch
|
|
60
65
|
for (const test of logEntry.tests) {
|
|
61
66
|
if (test.rid) {
|
|
@@ -89,6 +94,10 @@ export class Replay {
|
|
|
89
94
|
}
|
|
90
95
|
}
|
|
91
96
|
} else if (logEntry.action === 'addTest' && logEntry.testId) {
|
|
97
|
+
// Extract runId if available
|
|
98
|
+
if (logEntry.runId && !runId) {
|
|
99
|
+
runId = logEntry.runId;
|
|
100
|
+
}
|
|
92
101
|
const test = logEntry.testId;
|
|
93
102
|
if (test.rid) {
|
|
94
103
|
// Handle tests with rid (deduplicate)
|
|
@@ -129,7 +138,8 @@ export class Replay {
|
|
|
129
138
|
tests: allTests,
|
|
130
139
|
envVars,
|
|
131
140
|
parseErrors,
|
|
132
|
-
totalLines: lines.length
|
|
141
|
+
totalLines: lines.length,
|
|
142
|
+
runId
|
|
133
143
|
};
|
|
134
144
|
}
|
|
135
145
|
|
|
@@ -164,7 +174,7 @@ export class Replay {
|
|
|
164
174
|
|
|
165
175
|
// Parse the debug file
|
|
166
176
|
const debugData = this.parseDebugFile(debugFile);
|
|
167
|
-
const { runParams, finishParams, tests, envVars } = debugData;
|
|
177
|
+
const { runParams, finishParams, tests, envVars, runId } = debugData;
|
|
168
178
|
|
|
169
179
|
this.onLog(`Found ${tests.length} tests to replay`);
|
|
170
180
|
|
|
@@ -182,6 +192,7 @@ export class Replay {
|
|
|
182
192
|
runParams,
|
|
183
193
|
finishParams,
|
|
184
194
|
envVars,
|
|
195
|
+
runId,
|
|
185
196
|
dryRun: true
|
|
186
197
|
};
|
|
187
198
|
}
|
|
@@ -193,8 +204,14 @@ export class Replay {
|
|
|
193
204
|
...runParams,
|
|
194
205
|
});
|
|
195
206
|
|
|
196
|
-
|
|
197
|
-
|
|
207
|
+
// Use the stored runId if available, otherwise create a new run
|
|
208
|
+
if (runId) {
|
|
209
|
+
this.onLog(`Using existing run ID: ${runId}`);
|
|
210
|
+
client.runId = runId;
|
|
211
|
+
} else {
|
|
212
|
+
this.onLog('Publishing to run...');
|
|
213
|
+
await client.createRun(runParams);
|
|
214
|
+
}
|
|
198
215
|
|
|
199
216
|
// Send each test result
|
|
200
217
|
let successCount = 0;
|
|
@@ -233,7 +250,7 @@ export class Replay {
|
|
|
233
250
|
runParams,
|
|
234
251
|
finishParams,
|
|
235
252
|
envVars,
|
|
236
|
-
runId: client.runId
|
|
253
|
+
runId: runId || client.runId
|
|
237
254
|
};
|
|
238
255
|
|
|
239
256
|
this.onLog(`Successfully replayed ${successCount}/${tests.length} tests from debug file`);
|