@testomatio/reporter 2.0.1-beta-2-ignore-xml → 2.0.1-beta.2

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 (66) hide show
  1. package/lib/adapter/codecept.js +0 -2
  2. package/lib/adapter/cypress-plugin/index.js +0 -2
  3. package/lib/adapter/mocha.js +0 -1
  4. package/lib/adapter/nightwatch.d.ts +4 -0
  5. package/lib/adapter/nightwatch.js +80 -0
  6. package/lib/adapter/webdriver.d.ts +1 -1
  7. package/lib/adapter/webdriver.js +18 -8
  8. package/lib/bin/cli.js +73 -8
  9. package/lib/bin/reportXml.js +4 -2
  10. package/lib/bin/startTest.js +3 -2
  11. package/lib/bin/uploadArtifacts.js +5 -4
  12. package/lib/client.js +18 -9
  13. package/lib/config.js +2 -2
  14. package/lib/data-storage.d.ts +1 -1
  15. package/lib/data-storage.js +17 -7
  16. package/lib/junit-adapter/csharp.d.ts +1 -0
  17. package/lib/junit-adapter/csharp.js +11 -1
  18. package/lib/pipe/bitbucket.d.ts +2 -0
  19. package/lib/pipe/bitbucket.js +38 -26
  20. package/lib/pipe/debug.js +17 -3
  21. package/lib/pipe/github.d.ts +2 -2
  22. package/lib/pipe/github.js +35 -3
  23. package/lib/pipe/gitlab.d.ts +2 -0
  24. package/lib/pipe/gitlab.js +27 -9
  25. package/lib/pipe/html.d.ts +1 -0
  26. package/lib/pipe/html.js +1 -3
  27. package/lib/pipe/index.js +17 -7
  28. package/lib/pipe/testomatio.d.ts +3 -2
  29. package/lib/pipe/testomatio.js +85 -75
  30. package/lib/replay.d.ts +31 -0
  31. package/lib/replay.js +237 -0
  32. package/lib/reporter.d.ts +12 -12
  33. package/lib/services/artifacts.d.ts +1 -1
  34. package/lib/services/key-values.d.ts +1 -1
  35. package/lib/services/logger.d.ts +1 -1
  36. package/lib/services/logger.js +1 -2
  37. package/lib/template/testomatio.hbs +443 -68
  38. package/lib/uploader.js +10 -6
  39. package/lib/utils/utils.d.ts +3 -1
  40. package/lib/utils/utils.js +54 -21
  41. package/lib/xmlReader.js +54 -19
  42. package/package.json +8 -9
  43. package/src/adapter/codecept.js +0 -2
  44. package/src/adapter/cypress-plugin/index.js +0 -2
  45. package/src/adapter/mocha.js +0 -1
  46. package/src/adapter/nightwatch.js +88 -0
  47. package/src/adapter/webdriver.js +2 -2
  48. package/src/bin/cli.js +70 -2
  49. package/src/bin/reportXml.js +4 -1
  50. package/src/bin/startTest.js +2 -1
  51. package/src/bin/uploadArtifacts.js +2 -1
  52. package/src/client.js +1 -2
  53. package/src/config.js +2 -2
  54. package/src/junit-adapter/csharp.js +13 -1
  55. package/src/pipe/bitbucket.js +22 -24
  56. package/src/pipe/debug.js +18 -3
  57. package/src/pipe/github.js +1 -2
  58. package/src/pipe/gitlab.js +27 -9
  59. package/src/pipe/html.js +3 -4
  60. package/src/pipe/testomatio.js +106 -105
  61. package/src/replay.js +245 -0
  62. package/src/services/logger.js +1 -2
  63. package/src/template/testomatio.hbs +443 -68
  64. package/src/uploader.js +11 -6
  65. package/src/utils/utils.js +31 -12
  66. package/src/xmlReader.js +69 -17
