@testomatio/reporter 1.0.14-beta → 1.0.14

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.
@@ -4,7 +4,7 @@ const fs = require('fs');
4
4
  const os = require('os');
5
5
  const uuid = require('uuid');
6
6
  const { TESTOMAT_ARTIFACT_SUFFIX } = require('./constants');
7
- const { specificTestInfo } = require('./util');
7
+ const { specificTestInfo } = require('./utils/utils');
8
8
 
9
9
  class ArtifactStorage {
10
10
 
@@ -3,7 +3,7 @@ const chalk = require('chalk');
3
3
  const TestomatClient = require('../client');
4
4
  const { STATUS, APP_PREFIX, TESTOMAT_TMP_STORAGE } = require('../constants');
5
5
  const upload = require('../fileUploader');
6
- const { parseTest: getIdFromTestTitle, fileSystem } = require('../util');
6
+ const { parseTest: getIdFromTestTitle, fileSystem } = require('../utils/utils');
7
7
 
8
8
  if (!global.codeceptjs) {
9
9
  // eslint-disable-next-line global-require, import/no-extraneous-dependencies
@@ -5,7 +5,7 @@ const fs = require('fs');
5
5
  const { STATUS, TESTOMAT_TMP_STORAGE } = require('../../constants');
6
6
  const TestomatClient = require('../../client');
7
7
  const logger = require('../../logger');
8
- const { parseTest, fileSystem } = require('../../util');
8
+ const { parseTest, fileSystem } = require('../../utils/utils');
9
9
 
10
10
  const { GherkinDocumentParser, PickleParser } = formatterHelpers;
11
11
  const { getGherkinScenarioLocationMap, getGherkinStepMap } = GherkinDocumentParser;
@@ -1,7 +1,7 @@
1
1
  // eslint-disable-next-line global-require, import/no-extraneous-dependencies, import/no-unresolved
2
2
  const { Formatter } = require('cucumber');
3
3
  const chalk = require('chalk');
4
- const { parseTest, fileSystem } = require('../../util');
4
+ const { parseTest, fileSystem } = require('../../utils/utils');
5
5
  const { STATUS, TESTOMAT_TMP_STORAGE } = require('../../constants');
6
6
  const TestomatClient = require('../../client');
7
7
 
@@ -1,5 +1,5 @@
1
1
  const { STATUS } = require('../../constants');
2
- const { parseTest, parseSuite } = require('../../util');
2
+ const { parseTest, parseSuite } = require('../../utils/utils');
3
3
  const TestomatClient = require('../../client');
4
4
 
5
5
  const testomatioReporter = on => {
@@ -1,5 +1,5 @@
1
1
  const TestomatClient = require('../client');
2
- const { parseTest, ansiRegExp } = require('../util');
2
+ const { parseTest, ansiRegExp } = require('../utils/utils');
3
3
  const { STATUS } = require('../constants');
4
4
 
5
5
  class JasmineReporter {
@@ -1,6 +1,6 @@
1
1
  const TestomatClient = require('../client');
2
2
  const { STATUS, TESTOMAT_TMP_STORAGE } = require('../constants');
3
- const { parseTest, ansiRegExp, fileSystem } = require('../util');
3
+ const { parseTest, ansiRegExp, fileSystem } = require('../utils/utils');
4
4
 
5
5
  class JestReporter {
6
6
  constructor(globalConfig, options) {
@@ -4,7 +4,7 @@ const debug = require('debug')('@testomatio/reporter:adapter:mocha');
4
4
  const chalk = require('chalk');
5
5
  const TestomatClient = require('../client');
6
6
  const { STATUS, TESTOMAT_TMP_STORAGE } = require('../constants');
7
- const { parseTest, specificTestInfo, fileSystem } = require('../util');
7
+ const { parseTest, specificTestInfo, fileSystem } = require('../utils/utils');
8
8
  const ArtifactStorage = require('../_ArtifactStorageOld');
9
9
 
10
10
  const { EVENT_RUN_BEGIN, EVENT_RUN_END, EVENT_TEST_FAIL, EVENT_TEST_PASS, EVENT_TEST_PENDING } =
@@ -6,7 +6,7 @@ const fs = require('fs');
6
6
  const { APP_PREFIX, STATUS: Status, TESTOMAT_TMP_STORAGE } = require('../constants');
7
7
  const TestomatioClient = require('../client');
8
8
  const { isArtifactsEnabled } = require('../fileUploader');
9
- const { parseTest, fileSystem } = require('../util');
9
+ const { parseTest, fileSystem } = require('../utils/utils');
10
10
 
11
11
  const reportTestPromises = [];
12
12
 
@@ -1,7 +1,7 @@
1
1
  // eslint-disable-next-line global-require, import/no-extraneous-dependencies
2
2
  const WDIOReporter = require('@wdio/reporter').default;
3
3
  const TestomatClient = require('../client');
4
- const { parseTest } = require('../util');
4
+ const { parseTest } = require('../utils/utils');
5
5
 
6
6
  class WebdriverReporter extends WDIOReporter {
7
7
  constructor(options) {
@@ -13,9 +13,11 @@ program
13
13
  .option('--launch', 'Start a new run and return its ID')
14
14
  .option('--finish', 'Finish Run by its ID')
15
15
  .option("--env-file <envfile>", "Load environment variables from env file")
16
- .action(opts => {
16
+ .option("--filter <filter>", "Additional execution filter")
17
+ .action(async (opts) => {
18
+ const { launch, finish, filter } = opts;
19
+ let { command } = opts;
17
20
 
18
- const { command, launch, finish } = opts;
19
21
  if (opts.envFile) require('dotenv').config(opts.envFile); // eslint-disable-line
20
22
 
21
23
  const apiKey = process.env['INPUT_TESTOMATIO-KEY'] || process.env.TESTOMATIO;
@@ -51,6 +53,27 @@ program
51
53
 
52
54
  let exitCode = 0;
53
55
 
56
+ const client = new TestomatClient({ apiKey, title, parallel: true });
57
+
58
+ if(filter) {
59
+ const [pipe, ...optsArray] = filter.split(":");
60
+ const pipeOptions = optsArray.join(":");
61
+
62
+ try {
63
+ const tests = await client.prepareRun({pipe, pipeOptions});
64
+
65
+ if(!tests || tests.length === 0) {
66
+ return;
67
+ }
68
+
69
+ const grep = ` --grep (${tests.join('|')})`;
70
+ command += grep;
71
+ }
72
+ catch(err) {
73
+ console.log(APP_PREFIX, err);
74
+ }
75
+ }
76
+
54
77
  if (!command.split) {
55
78
  process.exitCode = 255;
56
79
  console.log(APP_PREFIX, `No command provided. Use -c option to launch a test runner.`);
@@ -73,8 +96,6 @@ program
73
96
  return;
74
97
  }
75
98
 
76
- const client = new TestomatClient({ apiKey, title, parallel: true });
77
-
78
99
  client.createRun().then(() => {
79
100
  const cmd = spawn(testCmds[0], testCmds.slice(1), { stdio: 'inherit' });
80
101
 
package/lib/client.js CHANGED
@@ -27,9 +27,64 @@ class Client {
27
27
  this.queue = Promise.resolve();
28
28
  this.totalUploaded = 0;
29
29
  this.version = JSON.parse(fs.readFileSync(join(__dirname, '..', 'package.json')).toString()).version;
30
+ this.executionList = Promise.resolve();
31
+
30
32
  console.log(APP_PREFIX, `Testomatio Reporter v${this.version}`);
31
33
  }
32
34
 
35
+ /**
36
+ * Asynchronously prepares the execution list for running tests through various pipes.
37
+ * Each pipe in the client is checked for enablement,
38
+ * and if all pipes are disabled, the function returns a resolved Promise.
39
+ * Otherwise, it executes the `prepareRun` method for each enabled pipe and collects the results.
40
+ * The results are then filtered to remove any undefined values.
41
+ * If no valid results are found, the function returns undefined.
42
+ * Otherwise, it returns the first non-empty array from the filtered results.
43
+ *
44
+ * @param {Object} params - The options for preparing the test execution list.
45
+ * @param {string} params.pipe - Name of the executed pipe.
46
+ * @param {string} params.pipeOptions - Filter option.
47
+ * @returns {Promise<any>} - A Promise that resolves to an
48
+ * array containing the prepared execution list,
49
+ * or resolves to undefined if no valid results are found or if all pipes are disabled.
50
+ */
51
+ async prepareRun(params) {
52
+ const { pipe, pipeOptions } = params;
53
+ // all pipes disabled, skipping
54
+ if (!this.pipes.some(p => p.isEnabled)) {
55
+ return Promise.resolve();
56
+ }
57
+
58
+ try {
59
+ const filterPipe = this.pipes.find(p => p.constructor.name.toLowerCase() === `${pipe.toLowerCase()}pipe`);
60
+
61
+ if (!filterPipe.isEnabled) {
62
+ // TODO:for the future for the another pipes
63
+ console.warn(
64
+ APP_PREFIX,
65
+ `At the moment processing is available only for the "testomatio" key. Example: "testomatio:tag-name=xxx"`
66
+ );
67
+ return;
68
+ }
69
+
70
+ const results = await Promise.all(this.pipes.map(async p =>
71
+ ({ pipe: p.toString(), result: await p.prepareRun(pipeOptions) })
72
+ ));
73
+
74
+ const result = results.filter(p => p.pipe.includes('Testomatio'))[0]?.result;
75
+
76
+ if (!result || result.length === 0) {
77
+ return;
78
+ }
79
+
80
+ debug('Execution tests list', result);
81
+
82
+ return result;
83
+ } catch (err) {
84
+ console.error(APP_PREFIX, err);
85
+ }
86
+ }
87
+
33
88
  /**
34
89
  * Used to create a new Test run
35
90
  *
@@ -5,8 +5,8 @@ const os = require('os');
5
5
  const { join } = require('path');
6
6
  const JestReporter = require('./adapter/jest');
7
7
  const { TESTOMAT_TMP_STORAGE } = require('./constants');
8
- const { fileSystem } = require('./util');
9
- const getTestIdFromTestTitle = require('./util').parseTest;
8
+ const { fileSystem } = require('./utils/utils');
9
+ const getTestIdFromTestTitle = require('./utils/utils').parseTest;
10
10
 
11
11
  class DataStorage {
12
12
  /**
package/lib/pipe/csv.js CHANGED
@@ -4,7 +4,7 @@ const fs = require('fs');
4
4
  const csvWriter = require('csv-writer');
5
5
  const chalk = require('chalk');
6
6
  const merge = require('lodash.merge');
7
- const { isSameTest, getCurrentDateTime } = require('../util');
7
+ const { isSameTest, getCurrentDateTime } = require('../utils/utils');
8
8
  const { CSV_HEADERS } = require('../constants');
9
9
 
10
10
  /**
@@ -40,6 +40,9 @@ class CsvPipe {
40
40
  }
41
41
  }
42
42
 
43
+ // TODO: to using SET opts as argument => prepareRun(opts)
44
+ async prepareRun() {}
45
+
43
46
  async createRun() {
44
47
  // empty
45
48
  }
@@ -5,7 +5,8 @@ const humanizeDuration = require('humanize-duration');
5
5
  const merge = require('lodash.merge');
6
6
  const { Octokit } = require('@octokit/rest');
7
7
  const { APP_PREFIX } = require('../constants');
8
- const { ansiRegExp, isSameTest } = require('../util');
8
+ const { ansiRegExp, isSameTest } = require('../utils/utils');
9
+ const { statusEmoji, fullName } = require('../utils/pipe_utils');
9
10
 
10
11
  /**
11
12
  * @typedef {import('../../types').Pipe} Pipe
@@ -37,6 +38,9 @@ class GitHubPipe {
37
38
  debug('GitHub Pipe: Enabled');
38
39
  }
39
40
 
41
+ // TODO: to using SET opts as argument => prepareRun(opts)
42
+ async prepareRun() {}
43
+
40
44
  async createRun() {}
41
45
 
42
46
  addTest(test) {
@@ -182,21 +186,6 @@ class GitHubPipe {
182
186
  }
183
187
  }
184
188
 
185
- function statusEmoji(status) {
186
- if (status === 'passed') return '🟢';
187
- if (status === 'failed') return '🔴';
188
- if (status === 'skipped') return '🟡';
189
- return '';
190
- }
191
-
192
- function fullName(t) {
193
- let line = '';
194
- if (t.suite_title) line = `${t.suite_title}: `;
195
- line += `**${t.title}**`;
196
- if (t.example) line += ` \`[${Object.values(t.example)}]\``;
197
- return line;
198
- }
199
-
200
189
  async function deletePreviousReport(octokit, owner, repo, issue, hiddenCommentData) {
201
190
  if (process.env.GH_KEEP_OUTDATED_REPORTS) return;
202
191
 
@@ -5,7 +5,8 @@ const humanizeDuration = require('humanize-duration');
5
5
  const merge = require('lodash.merge');
6
6
  const path = require('path');
7
7
  const { APP_PREFIX } = require('../constants');
8
- const { ansiRegExp, isSameTest } = require('../util');
8
+ const { ansiRegExp, isSameTest } = require('../utils/utils');
9
+ const { statusEmoji, fullName } = require('../utils/pipe_utils');
9
10
 
10
11
  //! GITLAB_PAT environment variable is required for this functionality to work
11
12
  //! and your pipeline trigger should be merge_request
@@ -46,6 +47,9 @@ class GitLabPipe {
46
47
  debug('GitLab Pipe: Enabled');
47
48
  }
48
49
 
50
+ // TODO: to using SET opts as argument => prepareRun(opts)
51
+ async prepareRun() {}
52
+
49
53
  async createRun() {}
50
54
 
51
55
  addTest(test) {
@@ -179,21 +183,6 @@ class GitLabPipe {
179
183
  updateRun() {}
180
184
  }
181
185
 
182
- function statusEmoji(status) {
183
- if (status === 'passed') return '🟢';
184
- if (status === 'failed') return '🔴';
185
- if (status === 'skipped') return '🟡';
186
- return '';
187
- }
188
-
189
- function fullName(t) {
190
- let line = '';
191
- if (t.suite_title) line = `${t.suite_title}: `;
192
- line += `**${t.title}**`;
193
- if (t.example) line += ` \`[${Object.values(t.example)}]\``;
194
- return line;
195
- }
196
-
197
186
  async function deletePreviousReport(axiosInstance, commentsRequestURL, hiddenCommentData, token) {
198
187
  if (process.env.GITLAB_KEEP_OUTDATED_REPORTS) return;
199
188
 
@@ -3,8 +3,8 @@ const chalk = require('chalk');
3
3
  const axios = require('axios');
4
4
  const JsonCycle = require('json-cycle');
5
5
  const { APP_PREFIX, STATUS } = require('../constants');
6
- const { isValidUrl } = require('../util');
7
- const { resetConfig } = require('../fileUploader');
6
+ const { isValidUrl, foundedTestLog } = require('../utils/utils');
7
+ const { parseFilterParams, generateFilterRequestParams, setS3Credentials, } = require('../utils/pipe_utils');
8
8
 
9
9
  const { TESTOMATIO_RUN } = process.env;
10
10
  if (TESTOMATIO_RUN) {
@@ -33,9 +33,12 @@ class TestomatioPipe {
33
33
  this.sharedRun = !!process.env.TESTOMATIO_SHARED_RUN;
34
34
  this.groupTitle = params.groupTitle || process.env.TESTOMATIO_RUNGROUP_TITLE;
35
35
  this.env = process.env.TESTOMATIO_ENV;
36
+
36
37
  this.axios = axios.create({
37
- timeout: 30000,
38
+ baseURL: `${this.url.trim()}`,
39
+ timeout: 30000
38
40
  });
41
+
39
42
  this.isEnabled = true;
40
43
  // do not finish this run (for parallel testing)
41
44
  this.proceed = process.env.TESTOMATIO_PROCEED;
@@ -49,6 +52,47 @@ class TestomatioPipe {
49
52
  }
50
53
  }
51
54
 
55
+ /**
56
+ * Asynchronously prepares and retrieves the Testomat.io test grepList based on the provided options.
57
+ * @param {Object} opts - The options for preparing the test grepList.
58
+ * @returns {Promise<string[]>} - An array containing the retrieved
59
+ * test grepList, or an empty array if no tests are found or the request is disabled.
60
+ * @throws {Error} - Throws an error if there was a problem while making the request.
61
+ */
62
+ async prepareRun(opts) {
63
+ if (!this.isEnabled) return [];
64
+
65
+ const { type, id } = parseFilterParams(opts);
66
+
67
+ try {
68
+ const q = generateFilterRequestParams({
69
+ type,
70
+ id,
71
+ apiKey: this.apiKey.trim()
72
+ });
73
+
74
+ if (!q) {
75
+ return;
76
+ }
77
+
78
+ const resp = await this.axios.get('/api/test_grep', q);
79
+ const { data } = resp;
80
+
81
+ if (Array.isArray(data?.tests) && data?.tests?.length > 0) {
82
+ foundedTestLog(APP_PREFIX, data.tests);
83
+ return data.tests;
84
+ }
85
+
86
+ console.log(APP_PREFIX, `⛔ No tests found for your --filter --> ${type}=${id}`);
87
+ }
88
+ catch (err) {
89
+ console.error(
90
+ APP_PREFIX,
91
+ `🚩 Error getting Testomat.io test grepList: ${err}`,
92
+ );
93
+ }
94
+ }
95
+
52
96
  /**
53
97
  * @returns Promise<void>
54
98
  */
@@ -88,15 +132,17 @@ class TestomatioPipe {
88
132
  shared_run: this.sharedRun,
89
133
  }).filter(([, value]) => !!value),
90
134
  );
135
+ debug('Run params', JSON.stringify(runParams, null, 2));
91
136
 
92
137
  if (this.runId) {
93
- const resp = await this.axios.put(`${this.url.trim()}/api/reporter/${this.runId}`, runParams);
138
+ debug(`Run with id ${this.runId} already created, updating...`);
139
+ const resp = await this.axios.put(`/api/reporter/${this.runId}`, runParams);
94
140
  if (resp.data.artifacts) setS3Credentials(resp.data.artifacts);
95
141
  return;
96
142
  }
97
143
 
98
144
  try {
99
- const resp = await this.axios.post(`${this.url.trim()}/api/reporter`, runParams, {
145
+ const resp = await this.axios.post(`/api/reporter`, runParams, {
100
146
  maxContentLength: Infinity,
101
147
  maxBodyLength: Infinity,
102
148
  });
@@ -109,6 +155,7 @@ class TestomatioPipe {
109
155
  this.store.runId = this.runId;
110
156
  console.log(APP_PREFIX, '📊 Report created. Report ID:', this.runId);
111
157
  process.env.runId = this.runId;
158
+ debug('Run created', this.runId);
112
159
  } catch (err) {
113
160
  console.error(
114
161
  APP_PREFIX,
@@ -116,7 +163,7 @@ class TestomatioPipe {
116
163
  err,
117
164
  );
118
165
  }
119
- debug('Run created');
166
+ debug('"createRun" function finished');
120
167
  }
121
168
 
122
169
  /**
@@ -132,38 +179,37 @@ class TestomatioPipe {
132
179
  data.create = this.createNewTests;
133
180
  const json = JsonCycle.stringify(data);
134
181
 
135
- return this.axios
136
- .post(`${this.url}/api/reporter/${this.runId}/testrun`, json, {
137
- maxContentLength: Infinity,
138
- maxBodyLength: Infinity,
139
- headers: {
140
- // Overwrite Axios's automatically set Content-Type
141
- 'Content-Type': 'application/json',
142
- },
143
- })
144
- .catch(err => {
145
- if (err.response) {
146
- if (err.response.status >= 400) {
147
- const responseData = err.response.data || { message: '' };
148
- console.log(
149
- APP_PREFIX,
150
- chalk.yellow(`Warning: ${responseData.message} (${err.response.status})`),
151
- chalk.grey(data?.title || ''),
152
- );
153
- if (err.response.data.message.includes('could not be matched')) {
154
- this.hasUnmatchedTests = true;
155
- }
156
- return;
157
- }
182
+ return this.axios.post(`/api/reporter/${this.runId}/testrun`, json, {
183
+ maxContentLength: Infinity,
184
+ maxBodyLength: Infinity,
185
+ headers: {
186
+ // Overwrite Axios's automatically set Content-Type
187
+ 'Content-Type': 'application/json',
188
+ },
189
+ })
190
+ .catch(err => {
191
+ if (err.response) {
192
+ if (err.response.status >= 400) {
193
+ const responseData = err.response.data || { message: '' };
158
194
  console.log(
159
195
  APP_PREFIX,
160
- chalk.yellow(`Warning: ${data?.title || ''} (${err.response?.status})`),
161
- `Report couldn't be processed: ${err?.response?.data?.message}`,
196
+ chalk.yellow(`Warning: ${responseData.message} (${err.response.status})`),
197
+ chalk.grey(data?.title || ''),
162
198
  );
163
- } else {
164
- console.log(APP_PREFIX, chalk.blue(data?.title || ''), "Report couldn't be processed", err);
199
+ if (err.response.data.message.includes('could not be matched')) {
200
+ this.hasUnmatchedTests = true;
201
+ }
202
+ return;
165
203
  }
166
- });
204
+ console.log(
205
+ APP_PREFIX,
206
+ chalk.yellow(`Warning: ${data?.title || ''} (${err.response?.status})`),
207
+ `Report couldn't be processed: ${err?.response?.data?.message}`,
208
+ );
209
+ } else {
210
+ console.log(APP_PREFIX, chalk.blue(data?.title || ''), "Report couldn't be processed", err);
211
+ }
212
+ });
167
213
  }
168
214
 
169
215
  /**
@@ -185,7 +231,7 @@ class TestomatioPipe {
185
231
 
186
232
  try {
187
233
  if (this.runId && !this.proceed) {
188
- await this.axios.put(`${this.url}/api/reporter/${this.runId}`, {
234
+ await this.axios.put(`/api/reporter/${this.runId}`, {
189
235
  api_key: this.apiKey,
190
236
  status_event,
191
237
  tests: params.tests,
@@ -239,17 +285,3 @@ class TestomatioPipe {
239
285
  }
240
286
 
241
287
  module.exports = TestomatioPipe;
242
-
243
- function setS3Credentials(artifacts) {
244
- if (!Object.keys(artifacts).length) return;
245
-
246
- console.log(APP_PREFIX, 'S3 were credentials obtained from Testomat.io...');
247
-
248
- if (artifacts.ACCESS_KEY_ID) process.env.S3_ACCESS_KEY_ID = artifacts.ACCESS_KEY_ID;
249
- if (artifacts.SECRET_ACCESS_KEY) process.env.S3_SECRET_ACCESS_KEY = artifacts.SECRET_ACCESS_KEY;
250
- if (artifacts.REGION) process.env.S3_REGION = artifacts.REGION;
251
- if (artifacts.BUCKET) process.env.S3_BUCKET = artifacts.BUCKET;
252
- if (artifacts.ENDPOINT) process.env.S3_ENDPOINT = artifacts.ENDPOINT;
253
- if (artifacts.presign) process.env.TESTOMATIO_PRIVATE_ARTIFACTS = '1';
254
- resetConfig();
255
- }
@@ -0,0 +1,135 @@
1
+ const { resetConfig } = require('../fileUploader');
2
+ const { APP_PREFIX } = require('../constants');
3
+
4
+ /**
5
+ * Set S3 credentials from the provided artifacts object.
6
+ * @param {Object} artifacts - The artifacts object containing S3 credentials.
7
+ */
8
+ function setS3Credentials(artifacts) {
9
+ if (!Object.keys(artifacts).length) return;
10
+
11
+ console.log(APP_PREFIX, 'S3 were credentials obtained from Testomat.io...');
12
+
13
+ if (artifacts.ACCESS_KEY_ID) process.env.S3_ACCESS_KEY_ID = artifacts.ACCESS_KEY_ID;
14
+ if (artifacts.SECRET_ACCESS_KEY) process.env.S3_SECRET_ACCESS_KEY = artifacts.SECRET_ACCESS_KEY;
15
+ if (artifacts.REGION) process.env.S3_REGION = artifacts.REGION;
16
+ if (artifacts.BUCKET) process.env.S3_BUCKET = artifacts.BUCKET;
17
+ if (artifacts.ENDPOINT) process.env.S3_ENDPOINT = artifacts.ENDPOINT;
18
+ if (artifacts.presign) process.env.TESTOMATIO_PRIVATE_ARTIFACTS = '1';
19
+ resetConfig();
20
+ }
21
+ /**
22
+ * Generates mode request parameters based on the input params.
23
+ * @param {Object} params - The input parameters for the request.
24
+ * @param {string} params.type - The type of the request (e.g., "tag").
25
+ * @param {string} params.id - The ID associated with the request.
26
+ * @param {string} params.apiKey - The API key for authentication.
27
+ * @returns {Object|null} - An object containing the generated request parameters, or null if the type is invalid.
28
+ */
29
+ function generateFilterRequestParams(params) {
30
+ const { type, id, apiKey } = params;
31
+
32
+ if (!type) {
33
+ return;
34
+ }
35
+
36
+ if (!id) {
37
+ console.error(APP_PREFIX, `Please make sure your settings "${type.toUpperCase()}"= "${id}" is correct!`);
38
+ return;
39
+ }
40
+
41
+ return {
42
+ params: {
43
+ type,
44
+ id: encodeURIComponent(id),
45
+ api_key: apiKey
46
+ },
47
+ responseType: "json"
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Parse filter parameters from a string in the format "type=id".
53
+ * @param {string} opts - The input string containing the filter parameters.
54
+ * @returns {Object} An object containing the parsed filter parameters.
55
+ * The object has properties "type" and "id".
56
+ */
57
+ function parseFilterParams(opts) {
58
+ const [type, id] = opts.split("=");
59
+ const validType = updateFilterType(type);
60
+
61
+ return {
62
+ type: validType,
63
+ id
64
+ };
65
+ }
66
+
67
+ /**
68
+ * Update and validate the filter type.
69
+ * @param {string} type - The original filter type.
70
+ * @returns {string|undefined} The updated and validated filter type.
71
+ * Returns undefined if the type is not valid.
72
+ */
73
+ function updateFilterType(type) {
74
+ const typeLowerCase = type.toLowerCase();
75
+
76
+ const filterTypes = [
77
+ "tag-name",
78
+ "plan-id",
79
+ "label",
80
+ "jira-ticket",
81
+ ];
82
+
83
+ const filterApi = [
84
+ "tag",
85
+ "plan",
86
+ "label",
87
+ "jira",
88
+ // "ims-issue", //TODO: WIP
89
+ ];
90
+
91
+ if (!filterTypes.includes(typeLowerCase)) {
92
+ console.log(APP_PREFIX, `❗❗❗ Invalid "filter=${type}" start settings! Available option list: ${filterTypes}`);
93
+ return;
94
+ }
95
+
96
+ const index = filterTypes.indexOf(typeLowerCase);
97
+
98
+ return (index !== -1)
99
+ ? filterApi[index]
100
+ : undefined
101
+ }
102
+
103
+ /**
104
+ * Return an emoji based on the provided status.
105
+ * @param {string} status - The status value ('passed', 'failed', or 'skipped').
106
+ * @returns {string} - An emoji corresponding to the provided status.
107
+ */
108
+ function statusEmoji(status) {
109
+ if (status === 'passed') return '🟢';
110
+ if (status === 'failed') return '🔴';
111
+ if (status === 'skipped') return '🟡';
112
+ return '';
113
+ }
114
+
115
+ /**
116
+ * Generate a full name string based on the provided test object.
117
+ * @param {object} t - The test object.
118
+ * @returns {string} - A formatted full name string for the test object.
119
+ */
120
+ function fullName(t) {
121
+ let line = '';
122
+ if (t.suite_title) line = `${t.suite_title}: `;
123
+ line += `**${t.title}**`;
124
+ if (t.example) line += ` \`[${Object.values(t.example)}]\``;
125
+ return line;
126
+ }
127
+
128
+ module.exports = {
129
+ updateFilterType,
130
+ parseFilterParams,
131
+ generateFilterRequestParams,
132
+ setS3Credentials,
133
+ statusEmoji,
134
+ fullName
135
+ };
@@ -227,6 +227,15 @@ const fileSystem = {
227
227
  },
228
228
  };
229
229
 
230
+
231
+ const foundedTestLog = (app, tests) => {
232
+ const n = tests.length;
233
+
234
+ return (n === 1)
235
+ ? console.log(app, `✅ We found one test!`)
236
+ : console.log(app, `✅ We found ${n} tests!`);
237
+ }
238
+
230
239
  const humanize = text => {
231
240
  text = decamelize(text);
232
241
  return text
@@ -297,4 +306,5 @@ module.exports = {
297
306
  parseSuite,
298
307
  humanize,
299
308
  removeColorCodes,
300
- };
309
+ foundedTestLog
310
+ };
package/lib/xmlReader.js CHANGED
@@ -8,12 +8,12 @@ const { fetchFilesFromStackTrace,
8
8
  fetchIdFromOutput,
9
9
  fetchSourceCode,
10
10
  fetchSourceCodeFromStackTrace,
11
- fetchIdFromCode
12
- } = require('./util');
11
+ fetchIdFromCode,
12
+ humanize
13
+ } = require('./utils/utils');
13
14
  const upload = require('./fileUploader');
14
15
  const pipesFactory = require('./pipe');
15
16
  const adapterFactory = require('./junit-adapter');
16
- const { humanize } = require('./util')
17
17
 
18
18
  const TESTOMATIO_URL = process.env.TESTOMATIO_URL || "https://app.testomat.io";
19
19
  const TESTOMATIO = process.env.TESTOMATIO; // key?
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@testomatio/reporter",
3
- "version": "1.0.14-beta",
3
+ "version": "1.0.14",
4
4
  "description": "Testomatio Reporter Client",
5
5
  "main": "./lib/reporter.js",
6
6
  "typings": "typings/index.d.ts",
@@ -55,7 +55,7 @@
55
55
  "@redocly/cli": "^1.0.0-beta.125",
56
56
  "@wdio/reporter": "^7.16.13",
57
57
  "chai": "^4.3.6",
58
- "codeceptjs": "^3.2.3",
58
+ "codeceptjs": "latest",
59
59
  "cucumber": "^6.0.7",
60
60
  "eslint": "^8.7.0",
61
61
  "eslint-config-airbnb-base": "^15.0.0",