@testomatio/reporter 1.3.6-beta → 1.4.1-beta-1

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/lib/client.js CHANGED
@@ -1,12 +1,14 @@
1
1
  const debug = require('debug')('@testomatio/reporter:client');
2
2
  const createCallsiteRecord = require('callsite-record');
3
3
  const { sep, join } = require('path');
4
+ const { minimatch } = require('minimatch')
4
5
  const fs = require('fs');
5
6
  const chalk = require('chalk');
6
7
  const { randomUUID } = require('crypto');
7
8
  const upload = require('./fileUploader');
8
9
  const { APP_PREFIX } = require('./constants');
9
10
  const pipesFactory = require('./pipe');
11
+ const artifactStorage = require('./storages/artifact-storage');
10
12
 
11
13
  /**
12
14
  * @typedef {import('../types').TestData} TestData
@@ -27,21 +29,74 @@ class Client {
27
29
  this.queue = Promise.resolve();
28
30
  this.totalUploaded = 0;
29
31
  this.version = JSON.parse(fs.readFileSync(join(__dirname, '..', 'package.json')).toString()).version;
32
+ this.executionList = Promise.resolve();
33
+
30
34
  console.log(APP_PREFIX, `Testomatio Reporter v${this.version}`);
31
35
  }
32
36
 
37
+ /**
38
+ * Asynchronously prepares the execution list for running tests through various pipes.
39
+ * Each pipe in the client is checked for enablement,
40
+ * and if all pipes are disabled, the function returns a resolved Promise.
41
+ * Otherwise, it executes the `prepareRun` method for each enabled pipe and collects the results.
42
+ * The results are then filtered to remove any undefined values.
43
+ * If no valid results are found, the function returns undefined.
44
+ * Otherwise, it returns the first non-empty array from the filtered results.
45
+ *
46
+ * @param {Object} params - The options for preparing the test execution list.
47
+ * @param {string} params.pipe - Name of the executed pipe.
48
+ * @param {string} params.pipeOptions - Filter option.
49
+ * @returns {Promise<any>} - A Promise that resolves to an
50
+ * array containing the prepared execution list,
51
+ * or resolves to undefined if no valid results are found or if all pipes are disabled.
52
+ */
53
+ async prepareRun(params) {
54
+ const { pipe, pipeOptions } = params;
55
+ // all pipes disabled, skipping
56
+ if (!this.pipes.some(p => p.isEnabled)) {
57
+ return Promise.resolve();
58
+ }
59
+
60
+ try {
61
+ const filterPipe = this.pipes.find(p => p.constructor.name.toLowerCase() === `${pipe.toLowerCase()}pipe`);
62
+
63
+ if (!filterPipe.isEnabled) {
64
+ // TODO:for the future for the another pipes
65
+ console.warn(
66
+ APP_PREFIX,
67
+ `At the moment processing is available only for the "testomatio" key. Example: "testomatio:tag-name=xxx"`
68
+ );
69
+ return;
70
+ }
71
+
72
+ const results = await Promise.all(this.pipes.map(async p =>
73
+ ({ pipe: p.toString(), result: await p.prepareRun(pipeOptions) })
74
+ ));
75
+
76
+ const result = results.filter(p => p.pipe.includes('Testomatio'))[0]?.result;
77
+
78
+ if (!result || result.length === 0) {
79
+ return;
80
+ }
81
+
82
+ debug('Execution tests list', result);
83
+
84
+ return result;
85
+ } catch (err) {
86
+ console.error(APP_PREFIX, err);
87
+ }
88
+ }
89
+
33
90
  /**
34
91
  * Used to create a new Test run
35
92
  *
36
93
  * @returns {Promise<any>} - resolves to Run id which should be used to update / add test
37
94
  */
