@testomatio/reporter 2.1.3-beta.3-multi-links → 2.2.2

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.
Files changed (42) hide show
  1. package/lib/adapter/codecept.js +3 -3
  2. package/lib/adapter/mocha.js +14 -0
  3. package/lib/adapter/webdriver.js +8 -6
  4. package/lib/bin/cli.js +9 -6
  5. package/lib/bin/startTest.js +38 -91
  6. package/lib/client.d.ts +1 -2
  7. package/lib/client.js +8 -6
  8. package/lib/data-storage.d.ts +4 -4
  9. package/lib/data-storage.js +7 -8
  10. package/lib/pipe/testomatio.d.ts +0 -1
  11. package/lib/pipe/testomatio.js +4 -8
  12. package/lib/replay.js +1 -1
  13. package/lib/reporter-functions.d.ts +20 -7
  14. package/lib/reporter-functions.js +27 -35
  15. package/lib/reporter.d.ts +22 -20
  16. package/lib/reporter.js +9 -7
  17. package/lib/services/artifacts.d.ts +1 -1
  18. package/lib/services/index.d.ts +2 -2
  19. package/lib/services/index.js +2 -2
  20. package/lib/services/key-values.d.ts +1 -1
  21. package/lib/services/labels.d.ts +1 -1
  22. package/lib/services/labels.js +2 -2
  23. package/lib/services/logger.d.ts +1 -1
  24. package/lib/utils/utils.js +3 -1
  25. package/package.json +1 -1
  26. package/src/adapter/codecept.js +3 -4
  27. package/src/adapter/mocha.js +15 -0
  28. package/src/adapter/webdriver.js +9 -6
  29. package/src/bin/cli.js +9 -6
  30. package/src/bin/startTest.js +43 -114
  31. package/src/client.js +7 -6
  32. package/src/data-storage.js +7 -9
  33. package/src/pipe/testomatio.js +4 -7
  34. package/src/replay.js +1 -1
  35. package/src/reporter-functions.js +27 -37
  36. package/src/reporter.js +8 -6
  37. package/src/services/index.js +2 -2
  38. package/src/services/labels.js +2 -2
  39. package/src/services/links.js +69 -0
  40. package/src/utils/utils.js +5 -3
  41. package/lib/utils/cli_utils.d.ts +0 -1
  42. package/lib/utils/cli_utils.js +0 -524304
@@ -48,7 +48,6 @@ function CodeceptReporter(config) {
48
48
  step: output.step,
49
49
  say: output.say,
50
50
  };
