@testomatio/reporter 2.3.7 β†’ 2.3.8

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 CHANGED
@@ -13,7 +13,7 @@ Testomat.io Reporter (this npm package) supports:
13
13
  - πŸ”Ž [Stack traces](./docs/stacktrace.md) and error messages
14
14
  - πŸ™ [GitHub](./docs/pipes/github.md), [GitLab](./docs/pipes/gitlab.md) & [Bitbucket](./docs/pipes/bitbucket.md) integration
15
15
  - πŸš… Realtime reports
16
- - πŸ—ƒοΈ Other test frameworks supported via [JUNit XML](./docs/junit.md)
16
+ - πŸ—ƒοΈ Other test frameworks supported via [JUnit XML](./docs/junit.md) with [XML import configuration](./docs/xml-imports.md)
17
17
  - πŸšΆβ€β™€οΈ Steps _(work in progress)_
18
18
  - πŸ“„ [Logger](./docs/logger.md) _(work in progress, supports Jest for now)_
19
19
  - ☁️ Custom properties and metadata _(work in progress)_
@@ -129,6 +129,7 @@ Bring this reporter on CI and never lose test results again!
129
129
  - [CSV](./docs/pipes/csv.md)
130
130
  - [HTML report](./docs/pipes/html.md)
131
131
  - [Bitbucket](./docs/pipes/bitbucket.md)
132
+ - πŸ”— [Linking Tests](./docs/linking-tests.md)
132
133
  - πŸ““ [JUnit](./docs/junit.md)
133
134
  - πŸ—„οΈ [Artifacts](./docs/artifacts.md)
134
135
  - πŸ”‚ [Workflows](./docs/workflows.md)
package/lib/bin/cli.js CHANGED
@@ -37,12 +37,17 @@ program
37
37
  program
38
38
  .command('start')
39
39
  .description('Start a new run and return its ID')
