@testomatio/reporter 1.1.1-beta.1.fix-logger → 1.1.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/README.md CHANGED
@@ -65,13 +65,16 @@ yarn add @testomatio/reporter --dev
65
65
 
66
66
  ### 1️⃣ Attach Reporter to the Test Runner
67
67
 
68
+ | | | |
69
+ |--|--|--|
68
70
  | [Playwright](./docs/frameworks.md#playwright) | [CodeceptJS](./docs/frameworks.md#CodeceptJS) | [Cypress](./docs/frameworks.md#Cypress) |
69
71
  | [Jest](./docs/frameworks.md#Jest) | [Mocha](./docs/frameworks.md#Mocha) | [WebDriverIO](./docs/frameworks.md#WebDriverIO) |
70
72
  | [TestCafe](./docs/frameworks.md#TestCafe) | [Detox](./docs/frameworks.md#Detox) | [Codeception](https://github.com/testomatio/php-reporter) |
71
73
  | [Newman (Postman)](./docs/frameworks.md#Newman) | [JUnit](./docs/junit.md#junit) | [NUnit](./docs/junit.md#nunit) |
72
74
  | [PyTest](./docs/junit.md#pytest) | [PHPUnit](./docs/junit.md#phpunit) | [Protractor](./docs/frameworks.md#protractor) |
73
75
 
74
- or any [other via JUnit](./docs/junit.md) report....
76
+
77
+ or **any [other via JUnit](./docs/junit.md)** report....
75
78
 
76
79
  ### 2️⃣ Configure Reports
77
80
 
@@ -7,6 +7,8 @@ const { APP_PREFIX, STATUS: Status, TESTOMAT_TMP_STORAGE_DIR } = require('../con
7
7
  const TestomatioClient = require('../client');
8
8
  const { isArtifactsEnabled } = require('../fileUploader');
9
9
  const { parseTest, fileSystem } = require('../utils/utils');
10
+ const { services } = require('../services');
11
+ const { dataStorage } = require('../data-storage');
10
12
 
11
13
  const reportTestPromises = [];
12
14
 
@@ -17,14 +19,20 @@ class PlaywrightReporter {
17
19
  this.uploads = [];
18
20
  }
19
21
 
20
- onBegin(_config, suite) {
22
+ onBegin(config, suite) {
21
23
  // clean data storage
22
24
  fileSystem.clearDir(TESTOMAT_TMP_STORAGE_DIR);
23
25
  if (!this.client) return;
24
26
  this.suite = suite;
27
+ this.config = config;
25
28
  this.client.createRun();
26
29
  }
27
30
 
31
+ onTestBegin(testInfo) {
32
+ const fullTestTitle = getTestContextName(testInfo);
33
+ dataStorage.setContext(fullTestTitle);
34
+ }
35
+
28
36
  onTestEnd(test, result) {
29
37
  if (!this.client) return;
30
38
 
@@ -34,17 +42,22 @@ class PlaywrightReporter {
34
42
 
35
43
  const { error, duration } = result;
36
44
 
37
- const suite_title = test.parent ? test.parent.title : null;
45
+ const suite_title = test.parent
46
+ ? test.parent?.title
47
+ : path.basename(test?.location?.file);
38
48
 
39
49
  const steps = [];
40
50
  for (const step of result.steps) {
41
51
  appendStep(step, steps);
42
52
  }
43
53
 
54
+ const fullTestTitle = getTestContextName(test);
44
55
  let logs = '';
45
56
  if (result.stderr.length || result.stdout.length) {
46
57
  logs = `\n\n${chalk.bold('Logs:')}\n${chalk.red(result.stderr.join(''))}\n${result.stdout.join('')}`;
47
58
  }
59
+ const manuallyAttachedArtifacts = services.artifacts.get(fullTestTitle);
60
+ const keyValues = services.keyValues.get(fullTestTitle);
48
61
 
49
62
  const reportTestPromise = this.client
50
63
  .addTestRun(checkStatus(result.status), {
@@ -55,7 +68,8 @@ class PlaywrightReporter {
55
68
  steps: steps.join('\n'),
56
69
  time: duration,
57
70
  logs,
58
- // TODO: attach artifacts
71
+ manuallyAttachedArtifacts,
72
+ meta: keyValues,
59
73
  })
60
74
  .then(pipes => {
61
75
  testId = pipes?.filter(p => p.pipe.includes('Testomatio'))[0]?.result?.data?.test_id;
@@ -73,7 +87,24 @@ class PlaywrightReporter {
73
87
  reportTestPromises.push(reportTestPromise);
74
88
  }
75
89
 
76
- async onEnd(result) {
90
+
91
+ #getArtifactPath(artifact) {
92
+ if (artifact.path) {
93
+ if (path.isAbsolute(artifact.path)) return artifact.path;
94
+
95
+ return path.join(this.config.outputDir || this.config.projects[0].outputDir, artifact.path);
96
+ }
97
+
98
+ if (artifact.body) {
99
+ const fileName = tmpFile();
100
+ fs.writeFileSync(fileName, artifact.body);
101
+ return fileName;
102
+ }
103
+
104
+ return null;
105
+ }
106
+
107
+ async onEnd(result, config) {
77
108
  if (!this.client) return;
78
109
 
79
110
  await Promise.all(reportTestPromises);
@@ -87,11 +118,7 @@ class PlaywrightReporter {
87
118
  const { title, testId, suite_title } = upload;
88
119
 
89
120
  const files = upload.files.map(attachment => {
90
- if (attachment.body) {
91
- const fileName = tmpFile();
92
- fs.writeFileSync(fileName, attachment.body);
93
- }
94
- return { path: attachment.path, title, type: attachment.contentType };
121
+ return { path: this.#getArtifactPath(attachment), title, type: attachment.contentType };
95
122
  });
96
123
 
97
124
  promises.push(
@@ -139,6 +166,15 @@ function tmpFile(prefix = 'tmp.') {
139
166
  return path.join(tmpdir, prefix + crypto.randomBytes(16).toString('hex'));
140
167
  }
141
168
 
169
+ /**
170
+ * Returns filename + test title
171
+ * @param {*} test - testInfo object from Playwright
172
+ * @returns
173
+ */
174
+ function getTestContextName(test) {
175
+ return `${test._requireFile || ''}_${test.title}`;
176
+ }
177
+
142
178
  function initPlaywrightForStorage() {
143
179
  try {
144
180
  // @ts-ignore-next-line
@@ -146,12 +182,11 @@ function initPlaywrightForStorage() {
146
182
  const { test } = require('@playwright/test');
147
183
  // eslint-disable-next-line no-empty-pattern
148
184
  test.beforeEach(async ({}, testInfo) => {
149
- const fullTestTitle = `${testInfo.file}_${testInfo.title}`;
150
- global.testomatioTestTitle = fullTestTitle;
185
+ global.testomatioTestTitle = `${testInfo.file || ''}_${testInfo.title}`;
151
186
  });
152
187
  } catch (e) {
153
188
  // ignore
154
- }
189
+ }
155
190
  }
156
191
 
157
192
  module.exports = PlaywrightReporter;
package/lib/client.js CHANGED
@@ -27,6 +27,7 @@ class Client {
27
27
  this.pipes = pipesFactory(params, store);
28
28
  this.queue = Promise.resolve();
29
29
  this.totalUploaded = 0;
30
+ this.failedToUpload = 0;
30
31
  this.version = JSON.parse(fs.readFileSync(join(__dirname, '..', 'package.json')).toString()).version;
31
32
  this.executionList = Promise.resolve();
32
33
 
@@ -163,11 +164,14 @@ class Client {
163
164
  uploadedFiles.push(upload.uploadFileAsBuffer(buffer, fileName, this.uuid));
164
165
  }
165
166
 
166
- const artifacts = await Promise.all(uploadedFiles);
167
+ const artifacts = (await Promise.all(uploadedFiles)).filter(n => !!n);
167
168
 
168
- // global.testomatioArtifacts = [];
169
+ if (artifacts.length < uploadedFiles.length) {
170
+ const failedUploading = uploadedFiles.length - artifacts.length;
171
+ this.failedToUpload += failedUploading;
172
+ }
169
173
 
170
- this.totalUploaded += uploadedFiles.filter(n => n).length;
174
+ this.totalUploaded += artifacts.length;
171
175
 
172
176
  const data = {
173
177
  files,
@@ -233,6 +237,16 @@ class Client {
233
237
  process.env.TESTOMATIO_PRIVATE_ARTIFACTS ? 'privately' : chalk.bold('publicly')
234
238
  } uploaded to S3 bucket`,
235
239
  );
240
+
241
+ if (this.failedToUpload > 0) {
242
+ console.log(
243
+ APP_PREFIX,
244
+ chalk.yellow(
245
+ `Some artifacts were not uploaded. ${this.failedToUpload} artifacts could not be uploaded. Run tests with DEBUG="@testomatio/reporter:file-uploader" to see details"`,
246
+ ),
247
+ );
248
+ }
249
+
236
250
  }
237
251
  })
238
252
  .catch(err => console.log(APP_PREFIX, err));
@@ -295,6 +309,7 @@ class Client {
295
309
 
296
310
  function isNotInternalFrame(frame) {
297
311
  return (
312
+ frame.getFileName() &&
298
313
  frame.getFileName().includes(sep) &&
299
314
  !frame.getFileName().includes('node_modules') &&
300
315
  !frame.getFileName().includes('internal')
@@ -59,7 +59,7 @@ class DataStorage {
59
59
  putData(dataType, data, context = null) {
60
60
  if (!dataType || !data) return;
61
61
 
62
- context = context || this.context || global.testomatioTestTitle || jestHelpers.getIdOfCurrentlyRunningTest();
62
+ context = context || this.context || global.testomatioTestTitle || jestHelpers.getNameOfCurrentlyRunningTest();
63
63
  if (!context) {
64
64
  debug(`No context provided for "${dataType}" data:`, data);
65
65
  return;
@@ -85,7 +85,7 @@ class DataStorage {
85
85
  */
86
86
  getData(dataType, context) {
87
87
  // TODO: think if it could be useful
88
- // context = context || this.context || global.testomatioTestTitle || jestHelpers.getIdOfCurrentlyRunningTest();
88
+ // context = context || this.context || global.testomatioTestTitle || jestHelpers.getNameOfCurrentlyRunningTest();
89
89
 
90
90
  if (!context) {
91
91
  debug(`Trying to get "${dataType}" data without context`);
@@ -11,7 +11,6 @@ const readFile = util.promisify(fs.readFile);
11
11
  const stat = util.promisify(fs.stat);
12
12
  const chalk = require('chalk');
13
13
  const { randomUUID } = require('crypto');
14
- const memoize = require('lodash.memoize');
15
14
 
16
15
  const { APP_PREFIX } = require('./constants');
17
16
 
@@ -146,8 +145,13 @@ const uploadUsingS3 = async (filePath, runId) => {
146
145
  params
147
146
  });
148
147
 
149
- return await getS3LocationLink(out);
150
- }
148
+
149
+ const link = await getS3LocationLink(out);
150
+
151
+ debug(`Succesfully uploaded ${filePath} => ${S3_BUCKET}/${Key} | URL: ${link}`);
152
+
153
+ return link;
154
+ }
151
155
  catch (e) {
152
156
  debug('S3 file uploading error: ', e);
153
157
 
@@ -279,8 +283,6 @@ const getS3LocationLink = async (out) => {
279
283
 
280
284
  let s3Location = response?.Location;
281
285
 
282
- debug('Uploaded response.Location', s3Location);
283
-
284
286
  if (!s3Location) {
285
287
  // TODO: out: a fallback case - remove after deeper testing
286
288
  s3Location = out?.singleUploadResult?.Location;
@@ -295,8 +297,8 @@ const getS3LocationLink = async (out) => {
295
297
  };
296
298
 
297
299
  module.exports = {
298
- uploadFileByPath: memoize(uploadFileByPath),
299
- uploadFileAsBuffer: memoize(uploadFileAsBuffer),
300
+ uploadFileByPath,
301
+ uploadFileAsBuffer,
300
302
  isArtifactsEnabled,
301
303
  resetConfig,
302
304
  };
@@ -299,7 +299,7 @@ function removeColorCodes(input) {
299
299
  }
300
300
 
301
301
  const jestHelpers = {
302
- getIdOfCurrentlyRunningTest: () => {
302
+ getNameOfCurrentlyRunningTest: () => {
303
303
  if (!process.env.JEST_WORKER_ID) return null;
304
304
  try {
305
305
  // TODO: expect?.getState()?.testPath + ' ' + expect?.getState()?.currentTestName
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@testomatio/reporter",
3
- "version": "1.1.1-beta.1.fix-logger",
3
+ "version": "1.1.1",
4
4
  "description": "Testomatio Reporter Client",
5
5
  "main": "./lib/reporter.js",
6
6
  "typings": "typings/index.d.ts",