@testomatio/reporter 2.3.9 → 2.5.0

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.
@@ -28,9 +28,15 @@ declare function logMessage(...args: any[]): void;
28
28
  /**
29
29
  * Similar to "log" function but marks message in report as a step
30
30
  * @param {string} message - step message
31
+ * @param {{[key: string]: any}} [logs] optional key-value object with additional info, e.g. logs
31
32
  * @returns {void}
33
+ *
34
+ * Example:
35
+ * step('Get response', { logs: {status: 'success'} });
32
36
  */
33
- declare function addStep(message: string): void;
37
+ declare function addStep(message: string, logs?: {
38
+ [key: string]: any;
39
+ }): void;
34
40
  /**
35
41
  * Add key-value pair(s) to the test report
36
42
  * @param {{[key: string]: string} | string} keyValue - object { key: value } (multiple props allowed) or key (string)
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ const helpers_js_1 = require("./helpers.js");
3
4
  const index_js_1 = require("./services/index.js");
4
5
  /**
5
6
  * Stores path to file as artifact and uploads it to the S3 storage
@@ -8,9 +9,7 @@ const index_js_1 = require("./services/index.js");
8
9
  * @returns {void}
9
10
  */
10
11
  function saveArtifact(data, context = null) {
11
- if (process.env.IS_PLAYWRIGHT)
12
- throw new Error(`This function is not available in Playwright framework.
13
- /Playwright supports artifacts out of the box`);
12
+ showPlaywrightWarning('artifact', 'Playwright supports artifacts out of the box.');
14
13
  if (!data)
15
14
  return;
16
15
  index_js_1.services.artifacts.put(data, context);
@@ -21,19 +20,25 @@ function saveArtifact(data, context = null) {
21
20
  * @returns {void}
22
21
  */
23
22
  function logMessage(...args) {
24
- if (process.env.IS_PLAYWRIGHT)
25
- throw new Error('This function is not available in Playwright framework');
26
23
  index_js_1.services.logger._templateLiteralLog(...args);
27
24
  }
28
25
  /**
29
26
  * Similar to "log" function but marks message in report as a step
30
27
  * @param {string} message - step message
28
+ * @param {{[key: string]: any}} [logs] optional key-value object with additional info, e.g. logs
31
29
  * @returns {void}
30
+ *
31
+ * Example:
32
+ * step('Get response', { logs: {status: 'success'} });
32
33
  */
33
- function addStep(message) {
34
- if (process.env.IS_PLAYWRIGHT)
35
- throw new Error('This function is not available in Playwright framework. Use playwright steps');
36
- index_js_1.services.logger.step(message);
34
+ function addStep(message, logs) {
35
+ // this is done because Playwright reporter intercepts console logs and then we gather them and show on Testomat
36
+ // if not console.log, the step message will be lost from reporter
37
+ if (helpers_js_1.isPlaywright)
38
+ index_js_1.services.logger._templateLiteralLog(message, logs);
39
+ // all other frameworks
40
+ else
41
+ index_js_1.services.logger.step(message, logs);
37
42
  }
38
43
  /**
39
44
  * Add key-value pair(s) to the test report
@@ -42,8 +47,7 @@ function addStep(message) {
42
47
  * @returns {void}
43
48
  */
44
49
  function setKeyValue(keyValue, value = null) {
45
- if (process.env.IS_PLAYWRIGHT)
46
- throw new Error('This function is not available in Playwright framework. Use test tag instead.');
50
+ showPlaywrightWarning('meta', 'Use test annotations instead.');
47
51
  if (typeof keyValue === 'string') {
48
52
  keyValue = { [keyValue]: value };
49
53
  }
@@ -56,6 +60,7 @@ function setKeyValue(keyValue, value = null) {
56
60
  * @returns {void}
57
61
  */
58
62
  function setLabel(key, value = null) {
63
+ showPlaywrightWarning('label', 'Use test tag instead.');
59
64
  if (Array.isArray(value)) {
60
65
  return value.forEach(label => setLabel(key, label));
61
66
  }
@@ -80,6 +85,11 @@ function linkJira(...jiraIds) {
80
85
  const links = jiraIds.map(jiraId => ({ jira: jiraId }));
81
86
  index_js_1.services.links.put(links);
82
87
  }
88
+ function showPlaywrightWarning(functionName, recommendation) {
89
+ if (helpers_js_1.isPlaywright) {
90
+ console.warn(`[TESTOMATIO] '${functionName}' function is not supported for Playwright. ${recommendation}`);
91
+ }
92
+ }
83
93
  module.exports = {
84
94
  artifact: saveArtifact,
85
95
  log: logMessage,
package/lib/reporter.d.ts CHANGED
@@ -12,7 +12,7 @@ export const artifact: (data: string | {
12
12
  }, context?: any) => void;
13
13
  export const log: (...args: any[]) => void;
14
14
  export const logger: {
15
- "__#13@#originalUserLogger": {
15
+ "__#14@#originalUserLogger": {
16
16
  assert(condition?: boolean, ...data: any[]): void;
17
17
  assert(value: any, message?: string, ...optionalParams: any[]): void;
18
18
  clear(): void;
@@ -57,13 +57,14 @@ export const logger: {
57
57
  profile(label?: string): void;
58
58
  profileEnd(label?: string): void;
59
59
  };
60
- "__#13@#userLoggerWithOverridenMethods": any;
60
+ "__#14@#userLoggerWithOverridenMethods": any;
61
61
  logLevel: string;
62
62
  step(strings: any, ...values: any[]): void;
63
63
  getLogs(context: string): string[];
64
- "__#13@#stringifyLogs"(...args: any[]): string;
64
+ "__#14@#stringifyLogs"(...args: any[]): string;
65
+ "__#14@#formatMessage"(strings: any, ...args: any[]): string;
65
66
  _templateLiteralLog(strings: any, ...args: any[]): void;
66
- "__#13@#logWrapper"(argsArray: any, level: any): void;
67
+ "__#14@#logWrapper"(argsArray: any, level: any): void;
67
68
  assert(...args: any[]): void;
68
69
  debug(...args: any[]): void;
69
70
  error(...args: any[]): void;
@@ -82,13 +83,15 @@ export const logger: {
82
83
  export const meta: (keyValue: {
83
84
  [key: string]: string;
84
85
  } | string, value?: string | null) => void;
85
- export const step: (message: string) => void;
86
+ export const step: (message: string, logs?: {
87
+ [key: string]: any;
88
+ }) => void;
86
89
  export const label: (key: string, value?: string | null) => void;
87
90
  export const linkTest: (...testIds: string[]) => void;
88
91
  export const linkJira: (...jiraIds: string[]) => void;
89
92
  declare namespace _default {
90
93
  export let testomatioLogger: {
91
- "__#13@#originalUserLogger": {
94
+ "__#14@#originalUserLogger": {
92
95
  assert(condition?: boolean, ...data: any[]): void;
93
96
  assert(value: any, message?: string, ...optionalParams: any[]): void;
94
97
  clear(): void;
@@ -133,13 +136,14 @@ declare namespace _default {
133
136
  profile(label?: string): void;
134
137
  profileEnd(label?: string): void;
135
138
  };
136
- "__#13@#userLoggerWithOverridenMethods": any;
139
+ "__#14@#userLoggerWithOverridenMethods": any;
137
140
  logLevel: string;
138
141
  step(strings: any, ...values: any[]): void;
139
142
  getLogs(context: string): string[];
140
- "__#13@#stringifyLogs"(...args: any[]): string;
143
+ "__#14@#stringifyLogs"(...args: any[]): string;
144
+ "__#14@#formatMessage"(strings: any, ...args: any[]): string;
141
145
  _templateLiteralLog(strings: any, ...args: any[]): void;
142
- "__#13@#logWrapper"(argsArray: any, level: any): void;
146
+ "__#14@#logWrapper"(argsArray: any, level: any): void;
143
147
  assert(...args: any[]): void;
144
148
  debug(...args: any[]): void;
145
149
  error(...args: any[]): void;
@@ -162,7 +166,7 @@ declare namespace _default {
162
166
  }, context?: any) => void;
163
167
  export let log: (...args: any[]) => void;
164
168
  export let logger: {
165
- "__#13@#originalUserLogger": {
169
+ "__#14@#originalUserLogger": {
166
170
  assert(condition?: boolean, ...data: any[]): void;
167
171
  assert(value: any, message?: string, ...optionalParams: any[]): void;
168
172
  clear(): void;
@@ -207,13 +211,14 @@ declare namespace _default {
207
211
  profile(label?: string): void;
208
212
  profileEnd(label?: string): void;
209
213
  };
210
- "__#13@#userLoggerWithOverridenMethods": any;
214
+ "__#14@#userLoggerWithOverridenMethods": any;
211
215
  logLevel: string;
212
216
  step(strings: any, ...values: any[]): void;
213
217
  getLogs(context: string): string[];
214
- "__#13@#stringifyLogs"(...args: any[]): string;
218
+ "__#14@#stringifyLogs"(...args: any[]): string;
219
+ "__#14@#formatMessage"(strings: any, ...args: any[]): string;
215
220
  _templateLiteralLog(strings: any, ...args: any[]): void;
216
- "__#13@#logWrapper"(argsArray: any, level: any): void;
221
+ "__#14@#logWrapper"(argsArray: any, level: any): void;
217
222
  assert(...args: any[]): void;
218
223
  debug(...args: any[]): void;
219
224
  error(...args: any[]): void;
@@ -232,7 +237,9 @@ declare namespace _default {
232
237
  export let meta: (keyValue: {
233
238
  [key: string]: string;
234
239
  } | string, value?: string | null) => void;
235
- export let step: (message: string) => void;
240
+ export let step: (message: string, logs?: {
241
+ [key: string]: any;
242
+ }) => void;
236
243
  export let label: (key: string, value?: string | null) => void;
237
244
  export let linkTest: (...testIds: string[]) => void;
238
245
  export let linkJira: (...jiraIds: string[]) => 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 "__#14@#instance": any;
6
+ static "__#15@#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 "__#15@#instance": any;
3
+ static "__#16@#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 "__#16@#instance": any;
3
+ static "__#17@#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 "__#13@#instance": any;
8
+ static "__#14@#instance": any;
9
9
  /**
10
10
  *
11
11
  * @returns {Logger}
@@ -26,8 +26,8 @@ declare class Logger {
26
26
  */
27
27
  getLogs(context: string): string[];
28
28
  /**
29
- * Tagget template literal. Allows to use different syntaxes:
30
- * 1. Tagget template: log`text ${someVar}`
29
+ * Tagged template literal. Allows to use different syntaxes:
30
+ * 1. Tagged template: log`text ${someVar}`
31
31
  * 2. Standard: log(`text ${someVar}`)
32
32
  * 3. Standard with multiple arguments: log('text', someVar)
33
33
  */
@@ -54,14 +54,10 @@ class Logger {
54
54
  * @param {...any} values
55
55
  */
56
56
  step(strings, ...values) {
57
- let logs = '';
58
- for (let i = 0; i < strings.length; i++) {
59
- logs += strings[i];
60
- if (i < values.length) {
61
- logs += values[i];
62
- }
63
- }
64
- logs = picocolors_1.default.blue(`> ${logs}`);
57
+ // Filter trailing undefined from optional params (e.g., step('message') called without second arg)
58
+ const filteredValues = values.filter(v => v !== undefined);
59
+ const message = this.#formatMessage(strings, ...filteredValues);
60
+ const logs = picocolors_1.default.blue(`> ${message}`);
65
61
  data_storage_js_1.dataStorage.putData('log', logs);
66
62
  }
67
63
  /**
@@ -82,7 +78,13 @@ class Logger {
82
78
  // ignore empty strings
83
79
  if (arg === '')
84
80
  continue;
85
- if (typeof arg === 'string') {
81
+ if (arg === undefined) {
82
+ logs.push('undefined');
83
+ }
84
+ else if (arg === null) {
85
+ logs.push('null');
86
+ }
87
+ else if (typeof arg === 'string') {
86
88
  logs.push(arg);
87
89
  }
88
90
  else if (Array.isArray(arg)) {
@@ -101,36 +103,37 @@ class Logger {
101
103
  return logs.join(' ');
102
104
  }
103
105
  /**
104
- * Tagget template literal. Allows to use different syntaxes:
105
- * 1. Tagget template: log`text ${someVar}`
106
- * 2. Standard: log(`text ${someVar}`)
107
- * 3. Standard with multiple arguments: log('text', someVar)
106
+ * Formats a message from either tagged template literal or standard function call.
107
+ * @param {*} strings - Template strings array or first argument
108
+ * @param {...any} args - Template values or additional arguments
109
+ * @returns {string} Formatted message
108
110
  */
109
- _templateLiteralLog(strings, ...args) {
110
- if (Array.isArray(strings))
111
- strings = strings.filter(item => item !== '').map(item => item.trim());
111
+ #formatMessage(strings, ...args) {
112
112
  if (Array.isArray(args))
113
113
  args = args.filter(item => item !== '');
114
- let logs;
115
- // this block means tagged template is used (syntax like $`text ${someVar}`)
114
+ // Tagged template syntax: func`text ${someVar}`
116
115
  if (Array.isArray(strings) && strings.length === args.length + 1) {
117
- logs = strings.reduce((result, current, index) => result +
116
+ return strings.reduce((result, current, index) => result +
118
117
  current +
119
- // strings are splitted by args when use tagged template, thus we add arg after each string
120
- // it looks like: `string1 arg1 string2 arg2 string3`
121
- (args[index] !== undefined
122
- ? typeof args[index] === 'string'
123
- ? args[index] // add arg as it is
124
- : this.#stringifyLogs(args[index]) // stringify arg
125
- : ''),
126
- // initial accumulator value
127
- '');
128
- }
129
- else {
130
- // this block means arguments syntax is used (syntax like $('text', someVar))
131
- // in this case strings represents just a first argument
132
- logs = this.#stringifyLogs(strings, ...args);
118
+ (index < args.length
119
+ ? args[index] === undefined
120
+ ? 'undefined'
121
+ : typeof args[index] === 'string'
122
+ ? args[index]
123
+ : this.#stringifyLogs(args[index])
124
+ : ''), '');
133
125
  }
126
+ // Standard function call: func('text', someVar)
127
+ return this.#stringifyLogs(strings, ...args);
128
+ }
129
+ /**
130
+ * Tagged template literal. Allows to use different syntaxes:
131
+ * 1. Tagged template: log`text ${someVar}`
132
+ * 2. Standard: log(`text ${someVar}`)
133
+ * 3. Standard with multiple arguments: log('text', someVar)
134
+ */
135
+ _templateLiteralLog(strings, ...args) {
136
+ const logs = this.#formatMessage(strings, ...args);
134
137
  this.#originalUserLogger.log(logs);
135
138
  data_storage_js_1.dataStorage.putData('log', logs);
136
139
  }
@@ -39,3 +39,18 @@ export function statusEmoji(status: string): string;
39
39
  * @returns {string} - A formatted full name string for the test object.
40
40
  */
41
41
  export function fullName(t: object): string;
42
+ /**
43
+ * Parses a comma-separated list of key-value pairs into an options object.
44
+ *
45
+ * The input string should be formatted as `"key1=value1,key2=value2,..."`.
46
+ * Whitespace around keys and values is trimmed. If the input is empty or undefined,
47
+ * an empty object is returned.
48
+ *
49
+ * @param {string} [optionsStr] - A comma-separated string of key=value pairs.
50
+ * @returns {Object} An object mapping option keys to their string values.
51
+ *
52
+ * @example
53
+ * parsePipeOptions('foo=bar,baz=qux');
54
+ * => Returns: { foo: 'bar', baz: 'qux' }
55
+ */
56
+ export function parsePipeOptions(optionsStr?: string): any;
@@ -6,6 +6,7 @@ exports.generateFilterRequestParams = generateFilterRequestParams;
6
6
  exports.setS3Credentials = setS3Credentials;
7
7
  exports.statusEmoji = statusEmoji;
8
8
  exports.fullName = fullName;
9
+ exports.parsePipeOptions = parsePipeOptions;
9
10
  const constants_js_1 = require("../constants.js");
10
11
  /**
11
12
  * Set S3 credentials from the provided artifacts object.
@@ -27,6 +28,8 @@ function setS3Credentials(artifacts) {
27
28
  process.env.S3_SESSION_TOKEN = artifacts.SESSION_TOKEN;
28
29
  if (artifacts.presign)
29
30
  process.env.TESTOMATIO_PRIVATE_ARTIFACTS = '1';
31
+ if (artifacts.stack_artifacts)
32
+ process.env.TESTOMATIO_STACK_ARTIFACTS = '1';
30
33
  // endpoint is not received from the server; and shuld be empty if IAM used (credentails obtained from the testomat)
31
34
  process.env.S3_ENDPOINT = artifacts.ENDPOINT || '';
32
35
  }
@@ -36,6 +39,11 @@ function setS3Credentials(artifacts) {
36
39
  * @returns {Object|null} - An object containing the generated request parameters, or null if the type is invalid.
37
40
  */
38
41
  function generateFilterRequestParams(params) {
42
+ // Defensive check: ensure params is an object
43
+ if (!params || typeof params !== 'object') {
44
+ console.error(constants_js_1.APP_PREFIX, `Invalid parameters provided. Expected an object, got: ${typeof params}`);
45
+ return;
46
+ }
39
47
  const { type, id, apiKey } = params;
40
48
  if (!type) {
41
49
  return;
@@ -60,8 +68,11 @@ function generateFilterRequestParams(params) {
60
68
  * The object has properties "type" and "id".
61
69
  */
62
70
  function parseFilterParams(opts) {
63
- const [type, id] = opts.split('=');
71
+ const [type, ...idParts] = opts.split('=');
72
+ const id = idParts.join('=');
64
73
  const validType = updateFilterType(type);
74
+ if (!validType)
75
+ return undefined;
65
76
  return {
66
77
  type: validType,
67
78
  id,
@@ -74,6 +85,8 @@ function parseFilterParams(opts) {
74
85
  * Returns undefined if the type is not valid.
75
86
  */
76
87
  function updateFilterType(type) {
88
+ if (!type || typeof type !== 'string')
89
+ return;
77
90
  let typeLowerCase = type.toLowerCase();
78
91
  const filterTypes = ['tag-name', 'plan', 'label', 'jira-ticket'];
79
92
  if (typeLowerCase === 'plan-id') {
@@ -87,7 +100,7 @@ function updateFilterType(type) {
87
100
  // "ims-issue", //TODO: WIP
88
101
  ];
89
102
  if (!filterTypes.includes(typeLowerCase)) {
90
- console.log(constants_js_1.APP_PREFIX, `❗❗❗ Invalid "filter=${type}" start settings! Available option list: ${filterTypes}`);
103
+ console.log(constants_js_1.APP_PREFIX, `❗❗❗ Invalid filter: "${type}" start settings! Available option list: ${filterTypes}`);
91
104
  return;
92
105
  }
93
106
  const index = filterTypes.indexOf(typeLowerCase);
@@ -121,6 +134,33 @@ function fullName(t) {
121
134
  line += ` \`[${Object.values(t.example)}]\``;
122
135
  return line;
123
136
  }
137
+ /**
138
+ * Parses a comma-separated list of key-value pairs into an options object.
139
+ *
140
+ * The input string should be formatted as `"key1=value1,key2=value2,..."`.
141
+ * Whitespace around keys and values is trimmed. If the input is empty or undefined,
142
+ * an empty object is returned.
143
+ *
144
+ * @param {string} [optionsStr] - A comma-separated string of key=value pairs.
145
+ * @returns {Object} An object mapping option keys to their string values.
146
+ *
147
+ * @example
148
+ * parsePipeOptions('foo=bar,baz=qux');
149
+ * => Returns: { foo: 'bar', baz: 'qux' }
150
+ */
151
+ function parsePipeOptions(optionsStr) {
152
+ const options = {};
153
+ if (!optionsStr)
154
+ return options;
155
+ const pairs = optionsStr.split(',');
156
+ for (const pair of pairs) {
157
+ const [key, value] = pair.split('=');
158
+ if (key && value) {
159
+ options[key.trim()] = value.trim();
160
+ }
161
+ }
162
+ return options;
163
+ }
124
164
 
125
165
  module.exports.updateFilterType = updateFilterType;
126
166
 
@@ -133,3 +173,5 @@ module.exports.setS3Credentials = setS3Credentials;
133
173
  module.exports.statusEmoji = statusEmoji;
134
174
 
135
175
  module.exports.fullName = fullName;
176
+
177
+ module.exports.parsePipeOptions = parsePipeOptions;
@@ -17,6 +17,11 @@ export namespace fileSystem {
17
17
  export function foundedTestLog(app: any, tests: any): void;
18
18
  export function formatStep(step: any, shift?: number): any;
19
19
  export function getCurrentDateTime(): string;
20
+ /**
21
+ * Gets current git commit SHA
22
+ * @returns {String|null} git commit SHA or null if not available
23
+ */
24
+ export function getGitCommitSha(): string | null;
20
25
  /**
21
26
  * @param {String} testTitle - Test title
22
27
  *
@@ -59,3 +64,4 @@ export function transformEnvVarToBoolean(value: any): boolean;
59
64
  * @returns {String|null} validated suite ID or null if invalid
60
65
  */
61
66
  export function validateSuiteId(suiteId: string): string | null;
67
+ export function applyFilter(command: any, tests: any): any;
@@ -36,7 +36,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
36
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
37
37
  };
38
38
  Object.defineProperty(exports, "__esModule", { value: true });
39
- exports.validateSuiteId = exports.testRunnerHelper = exports.specificTestInfo = exports.parseSuite = exports.isValidUrl = exports.humanize = exports.getTestomatIdFromTestTitle = exports.getCurrentDateTime = exports.foundedTestLog = exports.fileSystem = exports.fetchFilesFromStackTrace = exports.fetchIdFromOutput = exports.fetchIdFromCode = exports.fetchSourceCodeFromStackTrace = exports.fetchSourceCode = exports.isSameTest = exports.ansiRegExp = exports.SUITE_ID_REGEX = exports.TEST_ID_REGEX = void 0;
39
+ exports.validateSuiteId = exports.testRunnerHelper = exports.specificTestInfo = exports.parseSuite = exports.isValidUrl = exports.humanize = exports.getTestomatIdFromTestTitle = exports.getGitCommitSha = exports.getCurrentDateTime = exports.foundedTestLog = exports.fileSystem = exports.fetchFilesFromStackTrace = exports.fetchIdFromOutput = exports.fetchIdFromCode = exports.fetchSourceCodeFromStackTrace = exports.fetchSourceCode = exports.isSameTest = exports.ansiRegExp = exports.SUITE_ID_REGEX = exports.TEST_ID_REGEX = void 0;
40
40
  exports.getPackageVersion = getPackageVersion;
41
41
  exports.truncate = truncate;
42
42
  exports.cleanLatestRunId = cleanLatestRunId;
@@ -45,6 +45,7 @@ exports.readLatestRunId = readLatestRunId;
45
45
  exports.removeColorCodes = removeColorCodes;
46
46
  exports.storeRunId = storeRunId;
47
47
  exports.transformEnvVarToBoolean = transformEnvVarToBoolean;
48
+ exports.applyFilter = applyFilter;
48
49
  const url_1 = require("url");
49
50
  const path_1 = __importStar(require("path"));
50
51
  const picocolors_1 = __importDefault(require("picocolors"));
@@ -53,6 +54,7 @@ const is_valid_path_1 = __importDefault(require("is-valid-path"));
53
54
  const debug_1 = __importDefault(require("debug"));
54
55
  const os_1 = __importDefault(require("os"));
55
56
  const url_2 = require("url");
57
+ const child_process_1 = require("child_process");
56
58
  const debug = (0, debug_1.default)('@testomatio/reporter:util');
57
59
  // Use __dirname directly since we're compiling to CommonJS
58
60
  // prettier-ignore
@@ -98,6 +100,22 @@ const validateSuiteId = suiteId => {
98
100
  return match ? match[0] : null;
99
101
  };
100
102
  exports.validateSuiteId = validateSuiteId;
103
+ /**
104
+ * Gets current git commit SHA
105
+ * @returns {String|null} git commit SHA or null if not available
106
+ */
107
+ const getGitCommitSha = () => {
108
+ try {
109
+ const sha = (0, child_process_1.execSync)('git rev-parse --short HEAD', {
110
+ stdio: ['ignore', 'pipe', 'ignore']
111
+ }).toString().trim();
112
+ return sha || null;
113
+ }
114
+ catch (error) {
115
+ return null;
116
+ }
117
+ };
118
+ exports.getGitCommitSha = getGitCommitSha;
101
119
  const ansiRegExp = () => {
102
120
  const pattern = [
103
121
  '[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)',
@@ -641,6 +659,54 @@ function truncate(s, size = 255) {
641
659
  }
642
660
  return `${str.substring(0, size)}...`;
643
661
  }
662
+ function applyFilter(command, tests) {
663
+ if (!tests || !tests.length)
664
+ return command;
665
+ const lower = (command || '').toLowerCase();
666
+ const regexPattern = `(${tests.join('|')})`;
667
+ if (lower.includes('jest')) {
668
+ return `${command} --testNamePattern ${regexPattern}`;
669
+ }
670
+ if (lower.includes('cypress')) {
671
+ const grepValue = tests.join(',');
672
+ const baseEnv = {
673
+ grep: grepValue,
674
+ grepFilterSpecs: true,
675
+ grepOmitFiltered: true,
676
+ };
677
+ if (command.includes('--env')) {
678
+ return command.replace(/--env\s+(['"]?)([^\s'"]+)\1/, (match, quote, envVal) => {
679
+ const existingEnv = {};
680
+ if (envVal.startsWith('{') && envVal.endsWith('}')) {
681
+ try {
682
+ Object.assign(existingEnv, JSON.parse(envVal));
683
+ }
684
+ catch (e) {
685
+ }
686
+ }
687
+ if (!Object.keys(existingEnv).length) {
688
+ envVal.split(',').forEach((pair) => {
689
+ const [k, v] = pair.split('=');
690
+ if (!k)
691
+ return;
692
+ if (v === 'true')
693
+ existingEnv[k] = true;
694
+ else if (v === 'false')
695
+ existingEnv[k] = false;
696
+ else
697
+ existingEnv[k] = v;
698
+ });
699
+ }
700
+ const merged = { ...existingEnv, ...baseEnv };
701
+ const json = JSON.stringify(merged);
702
+ return `--env ${json}`;
703
+ });
704
+ }
705
+ const json = JSON.stringify(baseEnv);
706
+ return `${command} --env ${json}`;
707
+ }
708
+ return `${command} --grep ${regexPattern}`;
709
+ }
644
710
 
645
711
  module.exports.getPackageVersion = getPackageVersion;
646
712
 
@@ -658,12 +724,16 @@ module.exports.storeRunId = storeRunId;
658
724
 
659
725
  module.exports.transformEnvVarToBoolean = transformEnvVarToBoolean;
660
726
 
727
+ module.exports.applyFilter = applyFilter;
728
+
661
729
  module.exports.getTestomatIdFromTestTitle = getTestomatIdFromTestTitle;
662
730
 
663
731
  module.exports.parseSuite = parseSuite;
664
732
 
665
733
  module.exports.validateSuiteId = validateSuiteId;
666
734
 
735
+ module.exports.getGitCommitSha = getGitCommitSha;
736
+
667
737
  module.exports.ansiRegExp = ansiRegExp;
668
738
 
669
739
  module.exports.isValidUrl = isValidUrl;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@testomatio/reporter",
3
- "version": "2.3.9",
3
+ "version": "2.5.0",
4
4
  "description": "Testomatio Reporter Client",
5
5
  "engines": {
6
6
  "node": ">=18"
@@ -18,21 +18,22 @@
18
18
  "@cucumber/cucumber": "^10.9.0",
19
19
  "@octokit/rest": "^21.1.1",
20
20
  "aws-sdk": "^2.1072.0",
21
- "gaxios": ">=6.0 || >=7.0.0-rc.4 || <8",
22
21
  "callsite-record": "^4.1.4",
23
22
  "commander": "^12",
24
23
  "cross-spawn": "^7.0.3",
25
24
  "csv-writer": "^1.6.0",
26
- "debug": "^4.3.4",
25
+ "debug": "4.3.4",
27
26
  "dotenv": "^16.0.1",
28
27
  "fast-xml-parser": "^4.4.1",
29
28
  "file-url": "3.0.0",
30
29
  "filesize": "^10.1.6",
30
+ "gaxios": ">=6.0 || >=7.0.0-rc.4 || <8",
31
31
  "glob": "^10.3",
32
32
  "handlebars": "^4.7.8",
33
33
  "has-flag": "^5.0.1",
34
34
  "humanize-duration": "^3.27.3",
35
35
  "is-valid-path": "^0.1.1",
36
+ "js-yaml": "^4.1.1",
36
37
  "json-cycle": "^1.3.0",
37
38
  "lodash.memoize": "^4.1.2",
38
39
  "lodash.merge": "^4.6.2",
@@ -40,7 +41,7 @@
40
41
  "picocolors": "^1.0.1",
41
42
  "pretty-ms": "^7.0.1",
42
43
  "promise-retry": "^2.0.1",
43
- "strip-ansi": "^7.1.0",
44
+ "strip-ansi": "7.1.0",
44
45
  "uuid": "^9.0.0"
45
46
  },
46
47
  "files": [