40
- .action(async () => {
40
+ .option('--kind <type>', 'Specify run type: automated, manual, or mixed')
41
+ .action(async (opts) => {
41
42
  (0, utils_js_1.cleanLatestRunId)();
42
43
  console.log('Starting a new Run on Testomat.io...');
43
44
  const apiKey = process.env['INPUT_TESTOMATIO-KEY'] || config_js_1.config.TESTOMATIO;
44
45
  const client = new client_js_1.default({ apiKey });
45
- client.createRun().then(() => {
46
+ const createRunParams = {};
47
+ if (opts.kind) {
48
+ createRunParams.kind = opts.kind;
49
+ }
50
+ client.createRun(createRunParams).then(() => {
46
51
  console.log(process.env.runId);
47
52
  process.exit(0);
48
53
  });
@@ -70,6 +75,7 @@ program
70
75
  .description('Run tests with the specified command')
71
76
  .argument('<command>', 'Test runner command')
72
77
  .option('--filter <filter>', 'Additional execution filter')
78
+ .option('--kind <type>', 'Specify run type: automated, manual, or mixed')
73
79
  .action(async (command, opts) => {
74
80
  const apiKey = process.env['INPUT_TESTOMATIO-KEY'] || config_js_1.config.TESTOMATIO;
75
81
  const title = process.env.TESTOMATIO_TITLE;
@@ -108,8 +114,12 @@ program
108
114
  process.exit(code);
109
115
  });
110
116
  };
117
+ const createRunParams = {};
118
+ if (opts.kind) {
119
+ createRunParams.kind = opts.kind;
120
+ }
111
121
  if (apiKey) {
112
- await client.createRun().then(runTests);
122
+ await client.createRun(createRunParams).then(runTests);
113
123
  }
114
124
  else {
115
125
  await runTests();
@@ -145,7 +155,7 @@ program
145
155
  .option('--lang <lang>', 'Language used (python, ruby, java)')
146
156
  .option('--timelimit <time>', 'default time limit in seconds to kill a stuck process')
147
157
  .action(async (pattern, opts) => {
148
- if (!pattern.endsWith('.xml')) {
158
+ if (!pattern.endsWith('.xml') && !pattern.includes('*')) {
149
159
  pattern += '.xml';
150
160
  }
151
161
  let { javaTests, lang } = opts;
@@ -25,7 +25,7 @@ program
25
25
  .option('--timelimit <time>', 'default time limit in seconds to kill a stuck process')
26
26
  .option('--env-file <envfile>', 'Load environment variables from env file')
27
27
  .action(async (pattern, opts) => {
28
- if (!pattern.endsWith('.xml')) {
28
+ if (!pattern.endsWith('.xml') && !pattern.includes('*')) {
29
29
  pattern += '.xml';
30
30
  }
31
31
  let { javaTests, lang } = opts;
@@ -37,7 +37,10 @@ program
37
37
  lang = lang?.toLowerCase();
38
38
  if (javaTests === true || (lang === 'java' && !javaTests))
39
39
  javaTests = 'src/test/java';
40
- const runReader = new xmlReader_js_1.default({ javaTests, lang });
40
+ const runReader = new xmlReader_js_1.default({
41
+ javaTests,
42
+ lang,
43
+ });
41
44
  const files = glob_1.glob.sync(pattern, { cwd: opts.dir || process.cwd() });
42
45
  if (!files.length) {
43
46
  console.log(constants_js_1.APP_PREFIX, `Report can't be created. No XML files found πŸ˜₯`);
package/lib/client.d.ts CHANGED
@@ -44,7 +44,7 @@ export class Client {
44
44
  *
45
45
  * @returns {Promise<any>} - resolves to Run id which should be used to update / add test
46
46
  */
47
- createRun(params: any): Promise<any>;
47
+ createRun(params?: {}): Promise<any>;
48
48
  /**
49
49
  * Updates test status and its data
50
50
  *
package/lib/client.js CHANGED
@@ -131,7 +131,7 @@ class Client {
131
131
  *
132
132
  * @returns {Promise<any>} - resolves to Run id which should be used to update / add test
133
133
  */
134
- async createRun(params) {
134
+ async createRun(params = {}) {
135
135
  if (!this.pipes || !this.pipes.length)
136
136
  this.pipes = await (0, index_js_1.pipesFactory)(params || this.paramsForPipesFactory || {}, this.pipeStore);
137
137
  debug('Creating run...');
@@ -139,7 +139,7 @@ class Client {
139
139
  if (!this.pipes?.filter(p => p.isEnabled).length)
140
140
  return Promise.resolve();
141
141
  this.queue = this.queue
142
- .then(() => Promise.all(this.pipes.map(p => p.createRun())))
142
+ .then(() => Promise.all(this.pipes.map(p => p.createRun(params))))
143
143
  .catch(err => console.log(constants_js_1.APP_PREFIX, err))
144
144
  .then(() => {
145
145
  const runId = this.pipeStore?.runId;
@@ -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,57 @@ 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
+ // Extract example from title if not already present
11
+ if (!t.example) {
12
+ const exampleMatch = t.title.match(/\((.*?)\)/);
13
+ if (exampleMatch) {
14
+ // Extract parameters as object with numeric keys for API
15
+ const params = exampleMatch[1].split(',').map(param => param.trim()).filter(param => param !== '');
16
+ t.example = {};
17
+ params.forEach((param, index) => {
18
+ t.example[index] = param;
19
+ });
20
+ }
21
+ }
22
+ // Remove parameters from title to avoid duplicates in Test Suite
23
+ // The example field will be used for grouping on import
24
+ t.title = t.title.replace(/\(.*?\)/, '').trim();
14
25
  const suite = t.suite_title.split('.');
15
26
  t.suite_title = suite.pop();
16
27
  t.file = namespaceToFileName(t.file);
17
- t.title = title.trim();
18
28
  return t;
19
29
  }
20
30
  getFilePath(t) {
21
- const fileName = namespaceToFileName(t.file);
31
+ if (!t.file)
32
+ return null;
33
+ // Normalize path separators for cross-platform compatibility
34
+ let filePath = t.file.replace(/\\/g, '/');
35
+ // If file already has .cs extension, use it directly
36
+ if (filePath.endsWith('.cs')) {
37
+ // Make relative path if it's absolute
38
+ if (path_1.default.isAbsolute(filePath)) {
39
+ // Try to find project-relative path
40
+ const cwd = process.cwd().replace(/\\/g, '/');
41
+ if (filePath.startsWith(cwd)) {
42
+ filePath = path_1.default.relative(cwd, filePath).replace(/\\/g, '/');
43
+ }
44
+ }
45
+ return filePath;
46
+ }
47
+ // Convert namespace path to file path
48
+ const fileName = namespaceToFileName(filePath);
22
49
  return fileName;
23
50
  }
24
51
  }
25
52
  module.exports = CSharpAdapter;
26
53
  function namespaceToFileName(fileName) {
54
+ if (!fileName)
55
+ return '';
56
+ // If already a .cs file path, clean it up
57
+ if (fileName.endsWith('.cs')) {
58
+ return fileName.replace(/\\/g, '/');
59
+ }
27
60
  const fileParts = fileName.split('.');
28
61
  fileParts[fileParts.length - 1] = fileParts[fileParts.length - 1]?.replace(/\$.*/, '');
29
- return `${fileParts.join(path_1.default.sep)}.cs`;
62
+ return `${fileParts.join('/')}.cs`;
30
63
  }
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Enhanced NUnit XML Parser that properly handles test-suite hierarchy
3
+ * and parameterized tests
4
+ */
5
+ export class NUnitXmlParser {
6
+ constructor(options?: {});
7
+ options: {};
8
+ tests: any[];
9
+ stats: {
10
+ total: number;
11
+ passed: number;
12
+ failed: number;
13
+ skipped: number;
14
+ inconclusive: number;
15
+ };
16
+ /**
17
+ * Parse NUnit XML test-run structure
18
+ * @param {Object} testRun - Parsed XML test-run object
19
+ * @returns {Object} - Parsed test results
20
+ */
21
+ parseTestRun(testRun: any): any;
22
+ /**
23
+ * Recursively parse test-suite elements based on their type
24
+ * @param {Object|Array} testSuite - Test suite object or array
25
+ * @param {Array} parentPath - Current path in the hierarchy
26
+ */
27
+ parseTestSuite(testSuite: any | any[], parentPath?: any[]): void;
28
+ /**
29
+ * Process child elements of a test suite
30
+ * @param {Object} testSuite - Test suite object
31
+ * @param {Array} currentPath - Current path in hierarchy
32
+ */
33
+ processChildren(testSuite: any, currentPath: any[]): void;
34
+ /**
35
+ * Parse test-case elements (actual tests)
36
+ * @param {Object|Array} testCases - Test case object or array
37
+ * @param {Array} suitePath - Path to the test suite
38
+ * @param {Object} parentSuite - Parent test suite for context
39
+ */
40
+ parseTestCases(testCases: any | any[], suitePath: any[], parentSuite: any): void;
41
+ /**
42
+ * Parse individual test case
43
+ * @param {Object} testCase - Test case object
44
+ * @param {Array} suitePath - Path to the test suite
45
+ * @param {Object} parentSuite - Parent test suite for context
46
+ * @returns {Object|null} - Parsed test object
47
+ */
48
+ parseTestCase(testCase: any, suitePath: any[], parentSuite: any): any | null;
49
+ /**
50
+ * Extract method name and parameters from test name
51
+ * @param {string} testName - Full test name
52
+ * @returns {Object} - Extracted information
53
+ */
54
+ extractParameters(testName: string): any;
55
+ /**
56
+ * Parse parameter string into array of parameters
57
+ * @param {string} paramString - Parameter string
58
+ * @returns {Array} - Array of parameters
59
+ */
60
+ parseParameterString(paramString: string): any[];
61
+ /**
62
+ * Extract method name from test name (fallback)
63
+ * @param {string} testName - Test name
64
+ * @returns {string} - Method name
65
+ */
66
+ extractMethodName(testName: string): string;
67
+ /**
68
+ * Build file path from suite path and class name
69
+ * @param {Array} suitePath - Suite path array
70
+ * @param {string} className - Class name
71
+ * @param {Object} parentSuite - Parent suite for context
72
+ * @returns {string} - File path
73
+ */
74
+ buildFilePath(suitePath: any[], className: string, parentSuite: any): string;
75
+ /**
76
+ * Group parameterized tests by base method name
77
+ * @param {Array} tests - Array of parsed tests
78
+ * @returns {Object} - Grouped tests
79
+ */
80
+ groupParameterizedTests(tests: any[]): any;
81
+ }
82
+ export default NUnitXmlParser;