@testomatio/reporter 2.3.9-beta-bin-fix → 2.4.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.
Files changed (62) hide show
  1. package/README.md +3 -2
  2. package/lib/adapter/codecept.js +12 -9
  3. package/lib/bin/cli.js +40 -11
  4. package/lib/bin/reportXml.js +5 -2
  5. package/lib/client.d.ts +1 -11
  6. package/lib/client.js +57 -152
  7. package/lib/data-storage.d.ts +1 -1
  8. package/lib/helpers.d.ts +1 -0
  9. package/lib/helpers.js +4 -0
  10. package/lib/junit-adapter/csharp.d.ts +0 -1
  11. package/lib/junit-adapter/csharp.js +43 -7
  12. package/lib/junit-adapter/nunit-parser.d.ts +82 -0
  13. package/lib/junit-adapter/nunit-parser.js +433 -0
  14. package/lib/pipe/bitbucket.js +5 -5
  15. package/lib/pipe/coverage.d.ts +82 -0
  16. package/lib/pipe/coverage.js +373 -0
  17. package/lib/pipe/gitlab.js +4 -4
  18. package/lib/pipe/index.js +2 -0
  19. package/lib/pipe/testomatio.d.ts +3 -2
  20. package/lib/pipe/testomatio.js +44 -18
  21. package/lib/reporter-functions.js +14 -12
  22. package/lib/reporter.d.ts +31 -21
  23. package/lib/reporter.js +40 -5
  24. package/lib/services/artifacts.d.ts +1 -1
  25. package/lib/services/key-values.d.ts +1 -1
  26. package/lib/services/links.d.ts +1 -1
  27. package/lib/services/logger.d.ts +1 -1
  28. package/lib/uploader.js +4 -0
  29. package/lib/utils/log-formatter.d.ts +28 -0
  30. package/lib/utils/log-formatter.js +127 -0
  31. package/lib/utils/pipe_utils.d.ts +15 -0
  32. package/lib/utils/pipe_utils.js +44 -2
  33. package/lib/utils/utils.d.ts +6 -0
  34. package/lib/utils/utils.js +260 -25
  35. package/lib/xmlReader.d.ts +32 -26
  36. package/lib/xmlReader.js +121 -52
  37. package/package.json +12 -7
  38. package/src/adapter/codecept.js +19 -19
  39. package/src/adapter/mocha.js +1 -1
  40. package/src/adapter/playwright.js +2 -2
  41. package/src/bin/cli.js +51 -13
  42. package/src/bin/reportXml.js +5 -2
  43. package/src/client.js +69 -130
  44. package/src/helpers.js +1 -0
  45. package/src/junit-adapter/csharp.js +48 -6
  46. package/src/junit-adapter/nunit-parser.js +474 -0
  47. package/src/pipe/bitbucket.js +5 -5
  48. package/src/pipe/coverage.js +440 -0
  49. package/src/pipe/debug.js +1 -2
  50. package/src/pipe/gitlab.js +4 -4
  51. package/src/pipe/index.js +2 -0
  52. package/src/pipe/testomatio.js +109 -85
  53. package/src/reporter-functions.js +15 -12
  54. package/src/reporter.js +6 -4
  55. package/src/services/links.js +1 -1
  56. package/src/uploader.js +5 -0
  57. package/src/utils/log-formatter.js +113 -0
  58. package/src/utils/pipe_utils.js +52 -3
  59. package/src/utils/utils.js +277 -22
  60. package/src/xmlReader.js +144 -46
  61. package/types/types.d.ts +364 -0
  62. package/types/vitest.types.d.ts +93 -0
