@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.
@@ -1,6 +1,6 @@
1
1
  export const dataStorage: DataStorage;
2
2
  declare class DataStorage {
3
- static #instance: any;
3
+ static "__#12@#instance": any;
4
4
  /**
5
5
  *
6
6
  * @returns {DataStorage}
@@ -1,5 +1,4 @@
1
1
  export default CSharpAdapter;
2
2
  declare class CSharpAdapter extends Adapter {
3
- getFilePath(t: any): string;
4
3
  }
5
4
  import Adapter from './adapter.js';
@@ -7,24 +7,53 @@ const path_1 = __importDefault(require("path"));
7
7
  const adapter_js_1 = __importDefault(require("./adapter.js"));
8
8
  class CSharpAdapter extends adapter_js_1.default {
9
9
  formatTest(t) {
10
- const title = t.title.replace(/\(.*?\)/, '').trim();
11
- const example = t.title.match(/\((.*?)\)/);
12
- if (example)
13
- t.example = { ...example[1].split(',') };
10
+ // Don't override example if it already exists from NUnit XML processing
11
+ // The xmlReader.js already extracts parameters correctly from <arguments>
12
+ if (!t.example) {
13
+ const title = t.title.replace(/\(.*?\)/, '').trim();
14
+ const exampleMatch = t.title.match(/\((.*?)\)/);
15
+ if (exampleMatch) {
16
+ // Keep as array for consistency with NUnit XML processing
17
+ t.example = exampleMatch[1].split(',').map(param => param.trim());
18
+ }
19
+ t.title = title.trim();
20
+ }
14
21
  const suite = t.suite_title.split('.');
15
22
  t.suite_title = suite.pop();
16
23
  t.file = namespaceToFileName(t.file);
17
- t.title = title.trim();
18
24
  return t;
19
25
  }
20
26
  getFilePath(t) {
21
- const fileName = namespaceToFileName(t.file);
27
+ if (!t.file)
28
+ return null;
29
+ // Normalize path separators for cross-platform compatibility
30
+ let filePath = t.file.replace(/\\/g, '/');
31
+ // If file already has .cs extension, use it directly
32
+ if (filePath.endsWith('.cs')) {
33
+ // Make relative path if it's absolute
34
+ if (path_1.default.isAbsolute(filePath)) {
35
+ // Try to find project-relative path
36
+ const cwd = process.cwd().replace(/\\/g, '/');
37
+ if (filePath.startsWith(cwd)) {
38
+ filePath = path_1.default.relative(cwd, filePath).replace(/\\/g, '/');
39
+ }
40
+ }
41
+ return filePath;
42
+ }
43
+ // Convert namespace path to file path
44
+ const fileName = namespaceToFileName(filePath);
22
45
  return fileName;
23
46
  }
24
47
  }
25
48
  module.exports = CSharpAdapter;
26
49
  function namespaceToFileName(fileName) {
50
+ if (!fileName)
51
+ return '';
52
+ // If already a .cs file path, clean it up
53
+ if (fileName.endsWith('.cs')) {
54
+ return fileName.replace(/\\/g, '/');
55
+ }
27
56
  const fileParts = fileName.split('.');
28
57
  fileParts[fileParts.length - 1] = fileParts[fileParts.length - 1]?.replace(/\$.*/, '');
29
- return `${fileParts.join(path_1.default.sep)}.cs`;
58
+ return `${fileParts.join('/')}.cs`;
30
59
  }