51
- output.stepShift = 0;
52
51
  output.debug = function (msg) {
53
52
  originalOutput.debug(msg);
54
53
  data_storage_js_1.dataStorage.putData('log', repeat(this?.stepShift || 0) + picocolors_1.default.cyan(msg.toString()));
@@ -62,6 +61,7 @@ function CodeceptReporter(config) {
62
61
  originalOutput.log(msg);
63
62
  data_storage_js_1.dataStorage.putData('log', repeat(this?.stepShift || 0) + picocolors_1.default.gray(msg));
64
63
  };
64
+ output.stepShift = 0;
65
65
  recorder.startUnlessRunning();
66
66
  const hookSteps = new Map();
67
67
  let currentHook = null;
@@ -140,7 +140,7 @@ function CodeceptReporter(config) {
140
140
  const manuallyAttachedArtifacts = index_js_1.services.artifacts.get(test.fullTitle());
141
141
  const keyValues = index_js_1.services.keyValues.get(test.fullTitle());
142
142
  const stepHierarchy = buildUnifiedStepHierarchy(test.steps, hookSteps);
143
- const labels = index_js_1.services.labels.get(test.fullTitle());
143
+ const links = index_js_1.services.links.get(test.fullTitle());
144
144
  index_js_1.services.setContext(null);
145
145
  client.addTestRun(test.state, {
146
146
  ...stripExampleFromTitle(title),
@@ -153,7 +153,7 @@ function CodeceptReporter(config) {
153
153
  files,
154
154
  steps: stepHierarchy, // Array of step objects per API schema
155
155
  logs,
156
- labels,
156
+ links,
157
157
  manuallyAttachedArtifacts,
158
158
  meta: { ...keyValues, ...test.meta },
159
159
  });
@@ -43,6 +43,7 @@ function MochaReporter(runner, opts) {
43
43
  const logs = getTestLogs(test);
44
44
  const artifacts = index_js_1.services.artifacts.get(test.fullTitle());
45
45
  const keyValues = index_js_1.services.keyValues.get(test.fullTitle());
46
+ const links = index_js_1.services.links.get(test.fullTitle());
46
47
  client.addTestRun(constants_js_1.STATUS.PASSED, {
47
48
  test_id: testId,
48
49
  suite_title: getSuiteTitle(test),
@@ -53,12 +54,16 @@ function MochaReporter(runner, opts) {
53
54
  logs,
54
55
  manuallyAttachedArtifacts: artifacts,
55
56
  meta: keyValues,
57
+ links,
56
58
  });
57
59
  });
58
60
  runner.on(EVENT_TEST_PENDING, test => {
59
61
  skipped += 1;
60
62
  console.log('skip: %s', test.fullTitle());
61
63
  const testId = (0, utils_js_1.getTestomatIdFromTestTitle)(test.title);
64
+ const artifacts = index_js_1.services.artifacts.get(test.fullTitle());
65
+ const keyValues = index_js_1.services.keyValues.get(test.fullTitle());
66
+ const links = index_js_1.services.links.get(test.fullTitle());
62
67
  client.addTestRun(constants_js_1.STATUS.SKIPPED, {
63
68
  title: getTestName(test),
64
69
  suite_title: getSuiteTitle(test),
@@ -66,6 +71,9 @@ function MochaReporter(runner, opts) {
66
71
  file: getFile(test),
67
72
  test_id: testId,
68
73
  time: test.duration,
74
+ manuallyAttachedArtifacts: artifacts,
75
+ meta: keyValues,
76
+ links,
69
77
  });
70
78
  });
71
79
  runner.on(EVENT_TEST_FAIL, async (test, err) => {
@@ -73,6 +81,9 @@ function MochaReporter(runner, opts) {
73
81
  console.log(picocolors_1.default.bold(picocolors_1.default.red('✖')), test.fullTitle(), picocolors_1.default.gray(err.message));
74
82
  const testId = (0, utils_js_1.getTestomatIdFromTestTitle)(test.title);
75
83
  const logs = getTestLogs(test);
84
+ const artifacts = index_js_1.services.artifacts.get(test.fullTitle());
85
+ const keyValues = index_js_1.services.keyValues.get(test.fullTitle());
86
+ const links = index_js_1.services.links.get(test.fullTitle());
76
87
  client.addTestRun(constants_js_1.STATUS.FAILED, {
77
88
  error: err,
78
89
  suite_title: getSuiteTitle(test),
@@ -82,6 +93,9 @@ function MochaReporter(runner, opts) {
82
93
  code: process.env.TESTOMATIO_UPDATE_CODE ? test.body.toString() : '',
83
94
  time: test.duration,
84
95
  logs,
96
+ manuallyAttachedArtifacts: artifacts,
97
+ meta: keyValues,
98
+ links,
85
99
  });
86
100
  });
87
101
  runner.on(EVENT_RUN_END, () => {
@@ -41,6 +41,7 @@ const client_js_1 = __importDefault(require("../client.js"));
41
41
  const utils_js_1 = require("../utils/utils.js");
42
42
  const index_js_1 = require("../services/index.js");
43
43
  const constants_js_1 = require("../constants.js");
44
+ const data_storage_js_1 = require("../data-storage.js");
44
45
  class WebdriverReporter extends reporter_1.default {
45
46
  constructor(options) {
46
47
  super(options);
@@ -77,12 +78,12 @@ class WebdriverReporter extends reporter_1.default {
77
78
  onTestEnd(test) {
78
79
  test.suite = test.parent;
79
80
  const logs = getTestLogs(test.fullTitle);
80
- // TODO: FIX: artifacts for some reason leads to empty report on Testomat.io
81
- // const artifacts = services.artifacts.get(test.fullTitle);
82
- // const keyValues = services.keyValues.get(test.fullTitle);
81
+ // still be under investigation
82
+ const artifacts = index_js_1.services.artifacts.get(test.fullTitle);
83
+ const keyValues = index_js_1.services.keyValues.get(test.fullTitle);
83
84
  test.logs = logs;
84
- // test.artifacts = artifacts;
85
- // test.meta = keyValues;
85
+ test.artifacts = artifacts;
86
+ test.meta = keyValues;
86
87
  this._addTestPromises.push(this.addTest(test));
87
88
  }
88
89
  // wdio-cucumber does not trigger onTestEnd hook, thus, using this one
@@ -100,8 +101,9 @@ class WebdriverReporter extends reporter_1.default {
100
101
  const screenshotsBuffers = output
101
102
  .filter(el => el.endpoint === screenshotEndpoint && el.result && el.result.value)
102
103
  .map(el => Buffer.from(el.result.value, 'base64'));
104
+ const rid = (0, data_storage_js_1.stringToMD5Hash)(test.fullTitle);
103
105
  await this.client.addTestRun(state, {
104
- rid: test.uid || '',
106
+ rid,
105
107
  manuallyAttachedArtifacts: test.artifacts,
106
108
  error,
107
109
  logs: test.logs,
package/lib/bin/cli.js CHANGED
@@ -78,7 +78,7 @@ program
78
78
  console.log(constants_js_1.APP_PREFIX, `No command provided. Use -c option to launch a test runner.`);
79
79
  return process.exit(255);
80
80
  }
81
- const client = new client_js_1.default({ apiKey, title, parallel: true });
81
+ const client = new client_js_1.default({ apiKey, title });
82
82
  if (opts.filter) {
83
83
  const [pipe, ...optsArray] = opts.filter.split(':');
84
84
  const pipeOptions = optsArray.join(':');
@@ -95,13 +95,16 @@ program
95
95
  console.log(constants_js_1.APP_PREFIX, `🚀 Running`, picocolors_1.default.green(command));
96
96
  const runTests = async () => {
97
97
  const testCmds = command.split(' ');
98
- const cmd = (0, cross_spawn_1.spawn)(testCmds[0], testCmds.slice(1), { stdio: 'inherit' });
98
+ const cmd = (0, cross_spawn_1.spawn)(testCmds[0], testCmds.slice(1), {
99
+ stdio: 'inherit',
100
+ env: { ...process.env, TESTOMATIO_PROCEED: 'true', runId: client.runId },
101
+ });
99
102
  cmd.on('close', async (code) => {
100
103
  const emoji = code === 0 ? '🟢' : '🔴';
101
104
  console.log(constants_js_1.APP_PREFIX, emoji, `Runner exited with ${picocolors_1.default.bold(code)}`);
102
105
  if (apiKey) {
103
106
  const status = code === 0 ? 'passed' : 'failed';
104
- await client.updateRunStatus(status, true);
107
+ await client.updateRunStatus(status);
105
108
  }
106
109
  process.exit(code);
107
110
  });
@@ -257,13 +260,13 @@ program
257
260
  const replayService = new replay_js_1.default({
258
261
  apiKey: config_js_1.config.TESTOMATIO,
259
262
  dryRun: opts.dryRun,
260
- onLog: (message) => console.log(constants_js_1.APP_PREFIX, message),
261
- onError: (message) => console.error(constants_js_1.APP_PREFIX, '⚠️ ', message),
263
+ onLog: message => console.log(constants_js_1.APP_PREFIX, message),
264
+ onError: message => console.error(constants_js_1.APP_PREFIX, '⚠️ ', message),
262
265
  onProgress: ({ current, total }) => {
263
266
  if (current % 10 === 0 || current === total) {
264
267
  console.log(constants_js_1.APP_PREFIX, `📊 Progress: ${current}/${total} tests processed`);
265
268
  }
266
- }
269
+ },
267
270
  });
268
271
  const result = await replayService.replay(debugFile);
269
272
  if (result.dryRun) {
@@ -4,103 +4,50 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  return (mod && mod.__esModule) ? mod : { "default": mod };
5
5
  };
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- const cross_spawn_1 = require("cross-spawn");
8
- const commander_1 = require("commander");
9
- const picocolors_1 = __importDefault(require("picocolors"));
10
- const client_js_1 = __importDefault(require("../client.js"));
11
- const constants_js_1 = require("../constants.js");
7
+ const node_child_process_1 = require("node:child_process");
8
+ const node_path_1 = require("node:path");
12
9
  const utils_js_1 = require("../utils/utils.js");
13
- const config_js_1 = require("../config.js");
14
- const dotenv_1 = __importDefault(require("dotenv"));
10
+ const picocolors_1 = __importDefault(require("picocolors"));
11
+ // Define __dirname - this will be replaced by build script with actual __dirname for CommonJS
12
+ const cliPath = (0, node_path_1.join)(__dirname, 'cli.js');
15
13
  const version = (0, utils_js_1.getPackageVersion)();
16
14
  console.log(picocolors_1.default.cyan(picocolors_1.default.bold(` 🤩 Testomat.io Reporter v${version}`)));
17
- const program = new commander_1.Command();
18
- program
19
- .option('-c, --command <cmd>', 'Test runner command')
20
- .option('--launch', 'Start a new run and return its ID')
21
- .option('--finish', 'Finish Run by its ID')
22
- .option('--env-file <envfile>', 'Load environment variables from env file')
23
- .option('--filter <filter>', 'Additional execution filter')
24
- .action(async (opts) => {
25
- const { launch, finish, filter } = opts;
26
- let { command } = opts;
27
- if (opts.envFile)
28
- dotenv_1.default.config({ path: opts.envFile });
29
- const apiKey = process.env['INPUT_TESTOMATIO-KEY'] || config_js_1.config.TESTOMATIO;
30
- const title = process.env.TESTOMATIO_TITLE;
31
- if (launch) {
32
- console.log('Starting a new Run on Testomat.io...');
33
- const client = new client_js_1.default({ apiKey });
34
- client.createRun().then(() => {
35
- console.log(process.env.runId);
36
- process.exit(0);
37
- });
38
- return;
39
- }
40
- if (finish) {
41
- // TODO: add error in case of TESTOMATIO environment variable is not set
42
- // because command is fine in console, but actually (on testomat.io) run is not finished
43
- if (!process.env.TESTOMATIO_RUN) {
44
- console.log('TESTOMATIO_RUN environment variable must be set.');
45
- return process.exit(1);
15
+ // Parse command line arguments to map start-test-run options to @testomatio/reporter run format
16
+ const args = process.argv.slice(2);
17
+ const newArgs = ['run'];
18
+ let i = 0;
19
+ while (i < args.length) {
20
+ const arg = args[i];
21
+ if (arg === '-c' || arg === '--command') {
22
+ // Map -c/--command to positional argument for run command
23
+ i++;
24
+ if (i < args.length) {
25
+ newArgs.push(args[i]);
46
26
  }
47
- console.log('Finishing Run on Testomat.io...');
48
- const client = new client_js_1.default({ apiKey });
49
- // @ts-ignore
50
- client.updateRunStatus(constants_js_1.STATUS.FINISHED).then(() => {
51
- console.log(picocolors_1.default.yellow(`Run ${process.env.TESTOMATIO_RUN} was finished`));
52
- process.exit(0);
53
- });
54
- return;
55
27
  }
56
- let exitCode = 0;
57
- if (!command.split) {
58
- process.exitCode = 255;
59
- console.log(constants_js_1.APP_PREFIX, `No command provided. Use -c option to launch a test runner.`);
60
- return;
28
+ else if (arg.startsWith('--command=')) {
29
+ // Handle --command=value format
30
+ const command = arg.split('=', 2)[1];
31
+ newArgs.push(command);
61
32
  }
62
- const client = new client_js_1.default({ apiKey, title, parallel: true });
63
- if (filter) {
64
- const [pipe, ...optsArray] = filter.split(':');
65
- const pipeOptions = optsArray.join(':');
66
- try {
67
- const tests = await client.prepareRun({ pipe, pipeOptions });
68
- if (!tests || tests.length === 0) {
69
- return;
70
- }
71
- const grep = ` --grep (${tests.join('|')})`;
72
- command += grep;
73
- }
74
- catch (err) {
75
- console.log(constants_js_1.APP_PREFIX, err);
76
- }
33
+ else if (arg === '--launch') {
34
+ // Map --launch to start command
35
+ newArgs[0] = 'start';
77
36
  }
78
- const testCmds = command.split(' ');
79
- console.log(constants_js_1.APP_PREFIX, `🚀 Running`, picocolors_1.default.green(command));
80
- if (!apiKey) {
81
- const cmd = (0, cross_spawn_1.spawn)(testCmds[0], testCmds.slice(1), { stdio: 'inherit' });
82
- cmd.on('close', code => {
83
- console.log(constants_js_1.APP_PREFIX, '⚠️ ', `Runner exited with ${picocolors_1.default.bold(code)}, report is ignored`);
84
- if (code > exitCode)
85
- exitCode = code;
86
- process.exitCode = exitCode;
87
- });
88
- return;
37
+ else if (arg === '--finish') {
38
+ // Map --finish to finish command
39
+ newArgs[0] = 'finish';
89
40
  }
90
- client.createRun().then(() => {
91
- const cmd = (0, cross_spawn_1.spawn)(testCmds[0], testCmds.slice(1), { stdio: 'inherit' });
92
- cmd.on('close', code => {
93
- const emoji = code === 0 ? '🟢' : '🔴';
94
- console.log(constants_js_1.APP_PREFIX, emoji, `Runner exited with ${picocolors_1.default.bold(code)}`);
95
- const status = code === 0 ? 'passed' : 'failed';
96
- client.updateRunStatus(status, true);
97
- if (code > exitCode)
98
- exitCode = code;
99
- process.exitCode = exitCode;
100
- });
101
- });
102
- });
103
- if (process.argv.length <= 2) {
104
- program.outputHelp();
41
+ else {
42
+ // Pass through other arguments
43
+ newArgs.push(arg);
44
+ }
45
+ i++;
105
46
  }
106
- program.parse(process.argv);
47
+ // Execute the main CLI with mapped arguments
48
+ const child = (0, node_child_process_1.spawn)(process.execPath, [cliPath, ...newArgs], {
49
+ stdio: 'inherit'
50
+ });
51
+ child.on('exit', (code) => {
52
+ process.exit(code);
53
+ });
package/lib/client.d.ts CHANGED
@@ -58,10 +58,9 @@ export class Client {
58
58
  * Updates the status of the current test run and finishes the run.
59
59
  * @param {'passed' | 'failed' | 'skipped' | 'finished'} status - The status of the current test run.
60
60
  * Must be one of "passed", "failed", or "finished"
61
- * @param {boolean} [isParallel] - Whether the current test run was executed in parallel with other tests.
62
61
  * @returns {Promise<any>} - A Promise that resolves when finishes the run.
63
62
  */
64
- updateRunStatus(status: "passed" | "failed" | "skipped" | "finished", isParallel?: boolean): Promise<any>;
63
+ updateRunStatus(status: "passed" | "failed" | "skipped" | "finished"): Promise<any>;
65
64
  /**
66
65
  * Returns the formatted stack including the stack trace, steps, and logs.
67
66
  * @returns {string}
package/lib/client.js CHANGED
@@ -50,6 +50,7 @@ const path_1 = __importStar(require("path"));
50
50
  const node_url_1 = require("node:url");
51
51
  const uploader_js_1 = require("./uploader.js");
52
52
  const utils_js_1 = require("./utils/utils.js");
53
+ const links_js_1 = require("./services/links.js");
53
54
  const filesize_1 = require("filesize");
54
55
  const debug = (0, debug_1.default)('@testomatio/reporter:client');
55
56
  // removed __dirname usage, because:
@@ -181,7 +182,7 @@ class Client {
181
182
  /**
182
183
  * @type {TestData}
183
184
  */
184
- const { rid, error = null, time = 0, example = null, files = [], filesBuffers = [], steps, code = null, title, file, suite_title, suite_id, test_id, timestamp, manuallyAttachedArtifacts, labels, overwrite, } = testData;
185
+ const { rid, error = null, time = 0, example = null, files = [], filesBuffers = [], steps, code = null, title, file, suite_title, suite_id, test_id, timestamp, manuallyAttachedArtifacts, overwrite, } = testData;
185
186
  let { message = '', meta = {} } = testData;
186
187
  // stringify meta values and limit keys and values length to 255
187
188
  meta = Object.entries(meta)
@@ -220,7 +221,9 @@ class Client {
220
221
  acc[key] = value;
221
222
  return acc;
222
223
  }, {});
223
- // Labels are simple array of strings, no processing needed
224
+ // Get links from storage using the test context
225
+ const testContext = suite_title ? `${suite_title} ${title}` : title;
226
+ const links = links_js_1.linkStorage.get(testContext) || [];
224
227
  let errorFormatted = '';
225
228
  if (error) {
226
229
  errorFormatted += this.formatError(error) || '';
@@ -268,7 +271,7 @@ class Client {
268
271
  timestamp,
269
272
  artifacts,
270
273
  meta,
271
- labels,
274
+ links,
272
275
  overwrite,
273
276
  ...(rootSuiteId && { root_suite_id: rootSuiteId }),
274
277
  };
@@ -291,17 +294,16 @@ class Client {
291
294
  * Updates the status of the current test run and finishes the run.
292
295
  * @param {'passed' | 'failed' | 'skipped' | 'finished'} status - The status of the current test run.
293
296
  * Must be one of "passed", "failed", or "finished"
294
- * @param {boolean} [isParallel] - Whether the current test run was executed in parallel with other tests.
295
297
  * @returns {Promise<any>} - A Promise that resolves when finishes the run.
296
298
  */
297
- async updateRunStatus(status, isParallel = false) {
299
+ async updateRunStatus(status) {
298
300
  this.pipes ||= await (0, index_js_1.pipesFactory)(this.paramsForPipesFactory || {}, this.pipeStore);
299
301
  this.runId ||= (0, utils_js_1.readLatestRunId)();
300
302
  debug('Updating run status...');
301
303
  // all pipes disabled, skipping
302
304
  if (!this.pipes?.filter(p => p.isEnabled).length)
303
305
  return Promise.resolve();
304
- const runParams = { status, parallel: isParallel };
306
+ const runParams = { status };
305
307
  this.queue = this.queue
306
308
  .then(() => Promise.all(this.pipes.map(p => p.finishRun(runParams))))
307
309
  .then(() => {
@@ -12,22 +12,22 @@ declare class DataStorage {
12
12
  /**
13
13
  * Puts any data to storage (file or global variable).
14
14
  * If file: stores data as text, if global variable – stores as array of data.
15
- * @param {'log' | 'artifact' | 'keyvalue' | 'labels'} dataType
15
+ * @param {'log' | 'artifact' | 'keyvalue' | 'links'} dataType
16
16
  * @param {*} data anything you want to store (string, object, array, etc)
17
17
  * @param {*} context could be testId or any context (test name, suite name, including their IDs etc)
18
18
  * suite name + test name is used by default
19
19
  * @returns
20
20
  */
21
- putData(dataType: "log" | "artifact" | "keyvalue" | "labels", data: any, context?: any): void;
21
+ putData(dataType: "log" | "artifact" | "keyvalue" | "links", data: any, context?: any): void;
22
22
  /**
23
23
  * Returns data, stored for specific test/context (or data which was stored without test id specified).
24
24
  * This method will get data from global variable and/or from from file (previosly saved with put method).
25
25
  *
26
- * @param {'log' | 'artifact' | 'keyvalue' | 'labels'} dataType
26
+ * @param {'log' | 'artifact' | 'keyvalue' | 'links'} dataType
27
27
  * @param {string} context
28
28
  * @returns {any []} array of data (any type), null (if no data found for context) or string (if data type is log)
29
29
  */
30
- getData(dataType: "log" | "artifact" | "keyvalue" | "labels", context: string): any[];
30
+ getData(dataType: "log" | "artifact" | "keyvalue" | "links", context: string): any[];
31
31
  #private;
32
32
  }
33
33
  export function stringToMD5Hash(str: any): string;
@@ -45,7 +45,6 @@ const os_1 = __importDefault(require("os"));
45
45
  const constants_js_1 = require("./constants.js");
46
46
  const utils_js_1 = require("./utils/utils.js");
47
47
  const crypto_1 = __importDefault(require("crypto"));
48
- const startTime = Date.now();
49
48
  const debug = (0, debug_1.default)('@testomatio/reporter:storage');
50
49
  class DataStorage {
51
50
  static #instance;
@@ -76,7 +75,7 @@ class DataStorage {
76
75
  /**
77
76
  * Puts any data to storage (file or global variable).
78
77
  * If file: stores data as text, if global variable – stores as array of data.
79
- * @param {'log' | 'artifact' | 'keyvalue' | 'labels'} dataType
78
+ * @param {'log' | 'artifact' | 'keyvalue' | 'links'} dataType
80
79
  * @param {*} data anything you want to store (string, object, array, etc)
81
80
  * @param {*} context could be testId or any context (test name, suite name, including their IDs etc)
82
81
  * suite name + test name is used by default
@@ -104,7 +103,7 @@ class DataStorage {
104
103
  * Returns data, stored for specific test/context (or data which was stored without test id specified).
105
104
  * This method will get data from global variable and/or from from file (previosly saved with put method).
106
105
  *
107
- * @param {'log' | 'artifact' | 'keyvalue' | 'labels'} dataType
106
+ * @param {'log' | 'artifact' | 'keyvalue' | 'links'} dataType
108
107
  * @param {string} context
109
108
  * @returns {any []} array of data (any type), null (if no data found for context) or string (if data type is log)
110
109
  */
@@ -135,7 +134,7 @@ class DataStorage {
135
134
  return null;
136
135
  }
137
136
  /**
138
- * @param {'log' | 'artifact' | 'keyvalue' | 'labels'} dataType
137
+ * @param {'log' | 'artifact' | 'keyvalue' | 'links'} dataType
139
138
  * @param {string} context
140
139
  * @returns aray of data (any type)
141
140
  */
@@ -155,7 +154,7 @@ class DataStorage {
155
154
  }
156
155
  }
157
156
  /**
158
- * @param {'log' | 'artifact' | 'keyvalue' | 'labels'} dataType
157
+ * @param {'log' | 'artifact' | 'keyvalue' | 'links'} dataType
159
158
  * @param {*} context
160
159
  * @returns array of data (any type)
161
160
  */
@@ -180,7 +179,7 @@ class DataStorage {
180
179
  }
181
180
  /**
182
181
  * Puts data to global variable. Unlike the file storage, stores data in array (file storage just append as string).
183
- * @param {'log' | 'artifact' | 'keyvalue' | 'labels'} dataType
182
+ * @param {'log' | 'artifact' | 'keyvalue' | 'links'} dataType
184
183
  * @param {*} data
185
184
  * @param {*} context
186
185
  */
@@ -196,7 +195,7 @@ class DataStorage {
196
195
  }
197
196
  /**
198
197
  * Puts data to file. Unlike the global variable storage, stores data as string
199
- * @param {'log' | 'artifact' | 'keyvalue' | 'labels'} dataType
198
+ * @param {'log' | 'artifact' | 'keyvalue' | 'links'} dataType
200
199
  * @param {*} data
201
200
  * @param {string} context
202
201
  * @returns
@@ -223,7 +222,7 @@ function stringToMD5Hash(str) {
223
222
  const md5 = crypto_1.default.createHash('md5');
224
223
  md5.update(str);
225
224
  const hash = md5.digest('hex');
226
- return `${startTime}_${hash}`;
225
+ return hash;
227
226
  }
228
227
  exports.dataStorage = DataStorage.getInstance();
229
228
  // TODO: consider using fs promises instead of writeSync/appendFileSync to
@@ -23,7 +23,6 @@ declare class TestomatioPipe implements Pipe {
23
23
  isEnabled: boolean;
24
24
  url: any;
25
25
  apiKey: any;
26
- parallel: any;
27
26
  store: any;
28
27
  title: any;
29
28
  sharedRun: boolean;
@@ -43,7 +43,6 @@ class TestomatioPipe {
43
43
  debug('Testomatio Pipe: Enabled');
44
44
  const proxyUrl = process.env.HTTP_PROXY || process.env.HTTPS_PROXY;
45
45
  const proxy = proxyUrl ? new URL(proxyUrl) : null;
46
- this.parallel = params.parallel;
47
46
  this.store = store || {};
48
47
  this.title = params.title || process.env.TESTOMATIO_TITLE;
49
48
  this.sharedRun = !!process.env.TESTOMATIO_SHARED_RUN;
@@ -113,8 +112,7 @@ class TestomatioPipe {
113
112
  const resp = await this.client.request({
114
113
  method: 'GET',
115
114
  url: '/api/test_grep',
116
- params: q.params,
117
- responseType: q.responseType
115
+ ...q,
118
116
  });
119
117
  if (Array.isArray(resp.data?.tests) && resp.data?.tests?.length > 0) {
120
118
  (0, utils_js_1.foundedTestLog)(constants_js_1.APP_PREFIX, resp.data.tests);
@@ -155,7 +153,6 @@ class TestomatioPipe {
155
153
  const accessEvent = process.env.TESTOMATIO_PUBLISH ? 'publish' : null;
156
154
  const runParams = Object.fromEntries(Object.entries({
157
155
  ci_build_url: buildUrl,
158
- parallel: this.parallel,
159
156
  api_key: this.apiKey.trim(),
160
157
  group_title: this.groupTitle,
161
158
  access_event: accessEvent,
@@ -173,7 +170,8 @@ class TestomatioPipe {
173
170
  const resp = await this.client.request({
174
171
  method: 'PUT',
175
172
  url: `/api/reporter/${this.runId}`,
176
- data: runParams
173
+ data: runParams,
174
+ responseType: 'json'
177
175
  });
178
176
  if (resp.data.artifacts)
179
177
  (0, pipe_utils_js_1.setS3Credentials)(resp.data.artifacts);
@@ -377,7 +375,7 @@ class TestomatioPipe {
377
375
  const errorMessage = picocolors_1.default.red(`⚠️ Due to request failures, ${this.notReportedTestsCount} test(s) were not reported to Testomat.io`);
378
376
  console.warn(`${constants_js_1.APP_PREFIX} ${errorMessage}`);
379
377
  }
380
- const { status, parallel } = params;
378
+ const { status } = params;
381
379
  let status_event;
382
380
  if (status === constants_js_1.STATUS.FINISHED)
383
381
  status_event = 'finish';
@@ -385,8 +383,6 @@ class TestomatioPipe {
385
383
  status_event = 'pass';
386
384
  if (status === constants_js_1.STATUS.FAILED)
387
385
  status_event = 'fail';
388
- if (parallel)
389
- status_event += '_parallel';
390
386
  try {
391
387
  if (this.runId && !this.proceed) {
392
388
  await this.client.request({
package/lib/replay.js CHANGED
@@ -238,7 +238,7 @@ class Replay {
238
238
  });
239
239
  }
240
240
  }
241
- await client.updateRunStatus(finishParams.status || constants_js_1.STATUS.FINISHED, finishParams.parallel || false);
241
+ await client.updateRunStatus(finishParams.status || constants_js_1.STATUS.FINISHED);
242
242
  const result = {
243
243
  success: true,
244
244
  testsCount: tests.length,
@@ -4,11 +4,14 @@ declare namespace _default {
4
4
  export { addStep as step };
5
5
  export { setKeyValue as keyValue };
6
6
  export { setLabel as label };
7
+ export { linkTest };
7
8
  }
8
9
  export default _default;
9
10
  /**
10
11
  * Stores path to file as artifact and uploads it to the S3 storage
11
12
  * @param {string | {path: string, type: string, name: string}} data - path to file or object with path, type and name
13
+ * @param {any} [context=null] - optional context parameter
14
+ * @returns {void}
12
15
  */
13
16
  declare function saveArtifact(data: string | {
14
17
  path: string;
@@ -17,25 +20,35 @@ declare function saveArtifact(data: string | {
17
20
  }, context?: any): void;
18
21
  /**
19
22
  * Attach log message(s) to the test report
20
- * @param string
23
+ * @param {...any} args - log messages to attach
24
+ * @returns {void}
21
25
  */
22
26
  declare function logMessage(...args: any[]): void;
23
27
  /**
24
28
  * Similar to "log" function but marks message in report as a step
25
- * @param {string} message
29
+ * @param {string} message - step message
30
+ * @returns {void}
26
31
  */
27
32
  declare function addStep(message: string): void;
28
33
  /**
29
34
  * Add key-value pair(s) to the test report
30
- * @param {{[key: string]: string} | string} keyValue object { key: value } (multiple props allowed) or key (string)
31
- * @param {string?} value
35
+ * @param {{[key: string]: string} | string} keyValue - object { key: value } (multiple props allowed) or key (string)
36
+ * @param {string|null} [value=null] - optional value when keyValue is a string
37
+ * @returns {void}
32
38
  */
33
39
  declare function setKeyValue(keyValue: {
34
40
  [key: string]: string;
35
41
  } | string, value?: string | null): void;
36
42
  /**
37
- * Add a single label to the test report
43
+ * Add label(s) to the test report
38
44
  * @param {string} key - label key (e.g. 'severity', 'feature', or just 'smoke' for labels without values)
39
- * @param {string} [value] - optional label value (e.g. 'high', 'login')
45
+ * @param {string|string[]|null} [value=null] - optional label value(s) (e.g. 'high', 'login') or array of values
46
+ * @returns {void}
40
47
  */
41
- declare function setLabel(key: string, value?: string): void;
48
+ declare function setLabel(key: string, value?: string | string[] | null): void;
49
+ /**
50
+ * Add link(s) to the test report
51
+ * @param {...string} testIds - test IDs to link
52
+ * @returns {void}
53
+ */
54
+ declare function linkTest(...testIds: string[]): void;