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

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@testomatio/reporter",
3
- "version": "2.1.2-beta.1-alias",
3
+ "version": "2.1.3-beta.1-multi-links",
4
4
  "description": "Testomatio Reporter Client",
5
5
  "engines": {
6
6
  "node": ">=18"
@@ -56,20 +56,19 @@ function CodeceptReporter(config) {
56
56
 
57
57
  output.debug = function(msg) {
58
58
  originalOutput.debug(msg);
59
- dataStorage.putData('log', repeat(this?.stepShift || 0) + pc.cyan(msg.toString()));
59
+ dataStorage.putData('log', repeat(this.stepShift) + 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 || 0) + ` ${pc.bold(pc[color](message))}`;
64
+ const sayMsg = repeat(this.stepShift) + ` ${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 || 0) + pc.gray(msg));
70
+ dataStorage.putData('log', repeat(this.stepShift) + pc.gray(msg));
71
71
  };
72
- output.stepShift = 0;
73
72
 
74
73
  recorder.startUnlessRunning();
75
74
 
@@ -1,53 +1,124 @@
1
1
  #!/usr/bin/env node
2
- import { spawn } from 'node:child_process';
3
- import { join, dirname } from 'node:path';
4
- import { getPackageVersion } from '../utils/utils.js';
2
+ import { spawn } from 'cross-spawn';
3
+ import { Command } from 'commander';
5
4
  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');
5
+ import TestomatClient from '../client.js';
6
+ import { APP_PREFIX, STATUS } from '../constants.js';
7
+ import { getPackageVersion } from '../utils/utils.js';
8
+ import { config } from '../config.js';
9
+ import dotenv from 'dotenv';
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;
13
24
 
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]);
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
+
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;
59
+ }
60
+
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;
27
67
  }
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
- }
44
68
 
45
- // Execute the main CLI with mapped arguments
69
+ const client = new TestomatClient({ apiKey, title, parallel: true });
46
70
 
47
- const child = spawn(process.execPath, [cliPath, ...newArgs], {
48
- stdio: 'inherit'
49
- });
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
+ });
119
+
120
+ if (process.argv.length <= 2) {
121
+ program.outputHelp();
122
+ }
50
123
 
51
- child.on('exit', (code) => {
52
- process.exit(code);
53
- });
124
+ program.parse(process.argv);
@@ -119,7 +119,8 @@ class TestomatioPipe {
119
119
  const resp = await this.client.request({
120
120
  method: 'GET',
121
121
  url: '/api/test_grep',
122
- ...q,
122
+ params: q.params,
123
+ responseType: q.responseType
123
124
  });
124
125
 
125
126
  if (Array.isArray(resp.data?.tests) && resp.data?.tests?.length > 0) {
@@ -3,8 +3,6 @@ import { services } from './services/index.js';
3
3
  /**
4
4
  * Stores path to file as artifact and uploads it to the S3 storage
5
5
  * @param {string | {path: string, type: string, name: string}} data - path to file or object with path, type and name
6
- * @param {any} [context=null] - optional context parameter
7
- * @returns {void}
8
6
  */
9
7
  function saveArtifact(data, context = null) {
10
8
  if (process.env.IS_PLAYWRIGHT)
@@ -16,8 +14,7 @@ function saveArtifact(data, context = null) {
16
14
 
17
15
  /**
18
16
  * Attach log message(s) to the test report
19
- * @param {...any} args - log messages to attach
20
- * @returns {void}
17
+ * @param string
21
18
  */
22
19
  function logMessage(...args) {
23
20
  if (process.env.IS_PLAYWRIGHT) throw new Error('This function is not available in Playwright framework');
@@ -26,8 +23,7 @@ function logMessage(...args) {
26
23
 
27
24
  /**
28
25
  * Similar to "log" function but marks message in report as a step
29
- * @param {string} message - step message
30
- * @returns {void}
26
+ * @param {string} message
31
27
  */
32
28
  function addStep(message) {
33
29
  if (process.env.IS_PLAYWRIGHT)
@@ -38,9 +34,8 @@ function addStep(message) {
38
34
 
39
35
  /**
40
36
  * Add key-value pair(s) to the test report
41
- * @param {{[key: string]: string} | string} keyValue - object { key: value } (multiple props allowed) or key (string)
42
- * @param {string|null} [value=null] - optional value when keyValue is a string
43
- * @returns {void}
37
+ * @param {{[key: string]: string} | string} keyValue object { key: value } (multiple props allowed) or key (string)
38
+ * @param {string?} value
44
39
  */
45
40
  function setKeyValue(keyValue, value = null) {
46
41
  if (process.env.IS_PLAYWRIGHT)
@@ -55,10 +50,14 @@ function setKeyValue(keyValue, value = null) {
55
50
  /**
56
51
  * Add a single label to the test report
57
52
  * @param {string} key - label key (e.g. 'severity', 'feature', or just 'smoke' for labels without values)
58
- * @param {string|null} [value=null] - optional label value (e.g. 'high', 'login')
59
- * @returns {void}
53
+ * @param {string} [value] - optional label value (e.g. 'high', 'login')
60
54
  */
61
55
  function setLabel(key, value = null) {
56
+ if (Array.isArray(value)) {
57
+ value.forEach(v => setLabel(key, v));
58
+ return;
59
+ }
60
+
62
61
  if (!key || typeof key !== 'string') {
63
62
  console.warn('Label key must be a non-empty string');
64
63
  return;
package/src/reporter.js CHANGED
@@ -11,12 +11,12 @@ export const step = reporterFunctions.step;
11
11
  export const label = reporterFunctions.label;
12
12
 
13
13
  /**
14
- * @typedef {typeof import('./reporter-functions.js').default.artifact} ArtifactFunction
15
- * @typedef {typeof import('./reporter-functions.js').default.log} LogFunction
16
- * @typedef {typeof import('./services/index.js').services.logger} LoggerService
17
- * @typedef {typeof import('./reporter-functions.js').default.keyValue} MetaFunction
18
- * @typedef {typeof import('./reporter-functions.js').default.step} StepFunction
19
- * @typedef {typeof import('./reporter-functions.js').default.label} LabelFunction
14
+ * @typedef {import('./reporter-functions.js')} artifact
15
+ * @typedef {import('./reporter-functions.js')} log
16
+ * @typedef {import('./services/index.js')} logger
17
+ * @typedef {import('./reporter-functions.js')} meta
18
+ * @typedef {import('./reporter-functions.js')} step
19
+ * @typedef {import('./reporter-functions.js')} label
20
20
  */
21
21
  export default {
22
22
  /**