package/lib/pipe/debug.js CHANGED
@@ -18,7 +18,7 @@ class DebugPipe {
18
18
  this.isEnabled = !!process.env.TESTOMATIO_DEBUG || !!process.env.DEBUG;
19
19
  if (this.isEnabled) {
20
20
  this.batch = {
21
- isEnabled: this.params.isBatchEnabled ?? !process.env.TESTOMATIO_DISABLE_BATCH_UPLOAD,
21
+ isEnabled: this.params.isBatchEnabled ?? !process.env.TESTOMATIO_DISABLE_BATCH_UPLOAD ?? true,
22
22
  intervalFunction: null,
23
23
  intervalTime: 5000,
24
24
  tests: [],
@@ -23,7 +23,7 @@ if (process.env.TESTOMATIO_RUN)
23
23
  class TestomatioPipe {
24
24
  constructor(params, store) {
25
25
  this.batch = {
26
- isEnabled: params?.isBatchEnabled ?? !process.env.TESTOMATIO_DISABLE_BATCH_UPLOAD,
26
+ isEnabled: params?.isBatchEnabled ?? !process.env.TESTOMATIO_DISABLE_BATCH_UPLOAD ?? true,
27
27
  intervalFunction: null, // will be created in createRun by setInterval function
28
28
  intervalTime: 5000, // how often tests are sent
29
29
  tests: [], // array of tests in batch
@@ -60,7 +60,7 @@ class TestomatioPipe {
60
60
  retry: constants_js_1.REPORTER_REQUEST_RETRIES.retriesPerRequest,
61
61
  retryDelay: constants_js_1.REPORTER_REQUEST_RETRIES.retryTimeout,
62
62
  httpMethodsToRetry: ['GET', 'PUT', 'HEAD', 'OPTIONS', 'DELETE', 'POST'],
63
- shouldRetry: error => {
63
+ shouldRetry: (error) => {
64
64
  if (!error.response)
65
65
  return false;
66
66
  switch (error.response?.status) {
@@ -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
  this.isEnabled = true;
80
80
  // do not finish this run (for parallel testing)
@@ -171,7 +171,7 @@ class TestomatioPipe {
171
171
  method: 'PUT',
172
172
  url: `/api/reporter/${this.runId}`,
173
173
  data: runParams,
174
- responseType: 'json',
174
+ responseType: 'json'
175
175
  });
176
176
  if (resp.data.artifacts)
177
177
  (0, pipe_utils_js_1.setS3Credentials)(resp.data.artifacts);
@@ -184,7 +184,7 @@ class TestomatioPipe {
184
184
  url: '/api/reporter',
185
185
  data: runParams,
186
186
  maxContentLength: Infinity,
187
- responseType: 'json',
187
+ responseType: 'json'
188
188
  });
189
189
  this.runId = resp.data.uid;
190
190
  this.runUrl = `${this.url}/${resp.data.url.split('/').splice(3).join('/')}`;
@@ -241,17 +241,15 @@ class TestomatioPipe {
241
241
  }
242
242
  const json = json_cycle_1.default.stringify(data);
243
243
  debug('Adding test', json);
244
- return this.client
245
- .request({
244
+ return this.client.request({
246
245
  method: 'POST',
247
246
  url: `/api/reporter/${this.runId}/testrun`,
248
247
  data: json,
249
248
  headers: {
250
249
  'Content-Type': 'application/json',
251
250
  },
252
- maxContentLength: Infinity,
253
- })
254
- .catch(err => {
251
+ maxContentLength: Infinity
252
+ }).catch(err => {
255
253
  this.requestFailures++;
256
254
  this.notReportedTestsCount++;
257
255
  if (err.response) {
@@ -296,21 +294,19 @@ class TestomatioPipe {
296
294
  // get tests from batch and clear batch
297
295
  const testsToSend = this.batch.tests.splice(0);
298
296
  debug('📨 Batch upload', testsToSend.length, 'tests');
299
- return this.client
300
- .request({
297
+ return this.client.request({
301
298
  method: 'POST',
302
299
  url: `/api/reporter/${this.runId}/testrun`,
303
300
  data: {
304
301
  api_key: this.apiKey,
305
302
  tests: testsToSend,
306
- batch_index: this.batch.batchIndex,
303
+ batch_index: this.batch.batchIndex
307
304
  },
308
305
  headers: {
309
306
  'Content-Type': 'application/json',
310
307
  },
311
- maxContentLength: Infinity,
312
- })
313
- .catch(err => {
308
+ maxContentLength: Infinity
309
+ }).catch(err => {
314
310
  this.requestFailures++;
315
311
  this.notReportedTestsCount += testsToSend.length;
316
312
  if (err.response) {
@@ -398,7 +394,7 @@ class TestomatioPipe {
398
394
  status_event,
399
395
  detach: params.detach,
400
396
  tests: params.tests,
401
- },
397
+ }
402
398
  });
403
399
  if (this.runUrl) {
404
400
  console.log(constants_js_1.APP_PREFIX, '📊 Report Saved. Report URL:', picocolors_1.default.magenta(this.runUrl));
package/lib/reporter.d.ts CHANGED
@@ -5,7 +5,7 @@ export const artifact: (data: string | {
5
5
  }, context?: any) => void;
6
6
  export const log: (...args: any[]) => void;
7
7
  export const logger: {
8
- #originalUserLogger: {
8
+ "__#13@#originalUserLogger": {
9
9
  assert(condition?: boolean, ...data: any[]): void;
10
10
  assert(value: any, message?: string, ...optionalParams: any[]): void;
11
11
  clear(): void;
@@ -50,13 +50,13 @@ export const logger: {
50
50
  profile(label?: string): void;
51
51
  profileEnd(label?: string): void;
52
52
  };
53
- #userLoggerWithOverridenMethods: any;
53
+ "__#13@#userLoggerWithOverridenMethods": any;
54
54
  logLevel: string;
55
55
  step(strings: any, ...values: any[]): void;
56
56
  getLogs(context: string): string[];
57
- #stringifyLogs(...args: any[]): string;
57
+ "__#13@#stringifyLogs"(...args: any[]): string;
58
58
  _templateLiteralLog(strings: any, ...args: any[]): void;
59
- #logWrapper(argsArray: any, level: any): void;
59
+ "__#13@#logWrapper"(argsArray: any, level: any): void;
60
60
  assert(...args: any[]): void;
61
61
  debug(...args: any[]): void;
62
62
  error(...args: any[]): void;
@@ -81,7 +81,7 @@ export const linkTest: (...testIds: string[]) => void;
81
81
  export const linkJira: (...jiraIds: string[]) => void;
82
82
  declare namespace _default {
83
83
  let testomatioLogger: {
84
- #originalUserLogger: {
84
+ "__#13@#originalUserLogger": {
85
85
  assert(condition?: boolean, ...data: any[]): void;
86
86
  assert(value: any, message?: string, ...optionalParams: any[]): void;
87
87
  clear(): void;
@@ -126,13 +126,13 @@ declare namespace _default {
126
126
  profile(label?: string): void;
127
127
  profileEnd(label?: string): void;
128
128
  };
129
- #userLoggerWithOverridenMethods: any;
129
+ "__#13@#userLoggerWithOverridenMethods": any;
130
130
  logLevel: string;
131
131
  step(strings: any, ...values: any[]): void;
132
132
  getLogs(context: string): string[];
133
- #stringifyLogs(...args: any[]): string;
133
+ "__#13@#stringifyLogs"(...args: any[]): string;
134
134
  _templateLiteralLog(strings: any, ...args: any[]): void;
135
- #logWrapper(argsArray: any, level: any): void;
135
+ "__#13@#logWrapper"(argsArray: any, level: any): void;
136
136
  assert(...args: any[]): void;
137
137
  debug(...args: any[]): void;
138
138
  error(...args: any[]): void;
@@ -155,7 +155,7 @@ declare namespace _default {
155
155
  }, context?: any) => void;
156
156
  let log: (...args: any[]) => void;
157
157
  let logger: {
158
- #originalUserLogger: {
158
+ "__#13@#originalUserLogger": {
159
159
  assert(condition?: boolean, ...data: any[]): void;
160
160
  assert(value: any, message?: string, ...optionalParams: any[]): void;
161
161
  clear(): void;
@@ -200,13 +200,13 @@ declare namespace _default {
200
200
  profile(label?: string): void;
201
201
  profileEnd(label?: string): void;
202
202
  };
203
- #userLoggerWithOverridenMethods: any;
203
+ "__#13@#userLoggerWithOverridenMethods": any;
204
204
  logLevel: string;
205
205
  step(strings: any, ...values: any[]): void;
206
206
  getLogs(context: string): string[];
207
- #stringifyLogs(...args: any[]): string;
207
+ "__#13@#stringifyLogs"(...args: any[]): string;
208
208
  _templateLiteralLog(strings: any, ...args: any[]): void;
209
- #logWrapper(argsArray: any, level: any): void;
209
+ "__#13@#logWrapper"(argsArray: any, level: any): void;
210
210
  assert(...args: any[]): void;
211
211
  debug(...args: any[]): void;
212
212
  error(...args: any[]): void;
@@ -3,7 +3,7 @@ export const artifactStorage: ArtifactStorage;
3
3
  * Artifact storage is supposed to store file paths
4
4
  */
5
5
  declare class ArtifactStorage {
6
- static #instance: any;
6
+ static "__#14@#instance": any;
7
7
  /**
8
8
  * Singleton
9
9
  * @returns {ArtifactStorage}
@@ -1,6 +1,6 @@
1
1
  export const keyValueStorage: KeyValueStorage;
2
2
  declare class KeyValueStorage {
3
- static #instance: any;
3
+ static "__#15@#instance": any;
4
4
  /**
5
5
  *
6
6
  * @returns {KeyValueStorage}
@@ -1,6 +1,6 @@
1
1
  export const linkStorage: LinkStorage;
2
2
  declare class LinkStorage {
3
- static #instance: any;
3
+ static "__#16@#instance": any;
4
4
  /**
5
5
  *
6
6
  * @returns {LinkStorage}
@@ -5,7 +5,7 @@ export const logger: Logger;
5
5
  * Supports different syntaxes to satisfy any user preferences.
6
6
  */
7
7
  declare class Logger {
8
- static #instance: any;
8
+ static "__#13@#instance": any;
9
9
  /**
10
10
  *
11
11
  * @returns {Logger}
@@ -172,6 +172,8 @@ exports.fetchSourceCodeFromStackTrace = fetchSourceCodeFromStackTrace;
172
172
  exports.TEST_ID_REGEX = /@T([\w\d]{8})/;
173
173
  exports.SUITE_ID_REGEX = /@S([\w\d]{8})/;
174
174
  const fetchIdFromCode = (code, opts = {}) => {
175
+ if (!code)
176
+ return null;
175
177
  const comments = code
176
178
  .split('\n')
177
179
  .map(l => l.trim())
@@ -214,10 +216,29 @@ const fetchSourceCode = (contents, opts = {}) => {
214
216
  lineIndex = lines.findIndex(l => l.includes(`${title}(`));
215
217
  }
216
218
  else if (opts.lang === 'csharp') {
217
- if (lineIndex === -1)
218
- lineIndex = lines.findIndex(l => l.includes(`public void ${title}`));
219
- if (lineIndex === -1)
219
+ // Enhanced C# method detection for NUnit tests
220
+ lineIndex = lines.findIndex(l => l.includes(`public void ${title}(`));
221
+ if (lineIndex === -1) {
222
+ lineIndex = lines.findIndex(l => l.includes(`public async Task ${title}(`));
223
+ }
224
+ if (lineIndex === -1) {
220
225
  lineIndex = lines.findIndex(l => l.includes(`${title}(`));
226
+ }
227
+ // Look for TestCase or Test attributes above the method
228
+ if (lineIndex === -1) {
229
+ const testAttributeIndex = lines.findIndex((l, index) => {
230
+ if (l.includes('[TestCase') || l.includes('[Test')) {
231
+ // Check next few lines for the method
232
+ const nextLines = lines.slice(index, Math.min(lines.length, index + 5));
233
+ const hasMethod = nextLines.some(nextLine => nextLine.includes(`${title}(`));
234
+ return hasMethod;
235
+ }
236
+ return false;
237
+ });
238
+ if (testAttributeIndex !== -1) {
239
+ lineIndex = testAttributeIndex;
240
+ }
241
+ }
221
242
  }
222
243
  else {
223
244
  lineIndex = lines.findIndex(l => l.includes(title));
@@ -226,7 +247,7 @@ const fetchSourceCode = (contents, opts = {}) => {
226
247
  if (opts.prepend) {
227
248
  lineIndex -= opts.prepend;
228
249
  }
229
- if (lineIndex) {
250
+ if (lineIndex !== -1 && lineIndex !== undefined) {
230
251
  const result = [];
231
252
  for (let i = lineIndex; i < lineIndex + limit; i++) {
232
253
  if (lines[i] === undefined)
@@ -269,6 +290,14 @@ const fetchSourceCode = (contents, opts = {}) => {
269
290
  break;
270
291
  if (opts.lang === 'java' && lines[i].includes(' class '))
271
292
  break;
293
+ if (opts.lang === 'csharp' && lines[i].trim().match(/^\[Test/))
294
+ break;
295
+ if (opts.lang === 'csharp' && lines[i].includes(' public void '))
296
+ break;
297
+ if (opts.lang === 'csharp' && lines[i].includes(' public async Task '))
298
+ break;
299
+ if (opts.lang === 'csharp' && lines[i].includes(' class ') && lines[i].includes('public'))
300
+ break;
272
301
  }
273
302
  result.push(lines[i]);
274
303
  }
@@ -46,7 +46,7 @@ declare class XmlReader {
46
46
  passed_count: number;
47
47
  skipped_count: number;
48
48
  status: string;
49
- tests: any[];
49
+ tests: any;
50
50
  tests_count: number;
51
51
  };
52
52
  processNUnit(jsonSuite: any): {
@@ -77,6 +77,13 @@ declare class XmlReader {
77
77
  skipped_count: number;
78
78
  tests: any[];
79
79
  };
80
+ deduplicateTestsByFQN(tests: any): any[];
81
+ generateFQN(test: any): string;
82
+ generateNormalizedFQN(test: any): string;
83
+ extractAssemblyName(test: any): any;
84
+ extractNamespace(test: any): any;
85
+ extractClassName(test: any): any;
86
+ extractCsFileFromPath(test: any): any;
80
87
  calculateStats(): {};
81
88
  fetchSourceCode(): void;
82
89
  formatTests(): void;