38
95
  createRun() {
96
+ debug('Creating run...');
39
97
  // all pipes disabled, skipping
40
98
  if (!this.pipes?.filter(p => p.isEnabled).length) return Promise.resolve();
41
99
 
42
- global.testomatioArtifacts = [];
43
- if (!global.testomatioDataStore) global.testomatioDataStore = {};
44
-
45
100
  this.queue = this.queue
46
101
  .then(() => Promise.all(this.pipes.map(p => p.createRun())))
47
102
  .catch(err => console.log(APP_PREFIX, err))
@@ -55,10 +110,9 @@ class Client {
55
110
  *
56
111
  * @param {string|undefined} status
57
112
  * @param {TestData} [testData]
58
- * @param {string[]} [storeArtifacts]
59
113
  * @returns {Promise<PipeResult[]>}
60
114
  */
61
- async addTestRun(status, testData, storeArtifacts = []) {
115
+ async addTestRun(status, testData) {
62
116
  // all pipes disabled, skipping
63
117
  if (!this.pipes?.filter(p => p.isEnabled).length) return [];
64
118
 
@@ -92,28 +146,26 @@ class Client {
92
146
  message = error?.message;
93
147
  }
94
148
  if (steps) {
95
- stack += this.formatSteps(stack, steps);
149
+ stack = this.formatSteps(stack, steps);
96
150
  }
97
151
 
98
152
  stack += testData.stack || '';
99
153
 
154
+ // ATTACH LOGS from storage
100
155
  // in some cases (e.g. using cucumber) logger instance becomes empty object, if import at the top of the file
101
- const logger = require('./logger');
156
+ const logger = require('./storages/logger');
102
157
  const testLogs = logger.getLogs(test_id);
103
158
  // debug(`Test logs for ${test_id}:\n`, testLogs);
104
159
  if (stack) stack += '\n\n';
105
160
  stack += testLogs ? `${chalk.bold('Logs:')}\n${testLogs}` : '';
106
161
 
107
- if (Array.isArray(storeArtifacts) && storeArtifacts.length) {
108
- debug('CLIENT storeArtifact', storeArtifacts);
109
- files.push(...storeArtifacts);
110
- }
162
+ // GET ARTIFACTS from storage
163
+ const artifactFiles = artifactStorage.get(test_id);
164
+ if (artifactFiles) files.push(...artifactFiles);
111
165
 
112
- if (Array.isArray(global.testomatioArtifacts)) {
113
- debug('CLIENT global[testomatioArtifacts]', global.testomatioArtifacts);
114
- files.push(...global.testomatioArtifacts);
115
- global.testomatioArtifacts = [];
116
- }
166
+ // GET KEY-VALUEs from storage
167
+ const keyValueStorage = require('./storages/key-value-storage');
168
+ const keyValues = keyValueStorage.get(test_id);
117
169
 
118
170
  for (const file of files) {
119
171
  uploadedFiles.push(upload.uploadFileByPath(file, this.uuid));
@@ -126,7 +178,7 @@ class Client {
126
178
 
127
179
  const artifacts = await Promise.all(uploadedFiles);
128
180
 
129
- global.testomatioArtifacts = [];
181
+ // global.testomatioArtifacts = [];
130
182
 
131
183
  this.totalUploaded += uploadedFiles.filter(n => n).length;
132
184
 
@@ -144,6 +196,7 @@ class Client {
144
196
  message,
145
197
  run_time: parseFloat(time),
146
198
  artifacts,
199
+ meta: keyValues,
147
200
  };
148
201
 
149
202
  this.queue = this.queue.then(() =>
@@ -170,6 +223,7 @@ class Client {
170
223
  * @returns {Promise<any>} - A Promise that resolves when finishes the run.
171
224
  */
172
225
  updateRunStatus(status, isParallel = false) {
226
+ debug('Updating run status...');
173
227
  // all pipes disabled, skipping
174
228
  if (!this.pipes?.filter(p => p.isEnabled).length) return Promise.resolve();
175
229
 
@@ -178,14 +232,16 @@ class Client {
178
232
  this.queue = this.queue
179
233
  .then(() => Promise.all(this.pipes.map(p => p.finishRun(runParams))))
180
234
  .then(() => {
181
- debug('TOTAL uploaded files', this.totalUploaded);
235
+ debug('TOTAL artifacts', this.totalUploaded);
236
+ if (this.totalUploaded && !upload.isArtifactsEnabled())
237
+ debug(`${this.totalUploaded} artifacts are not uploaded, because artifacts uploading is not enabled`);
182
238
 
183
- if (upload.isArtifactsEnabled() && this.totalUploaded > 0) {
239
+ if (this.totalUploaded && upload.isArtifactsEnabled()) {
184
240
  console.log(
185
241
  APP_PREFIX,
186
- `🗄️ Total ${this.totalUploaded} artifacts ${
242
+ `🗄️ ${this.totalUploaded} artifacts ${
187
243
  process.env.TESTOMATIO_PRIVATE_ARTIFACTS ? 'privately' : chalk.bold('publicly')
188
- } uploaded to S3 bucket `,
244
+ } uploaded to S3 bucket`,
189
245
  );
190
246
  }
191
247
  })
@@ -212,17 +268,21 @@ class Client {
212
268
  stack += '\n\n';
213
269
  }
214
270
 
271
+ const customFilter = process.env.TESTOMATIO_STACK_IGNORE;
272
+
215
273
  try {
274
+ let hasFrame = false;
216
275
  const record = createCallsiteRecord({
217
276
  forError: error,
277
+ isCallsiteFrame: frame => {
278
+ if (customFilter && minimatch(frame.getFileName(), customFilter)) return false;
279
+ if (hasFrame) return false;
280
+ if (isNotInternalFrame(frame)) hasFrame = true;
281
+ return hasFrame;
282
+ }
218
283
  });
219
284
  if (record && !record.filename.startsWith('http')) {
220
- stack += record.renderSync({
221
- stackFilter: frame =>
222
- frame.getFileName().indexOf(sep) > -1 &&
223
- frame.getFileName().indexOf('node_modules') < 0 &&
224
- frame.getFileName().indexOf('internal') < 0,
225
- });
285
+ stack += record.renderSync({ stackFilter: isNotInternalFrame });
226
286
  }
227
287
  return stack;
228
288
  } catch (e) {
@@ -231,4 +291,10 @@ class Client {
231
291
  }
232
292
  }
233
293
 
294
+ function isNotInternalFrame(frame) {
295
+ return frame.getFileName().includes(sep) &&
296
+ !frame.getFileName().includes('node_modules') &&
297
+ !frame.getFileName().includes('internal')
298
+ }
299
+
234
300
  module.exports = Client;
package/lib/constants.js CHANGED
@@ -1,11 +1,10 @@
1
1
  const chalk = require('chalk');
2
+ const os = require('os');
3
+ const path = require('path');
2
4
 
3
5
  const APP_PREFIX = chalk.gray('[TESTOMATIO]');
4
- const TESTOMAT_ARTIFACT_SUFFIX = "testomatio_artifact_";
5
6
 
6
- const TESTOMAT_TMP_STORAGE = {
7
- mainDir: "testomatio_tmp",
8
- }
7
+ const TESTOMAT_TMP_STORAGE_DIR = path.join(os.tmpdir(), 'testomatio_tmp');
9
8
 
10
9
  const CSV_HEADERS = [
11
10
  { id: 'suite_title', title: 'Suite_title' },
@@ -24,8 +23,7 @@ const STATUS = {
24
23
 
25
24
  module.exports = {
26
25
  APP_PREFIX,
27
- TESTOMAT_ARTIFACT_SUFFIX,
28
- TESTOMAT_TMP_STORAGE,
26
+ TESTOMAT_TMP_STORAGE_DIR,
29
27
  CSV_HEADERS,
30
28
  STATUS,
31
29
  }
@@ -3,10 +3,16 @@ const { S3 } = require('@aws-sdk/client-s3');
3
3
  const { Upload } = require('@aws-sdk/lib-storage');
4
4
 
5
5
  const fs = require('fs');
6
+ const util = require('util');
6
7
  const path = require('path');
8
+ const promiseRetry = require('promise-retry');
9
+
10
+ const readFile = util.promisify(fs.readFile);
11
+ const stat = util.promisify(fs.stat);
7
12
  const chalk = require('chalk');
8
13
  const { randomUUID } = require('crypto');
9
14
  const memoize = require('lodash.memoize');
15
+
10
16
  const { APP_PREFIX } = require('./constants');
11
17
 
12
18
  const keys = [
@@ -86,6 +92,7 @@ const _getS3Config = () => {
86
92
  const uploadUsingS3 = async (filePath, runId) => {
87
93
  let ContentType;
88
94
  let Key;
95
+ let s3FileLocation;
89
96
 
90
97
  if (typeof filePath === 'object') {
91
98
  ContentType = filePath.type;
@@ -93,48 +100,67 @@ const uploadUsingS3 = async (filePath, runId) => {
93
100
  Key = filePath.name;
94
101
  }
95
102
 
96
- if (!fs.existsSync(filePath)) {
97
- console.error(chalk.yellow(`Artifacts file ${filePath} does not exist. Skipping...`));
98
- return;
99
- }
100
-
101
103
  const {
102
- TESTOMATIO_PRIVATE_ARTIFACTS, S3_BUCKET
104
+ TESTOMATIO_PRIVATE_ARTIFACTS,
105
+ S3_BUCKET
103
106
  } = getConfig();
104
107
 
105
- debug('S3 config', getMaskedConfig());
106
- debug('Uploading', filePath, 'to', S3_BUCKET);
107
-
108
- const fileData = fs.readFileSync(filePath);
108
+ try {
109
+ debug('S3 config', getMaskedConfig());
110
+ debug('Try upload', filePath, 'to', S3_BUCKET);
109
111
 
110
- Key = `${runId}/${randomUUID()}-${Key || path.basename(filePath)}`;
111
- const ACL = TESTOMATIO_PRIVATE_ARTIFACTS ? 'private' : 'public-read';
112
+ // Verification that the file was actually created: 20 attempts of 0.5 second => 10sec
113
+ const isFileExist = await checkFileExists(filePath, 20, 500);
112
114
 
113
- const s3 = new S3(_getS3Config());
115
+ if (!isFileExist) {
116
+ console.error(chalk.yellow(`Artifacts file ${filePath} does not exist. Skipping...`));
117
+ return;
118
+ }
114
119
 
115
- const params = {
116
- Bucket: S3_BUCKET,
117
- Key,
118
- Body: fileData,
119
- ContentType,
120
- ACL,
121
- };
120
+ debug('Yes, ', filePath, 'is exist.');
121
+
122
+ const fileData = await readFile(filePath);
123
+
124
+ Key = `${runId}/${randomUUID()}-${Key || path.basename(filePath)}`;
125
+
126
+ const ACL = TESTOMATIO_PRIVATE_ARTIFACTS ? 'private' : 'public-read';
127
+
128
+ if (!S3_BUCKET || !fileData) {
129
+ console.log(
130
+ APP_PREFIX,
131
+ chalk.bold.red(`Failed uploading '${Key}'. Please check S3 credentials`), getMaskedConfig());
132
+ return;
133
+ }
134
+
135
+ const s3 = new S3(_getS3Config());
136
+
137
+ const params = {
138
+ Bucket: S3_BUCKET,
139
+ Key,
140
+ Body: fileData,
141
+ ContentType,
142
+ ACL,
143
+ };
122
144
 
123
- try {
124
145
  const out = new Upload({
125
146
  client: s3,
126
147
  params
127
148
  });
128
149
 
129
- await out.done();
130
- debug('Uploaded', out.singleUploadResult.Location)
150
+ const result = await out.done();
131
151
 
132
- return out.singleUploadResult.Location;
133
- } catch (e) {
152
+ s3FileLocation = result?.Location;
153
+ debug('Uploaded location', s3FileLocation);
154
+
155
+ return s3FileLocation || console.log(
156
+ chalk.bold.red(`Problems getting the S3 artifact's link , contact the ${APP_PREFIX} team!`)
157
+ );
158
+ }
159
+ catch (e) {
134
160
  console.log(e);
135
- console.log(APP_PREFIX, chalk.red(`Failed uploading '${Key}'. Please check S3 credentials`), getMaskedConfig());
136
161
 
137
162
  console.log(APP_PREFIX, `To ${chalk.bold('disable')} artifact uploads set: TESTOMATIO_DISABLE_ARTIFACTS=1`);
163
+
138
164
  if (!TESTOMATIO_PRIVATE_ARTIFACTS) {
139
165
  console.log(APP_PREFIX, `To enable ${chalk.bold('PRIVATE')} uploads set: TESTOMATIO_PRIVATE_ARTIFACTS=1`);
140
166
  } else {
@@ -144,10 +170,11 @@ const fileData = fs.readFileSync(filePath);
144
170
  );
145
171
  }
146
172
  console.log(APP_PREFIX, '---------------');
147
- }
173
+ }
148
174
  };
149
175
 
150
176
  const uploadUsingS3AsBuffer = async (buffer, fileName, runId) => {
177
+ let s3BufferLocation;
151
178
 
152
179
  const {
153
180
  S3_REGION, S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY, S3_ENDPOINT, TESTOMATIO_PRIVATE_ARTIFACTS, S3_BUCKET
@@ -158,6 +185,18 @@ const uploadUsingS3AsBuffer = async (buffer, fileName, runId) => {
158
185
  const fileExtension = _getFileExtBase64(buffer.toString('base64'));
159
186
  const Key = `${runId}/${fileName}${fileExtension}`;
160
187
 
188
+ if (!S3_BUCKET || !buffer) {
189
+ console.log(APP_PREFIX, chalk.bold.red(`Failed uploading '${Key}'. Please check S3 credentials`), {
190
+ accessKeyId: S3_ACCESS_KEY_ID,
191
+ secretAccessKey: S3_SECRET_ACCESS_KEY ? '**** (hidden) ***' : '(empty)',
192
+ region: S3_REGION,
193
+ bucket: S3_BUCKET,
194
+ acl: ACL,
195
+ endpoint: S3_ENDPOINT,
196
+ });
197
+ return;
198
+ }
199
+
161
200
  const s3 = new S3(_getS3Config());
162
201
 
163
202
  try {
@@ -171,20 +210,20 @@ const uploadUsingS3AsBuffer = async (buffer, fileName, runId) => {
171
210
  ACL,
172
211
  }
173
212
  });
174
- await out.done();
213
+ const result = await out.done();
175
214
 
176
- return out.singleUploadResult.Location;
177
- } catch (e) {
178
- console.log(APP_PREFIX, chalk.bold.red(`Failed uploading '${Key}'. Please check S3 credentials`), {
179
- accessKeyId: S3_ACCESS_KEY_ID,
180
- secretAccessKey: S3_SECRET_ACCESS_KEY ? '**** (hidden) ***' : '(empty)',
181
- region: S3_REGION,
182
- bucket: S3_BUCKET,
183
- acl: ACL,
184
- endpoint: S3_ENDPOINT,
185
- });
215
+ s3BufferLocation = result?.Location;
216
+ debug('Uploaded location', s3BufferLocation);
217
+
218
+ return s3BufferLocation || console.log(
219
+ chalk.bold.red(`Problems getting the S3 artifact's link , contact the ${APP_PREFIX} team!`)
220
+ );
221
+ }
222
+ catch (e) {
223
+ console.log(e);
186
224
 
187
225
  console.log(APP_PREFIX, `To ${chalk.bold('disable')} artifact uploads set: TESTOMATIO_DISABLE_ARTIFACTS=1`);
226
+
188
227
  if (!TESTOMATIO_PRIVATE_ARTIFACTS) {
189
228
  console.log(APP_PREFIX, `To enable ${chalk.bold('PRIVATE')} uploads set: TESTOMATIO_PRIVATE_ARTIFACTS=1`);
190
229
  } else {
@@ -217,6 +256,35 @@ const uploadFileAsBuffer = async (buffer, fileName, runId) => {
217
256
  }
218
257
  };
219
258
 
259
+ const checkFileExists = async (filePath, attempts = 5, intervalMs = 500) => {
260
+ const checkFile = async () => {
261
+ const fileStats = await stat(filePath);
262
+ if (fileStats.isFile()) {
263
+ return true;
264
+ }
265
+
266
+ throw new Error('File not found');
267
+ };
268
+
269
+ try {
270
+ await promiseRetry(
271
+ {
272
+ retries: attempts,
273
+ minTimeout: intervalMs
274
+ },
275
+ checkFile
276
+ );
277
+
278
+ return true;
279
+ } catch (err) {
280
+ console.error(
281
+ chalk.yellow(`File ${filePath} was not found or did not have time to be generated...`)
282
+ );
283
+
284
+ return false;
285
+ }
286
+ };
287
+
220
288
  module.exports = {
221
289
  uploadFileByPath: memoize(uploadFileByPath),
222
290
  uploadFileAsBuffer: memoize(uploadFileAsBuffer),
@@ -10,24 +10,42 @@ class JavaAdapter extends Adapter {
10
10
 
11
11
  formatTest(t) {
12
12
  const fileParts = t.suite_title.split('.')
13
- const example = t.title.match(/\[(.*)\]/)?.[1];
14
- if (example) t.example = { "#": example }
15
13
 
16
14
  t.file = namespaceToFileName(t.suite_title);
17
15
  t.title = t.title.split('(')[0];
16
+
17
+ // detect params
18
+ const paramMatches = t.title.match(/\[(.*?)\]/g);
19
+
20
+ if (paramMatches) {
21
+ const params = paramMatches.map((_match, index) => `param${index + 1}`);
22
+ if (params.length === 1) params[0] = 'param';
23
+ let paramIndex = 0;
24
+
25
+ t.title = t.title.replace(/: \[(.*?)\]/g, () => {
26
+ if (params.length < 2) return `\${param}`
27
+ const paramName = params[paramIndex] || `param${paramIndex + 1}`;
28
+ paramIndex++;
29
+ return `\${${paramName}}`;
30
+ });
31
+ const example = {};
32
+ paramMatches.forEach((match, index) => { example[params[index]] = match.replace(/[[\]]/g, '') });
33
+ t.example = example;
34
+ }
35
+
18
36
  t.suite_title = fileParts[fileParts.length - 1].replace(/\$/g, ' | ')
19
37
  return t;
20
38
  }
21
39
 
22
- formatStack(t) {
23
- const stack = super.formatStack(t);
40
+ // formatStack(t) {
41
+ // const stack = super.formatStack(t);
24
42
 
25
- const file = t.suite_title.split('.');
43
+ // const file = t.suite_title.split('.');
26
44
 
27
- const fileLine = `at .*${file[file.length - 1]}\.java:(\\d+)` // eslint-disable-line no-useless-escape
28
- const regexp = new RegExp(fileLine,"g")
29
- return stack.replace(regexp, `${this.opts.javaTests}${path.sep}${namespaceToFileName(t.suite_title)}:$1:`);
30
- }
45
+ // const fileLine = `at .*${file[file.length - 1]}\.java:(\\d+)` // eslint-disable-line no-useless-escape
46
+ // const regexp = new RegExp(fileLine,"g")
47
+ // return stack.replace(regexp, `${this.opts.javaTests}${path.sep}${namespaceToFileName(t.suite_title)}:$1:`);
48
+ // }
31
49
  }
32
50
 
33
51
  function namespaceToFileName(fileName) {
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