@testomatio/reporter 2.3.1-beta.1-dependency → 2.3.2-beta.3-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,
23
+ isEnabled: params?.isBatchEnabled ?? !process.env.TESTOMATIO_DISABLE_BATCH_UPLOAD ?? 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;
@@ -186,7 +186,7 @@ class TestomatioPipe {
186
186
  method: 'PUT',
187
187
  url: `/api/reporter/${this.runId}`,
188
188
  data: runParams,
189
- responseType: 'json',
189
+ responseType: 'json'
190
190
  });
191
191
  if (resp.data.artifacts) setS3Credentials(resp.data.artifacts);
192
192
  return;
@@ -199,7 +199,7 @@ class TestomatioPipe {
199
199
  url: '/api/reporter',
200
200
  data: runParams,
201
201
  maxContentLength: Infinity,
202
- responseType: 'json',
202
+ responseType: 'json'
203
203
  });
204
204
 
205
205
  this.runId = resp.data.uid;
@@ -263,42 +263,40 @@ class TestomatioPipe {
263
263
 
264
264
  debug('Adding test', json);
265
265
 
266
- return this.client
267
- .request({
268
- method: 'POST',
269
- url: `/api/reporter/${this.runId}/testrun`,
270
- data: json,
271
- headers: {
272
- 'Content-Type': 'application/json',
273
- },
274
- maxContentLength: Infinity,
275
- })
276
- .catch(err => {
277
- this.requestFailures++;
278
- this.notReportedTestsCount++;
279
- if (err.response) {
280
- if (err.response.status >= 400) {
281
- const responseData = err.response.data || { message: '' };
282
- console.log(
283
- APP_PREFIX,
284
- pc.yellow(`Warning: ${responseData.message} (${err.response.status})`),
285
- pc.gray(data?.title || ''),
286
- );
287
- if (err.response?.data?.message?.includes('could not be matched')) {
288
- this.hasUnmatchedTests = true;
289
- }
290
- return;
291
- }
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: '' };
292
280
  console.log(
293
281
  APP_PREFIX,
294
- pc.yellow(`Warning: ${data?.title || ''} (${err.response?.status})`),
295
- `Report couldn't be processed: ${err?.response?.data?.message}`,
282
+ pc.yellow(`Warning: ${responseData.message} (${err.response.status})`),
283
+ pc.gray(data?.title || ''),
296
284
  );
297
- printCreateIssue(err);
298
- } else {
299
- console.log(APP_PREFIX, pc.blue(data?.title || ''), "Report couldn't be processed", err);
285
+ if (err.response?.data?.message?.includes('could not be matched')) {
286
+ this.hasUnmatchedTests = true;
287
+ }
288
+ return;
300
289
  }
301
- });
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
+ });
302
300
  };
303
301
 
304
302
  /**
@@ -325,42 +323,43 @@ class TestomatioPipe {
325
323
  const testsToSend = this.batch.tests.splice(0);
326
324
  debug('📨 Batch upload', testsToSend.length, 'tests');
327
325
 
328
- return this.client
329
- .request({
330
- method: 'POST',
331
- url: `/api/reporter/${this.runId}/testrun`,
332
- data: {
333
- api_key: this.apiKey,
334
- tests: testsToSend,
335
- batch_index: this.batch.batchIndex,
336
- },
337
- headers: {
338
- 'Content-Type': 'application/json',
339
- },
340
- maxContentLength: Infinity,
341
- })
342
- .catch(err => {
343
- this.requestFailures++;
344
- this.notReportedTestsCount += testsToSend.length;
345
- if (err.response) {
346
- if (err.response.status >= 400) {
347
- const responseData = err.response.data || { message: '' };
348
- console.log(APP_PREFIX, pc.yellow(`Warning: ${responseData.message} (${err.response.status})`));
349
- if (err.response?.data?.message?.includes('could not be matched')) {
350
- this.hasUnmatchedTests = true;
351
- }
352
- return;
353
- }
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: '' };
354
344
  console.log(
355
345
  APP_PREFIX,
356
- pc.yellow(`Warning: (${err.response?.status})`),
357
- `Report couldn't be processed: ${err?.response?.data?.message}`,
346
+ pc.yellow(`Warning: ${responseData.message} (${err.response.status})`),
358
347
  );
359
- printCreateIssue(err);
360
- } else {
361
- console.log(APP_PREFIX, "Report couldn't be processed", err);
348
+ if (err.response?.data?.message?.includes('could not be matched')) {
349
+ this.hasUnmatchedTests = true;
350
+ }
351
+ return;
362
352
  }
363
- });
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
+ });
364
363
  };
365
364
 
366
365
  /**
@@ -386,9 +385,9 @@ class TestomatioPipe {
386
385
  else this.batch.tests.push(data);
387
386
 
388
387
  // if test is added after run which is already finished
389
- if (!this.batch.intervalFunction) uploading = this.#batchUpload();
388
+ if (!this.batch.intervalFunction) uploading = this.#batchUpload();
390
389
 
391
- // return promise to be able to wait for it
390
+ // return promise to be able to wait for it
392
391
  return uploading;
393
392
  }
394
393
 
@@ -437,7 +436,7 @@ class TestomatioPipe {
437
436
  status_event,
438
437
  detach: params.detach,
439
438
  tests: params.tests,
440
- },
439
+ }
441
440
  });
442
441
  if (this.runUrl) {
443
442
  console.log(APP_PREFIX, '📊 Report Saved. Report URL:', pc.magenta(this.runUrl));
@@ -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
  }
@@ -361,7 +391,7 @@ function readLatestRunId() {
361
391
  try {
362
392
  const filePath = path.join(os.tmpdir(), `testomatio.latest.run`);
363
393
  if (!fs.existsSync(filePath)) return null;
364
-
394
+
365
395
  const stats = fs.statSync(filePath);
366
396
  const diff = +new Date() - +stats.mtime;
367
397
  const diffHours = diff / 1000 / 60 / 60;