package/lib/reporter.d.ts CHANGED
@@ -1,3 +1,10 @@
1
+ export { Client };
2
+ export const STATUS: {
3
+ PASSED: string;
4
+ FAILED: string;
5
+ SKIPPED: string;
6
+ FINISHED: string;
7
+ };
1
8
  export const artifact: (data: string | {
2
9
  path: string;
3
10
  type: string;
@@ -5,7 +12,7 @@ export const artifact: (data: string | {
5
12
  }, context?: any) => void;
6
13
  export const log: (...args: any[]) => void;
7
14
  export const logger: {
8
- "__#13@#originalUserLogger": {
15
+ "__#14@#originalUserLogger": {
9
16
  assert(condition?: boolean, ...data: any[]): void;
10
17
  assert(value: any, message?: string, ...optionalParams: any[]): void;
11
18
  clear(): void;
@@ -50,13 +57,13 @@ export const logger: {
50
57
  profile(label?: string): void;
51
58
  profileEnd(label?: string): void;
52
59
  };
53
- "__#13@#userLoggerWithOverridenMethods": any;
60
+ "__#14@#userLoggerWithOverridenMethods": any;
54
61
  logLevel: string;
55
62
  step(strings: any, ...values: any[]): void;
56
63
  getLogs(context: string): string[];
57
- "__#13@#stringifyLogs"(...args: any[]): string;
64
+ "__#14@#stringifyLogs"(...args: any[]): string;
58
65
  _templateLiteralLog(strings: any, ...args: any[]): void;
59
- "__#13@#logWrapper"(argsArray: any, level: any): void;
66
+ "__#14@#logWrapper"(argsArray: any, level: any): void;
60
67
  assert(...args: any[]): void;
61
68
  debug(...args: any[]): void;
62
69
  error(...args: any[]): void;
@@ -80,8 +87,8 @@ export const label: (key: string, value?: string | null) => void;
80
87
  export const linkTest: (...testIds: string[]) => void;
81
88
  export const linkJira: (...jiraIds: string[]) => void;
82
89
  declare namespace _default {
83
- let testomatioLogger: {
84
- "__#13@#originalUserLogger": {
90
+ export let testomatioLogger: {
91
+ "__#14@#originalUserLogger": {
85
92
  assert(condition?: boolean, ...data: any[]): void;
86
93
  assert(value: any, message?: string, ...optionalParams: any[]): void;
87
94
  clear(): void;
@@ -126,13 +133,13 @@ declare namespace _default {
126
133
  profile(label?: string): void;
127
134
  profileEnd(label?: string): void;
128
135
  };
129
- "__#13@#userLoggerWithOverridenMethods": any;
136
+ "__#14@#userLoggerWithOverridenMethods": any;
130
137
  logLevel: string;
131
138
  step(strings: any, ...values: any[]): void;
132
139
  getLogs(context: string): string[];
133
- "__#13@#stringifyLogs"(...args: any[]): string;
140
+ "__#14@#stringifyLogs"(...args: any[]): string;
134
141
  _templateLiteralLog(strings: any, ...args: any[]): void;
135
- "__#13@#logWrapper"(argsArray: any, level: any): void;
142
+ "__#14@#logWrapper"(argsArray: any, level: any): void;
136
143
  assert(...args: any[]): void;
137
144
  debug(...args: any[]): void;
138
145
  error(...args: any[]): void;
@@ -148,14 +155,14 @@ declare namespace _default {
148
155
  }): void;
149
156
  prettyObjects: boolean;
150
157
  };
151
- let artifact: (data: string | {
158
+ export let artifact: (data: string | {
152
159
  path: string;
153
160
  type: string;
154
161
  name: string;
155
162
  }, context?: any) => void;
156
- let log: (...args: any[]) => void;
157
- let logger: {
158
- "__#13@#originalUserLogger": {
163
+ export let log: (...args: any[]) => void;
164
+ export let logger: {
165
+ "__#14@#originalUserLogger": {
159
166
  assert(condition?: boolean, ...data: any[]): void;
160
167
  assert(value: any, message?: string, ...optionalParams: any[]): void;
161
168
  clear(): void;
@@ -200,13 +207,13 @@ declare namespace _default {
200
207
  profile(label?: string): void;
201
208
  profileEnd(label?: string): void;
202
209
  };
203
- "__#13@#userLoggerWithOverridenMethods": any;
210
+ "__#14@#userLoggerWithOverridenMethods": any;
204
211
  logLevel: string;
205
212
  step(strings: any, ...values: any[]): void;
206
213
  getLogs(context: string): string[];
207
- "__#13@#stringifyLogs"(...args: any[]): string;
214
+ "__#14@#stringifyLogs"(...args: any[]): string;
208
215
  _templateLiteralLog(strings: any, ...args: any[]): void;
209
- "__#13@#logWrapper"(argsArray: any, level: any): void;
216
+ "__#14@#logWrapper"(argsArray: any, level: any): void;
210
217
  assert(...args: any[]): void;
211
218
  debug(...args: any[]): void;
212
219
  error(...args: any[]): void;
@@ -222,13 +229,15 @@ declare namespace _default {
222
229
  }): void;
223
230
  prettyObjects: boolean;
224
231
  };
225
- let meta: (keyValue: {
232
+ export let meta: (keyValue: {
226
233
  [key: string]: string;
227
234
  } | string, value?: string | null) => void;
228
- let step: (message: string) => void;
229
- let label: (key: string, value?: string | null) => void;
230
- let linkTest: (...testIds: string[]) => void;
231
- let linkJira: (...jiraIds: string[]) => void;
235
+ export let step: (message: string) => void;
236
+ export let label: (key: string, value?: string | null) => void;
237
+ export let linkTest: (...testIds: string[]) => void;
238
+ export let linkJira: (...jiraIds: string[]) => void;
239
+ export { Client as TestomatioClient };
240
+ export { STATUS };
232
241
  }
233
242
  export default _default;
234
243
  export type ArtifactFunction = typeof import("./reporter-functions.js").default.artifact;
@@ -237,3 +246,4 @@ export type LoggerService = typeof import("./services/index.js").services.logger
237
246
  export type MetaFunction = typeof import("./reporter-functions.js").default.keyValue;
238
247
  export type StepFunction = typeof import("./reporter-functions.js").default.step;
239
248
  export type LabelFunction = typeof import("./reporter-functions.js").default.label;
249
+ import Client from './client.js';
package/lib/reporter.js CHANGED
@@ -1,13 +1,48 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
37
  };
5
38
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.linkJira = exports.linkTest = exports.label = exports.step = exports.meta = exports.logger = exports.log = exports.artifact = void 0;
7
- // import TestomatClient from './client.js';
8
- // import * as TRConstants from './constants.js';
39
+ exports.linkJira = exports.linkTest = exports.label = exports.step = exports.meta = exports.logger = exports.log = exports.artifact = exports.STATUS = exports.Client = void 0;
40
+ const client_js_1 = __importDefault(require("./client.js"));
41
+ exports.Client = client_js_1.default;
42
+ const TestomatioConstants = __importStar(require("./constants.js"));
9
43
  const index_js_1 = require("./services/index.js");
10
44
  const reporter_functions_js_1 = __importDefault(require("./reporter-functions.js"));
45
+ exports.STATUS = TestomatioConstants.STATUS;
11
46
  exports.artifact = reporter_functions_js_1.default.artifact;
12
47
  exports.log = reporter_functions_js_1.default.log;
13
48
  exports.logger = index_js_1.services.logger;
@@ -37,6 +72,6 @@ module.exports = {
37
72
  label: reporter_functions_js_1.default.label,
38
73
  linkTest: reporter_functions_js_1.default.linkTest,
39
74
  linkJira: reporter_functions_js_1.default.linkJira,
40
- // TestomatClient,
41
- // TRConstants,
75
+ TestomatioClient: client_js_1.default,
76
+ STATUS: exports.STATUS,
42
77
  };
@@ -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}
package/lib/uploader.js CHANGED
@@ -170,6 +170,10 @@ class S3Uploader {
170
170
  if (typeof filePath === 'string' && !path_1.default.isAbsolute(filePath)) {
171
171
  filePath = path_1.default.join(process.cwd(), filePath);
172
172
  }
173
+ // Normalize path separators for cross-platform compatibility
174
+ if (typeof filePath === 'string') {
175
+ filePath = filePath.replace(/\\/g, '/');
176
+ }
173
177
  const data = { rid, file: filePath, uploaded };
174
178
  const jsonLine = `${JSON.stringify(data)}\n`;
175
179
  fs_1.default.appendFileSync(tempFilePath, jsonLine);
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Returns the formatted stack including the stack trace, steps, and logs.
3
+ * @param {Object} params - Parameters for formatting logs
4
+ * @param {string} params.error - Error message
5
+ * @param {Array|any} params.steps - Test steps (array or other types)
6
+ * @param {string} params.logs - Test logs
7
+ * @returns {string}
8
+ */
9
+ export function formatLogs({ error, steps, logs }: {
10
+ error: string;
11
+ steps: any[] | any;
12
+ logs: string;
13
+ }): string;
14
+ /**
15
+ * Formats an error with stack trace and diff information
16
+ * @param {Error & {inspect?: () => string, operator?: string, diff?: string, actual?: any, expected?: any}} error
17
+ * The error object to format
18
+ * @param {string} [message] - Optional error message override
19
+ * @returns {string}
20
+ */
21
+ export function formatError(error: Error & {
22
+ inspect?: () => string;
23
+ operator?: string;
24
+ diff?: string;
25
+ actual?: any;
26
+ expected?: any;
27
+ }, message?: string): string;
28
+ export function stripColors(str: string): string;
@@ -0,0 +1,127 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.stripColors = void 0;
7
+ exports.formatLogs = formatLogs;
8
+ exports.formatError = formatError;
9
+ const callsite_record_1 = __importDefault(require("callsite-record"));
10
+ const minimatch_1 = require("minimatch");
11
+ const picocolors_1 = __importDefault(require("picocolors"));
12
+ const util_1 = require("util");
13
+ const path_1 = require("path");
14
+ const utils_js_1 = require("./utils.js");
15
+ const stripColors = util_1.stripVTControlCharacters || (str => str?.replace(/\x1b\[[0-9;]*m/g, '') || '');
16
+ exports.stripColors = stripColors;
17
+ /**
18
+ * Returns the formatted stack including the stack trace, steps, and logs.
19
+ * @param {Object} params - Parameters for formatting logs
20
+ * @param {string} params.error - Error message
21
+ * @param {Array|any} params.steps - Test steps (array or other types)
22
+ * @param {string} params.logs - Test logs
23
+ * @returns {string}
24
+ */
25
+ function formatLogs({ error, steps, logs }) {
26
+ error = error?.trim();
27
+ logs = logs
28
+ ?.trim()
29
+ .split('\n')
30
+ .map(l => (0, utils_js_1.truncate)(l))
31
+ .join('\n');
32
+ if (Array.isArray(steps)) {
33
+ steps = steps
34
+ .map(step => (0, utils_js_1.formatStep)(step))
35
+ .flat()
36
+ .join('\n');
37
+ }
38
+ else {
39
+ steps = null;
40
+ }
41
+ let testLogs = '';
42
+ if (steps)
43
+ testLogs += `${picocolors_1.default.bold(picocolors_1.default.blue('################[ Steps ]################'))}\n${steps}\n\n`;
44
+ if (logs)
45
+ testLogs += `${picocolors_1.default.bold(picocolors_1.default.gray('################[ Logs ]################'))}\n${logs}\n\n`;
46
+ if (error)
47
+ testLogs += `${picocolors_1.default.bold(picocolors_1.default.red('################[ Failure ]################'))}\n${error}`;
48
+ return testLogs;
49
+ }
50
+ /**
51
+ * Formats an error with stack trace and diff information
52
+ * @param {Error & {inspect?: () => string, operator?: string, diff?: string, actual?: any, expected?: any}} error
53
+ * The error object to format
54
+ * @param {string} [message] - Optional error message override
55
+ * @returns {string}
56
+ */
57
+ function formatError(error, message) {
58
+ if (!message)
59
+ message = error.message;
60
+ // @ts-ignore - inspect is a custom property added by some testing frameworks
61
+ if (error.inspect)
62
+ message = error.inspect() || '';
63
+ let stack = '';
64
+ if (error.name)
65
+ stack += `${picocolors_1.default.red(error.name)}`;
66
+ // @ts-ignore - operator is a custom property added by assertion libraries
67
+ if (error.operator)
68
+ stack += ` (${picocolors_1.default.red(error.operator)})`;
69
+ // add new line if something was added to stack
70
+ if (stack)
71
+ stack += ': ';
72
+ stack += `${message}\n`;
73
+ // @ts-ignore - diff is a custom property added by vitest
74
+ if (error.diff) {
75
+ // diff for vitest
76
+ stack += error.diff;
77
+ stack += '\n\n';
78
+ }
79
+ else if (error.actual && error.expected && error.actual !== error.expected) {
80
+ // diffs for mocha, cypress, codeceptjs style
81
+ stack += `\n\n${picocolors_1.default.bold(picocolors_1.default.green('+ expected'))} ${picocolors_1.default.bold(picocolors_1.default.red('- actual'))}`;
82
+ stack += `\n${picocolors_1.default.green(`+ ${error.expected.toString().split('\n').join('\n+ ')}`)}`;
83
+ stack += `\n${picocolors_1.default.red(`- ${error.actual.toString().split('\n').join('\n- ')}`)}`;
84
+ stack += '\n\n';
85
+ }
86
+ const customFilter = process.env.TESTOMATIO_STACK_IGNORE;
87
+ try {
88
+ let hasFrame = false;
89
+ const record = (0, callsite_record_1.default)({
90
+ forError: error,
91
+ isCallsiteFrame: frame => {
92
+ if (customFilter && (0, minimatch_1.minimatch)(frame.fileName, customFilter))
93
+ return false;
94
+ if (hasFrame)
95
+ return false;
96
+ if (isNotInternalFrame(frame))
97
+ hasFrame = true;
98
+ return hasFrame;
99
+ },
100
+ });
101
+ // @ts-ignore
102
+ if (record && !record.filename.startsWith('http')) {
103
+ stack += record.renderSync({ stackFilter: isNotInternalFrame });
104
+ }
105
+ return stack;
106
+ }
107
+ catch (e) {
108
+ console.log(e);
109
+ }
110
+ }
111
+ /**
112
+ * Checks if a stack frame is not an internal frame (node_modules or internal)
113
+ * @param {Object} frame - Stack frame object
114
+ * @returns {boolean}
115
+ */
116
+ function isNotInternalFrame(frame) {
117
+ return (frame.getFileName() &&
118
+ frame.getFileName().includes(path_1.sep) &&
119
+ !frame.getFileName().includes('node_modules') &&
120
+ !frame.getFileName().includes('internal'));
121
+ }
122
+
123
+ module.exports.formatLogs = formatLogs;
124
+
125
+ module.exports.formatError = formatError;
126
+
127
+ module.exports.stripColors = stripColors;
@@ -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;