@testomatio/reporter 2.3.3 → 2.3.5-beta-5-xml-import

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.
@@ -20,7 +20,7 @@ if (process.env.TESTOMATIO_RUN) process.env.runId = process.env.TESTOMATIO_RUN;
20
20
  class TestomatioPipe {
21
21
  constructor(params, store) {
22
22
  this.batch = {
23
- isEnabled: params?.isBatchEnabled ?? !process.env.TESTOMATIO_DISABLE_BATCH_UPLOAD ?? true,
23
+ isEnabled: params?.isBatchEnabled ?? (process.env.TESTOMATIO_DISABLE_BATCH_UPLOAD ? false : true),
24
24
  intervalFunction: null, // will be created in createRun by setInterval function
25
25
  intervalTime: 5000, // how often tests are sent
26
26
  tests: [], // array of tests in batch
@@ -60,8 +60,8 @@ class TestomatioPipe {
60
60
  retryConfig: {
61
61
  retry: REPORTER_REQUEST_RETRIES.retriesPerRequest,
62
62
  retryDelay: REPORTER_REQUEST_RETRIES.retryTimeout,
63
- httpMethodsToRetry: ['GET','PUT','HEAD','OPTIONS','DELETE','POST'],
64
- shouldRetry: (error) => {
63
+ httpMethodsToRetry: ['GET', 'PUT', 'HEAD', 'OPTIONS', 'DELETE', 'POST'],
64
+ shouldRetry: error => {
65
65
  if (!error.response) return false;
66
66
  switch (error.response?.status) {
67
67
  case 400: // Bad request (probably wrong API key)
@@ -73,8 +73,8 @@ class TestomatioPipe {
73
73
  break;
74
74
  }
75
75
  return error.response?.status >= 401; // Retry on 401+ and 5xx
76
- }
77
- }
76
+ },
77
+ },
78
78
  });
79
79
 
80
80
  this.isEnabled = true;
@@ -92,6 +92,33 @@ class TestomatioPipe {
92
92
  }
93
93
  }
94
94
 
95
+ /**
96
+ * Prepares data for sending to Testomat.io.
97
+ * @param {*} data - The data to be formatted.
98
+ * @returns
99
+ */
100
+ #formatData(data) {
101
+ data.api_key = this.apiKey;
102
+ data.create = this.createNewTests;
103
+
104
+ // add test ID + run ID
105
+ if (data.rid) data.rid = `${this.runId}-${data.rid}`;
106
+
107
+ if (!process.env.TESTOMATIO_STACK_PASSED && data.status === STATUS.PASSED) {
108
+ data.stack = null;
109
+ }
110
+
111
+ if (!process.env.TESTOMATIO_STEPS_PASSED && data.status === STATUS.PASSED) {
112
+ data.steps = null;
113
+ }
114
+
115
+ if (process.env.TESTOMATIO_NO_STEPS) {
116
+ data.steps = null;
117
+ }
118
+
119
+ return data;
120
+ }
121
+
95
122
  /**
96
123
  * Asynchronously prepares and retrieves the Testomat.io test grepList based on the provided options.
97
124
  * @param {Object} opts - The options for preparing the test grepList.
@@ -186,7 +213,7 @@ class TestomatioPipe {
186
213
  method: 'PUT',
187
214
  url: `/api/reporter/${this.runId}`,
188
215
  data: runParams,
189
- responseType: 'json'
216
+ responseType: 'json',
190
217
  });
191
218
  if (resp.data.artifacts) setS3Credentials(resp.data.artifacts);
192
219
  return;
@@ -199,7 +226,7 @@ class TestomatioPipe {
199
226
  url: '/api/reporter',
200
227
  data: runParams,
201
228
  maxContentLength: Infinity,
202
- responseType: 'json'
229
+ responseType: 'json',
203
230
  });
204
231
 
205
232
  this.runId = resp.data.uid;
@@ -252,51 +279,48 @@ class TestomatioPipe {
252
279
  if (!this.runId) return;
253
280
  if (this.#cancelTestReportingInCaseOfTooManyReqFailures()) return;
254
281
 
255
- data.api_key = this.apiKey;
256
- data.create = this.createNewTests;
257
-
258
- if (!process.env.TESTOMATIO_STACK_PASSED && data.status === STATUS.PASSED) {
259
- data.stack = null;
260
- }
282
+ this.#formatData(data);
261
283
 
262
284
  const json = JsonCycle.stringify(data);
263
285
 
264
286
  debug('Adding test', json);
265
287
 
266
- return this.client.request({
267
- method: 'POST',
268
- url: `/api/reporter/${this.runId}/testrun`,
269
- data: json,
270
- headers: {
271
- 'Content-Type': 'application/json',
272
- },
273
- maxContentLength: Infinity
274
- }).catch(err => {
275
- this.requestFailures++;
276
- this.notReportedTestsCount++;
277
- if (err.response) {
278
- if (err.response.status >= 400) {
279
- const responseData = err.response.data || { message: '' };
288
+ return this.client
289
+ .request({
290
+ method: 'POST',
291
+ url: `/api/reporter/${this.runId}/testrun`,
292
+ data: json,
293
+ headers: {
294
+ 'Content-Type': 'application/json',
295
+ },
296
+ maxContentLength: Infinity,
297
+ })
298
+ .catch(err => {
299
+ this.requestFailures++;
300
+ this.notReportedTestsCount++;
301
+ if (err.response) {
302
+ if (err.response.status >= 400) {
303
+ const responseData = err.response.data || { message: '' };
304
+ console.log(
305
+ APP_PREFIX,
306
+ pc.yellow(`Warning: ${responseData.message} (${err.response.status})`),
307
+ pc.gray(data?.title || ''),
308
+ );
309
+ if (err.response?.data?.message?.includes('could not be matched')) {
310
+ this.hasUnmatchedTests = true;
311
+ }
312
+ return;
313
+ }
280
314
  console.log(
281
315
  APP_PREFIX,
282
- pc.yellow(`Warning: ${responseData.message} (${err.response.status})`),
283
- pc.gray(data?.title || ''),
316
+ pc.yellow(`Warning: ${data?.title || ''} (${err.response?.status})`),
317
+ `Report couldn't be processed: ${err?.response?.data?.message}`,
284
318
  );
285
- if (err.response?.data?.message?.includes('could not be matched')) {
286
- this.hasUnmatchedTests = true;
287
- }
288
- return;
319
+ printCreateIssue(err);
320
+ } else {
321
+ console.log(APP_PREFIX, pc.blue(data?.title || ''), "Report couldn't be processed", err);
289
322
  }
290
- console.log(
291
- APP_PREFIX,
292
- pc.yellow(`Warning: ${data?.title || ''} (${err.response?.status})`),
293
- `Report couldn't be processed: ${err?.response?.data?.message}`,
294
- );
295
- printCreateIssue(err);
296
- } else {
297
- console.log(APP_PREFIX, pc.blue(data?.title || ''), "Report couldn't be processed", err);
298
- }
299
- });
323
+ });
300
324
  };
301
325
 
302
326
  /**
@@ -323,43 +347,42 @@ class TestomatioPipe {
323
347
  const testsToSend = this.batch.tests.splice(0);
324
348
  debug('📨 Batch upload', testsToSend.length, 'tests');
325
349
 
326
- return this.client.request({
327
- method: 'POST',
328
- url: `/api/reporter/${this.runId}/testrun`,
329
- data: {
330
- api_key: this.apiKey,
331
- tests: testsToSend,
332
- batch_index: this.batch.batchIndex
333
- },
334
- headers: {
335
- 'Content-Type': 'application/json',
336
- },
337
- maxContentLength: Infinity
338
- }).catch(err => {
339
- this.requestFailures++;
340
- this.notReportedTestsCount += testsToSend.length;
341
- if (err.response) {
342
- if (err.response.status >= 400) {
343
- const responseData = err.response.data || { message: '' };
350
+ return this.client
351
+ .request({
352
+ method: 'POST',
353
+ url: `/api/reporter/${this.runId}/testrun`,
354
+ data: {
355
+ api_key: this.apiKey,
356
+ tests: testsToSend,
357
+ batch_index: this.batch.batchIndex,
358
+ },
359
+ headers: {
360
+ 'Content-Type': 'application/json',
361
+ },
362
+ maxContentLength: Infinity,
363
+ })
364
+ .catch(err => {
365
+ this.requestFailures++;
366
+ this.notReportedTestsCount += testsToSend.length;
367
+ if (err.response) {
368
+ if (err.response.status >= 400) {
369
+ const responseData = err.response.data || { message: '' };
370
+ console.log(APP_PREFIX, pc.yellow(`Warning: ${responseData.message} (${err.response.status})`));
371
+ if (err.response?.data?.message?.includes('could not be matched')) {
372
+ this.hasUnmatchedTests = true;
373
+ }
374
+ return;
375
+ }
344
376
  console.log(
345
377
  APP_PREFIX,
346
- pc.yellow(`Warning: ${responseData.message} (${err.response.status})`),
378
+ pc.yellow(`Warning: (${err.response?.status})`),
379
+ `Report couldn't be processed: ${err?.response?.data?.message}`,
347
380
  );
348
- if (err.response?.data?.message?.includes('could not be matched')) {
349
- this.hasUnmatchedTests = true;
350
- }
351
- return;
381
+ printCreateIssue(err);
382
+ } else {
383
+ console.log(APP_PREFIX, "Report couldn't be processed", err);
352
384
  }
353
- console.log(
354
- APP_PREFIX,
355
- pc.yellow(`Warning: (${err.response?.status})`),
356
- `Report couldn't be processed: ${err?.response?.data?.message}`,
357
- );
358
- printCreateIssue(err);
359
- } else {
360
- console.log(APP_PREFIX, "Report couldn't be processed", err);
361
- }
362
- });
385
+ });
363
386
  };
364
387
 
365
388
  /**
@@ -375,19 +398,16 @@ class TestomatioPipe {
375
398
  return;
376
399
  }
377
400
 
378
- // add test ID + run ID
379
- if (data.rid) data.rid = `${this.runId}-${data.rid}`;
380
- data.api_key = this.apiKey;
381
- data.create = this.createNewTests;
401
+ this.#formatData(data);
382
402
 
383
403
  let uploading = null;
384
404
  if (!this.batch.isEnabled) uploading = this.#uploadSingleTest(data);
385
405
  else this.batch.tests.push(data);
386
406
 
387
407
  // if test is added after run which is already finished
388
- if (!this.batch.intervalFunction) uploading = this.#batchUpload();
408
+ if (!this.batch.intervalFunction) uploading = this.#batchUpload();
389
409
 
390
- // return promise to be able to wait for it
410
+ // return promise to be able to wait for it
391
411
  return uploading;
392
412
  }
393
413
 
@@ -436,7 +456,7 @@ class TestomatioPipe {
436
456
  status_event,
437
457
  detach: params.detach,
438
458
  tests: params.tests,
439
- }
459
+ },
440
460
  });
441
461
 
442
462
  console.log(APP_PREFIX, '✅ Testrun finished');
@@ -139,6 +139,8 @@ export const TEST_ID_REGEX = /@T([\w\d]{8})/;
139
139
  export const SUITE_ID_REGEX = /@S([\w\d]{8})/;
140
140
 
141
141
  const fetchIdFromCode = (code, opts = {}) => {
142
+ if (!code) return null;
143
+
142
144
  const comments = code
143
145
  .split('\n')
144
146
  .map(l => l.trim())
@@ -180,8 +182,32 @@ const fetchSourceCode = (contents, opts = {}) => {
180
182
  if (lineIndex === -1) lineIndex = lines.findIndex(l => l.includes(`public void ${title}`));
181
183
  if (lineIndex === -1) lineIndex = lines.findIndex(l => l.includes(`${title}(`));
182
184
  } else if (opts.lang === 'csharp') {
183
- if (lineIndex === -1) lineIndex = lines.findIndex(l => l.includes(`public void ${title}`));
184
- if (lineIndex === -1) lineIndex = lines.findIndex(l => l.includes(`${title}(`));
185
+ // Enhanced C# method detection for NUnit tests
186
+ lineIndex = lines.findIndex(l => l.includes(`public void ${title}(`));
187
+
188
+ if (lineIndex === -1) {
189
+ lineIndex = lines.findIndex(l => l.includes(`public async Task ${title}(`));
190
+ }
191
+
192
+ if (lineIndex === -1) {
193
+ lineIndex = lines.findIndex(l => l.includes(`${title}(`));
194
+ }
195
+
196
+ // Look for TestCase or Test attributes above the method
197
+ if (lineIndex === -1) {
198
+ const testAttributeIndex = lines.findIndex((l, index) => {
199
+ if (l.includes('[TestCase') || l.includes('[Test')) {
200
+ // Check next few lines for the method
201
+ const nextLines = lines.slice(index, Math.min(lines.length, index + 5));
202
+ const hasMethod = nextLines.some(nextLine => nextLine.includes(`${title}(`));
203
+ return hasMethod;
204
+ }
205
+ return false;
206
+ });
207
+ if (testAttributeIndex !== -1) {
208
+ lineIndex = testAttributeIndex;
209
+ }
210
+ }
185
211
  } else {
186
212
  lineIndex = lines.findIndex(l => l.includes(title));
187
213
  }
@@ -191,7 +217,7 @@ const fetchSourceCode = (contents, opts = {}) => {
191
217
  lineIndex -= opts.prepend;
192
218
  }
193
219
 
194
- if (lineIndex) {
220
+ if (lineIndex !== -1 && lineIndex !== undefined) {
195
221
  const result = [];
196
222
  for (let i = lineIndex; i < lineIndex + limit; i++) {
197
223
  if (lines[i] === undefined) continue;
@@ -216,6 +242,10 @@ const fetchSourceCode = (contents, opts = {}) => {
216
242
  if (opts.lang === 'java' && lines[i].trim().match(/^@\w+/)) break;
217
243
  if (opts.lang === 'java' && lines[i].includes(' public void ')) break;
218
244
  if (opts.lang === 'java' && lines[i].includes(' class ')) break;
245
+ if (opts.lang === 'csharp' && lines[i].trim().match(/^\[Test/)) break;
246
+ if (opts.lang === 'csharp' && lines[i].includes(' public void ')) break;
247
+ if (opts.lang === 'csharp' && lines[i].includes(' public async Task ')) break;
248
+ if (opts.lang === 'csharp' && lines[i].includes(' class ') && lines[i].includes('public')) break;
219
249
  }
220
250
  result.push(lines[i]);
221
251
  }