@testomatio/reporter 2.1.3-beta.1-multi-links → 2.2.1

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/lib/reporter.d.ts CHANGED
@@ -1,14 +1,11 @@
1
- export type artifact = typeof import("./reporter-functions.js");
2
1
  export const artifact: (data: string | {
3
2
  path: string;
4
3
  type: string;
5
4
  name: string;
6
5
  }, context?: any) => void;
7
- export type log = typeof import("./reporter-functions.js");
8
6
  export const log: (...args: any[]) => void;
9
- export type logger = typeof import("./services/index.js");
10
7
  export const logger: {
11
- "__#13@#originalUserLogger": {
8
+ "__#14@#originalUserLogger": {
12
9
  assert(condition?: boolean, ...data: any[]): void;
13
10
  assert(value: any, message?: string, ...optionalParams: any[]): void;
14
11
  clear(): void;
@@ -53,13 +50,13 @@ export const logger: {
53
50
  profile(label?: string): void;
54
51
  profileEnd(label?: string): void;
55
52
  };
56
- "__#13@#userLoggerWithOverridenMethods": any;
53
+ "__#14@#userLoggerWithOverridenMethods": any;
57
54
  logLevel: string;
58
55
  step(strings: any, ...values: any[]): void;
59
56
  getLogs(context: string): string[];
60
- "__#13@#stringifyLogs"(...args: any[]): string;
57
+ "__#14@#stringifyLogs"(...args: any[]): string;
61
58
  _templateLiteralLog(strings: any, ...args: any[]): void;
62
- "__#13@#logWrapper"(argsArray: any, level: any): void;
59
+ "__#14@#logWrapper"(argsArray: any, level: any): void;
63
60
  assert(...args: any[]): void;
64
61
  debug(...args: any[]): void;
65
62
  error(...args: any[]): void;
@@ -75,17 +72,15 @@ export const logger: {
75
72
  }): void;
76
73
  prettyObjects: boolean;
77
74
  };
78
- export type meta = typeof import("./reporter-functions.js");
79
75
  export const meta: (keyValue: {
80
76
  [key: string]: string;
81
77
  } | string, value?: string | null) => void;
82
- export type step = typeof import("./reporter-functions.js");
83
78
  export const step: (message: string) => void;
84
- export type label = typeof import("./reporter-functions.js");
85
- export const label: (key: string, value?: string) => void;
79
+ export const label: (key: string, value?: string | string[] | null) => void;
80
+ export const linkTest: (...testIds: string[]) => void;
86
81
  declare namespace _default {
87
82
  let testomatioLogger: {
88
- "__#13@#originalUserLogger": {
83
+ "__#14@#originalUserLogger": {
89
84
  assert(condition?: boolean, ...data: any[]): void;
90
85
  assert(value: any, message?: string, ...optionalParams: any[]): void;
91
86
  clear(): void;
@@ -130,13 +125,13 @@ declare namespace _default {
130
125
  profile(label?: string): void;
131
126
  profileEnd(label?: string): void;
132
127
  };
133
- "__#13@#userLoggerWithOverridenMethods": any;
128
+ "__#14@#userLoggerWithOverridenMethods": any;
134
129
  logLevel: string;
135
130
  step(strings: any, ...values: any[]): void;
136
131
  getLogs(context: string): string[];
137
- "__#13@#stringifyLogs"(...args: any[]): string;
132
+ "__#14@#stringifyLogs"(...args: any[]): string;
138
133
  _templateLiteralLog(strings: any, ...args: any[]): void;
139
- "__#13@#logWrapper"(argsArray: any, level: any): void;
134
+ "__#14@#logWrapper"(argsArray: any, level: any): void;
140
135
  assert(...args: any[]): void;
141
136
  debug(...args: any[]): void;
142
137
  error(...args: any[]): void;
@@ -159,7 +154,7 @@ declare namespace _default {
159
154
  }, context?: any) => void;
160
155
  let log: (...args: any[]) => void;
161
156
  let logger: {
162
- "__#13@#originalUserLogger": {
157
+ "__#14@#originalUserLogger": {
163
158
  assert(condition?: boolean, ...data: any[]): void;
164
159
  assert(value: any, message?: string, ...optionalParams: any[]): void;
165
160
  clear(): void;
@@ -204,13 +199,13 @@ declare namespace _default {
204
199
  profile(label?: string): void;
205
200
  profileEnd(label?: string): void;
206
201
  };
207
- "__#13@#userLoggerWithOverridenMethods": any;
202
+ "__#14@#userLoggerWithOverridenMethods": any;
208
203
  logLevel: string;
209
204
  step(strings: any, ...values: any[]): void;
210
205
  getLogs(context: string): string[];
211
- "__#13@#stringifyLogs"(...args: any[]): string;
206
+ "__#14@#stringifyLogs"(...args: any[]): string;
212
207
  _templateLiteralLog(strings: any, ...args: any[]): void;
213
- "__#13@#logWrapper"(argsArray: any, level: any): void;
208
+ "__#14@#logWrapper"(argsArray: any, level: any): void;
214
209
  assert(...args: any[]): void;
215
210
  debug(...args: any[]): void;
216
211
  error(...args: any[]): void;
@@ -230,6 +225,13 @@ declare namespace _default {
230
225
  [key: string]: string;
231
226
  } | string, value?: string | null) => void;
232
227
  let step: (message: string) => void;
233
- let label: (key: string, value?: string) => void;
228
+ let label: (key: string, value?: string | string[] | null) => void;
229
+ let linkTest: (...testIds: string[]) => void;
234
230
  }
235
231
  export default _default;
232
+ export type ArtifactFunction = typeof import("./reporter-functions.js").default.artifact;
233
+ export type LogFunction = typeof import("./reporter-functions.js").default.log;
234
+ export type LoggerService = typeof import("./services/index.js").services.logger;
235
+ export type MetaFunction = typeof import("./reporter-functions.js").default.keyValue;
236
+ export type StepFunction = typeof import("./reporter-functions.js").default.step;
237
+ export type LabelFunction = typeof import("./reporter-functions.js").default.label;
package/lib/reporter.js CHANGED
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.label = exports.step = exports.meta = exports.logger = exports.log = exports.artifact = void 0;
6
+ exports.linkTest = exports.label = exports.step = exports.meta = exports.logger = exports.log = exports.artifact = void 0;
7
7
  // import TestomatClient from './client.js';
8
8
  // import * as TRConstants from './constants.js';
9
9
  const index_js_1 = require("./services/index.js");
@@ -14,13 +14,14 @@ exports.logger = index_js_1.services.logger;
14
14
  exports.meta = reporter_functions_js_1.default.keyValue;
15
15
  exports.step = reporter_functions_js_1.default.step;
16
16
  exports.label = reporter_functions_js_1.default.label;
17
+ exports.linkTest = reporter_functions_js_1.default.linkTest;
17
18
  /**
18
- * @typedef {import('./reporter-functions.js')} artifact
19
- * @typedef {import('./reporter-functions.js')} log
20
- * @typedef {import('./services/index.js')} logger
21
- * @typedef {import('./reporter-functions.js')} meta
22
- * @typedef {import('./reporter-functions.js')} step
23
- * @typedef {import('./reporter-functions.js')} label
19
+ * @typedef {typeof import('./reporter-functions.js').default.artifact} ArtifactFunction
20
+ * @typedef {typeof import('./reporter-functions.js').default.log} LogFunction
21
+ * @typedef {typeof import('./services/index.js').services.logger} LoggerService
22
+ * @typedef {typeof import('./reporter-functions.js').default.keyValue} MetaFunction
23
+ * @typedef {typeof import('./reporter-functions.js').default.step} StepFunction
24
+ * @typedef {typeof import('./reporter-functions.js').default.label} LabelFunction
24
25
  */
25
26
  module.exports = {
26
27
  /**
@@ -33,6 +34,7 @@ module.exports = {
33
34
  meta: reporter_functions_js_1.default.keyValue,
34
35
  step: reporter_functions_js_1.default.step,
35
36
  label: reporter_functions_js_1.default.label,
37
+ linkTest: reporter_functions_js_1.default.linkTest,
36
38
  // TestomatClient,
37
39
  // TRConstants,
38
40
  };
@@ -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 "__#14@#instance": any;
6
+ static "__#15@#instance": any;
7
7
  /**
8
8
  * Singleton
9
9
  * @returns {ArtifactStorage}
@@ -2,10 +2,10 @@ export namespace services {
2
2
  export { logger };
3
3
  export { artifactStorage as artifacts };
4
4
  export { keyValueStorage as keyValues };
5
- export { labelStorage as labels };
5
+ export { linkStorage as links };
6
6
  export function setContext(context: any): void;
7
7
  }
8
8
  import { logger } from './logger.js';
9
9
  import { artifactStorage } from './artifacts.js';
10
10
  import { keyValueStorage } from './key-values.js';
11
- import { labelStorage } from './labels.js';
11
+ import { linkStorage } from './links.js';
@@ -4,13 +4,13 @@ exports.services = void 0;
4
4
  const logger_js_1 = require("./logger.js");
5
5
  const artifacts_js_1 = require("./artifacts.js");
6
6
  const key_values_js_1 = require("./key-values.js");
7
- const labels_js_1 = require("./labels.js");
7
+ const links_js_1 = require("./links.js");
8
8
  const data_storage_js_1 = require("../data-storage.js");
9
9
  exports.services = {
10
10
  logger: logger_js_1.logger,
11
11
  artifacts: artifacts_js_1.artifactStorage,
12
12
  keyValues: key_values_js_1.keyValueStorage,
13
- labels: labels_js_1.labelStorage,
13
+ links: links_js_1.linkStorage,
14
14
  setContext: context => {
15
15
  data_storage_js_1.dataStorage.setContext(context);
16
16
  },
@@ -1,6 +1,6 @@
1
1
  export const keyValueStorage: KeyValueStorage;
2
2
  declare class KeyValueStorage {
3
- static "__#15@#instance": any;
3
+ static "__#16@#instance": any;
4
4
  /**
5
5
  *
6
6
  * @returns {KeyValueStorage}
@@ -1,6 +1,6 @@
1
1
  export const labelStorage: LabelStorage;
2
2
  declare class LabelStorage {
3
- static "__#16@#instance": any;
3
+ static "__#19@#instance": any;
4
4
  /**
5
5
  *
6
6
  * @returns {LabelStorage}
@@ -27,7 +27,7 @@ class LabelStorage {
27
27
  put(labels, context = null) {
28
28
  if (!labels || !Array.isArray(labels))
29
29
  return;
30
- data_storage_js_1.dataStorage.putData('labels', labels, context);
30
+ data_storage_js_1.dataStorage.putData('links', labels, context);
31
31
  }
32
32
  /**
33
33
  * Returns labels array for the test
@@ -35,7 +35,7 @@ class LabelStorage {
35
35
  * @returns {string[]} labels array, e.g. ['smoke', 'severity:high', 'feature:user_account']
36
36
  */
37
37
  get(context = null) {
38
- const labelsList = data_storage_js_1.dataStorage.getData('labels', context);
38
+ const labelsList = data_storage_js_1.dataStorage.getData('links', context);
39
39
  if (!labelsList || !labelsList?.length)
40
40
  return [];
41
41
  const allLabels = [];
@@ -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 "__#13@#instance": any;
8
+ static "__#14@#instance": any;
9
9
  /**
10
10
  *
11
11
  * @returns {Logger}
@@ -321,7 +321,7 @@ const fileSystem = {
321
321
  exports.fileSystem = fileSystem;
322
322
  const foundedTestLog = (app, tests) => {
323
323
  const n = tests.length;
324
- return n === 1 ? console.log(app, `✅ We found one test!`) : console.log(app, `✅ We found ${n} tests!`);
324
+ return console.log(app, `✅ We found ${n === 1 ? 'one test' : `${n} tests`} in Testomat.io!`);
325
325
  };
326
326
  exports.foundedTestLog = foundedTestLog;
327
327
  const humanize = text => {
@@ -399,6 +399,8 @@ function storeRunId(runId) {
399
399
  function readLatestRunId() {
400
400
  try {
401
401
  const filePath = path_1.default.join(os_1.default.tmpdir(), `testomatio.latest.run`);
402
+ if (!fs_1.default.existsSync(filePath))
403
+ return null;
402
404
  const stats = fs_1.default.statSync(filePath);
403
405
  const diff = +new Date() - +stats.mtime;
404
406
  const diffHours = diff / 1000 / 60 / 60;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@testomatio/reporter",
3
- "version": "2.1.3-beta.1-multi-links",
3
+ "version": "2.2.1",
4
4
  "description": "Testomatio Reporter Client",
5
5
  "engines": {
6
6
  "node": ">=18"
@@ -56,19 +56,20 @@ function CodeceptReporter(config) {
56
56
 
57
57
  output.debug = function(msg) {
58
58
  originalOutput.debug(msg);
59
- dataStorage.putData('log', repeat(this.stepShift) + pc.cyan(msg.toString()));
59
+ dataStorage.putData('log', repeat(this?.stepShift || 0) + pc.cyan(msg.toString()));
60
60
  };
61
61
 
62
62
  output.say = function(message, color = 'cyan') {
63
63
  originalOutput.say(message, color);
64
- const sayMsg = repeat(this.stepShift) + ` ${pc.bold(pc[color](message))}`;
64
+ const sayMsg = repeat(this?.stepShift || 0) + ` ${pc.bold(pc[color](message))}`;
65
65
  dataStorage.putData('log', sayMsg);
66
66
  };
67
67
 
68
68
  output.log = function(msg) {
69
69
  originalOutput.log(msg);
70
- dataStorage.putData('log', repeat(this.stepShift) + pc.gray(msg));
70
+ dataStorage.putData('log', repeat(this?.stepShift || 0) + pc.gray(msg));
71
71
  };
72
+ output.stepShift = 0;
72
73
 
73
74
  recorder.startUnlessRunning();
74
75
 
@@ -162,7 +163,7 @@ function CodeceptReporter(config) {
162
163
  const manuallyAttachedArtifacts = services.artifacts.get(test.fullTitle());
163
164
  const keyValues = services.keyValues.get(test.fullTitle());
164
165
  const stepHierarchy = buildUnifiedStepHierarchy(test.steps, hookSteps);
165
- const labels = services.labels.get(test.fullTitle());
166
+ const links = services.links.get(test.fullTitle());
166
167
 
167
168
  services.setContext(null);
168
169
 
@@ -177,7 +178,7 @@ function CodeceptReporter(config) {
177
178
  files,
178
179
  steps: stepHierarchy, // Array of step objects per API schema
179
180
  logs,
180
- labels,
181
+ links,
181
182
  manuallyAttachedArtifacts,
182
183
  meta: { ...keyValues, ...test.meta },
183
184
  });
@@ -61,6 +61,7 @@ function MochaReporter(runner, opts) {
61
61
  const logs = getTestLogs(test);
62
62
  const artifacts = services.artifacts.get(test.fullTitle());
63
63
  const keyValues = services.keyValues.get(test.fullTitle());
64
+ const links = services.links.get(test.fullTitle());
64
65
 
65
66
  client.addTestRun(STATUS.PASSED, {
66
67
  test_id: testId,
@@ -72,6 +73,7 @@ function MochaReporter(runner, opts) {
72
73
  logs,
73
74
  manuallyAttachedArtifacts: artifacts,
74
75
  meta: keyValues,
76
+ links,
75
77
  });
76
78
  });
77
79
 
@@ -79,6 +81,10 @@ function MochaReporter(runner, opts) {
79
81
  skipped += 1;
80
82
  console.log('skip: %s', test.fullTitle());
81
83
  const testId = getTestomatIdFromTestTitle(test.title);
84
+ const artifacts = services.artifacts.get(test.fullTitle());
85
+ const keyValues = services.keyValues.get(test.fullTitle());
86
+ const links = services.links.get(test.fullTitle());
87
+
82
88
  client.addTestRun(STATUS.SKIPPED, {
83
89
  title: getTestName(test),
84
90
  suite_title: getSuiteTitle(test),
@@ -86,6 +92,9 @@ function MochaReporter(runner, opts) {
86
92
  file: getFile(test),
87
93
  test_id: testId,
88
94
  time: test.duration,
95
+ manuallyAttachedArtifacts: artifacts,
96
+ meta: keyValues,
97
+ links,
89
98
  });
90
99
  });
91
100
 
@@ -95,6 +104,9 @@ function MochaReporter(runner, opts) {
95
104
  const testId = getTestomatIdFromTestTitle(test.title);
96
105
 
97
106
  const logs = getTestLogs(test);
107
+ const artifacts = services.artifacts.get(test.fullTitle());
108
+ const keyValues = services.keyValues.get(test.fullTitle());
109
+ const links = services.links.get(test.fullTitle());
98
110
 
99
111
  client.addTestRun(STATUS.FAILED, {
100
112
  error: err,
@@ -105,6 +117,9 @@ function MochaReporter(runner, opts) {
105
117
  code: process.env.TESTOMATIO_UPDATE_CODE ? test.body.toString() : '',
106
118
  time: test.duration,
107
119
  logs,
120
+ manuallyAttachedArtifacts: artifacts,
121
+ meta: keyValues,
122
+ links,
108
123
  });
109
124
  });
110
125
 
@@ -53,11 +53,13 @@ class WebdriverReporter extends WDIOReporter {
53
53
  test.suite = test.parent;
54
54
  const logs = getTestLogs(test.fullTitle);
55
55
  // TODO: FIX: artifacts for some reason leads to empty report on Testomat.io
56
- // const artifacts = services.artifacts.get(test.fullTitle);
57
- // const keyValues = services.keyValues.get(test.fullTitle);
56
+ // ^ not reproduced anymore (Jul 2025)
57
+ // but still be under investigation
58
+ const artifacts = services.artifacts.get(test.fullTitle);
59
+ const keyValues = services.keyValues.get(test.fullTitle);
58
60
  test.logs = logs;
59
- // test.artifacts = artifacts;
60
- // test.meta = keyValues;
61
+ test.artifacts = artifacts;
62
+ test.meta = keyValues;
61
63
 
62
64
  this._addTestPromises.push(this.addTest(test));
63
65
  }
@@ -1,124 +1,53 @@
1
1
  #!/usr/bin/env node
2
- import { spawn } from 'cross-spawn';
3
- import { Command } from 'commander';
4
- import pc from 'picocolors';
5
- import TestomatClient from '../client.js';
6
- import { APP_PREFIX, STATUS } from '../constants.js';
2
+ import { spawn } from 'node:child_process';
3
+ import { join, dirname } from 'node:path';
7
4
  import { getPackageVersion } from '../utils/utils.js';
8
- import { config } from '../config.js';
9
- import dotenv from 'dotenv';
5
+ import pc from 'picocolors';
6
+
7
+ // Define __dirname - this will be replaced by build script with actual __dirname for CommonJS
8
+ const __dirname = typeof globalThis.__dirname !== 'undefined' ? globalThis.__dirname : '.';
9
+ const cliPath = join(__dirname, 'cli.js');
10
10
 
11
11
  const version = getPackageVersion();
12
12
  console.log(pc.cyan(pc.bold(` 🤩 Testomat.io Reporter v${version}`)));
13
- const program = new Command();
14
-
15
- program
16
- .option('-c, --command <cmd>', 'Test runner command')
17
- .option('--launch', 'Start a new run and return its ID')
18
- .option('--finish', 'Finish Run by its ID')
19
- .option('--env-file <envfile>', 'Load environment variables from env file')
20
- .option('--filter <filter>', 'Additional execution filter')
21
- .action(async opts => {
22
- const { launch, finish, filter } = opts;
23
- let { command } = opts;
24
-
25
- if (opts.envFile) dotenv.config({ path: opts.envFile });
26
-
27
- const apiKey = process.env['INPUT_TESTOMATIO-KEY'] || config.TESTOMATIO;
28
- const title = process.env.TESTOMATIO_TITLE;
29
-
30
- if (launch) {
31
- console.log('Starting a new Run on Testomat.io...');
32
- const client = new TestomatClient({ apiKey });
33
-
34
- client.createRun().then(() => {
35
- console.log(process.env.runId);
36
- process.exit(0);
37
- });
38
- return;
39
- }
40
-
41
- if (finish) {
42
- // TODO: add error in case of TESTOMATIO environment variable is not set
43
- // because command is fine in console, but actually (on testomat.io) run is not finished
44
- if (!process.env.TESTOMATIO_RUN) {
45
- console.log('TESTOMATIO_RUN environment variable must be set.');
46
- return process.exit(1);
47
- }
48
-
49
- console.log('Finishing Run on Testomat.io...');
50
-
51
- const client = new TestomatClient({ apiKey });
52
13
 
53
- // @ts-ignore
54
- client.updateRunStatus(STATUS.FINISHED).then(() => {
55
- console.log(pc.yellow(`Run ${process.env.TESTOMATIO_RUN} was finished`));
56
- process.exit(0);
57
- });
58
- return;
14
+ // Parse command line arguments to map start-test-run options to @testomatio/reporter run format
15
+ const args = process.argv.slice(2);
16
+ const newArgs = ['run'];
17
+
18
+ let i = 0;
19
+ while (i < args.length) {
20
+ const arg = args[i];
21
+
22
+ if (arg === '-c' || arg === '--command') {
23
+ // Map -c/--command to positional argument for run command
24
+ i++;
25
+ if (i < args.length) {
26
+ newArgs.push(args[i]);
59
27
  }
28
+ } else if (arg.startsWith('--command=')) {
29
+ // Handle --command=value format
30
+ const command = arg.split('=', 2)[1];
31
+ newArgs.push(command);
32
+ } else if (arg === '--launch') {
33
+ // Map --launch to start command
34
+ newArgs[0] = 'start';
35
+ } else if (arg === '--finish') {
36
+ // Map --finish to finish command
37
+ newArgs[0] = 'finish';
38
+ } else {
39
+ // Pass through other arguments
40
+ newArgs.push(arg);
41
+ }
42
+ i++;
43
+ }
60
44
 
61
- let exitCode = 0;
62
-
63
- if (!command.split) {
64
- process.exitCode = 255;
65
- console.log(APP_PREFIX, `No command provided. Use -c option to launch a test runner.`);
66
- return;
67
- }
68
-
69
- const client = new TestomatClient({ apiKey, title, parallel: true });
70
-
71
- if (filter) {
72
- const [pipe, ...optsArray] = filter.split(':');
73
- const pipeOptions = optsArray.join(':');
74
-
75
- try {
76
- const tests = await client.prepareRun({ pipe, pipeOptions });
77
-
78
- if (!tests || tests.length === 0) {
79
- return;
80
- }
81
-
82
- const grep = ` --grep (${tests.join('|')})`;
83
- command += grep;
84
- } catch (err) {
85
- console.log(APP_PREFIX, err);
86
- }
87
- }
88
-
89
- const testCmds = command.split(' ');
90
- console.log(APP_PREFIX, `🚀 Running`, pc.green(command));
91
-
92
- if (!apiKey) {
93
- const cmd = spawn(testCmds[0], testCmds.slice(1), { stdio: 'inherit' });
94
-
95
- cmd.on('close', code => {
96
- console.log(APP_PREFIX, '⚠️ ', `Runner exited with ${pc.bold(code)}, report is ignored`);
97
-
98
- if (code > exitCode) exitCode = code;
99
- process.exitCode = exitCode;
100
- });
101
-
102
- return;
103
- }
104
-
105
- client.createRun().then(() => {
106
- const cmd = spawn(testCmds[0], testCmds.slice(1), { stdio: 'inherit' });
107
-
108
- cmd.on('close', code => {
109
- const emoji = code === 0 ? '🟢' : '🔴';
110
- console.log(APP_PREFIX, emoji, `Runner exited with ${pc.bold(code)}`);
111
- const status = code === 0 ? 'passed' : 'failed';
112
- client.updateRunStatus(status, true);
113
-
114
- if (code > exitCode) exitCode = code;
115
- process.exitCode = exitCode;
116
- });
117
- });
118
- });
45
+ // Execute the main CLI with mapped arguments
119
46
 
120
- if (process.argv.length <= 2) {
121
- program.outputHelp();
122
- }
47
+ const child = spawn(process.execPath, [cliPath, ...newArgs], {
48
+ stdio: 'inherit'
49
+ });
123
50
 
124
- program.parse(process.argv);
51
+ child.on('exit', (code) => {
52
+ process.exit(code);
53
+ });
package/src/client.js CHANGED
@@ -11,6 +11,7 @@ import path, { sep } from 'path';
11
11
  import { fileURLToPath } from 'node:url';
12
12
  import { S3Uploader } from './uploader.js';
13
13
  import { formatStep, readLatestRunId, storeRunId, validateSuiteId } from './utils/utils.js';
14
+ import { linkStorage } from './services/links.js';
14
15
  import { filesize as prettyBytes } from 'filesize';
15
16
 
16
17
  const debug = createDebugMessages('@testomatio/reporter:client');
@@ -182,7 +183,6 @@ class Client {
182
183
  test_id,
183
184
  timestamp,
184
185
  manuallyAttachedArtifacts,
185
- labels,
186
186
  overwrite,
187
187
  } = testData;
188
188
  let { message = '', meta = {} } = testData;
@@ -224,7 +224,9 @@ class Client {
224
224
  return acc;
225
225
  }, {});
226
226
 
227
- // Labels are simple array of strings, no processing needed
227
+ // Get links from storage using the test context
228
+ const testContext = suite_title ? `${suite_title} ${title}` : title;
229
+ const links = linkStorage.get(testContext) || [];
228
230
 
229
231
  let errorFormatted = '';
230
232
  if (error) {
@@ -280,7 +282,7 @@ class Client {
280
282
  timestamp,
281
283
  artifacts,
282
284
  meta,
283
- labels,
285
+ links,
284
286
  overwrite,
285
287
  ...(rootSuiteId && { root_suite_id: rootSuiteId }),
286
288
  };
@@ -41,7 +41,7 @@ class DataStorage {
41
41
  /**
42
42
  * Puts any data to storage (file or global variable).
43
43
  * If file: stores data as text, if global variable – stores as array of data.
44
- * @param {'log' | 'artifact' | 'keyvalue' | 'labels'} dataType
44
+ * @param {'log' | 'artifact' | 'keyvalue' | 'links'} dataType
45
45
  * @param {*} data anything you want to store (string, object, array, etc)
46
46
  * @param {*} context could be testId or any context (test name, suite name, including their IDs etc)
47
47
  * suite name + test name is used by default
@@ -70,7 +70,7 @@ class DataStorage {
70
70
  * Returns data, stored for specific test/context (or data which was stored without test id specified).
71
71
  * This method will get data from global variable and/or from from file (previosly saved with put method).
72
72
  *
73
- * @param {'log' | 'artifact' | 'keyvalue' | 'labels'} dataType
73
+ * @param {'log' | 'artifact' | 'keyvalue' | 'links'} dataType
74
74
  * @param {string} context
75
75
  * @returns {any []} array of data (any type), null (if no data found for context) or string (if data type is log)
76
76
  */
@@ -108,7 +108,7 @@ class DataStorage {
108
108
  }
109
109
 
110
110
  /**
111
- * @param {'log' | 'artifact' | 'keyvalue' | 'labels'} dataType
111
+ * @param {'log' | 'artifact' | 'keyvalue' | 'links'} dataType
112
112
  * @param {string} context
113
113
  * @returns aray of data (any type)
114
114
  */
@@ -127,7 +127,7 @@ class DataStorage {
127
127
  }
128
128
 
129
129
  /**
130
- * @param {'log' | 'artifact' | 'keyvalue' | 'labels'} dataType
130
+ * @param {'log' | 'artifact' | 'keyvalue' | 'links'} dataType
131
131
  * @param {*} context
132
132
  * @returns array of data (any type)
133
133
  */
@@ -151,7 +151,7 @@ class DataStorage {
151
151
 
152
152
  /**
153
153
  * Puts data to global variable. Unlike the file storage, stores data in array (file storage just append as string).
154
- * @param {'log' | 'artifact' | 'keyvalue' | 'labels'} dataType
154
+ * @param {'log' | 'artifact' | 'keyvalue' | 'links'} dataType
155
155
  * @param {*} data
156
156
  * @param {*} context
157
157
  */
@@ -166,7 +166,7 @@ class DataStorage {
166
166
 
167
167
  /**
168
168
  * Puts data to file. Unlike the global variable storage, stores data as string
169
- * @param {'log' | 'artifact' | 'keyvalue' | 'labels'} dataType
169
+ * @param {'log' | 'artifact' | 'keyvalue' | 'links'} dataType
170
170
  * @param {*} data
171
171
  * @param {string} context
172
172
  * @returns
@@ -119,8 +119,7 @@ class TestomatioPipe {
119
119
  const resp = await this.client.request({
120
120
  method: 'GET',
121
121
  url: '/api/test_grep',
122
- params: q.params,
123
- responseType: q.responseType
122
+ ...q,
124
123
  });
125
124
 
126
125
  if (Array.isArray(resp.data?.tests) && resp.data?.tests?.length > 0) {
@@ -188,7 +187,8 @@ class TestomatioPipe {
188
187
  const resp = await this.client.request({
189
188
  method: 'PUT',
190
189
  url: `/api/reporter/${this.runId}`,
191
- data: runParams
190
+ data: runParams,
191
+ responseType: 'json'
192
192
  });
193
193
  if (resp.data.artifacts) setS3Credentials(resp.data.artifacts);
194
194
  return;