package/lib/pipe/debug.js CHANGED
@@ -27,7 +27,21 @@ class DebugPipe {
27
27
  this.logFilePath = path_1.default.join(os_1.default.tmpdir(), `testomatio.debug.${Date.now()}.json`);
28
28
  debug('Creating debug file:', this.logFilePath);
29
29
  fs_1.default.writeFileSync(this.logFilePath, '');
30
- console.log(constants_js_1.APP_PREFIX, '🪲. Debug created:');
30
+ // Create symlink to ensure consistent path to latest debug file
31
+ const symlinkPath = path_1.default.join(os_1.default.tmpdir(), 'testomatio.debug.latest.json');
32
+ try {
33
+ // Remove existing symlink if it exists
34
+ if (fs_1.default.existsSync(symlinkPath)) {
35
+ fs_1.default.unlinkSync(symlinkPath);
36
+ }
37
+ // Create new symlink pointing to the timestamped debug file
38
+ fs_1.default.symlinkSync(this.logFilePath, symlinkPath);
39
+ debug('Created symlink:', symlinkPath, '->', this.logFilePath);
40
+ }
41
+ catch (err) {
42
+ debug('Failed to create symlink:', err.message);
43
+ }
44
+ console.log(constants_js_1.APP_PREFIX, '🪲 Debug file created');
31
45
  this.testomatioEnvVars = Object.keys(process.env)
32
46
  .filter(key => key.startsWith('TESTOMATIO_'))
33
47
  .reduce((acc, key) => {
@@ -93,11 +107,11 @@ class DebugPipe {
93
107
  async finishRun(params) {
94
108
  if (!this.isEnabled)
95
109
  return;
96
- this.logToFile({ actions: 'finishRun', params });
97
110
  await this.batchUpload();
98
111
  if (this.batch.intervalFunction)
99
112
  clearInterval(this.batch.intervalFunction);
100
- console.log(constants_js_1.APP_PREFIX, '🪲. Debug Saved to', this.logFilePath);
113
+ this.logToFile({ action: 'finishRun', params });
114
+ console.log(constants_js_1.APP_PREFIX, '🪲 Debug Saved to', this.logFilePath);
101
115
  }
102
116
  toString() {
103
117
  return 'Debug Reporter';
@@ -23,8 +23,8 @@ declare class GitHubPipe implements Pipe {
23
23
  createRun(): Promise<void>;
24
24
  addTest(test: any): void;
25
25
  finishRun(runParams: any): Promise<void>;
26
- octokit: import("@octokit/core").Octokit & {
26
+ octokit: import("@octokit/core").Octokit & import("@octokit/plugin-rest-endpoint-methods/dist-types/generated/method-types.js").RestEndpointMethods & import("@octokit/plugin-rest-endpoint-methods").Api & {
27
27
  paginate: import("@octokit/plugin-paginate-rest").PaginateInterface;
28
- } & import("@octokit/plugin-rest-endpoint-methods/dist-types/generated/method-types.js").RestEndpointMethods & import("@octokit/plugin-rest-endpoint-methods/dist-types/types.js").Api;
28
+ };
29
29
  toString(): string;
30
30
  }
@@ -1,4 +1,37 @@
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
  };
@@ -8,7 +41,6 @@ const path_1 = __importDefault(require("path"));
8
41
  const picocolors_1 = __importDefault(require("picocolors"));
9
42
  const humanize_duration_1 = __importDefault(require("humanize-duration"));
10
43
  const lodash_merge_1 = __importDefault(require("lodash.merge"));
11
- const rest_1 = require("@octokit/rest");
12
44
  const constants_js_1 = require("../constants.js");
13
45
  const utils_js_1 = require("../utils/utils.js");
14
46
  const pipe_utils_js_1 = require("../utils/pipe_utils.js");
@@ -62,7 +94,8 @@ class GitHubPipe {
62
94
  return;
63
95
  if (runParams.tests)
64
96
  runParams.tests.forEach(t => this.addTest(t));
65
- this.octokit = new rest_1.Octokit({
97
+ const { Octokit } = await Promise.resolve().then(() => __importStar(require('@octokit/rest')));
98
+ this.octokit = new Octokit({
66
99
  auth: this.token,
67
100
  });
68
101
  const [owner, repo] = (this.repo || '').split('/');
@@ -130,7 +163,6 @@ class GitHubPipe {
130
163
  if (this.tests.length > 0) {
131
164
  body += '\n<details>\n<summary><h3>🐢 Slowest Tests</h3></summary>\n\n';
132
165
  body += this.tests
133
- // eslint-disable-next-line no-unsafe-optional-chaining
134
166
  .sort((a, b) => b?.run_time - a?.run_time)
135
167
  .slice(0, 5)
136
168
  .map(t => `* ${(0, pipe_utils_js_1.fullName)(t)} (${(0, humanize_duration_1.default)(parseFloat(t.run_time))})`)
@@ -14,6 +14,7 @@ declare class GitLabPipe {
14
14
  tests: any[];
15
15
  token: any;
16
16
  hiddenCommentData: string;
17
+ client: Gaxios;
17
18
  prepareRun(): Promise<void>;
18
19
  createRun(): Promise<void>;
19
20
  addTest(test: any): void;
@@ -21,3 +22,4 @@ declare class GitLabPipe {
21
22
  toString(): string;
22
23
  updateRun(): void;
23
24
  }
25
+ import { Gaxios } from 'gaxios';
@@ -4,7 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const debug_1 = __importDefault(require("debug"));
7
- const axios_1 = __importDefault(require("axios"));
7
+ const gaxios_1 = require("gaxios");
8
8
  const picocolors_1 = __importDefault(require("picocolors"));
9
9
  const humanize_duration_1 = __importDefault(require("humanize-duration"));
10
10
  const lodash_merge_1 = __importDefault(require("lodash.merge"));
@@ -39,6 +39,12 @@ class GitLabPipe {
39
39
  return;
40
40
  }
41
41
  this.isEnabled = true;
42
+ this.client = new gaxios_1.Gaxios({
43
+ baseURL: 'https://gitlab.com/api/v4',
44
+ headers: {
45
+ 'Content-Type': 'application/json',
46
+ }
47
+ });
42
48
  debug('GitLab Pipe: Enabled');
43
49
  }
44
50
  // TODO: to using SET opts as argument => prepareRun(opts)
@@ -119,7 +125,6 @@ class GitLabPipe {
119
125
  if (this.tests.length > 0) {
120
126
  body += '\n<details>\n<summary><h3>🐢 Slowest Tests</h3></summary>\n\n';
121
127
  body += this.tests
122
- // eslint-disable-next-line no-unsafe-optional-chaining
123
128
  .sort((a, b) => b?.run_time - a?.run_time)
124
129
  .slice(0, 5)
125
130
  .map(t => `* ${(0, pipe_utils_js_1.fullName)(t)} (${(0, humanize_duration_1.default)(parseFloat(t.run_time))})`)
@@ -127,13 +132,18 @@ class GitLabPipe {
127
132
  body += '\n</details>';
128
133
  }
129
134
  // eslint-disable-next-line max-len
130
- const commentsRequestURL = `https://gitlab.com/api/v4/projects/${this.ENV.CI_PROJECT_ID}/merge_requests/${this.ENV.CI_MERGE_REQUEST_IID}/notes`;
135
+ const commentsRequestURL = `/projects/${this.ENV.CI_PROJECT_ID}/merge_requests/${this.ENV.CI_MERGE_REQUEST_IID}/notes`;
131
136
  // delete previous report
132
- await deletePreviousReport(axios_1.default, commentsRequestURL, this.hiddenCommentData, this.token);
137
+ await deletePreviousReport(this.client, commentsRequestURL, this.hiddenCommentData, this.token);
133
138
  // add current report
134
139
  debug(`Adding comment via url: ${commentsRequestURL}`);
135
140
  try {
136
- const addCommentResponse = await axios_1.default.post(`${commentsRequestURL}?access_token=${this.token}`, { body });
141
+ const addCommentResponse = await this.client.request({
142
+ method: 'POST',
143
+ url: commentsRequestURL,
144
+ params: { access_token: this.token },
145
+ data: { body }
146
+ });
137
147
  const commentID = addCommentResponse.data.id;
138
148
  // eslint-disable-next-line max-len
139
149
  const commentURL = `${this.ENV.CI_PROJECT_URL}/-/merge_requests/${this.ENV.CI_MERGE_REQUEST_IID}#note_${commentID}`;
@@ -150,13 +160,17 @@ class GitLabPipe {
150
160
  }
151
161
  updateRun() { }
152
162
  }
153
- async function deletePreviousReport(axiosInstance, commentsRequestURL, hiddenCommentData, token) {
163
+ async function deletePreviousReport(client, commentsRequestURL, hiddenCommentData, token) {
154
164
  if (process.env.GITLAB_KEEP_OUTDATED_REPORTS)
155
165
  return;
156
166
  // get comments
157
167
  let comments = [];
158
168
  try {
159
- const response = await axiosInstance.get(`${commentsRequestURL}?access_token=${token}`);
169
+ const response = await client.request({
170
+ method: 'GET',
171
+ url: commentsRequestURL,
172
+ params: { access_token: token }
173
+ });
160
174
  comments = response.data;
161
175
  }
162
176
  catch (e) {
@@ -169,8 +183,12 @@ async function deletePreviousReport(axiosInstance, commentsRequestURL, hiddenCom
169
183
  if (comment.body.includes(hiddenCommentData)) {
170
184
  try {
171
185
  // delete previous comment
172
- const deleteCommentURL = `${commentsRequestURL}/${comment.id}?access_token=${token}`;
173
- await axiosInstance.delete(deleteCommentURL);
186
+ const deleteCommentURL = `${commentsRequestURL}/${comment.id}`;
187
+ await client.request({
188
+ method: 'DELETE',
189
+ url: deleteCommentURL,
190
+ params: { access_token: token }
191
+ });
174
192
  }
175
193
  catch (e) {
176
194
  console.warn(`Can't delete previously added comment with testomat.io report. Ignore.`);
@@ -15,6 +15,7 @@ declare class HtmlPipe {
15
15
  templateFolderPath: string;
16
16
  templateHtmlPath: string;
17
17
  createRun(): Promise<void>;
18
+ prepareRun(): Promise<void>;
18
19
  updateRun(): void;
19
20
  /**
20
21
  * Add test data to the result array for saving. As a result of this function, we get a result object to save.
package/lib/pipe/html.js CHANGED
@@ -53,6 +53,7 @@ class HtmlPipe {
53
53
  async createRun() {
54
54
  // empty
55
55
  }
56
+ async prepareRun() { }
56
57
  updateRun() {
57
58
  // empty
58
59
  }
@@ -192,7 +193,6 @@ class HtmlPipe {
192
193
  <option value="1">25</option>
193
194
  <option value="2">50</option>
194
195
  </select>`));
195
- /* eslint-disable */
196
196
  handlebars_1.default.registerHelper('emptyDataComponent', () => {
197
197
  const svgFilePath = path_1.default.join(__dirname, '..', 'template', 'emptyData.svg');
198
198
  const svgContent = fs_1.default.readFileSync(svgFilePath, 'utf8');
@@ -206,7 +206,6 @@ class HtmlPipe {
206
206
  </div>
207
207
  <div>`);
208
208
  });
209
- /* eslint-enable */
210
209
  handlebars_1.default.registerHelper('pageDispleyElements', tests => {
211
210
  // We wrapp the lines to the HTML format we need
212
211
  const totalTests = JSON.parse(JSON.stringify(tests)
@@ -234,7 +233,6 @@ class HtmlPipe {
234
233
  }
235
234
  statuses.forEach(status => {
236
235
  for (const option in paginationOptions) {
237
- // eslint-disable-next-line no-prototype-builtins
238
236
  if (paginationOptions.hasOwnProperty(option)) {
239
237
  const pageSize = paginationOptions[option];
240
238
  let filteredItems = totalTests;
package/lib/pipe/index.js CHANGED
@@ -15,13 +15,23 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
15
15
  }) : function(o, v) {
16
16
  o["default"] = v;
17
17
  });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
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
+ })();
25
35
  var __importDefault = (this && this.__importDefault) || function (mod) {
26
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
37
  };
@@ -31,7 +31,7 @@ declare class TestomatioPipe implements Pipe {
31
31
  groupTitle: any;
32
32
  env: string;
33
33
  label: string;
34
- axios: any;
34
+ client: Gaxios;
35
35
  proceed: string;
36
36
  jiraId: string;
37
37
  runId: any;
@@ -59,7 +59,7 @@ declare class TestomatioPipe implements Pipe {
59
59
  /**
60
60
  * Adds a test to the batch uploader (or reports a single test if batch uploading is disabled)
61
61
  */
62
- addTest(data: any): void;
62
+ addTest(data: any): Promise<void | import("gaxios").GaxiosResponse<any>>;
63
63
  /**
64
64
  * @param {import('../../types/types.js').RunData} params
65
65
  * @returns
@@ -68,3 +68,4 @@ declare class TestomatioPipe implements Pipe {
68
68
  toString(): string;
69
69
  #private;
70
70
  }
71
+ import { Gaxios } from 'gaxios';
@@ -5,19 +5,15 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const debug_1 = __importDefault(require("debug"));
7
7
  const picocolors_1 = __importDefault(require("picocolors"));
8
- // Retry interceptor function
9
- const axios_retry_1 = __importDefault(require("axios-retry"));
10
- // Default axios instance
11
- const axios_1 = __importDefault(require("axios"));
8
+ const gaxios_1 = require("gaxios");
12
9
  const json_cycle_1 = __importDefault(require("json-cycle"));
13
10
  const constants_js_1 = require("../constants.js");
14
11
  const utils_js_1 = require("../utils/utils.js");
15
12
  const pipe_utils_js_1 = require("../utils/pipe_utils.js");
16
13
  const config_js_1 = require("../config.js");
17
14
  const debug = (0, debug_1.default)('@testomatio/reporter:pipe:testomatio');
18
- if (process.env.TESTOMATIO_RUN) {
19
- // process.env.runId = process.env.TESTOMATIO_RUN;
20
- }
15
+ if (process.env.TESTOMATIO_RUN)
16
+ process.env.runId = process.env.TESTOMATIO_RUN;
21
17
  /**
22
18
  * @typedef {import('../../types/types.js').Pipe} Pipe
23
19
  * @typedef {import('../../types/types.js').TestData} TestData
@@ -55,48 +51,37 @@ class TestomatioPipe {
55
51
  this.groupTitle = params.groupTitle || process.env.TESTOMATIO_RUNGROUP_TITLE;
56
52
  this.env = process.env.TESTOMATIO_ENV;
57
53
  this.label = process.env.TESTOMATIO_LABEL;
58
- // Create a new instance of axios with a custom config
59
- this.axios = axios_1.default.create({
54
+ // Create a new instance of gaxios with a custom config
55
+ this.client = new gaxios_1.Gaxios({
60
56
  baseURL: `${this.url.trim()}`,
61
57
  timeout: constants_js_1.AXIOS_TIMEOUT,
62
- proxy: proxy
63
- ? {
64
- host: proxy.hostname,
65
- port: parseInt(proxy.port, 10),
66
- protocol: proxy.protocol,
67
- }
68
- : false,
69
- });
70
- // Pass the axios instance to the retry function
71
- (0, axios_retry_1.default)(this.axios, {
72
- // do not use retries for unit tests
73
- retries: constants_js_1.REPORTER_REQUEST_RETRIES.retriesPerRequest, // Number of retries
74
- shouldResetTimeout: true,
75
- retryCondition: error => {
76
- if (!error.response)
77
- return false;
78
- switch (error.response?.status) {
79
- case 400: // Bad request (probably wrong API key)
80
- case 404: // Test not matched
81
- case 429: // Rate limit exceeded
82
- case 500: // Internal server error
58
+ proxy: proxy ? proxy.toString() : undefined,
59
+ retry: true,
60
+ retryConfig: {
61
+ retry: constants_js_1.REPORTER_REQUEST_RETRIES.retriesPerRequest,
62
+ retryDelay: constants_js_1.REPORTER_REQUEST_RETRIES.retryTimeout,
63
+ httpMethodsToRetry: ['GET', 'PUT', 'HEAD', 'OPTIONS', 'DELETE', 'POST'],
64
+ shouldRetry: (error) => {
65
+ if (!error.response)
83
66
  return false;
84
- default:
85
- break;
67
+ switch (error.response?.status) {
68
+ case 400: // Bad request (probably wrong API key)
69
+ case 404: // Test not matched
70
+ case 429: // Rate limit exceeded
71
+ case 500: // Internal server error
72
+ return false;
73
+ default:
74
+ break;
75
+ }
76
+ return error.response?.status >= 401; // Retry on 401+ and 5xx
86
77
  }
87
- return error.response?.status >= 401; // Retry on 401+ and 5xx
88
- },
89
- retryDelay: () => constants_js_1.REPORTER_REQUEST_RETRIES.retryTimeout, // sum = 15sec
90
- onRetry: async (retryCount, error) => {
91
- this.retriesTimestamps.push(Date.now());
92
- debug(`${error.message || `Request failed ${error.status}`}. Retry #${retryCount} ...`);
93
- },
78
+ }
94
79
  });
95
80
  this.isEnabled = true;
96
81
  // do not finish this run (for parallel testing)
97
82
  this.proceed = process.env.TESTOMATIO_PROCEED;
98
83
  this.jiraId = process.env.TESTOMATIO_JIRA_ID;
99
- this.runId = params.runId || process.env.runId;
84
+ this.runId = params.runId || process.env.TESTOMATIO_RUN;
100
85
  this.createNewTests = params.createNewTests ?? !!process.env.TESTOMATIO_CREATE;
101
86
  this.hasUnmatchedTests = false;
102
87
  this.requestFailures = 0;
@@ -125,11 +110,14 @@ class TestomatioPipe {
125
110
  if (!q) {
126
111
  return;
127
112
  }
128
- const resp = await this.axios.get('/api/test_grep', q);
129
- const { data } = resp;
130
- if (Array.isArray(data?.tests) && data?.tests?.length > 0) {
131
- (0, utils_js_1.foundedTestLog)(constants_js_1.APP_PREFIX, data.tests);
132
- return data.tests;
113
+ const resp = await this.client.request({
114
+ method: 'GET',
115
+ url: '/api/test_grep',
116
+ params: q
117
+ });
118
+ if (Array.isArray(resp.data?.tests) && resp.data?.tests?.length > 0) {
119
+ (0, utils_js_1.foundedTestLog)(constants_js_1.APP_PREFIX, resp.data.tests);
120
+ return resp.data.tests;
133
121
  }
134
122
  console.log(constants_js_1.APP_PREFIX, `⛔ No tests found for your --filter --> ${type}=${id}`);
135
123
  }
@@ -181,16 +169,23 @@ class TestomatioPipe {
181
169
  if (this.runId) {
182
170
  this.store.runId = this.runId;
183
171
  debug(`Run with id ${this.runId} already created, updating...`);
184
- const resp = await this.axios.put(`/api/reporter/${this.runId}`, runParams);
172
+ const resp = await this.client.request({
173
+ method: 'PUT',
174
+ url: `/api/reporter/${this.runId}`,
175
+ data: runParams
176
+ });
185
177
  if (resp.data.artifacts)
186
178
  (0, pipe_utils_js_1.setS3Credentials)(resp.data.artifacts);
187
179
  return;
188
180
  }
189
181
  debug('Creating run...');
190
182
  try {
191
- const resp = await this.axios.post(`/api/reporter`, runParams, {
183
+ const resp = await this.client.request({
184
+ method: 'POST',
185
+ url: '/api/reporter',
186
+ data: runParams,
192
187
  maxContentLength: Infinity,
193
- maxBodyLength: Infinity,
188
+ responseType: 'json'
194
189
  });
195
190
  this.runId = resp.data.uid;
196
191
  this.runUrl = `${this.url}/${resp.data.url.split('/').splice(3).join('/')}`;
@@ -206,6 +201,7 @@ class TestomatioPipe {
206
201
  }
207
202
  catch (err) {
208
203
  const errorText = err.response?.data?.message || err.message;
204
+ debug('Error creating run', err);
209
205
  console.log(errorText || err);
210
206
  if (!this.apiKey)
211
207
  console.error('Testomat.io API key is not set');
@@ -246,7 +242,15 @@ class TestomatioPipe {
246
242
  }
247
243
  const json = json_cycle_1.default.stringify(data);
248
244
  debug('Adding test', json);
249
- return this.axios.post(`/api/reporter/${this.runId}/testrun`, json, axiosAddTestrunRequestConfig).catch(err => {
245
+ return this.client.request({
246
+ method: 'POST',
247
+ url: `/api/reporter/${this.runId}/testrun`,
248
+ data: json,
249
+ headers: {
250
+ 'Content-Type': 'application/json',
251
+ },
252
+ maxContentLength: Infinity
253
+ }).catch(err => {
250
254
  this.requestFailures++;
251
255
  this.notReportedTestsCount++;
252
256
  if (err.response) {
@@ -291,9 +295,19 @@ class TestomatioPipe {
291
295
  // get tests from batch and clear batch
292
296
  const testsToSend = this.batch.tests.splice(0);
293
297
  debug('📨 Batch upload', testsToSend.length, 'tests');
294
- return this.axios
295
- .post(`/api/reporter/${this.runId}/testrun`, { api_key: this.apiKey, tests: testsToSend, batch_index: this.batch.batchIndex }, axiosAddTestrunRequestConfig)
296
- .catch(err => {
298
+ return this.client.request({
299
+ method: 'POST',
300
+ url: `/api/reporter/${this.runId}/testrun`,
301
+ data: {
302
+ api_key: this.apiKey,
303
+ tests: testsToSend,
304
+ batch_index: this.batch.batchIndex
305
+ },
306
+ headers: {
307
+ 'Content-Type': 'application/json',
308
+ },
309
+ maxContentLength: Infinity
310
+ }).catch(err => {
297
311
  this.requestFailures++;
298
312
  this.notReportedTestsCount += testsToSend.length;
299
313
  if (err.response) {
@@ -317,6 +331,7 @@ class TestomatioPipe {
317
331
  * Adds a test to the batch uploader (or reports a single test if batch uploading is disabled)
318
332
  */
319
333
  addTest(data) {
334
+ this.isEnabled = this.apiKey ?? this.isEnabled;
320
335
  if (!this.isEnabled)
321
336
  return;
322
337
  if (!this.runId)
@@ -326,13 +341,16 @@ class TestomatioPipe {
326
341
  data.rid = `${this.runId}-${data.rid}`;
327
342
  data.api_key = this.apiKey;
328
343
  data.create = this.createNewTests;
344
+ let uploading = null;
329
345
  if (!this.batch.isEnabled)
330
- this.#uploadSingleTest(data);
346
+ uploading = this.#uploadSingleTest(data);
331
347
  else
332
348
  this.batch.tests.push(data);
333
349
  // if test is added after run which is already finished
334
350
  if (!this.batch.intervalFunction)
335
- this.#batchUpload();
351
+ uploading = this.#batchUpload();
352
+ // return promise to be able to wait for it
353
+ return uploading;
336
354
  }
337
355
  /**
338
356
  * @param {import('../../types/types.js').RunData} params
@@ -367,12 +385,16 @@ class TestomatioPipe {
367
385
  status_event += '_parallel';
368
386
  try {
369
387
  if (this.runId && !this.proceed) {
370
- await this.axios.put(`/api/reporter/${this.runId}`, {
371
- api_key: this.apiKey,
372
- duration: params.duration,
373
- status_event,
374
- detach: params.detach,
375
- tests: params.tests,
388
+ await this.client.request({
389
+ method: 'PUT',
390
+ url: `/api/reporter/${this.runId}`,
391
+ data: {
392
+ api_key: this.apiKey,
393
+ duration: params.duration,
394
+ status_event,
395
+ detach: params.detach,
396
+ tests: params.tests,
397
+ }
376
398
  });
377
399
  if (this.runUrl) {
378
400
  console.log(constants_js_1.APP_PREFIX, '📊 Report Saved. Report URL:', picocolors_1.default.magenta(this.runUrl));
@@ -388,17 +410,13 @@ class TestomatioPipe {
388
410
  }
389
411
  if (this.hasUnmatchedTests) {
390
412
  console.log('');
391
- // eslint-disable-next-line max-len
392
413
  console.log(constants_js_1.APP_PREFIX, picocolors_1.default.yellow(picocolors_1.default.bold('⚠️ Some reported tests were not found in Testomat.io project')));
393
- // eslint-disable-next-line max-len
394
414
  console.log(constants_js_1.APP_PREFIX, `If you use Testomat.io as a reporter only, please re-run tests using ${picocolors_1.default.bold('TESTOMATIO_CREATE=1')}`);
395
- // eslint-disable-next-line max-len
396
415
  console.log(constants_js_1.APP_PREFIX, `But to keep your tests consistent it is recommended to ${picocolors_1.default.bold('import tests first')}`);
397
416
  console.log(constants_js_1.APP_PREFIX, 'If tests were imported but still not matched, assign test IDs to your tests.');
398
417
  console.log(constants_js_1.APP_PREFIX, 'You can do that automatically via command line tools:');
399
418
  console.log(constants_js_1.APP_PREFIX, picocolors_1.default.bold('npx check-tests ... --update-ids'), 'See: https://bit.ly/js-update-ids');
400
419
  console.log(constants_js_1.APP_PREFIX, 'or for Cucumber:');
401
- // eslint-disable-next-line max-len
402
420
  console.log(constants_js_1.APP_PREFIX, picocolors_1.default.bold('npx check-cucumber ... --update-ids'), 'See: https://bit.ly/bdd-update-ids');
403
421
  }
404
422
  }
@@ -420,24 +438,16 @@ function printCreateIssue(err) {
420
438
  process.on('exit', () => {
421
439
  console.log();
422
440
  console.log(constants_js_1.APP_PREFIX, 'There was an error reporting to Testomat.io:');
423
- console.log(constants_js_1.APP_PREFIX, 'If you think this is a bug please create an issue: https://github.com/testomatio/reporter/issues/new'); // eslint-disable-line max-len
441
+ console.log(constants_js_1.APP_PREFIX, 'If you think this is a bug please create an issue: https://github.com/testomatio/reporter/issues/new');
424
442
  console.log(constants_js_1.APP_PREFIX, 'Provide this information:');
425
443
  console.log('Error:', err.message || err.code);
426
444
  if (!err.config)
427
445
  return;
428
446
  const time = new Date().toUTCString();
429
- const { data, url, baseURL, method } = err?.config || {};
447
+ const { body, url, baseURL, method } = err?.config || {};
430
448
  console.log('```js');
431
- console.log({ data: data?.replace(/"(tstmt_[^"]+)"/g, 'tstmt_*'), url, baseURL, method, time });
449
+ console.log({ body: body?.replace(/"(tstmt_[^"]+)"/g, 'tstmt_*'), url, baseURL, method, time });
432
450
  console.log('```');
433
451
  });
434
452
  }
435
- const axiosAddTestrunRequestConfig = {
436
- maxContentLength: Infinity,
437
- maxBodyLength: Infinity,
438
- headers: {
439
- // Overwrite Axios's automatically set Content-Type
440
- 'Content-Type': 'application/json',
441
- },
442
- };
443
453
  module.exports = TestomatioPipe;
@@ -0,0 +1,31 @@
1
+ export class Replay {
2
+ constructor(options?: {});
3
+ apiKey: any;
4
+ dryRun: any;
5
+ onProgress: any;
6
+ onLog: any;
7
+ onError: any;
8
+ /**
9
+ * Get the default debug file path
10
+ * @returns {string} Path to the latest debug file
11
+ */
12
+ getDefaultDebugFile(): string;
13
+ /**
14
+ * Parse a debug file and extract test data
15
+ * @param {string} debugFile - Path to the debug file
16
+ * @returns {Object} Parsed debug data
17
+ */
18
+ parseDebugFile(debugFile: string): any;
19
+ /**
20
+ * Restore environment variables from debug data
21
+ * @param {Object} envVars - Environment variables to restore
22
+ */
23
+ restoreEnvironmentVariables(envVars: any): void;
24
+ /**
25
+ * Replay test data to Testomat.io
26
+ * @param {string} debugFile - Path to debug file (optional, uses default if not provided)
27
+ * @returns {Promise<Object>} Replay results
28
+ */
29
+ replay(debugFile: string): Promise<any>;
30
+ }
31
+ export default Replay;