@testomatio/reporter 2.7.6 → 2.7.8

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.
@@ -15,7 +15,8 @@ export namespace HTML_REPORT {
15
15
  let REPORT_DEFAULT_NAME: string;
16
16
  let TEMPLATE_NAME: string;
17
17
  }
18
- export const AXIOS_TIMEOUT: number;
18
+ export const REQUEST_TIMEOUT: number;
19
+ export function getCreateRunRequestTimeout(): number;
19
20
  export const testomatLogoURL: "https://avatars.githubusercontent.com/u/59105116?s=36&v=4";
20
21
  export namespace REPORTER_REQUEST_RETRIES {
21
22
  let retryTimeout: number;
package/lib/constants.js CHANGED
@@ -3,7 +3,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.SCREENSHOTS_ON_STEPS = exports.REPORTER_REQUEST_RETRIES = exports.testomatLogoURL = exports.AXIOS_TIMEOUT = exports.HTML_REPORT = exports.STATUS = exports.CSV_HEADERS = exports.TESTOMAT_TMP_STORAGE_DIR = exports.APP_PREFIX = void 0;
6
+ exports.SCREENSHOTS_ON_STEPS = exports.REPORTER_REQUEST_RETRIES = exports.testomatLogoURL = exports.REQUEST_TIMEOUT = exports.HTML_REPORT = exports.STATUS = exports.CSV_HEADERS = exports.TESTOMAT_TMP_STORAGE_DIR = exports.APP_PREFIX = void 0;
7
+ exports.getCreateRunRequestTimeout = getCreateRunRequestTimeout;
7
8
  const picocolors_1 = __importDefault(require("picocolors"));
8
9
  const os_1 = __importDefault(require("os"));
9
10
  const path_1 = __importDefault(require("path"));
@@ -14,8 +15,8 @@ const TESTOMATIO_REQUEST_TIMEOUT = parseInt(process.env.TESTOMATIO_REQUEST_TIMEO
14
15
  if (TESTOMATIO_REQUEST_TIMEOUT) {
15
16
  console.log(`${APP_PREFIX} Request timeout is set to ${TESTOMATIO_REQUEST_TIMEOUT / 1000}s`);
16
17
  }
17
- const AXIOS_TIMEOUT = TESTOMATIO_REQUEST_TIMEOUT || 20 * 1000;
18
- exports.AXIOS_TIMEOUT = AXIOS_TIMEOUT;
18
+ const REQUEST_TIMEOUT = TESTOMATIO_REQUEST_TIMEOUT || 20 * 1000;
19
+ exports.REQUEST_TIMEOUT = REQUEST_TIMEOUT;
19
20
  const SCREENSHOTS_ON_STEPS = process.env.TESTOMATIO_SCREENSHOTS_ON_STEPS == null
20
21
  || (0, utils_js_1.transformEnvVarToBoolean)(process.env.TESTOMATIO_SCREENSHOTS_ON_STEPS);
21
22
  exports.SCREENSHOTS_ON_STEPS = SCREENSHOTS_ON_STEPS;
@@ -52,10 +53,15 @@ const REPORTER_REQUEST_RETRIES = {
52
53
  withinTimeSeconds: Number(process.env.TESTOMATIO_MAX_REQUEST_RETRIES_WITHIN_TIME_SECONDS) || 60,
53
54
  };
54
55
  exports.REPORTER_REQUEST_RETRIES = REPORTER_REQUEST_RETRIES;
56
+ function getCreateRunRequestTimeout() {
57
+ return Math.max(REQUEST_TIMEOUT, 80 * 1000);
58
+ }
59
+
60
+ module.exports.getCreateRunRequestTimeout = getCreateRunRequestTimeout;
55
61
 
56
62
  module.exports.APP_PREFIX = APP_PREFIX;
57
63
 
58
- module.exports.AXIOS_TIMEOUT = AXIOS_TIMEOUT;
64
+ module.exports.REQUEST_TIMEOUT = REQUEST_TIMEOUT;
59
65
 
60
66
  module.exports.SCREENSHOTS_ON_STEPS = SCREENSHOTS_ON_STEPS;
61
67
 
@@ -67,7 +67,7 @@ class CoveragePipe {
67
67
  // Create a new instance of gaxios with a custom config
68
68
  this.client = new gaxios_1.Gaxios({
69
69
  baseURL: `${this.url.trim()}`,
70
- timeout: constants_js_1.AXIOS_TIMEOUT,
70
+ timeout: constants_js_1.REQUEST_TIMEOUT,
71
71
  proxy: proxy ? proxy.toString() : undefined,
72
72
  retry: true,
73
73
  retryConfig: {
@@ -70,7 +70,7 @@ class TestomatioPipe {
70
70
  // Create a new instance of gaxios with a custom config
71
71
  this.client = new gaxios_1.Gaxios({
72
72
  baseURL: `${this.url.trim()}`,
73
- timeout: constants_js_1.AXIOS_TIMEOUT,
73
+ timeout: constants_js_1.REQUEST_TIMEOUT,
74
74
  proxy: proxy ? proxy.toString() : undefined,
75
75
  retry: true,
76
76
  retryConfig: {
@@ -225,6 +225,7 @@ class TestomatioPipe {
225
225
  method: 'PUT',
226
226
  url: `/api/reporter/${this.runId}`,
227
227
  data: runParams,
228
+ timeout: (0, constants_js_1.getCreateRunRequestTimeout)(),
228
229
  responseType: 'json',
229
230
  });
230
231
  if (resp.data.artifacts)
@@ -246,6 +247,7 @@ class TestomatioPipe {
246
247
  method: 'POST',
247
248
  url: '/api/reporter',
248
249
  data: runParams,
250
+ timeout: (0, constants_js_1.getCreateRunRequestTimeout)(),
249
251
  maxContentLength: Infinity,
250
252
  responseType: 'json',
251
253
  });
@@ -262,17 +264,14 @@ class TestomatioPipe {
262
264
  debug('Run created', this.runId);
263
265
  }
264
266
  catch (err) {
267
+ if (!this.apiKey)
268
+ console.error('Testomat.io API key is not set');
265
269
  const errorText = err.response?.data?.message || err.message;
266
270
  debug('Error creating run', err);
267
- console.log(errorText || err);
271
+ console.log(constants_js_1.APP_PREFIX, errorText || err);
268
272
  if (err.response?.status === 403)
269
273
  this.#disablePipe();
270
- if (!this.apiKey)
271
- console.error('Testomat.io API key is not set');
272
- if (!this.apiKey?.startsWith('tstmt'))
273
- console.error('Testomat.io API key is invalid');
274
- if (process.env.DEBUG || process.env.TESTOMATIO_DEBUG)
275
- this.#logFailedResponse(err);
274
+ this.#logFailedResponse(err);
276
275
  console.error(constants_js_1.APP_PREFIX, 'Error creating Testomat.io report (see details above), please check if your API key is valid. Skipping report');
277
276
  printCreateIssue();
278
277
  }
@@ -477,9 +476,8 @@ class TestomatioPipe {
477
476
  }
478
477
  }
479
478
  catch (err) {
480
- log_js_1.log.info('Error updating status, skipping...', err);
481
- if (process.env.DEBUG || process.env.TESTOMATIO_DEBUG)
482
- this.#logFailedResponse(err);
479
+ console.log(constants_js_1.APP_PREFIX, 'Error updating status, skipping...', err);
480
+ this.#logFailedResponse(err);
483
481
  printCreateIssue();
484
482
  }
485
483
  debug('Run finished');
@@ -501,18 +499,23 @@ class TestomatioPipe {
501
499
  responseBody = '<empty>';
502
500
  responseBody = hideTestomatioToken(responseBody);
503
501
  const statusCode = error.status || error.code || error.response?.status || '<unknown status code>';
504
- const method = error.response?.config.method || '<unknown method>';
505
- const url = error.response?.config.url || '<unknown url>';
506
- let message = picocolors_1.default.yellow('\n⚠️ Request to Testomat.io failed:\n');
507
- message += picocolors_1.default.bold(`${picocolors_1.default.red(statusCode)} ${method} ${url}\n`);
502
+ const method = error.response?.config?.method || '<unknown method>';
503
+ const url = String(error.response?.config?.url || '<unknown url>');
504
+ let message = picocolors_1.default.yellow('⚠️ Request to Testomat.io failed:\n');
505
+ message += picocolors_1.default.bold(`${picocolors_1.default.red(statusCode)} ${method} ${picocolors_1.default.gray(url)}\n`);
506
+ if (statusCode === 403) {
507
+ message += `\t${picocolors_1.default.red('Please check your API token. It might be invalid or expired.')}\n`;
508
+ }
508
509
  message += `\t${picocolors_1.default.bold('response: ')}${picocolors_1.default.gray(responseBody)}\n`;
509
510
  const requestBody = hideTestomatioToken(stringify(error.response?.config?.data));
510
- if (process.env.DEBUG || process.env.TESTOMATIO_DEBUG) {
511
+ if (process.env.DEBUG || process.env.TESTOMATIO_DEBUG || requestBody.length < 1000) {
512
+ // full body
511
513
  message += `\t${picocolors_1.default.bold('request: ')}${picocolors_1.default.gray(requestBody)}\n`;
512
514
  }
513
515
  else {
516
+ // cut body
514
517
  const requestBodyCut = requestBody.slice(0, 1000);
515
- message += `\t${picocolors_1.default.bold('request: ')}${picocolors_1.default.gray(`${requestBodyCut}.....`)}\n`;
518
+ message += `\t${picocolors_1.default.bold('request: ')}${picocolors_1.default.gray(`${requestBodyCut}...`)}\n`;
516
519
  message += '\trequest body is cut, run with TESTOMATIO_DEBUG=1 to see full body\n';
517
520
  }
518
521
  console.log(message);
package/lib/xmlReader.js CHANGED
@@ -22,15 +22,25 @@ const log_js_1 = require("./utils/log.js");
22
22
  const debug = (0, debug_1.default)('@testomatio/reporter:xml');
23
23
  const ridRunId = (0, crypto_1.randomUUID)();
24
24
  const TESTOMATIO_URL = process.env.TESTOMATIO_URL || 'https://app.testomat.io';
25
- const { TESTOMATIO_RUNGROUP_TITLE, TESTOMATIO_SUITE, TESTOMATIO_MAX_STACK_TRACE, TESTOMATIO_TITLE, TESTOMATIO_ENV, TESTOMATIO_RUN, TESTOMATIO_MARK_DETACHED, TESTOMATIO_LEGACY_NUNIT, } = process.env;
25
+ const { TESTOMATIO_RUNGROUP_TITLE, TESTOMATIO_SUITE, TESTOMATIO_MAX_STACK_TRACE, TESTOMATIO_TITLE, TESTOMATIO_ENV, TESTOMATIO_RUN, TESTOMATIO_MARK_DETACHED, TESTOMATIO_LEGACY_NUNIT, TESTOMATIO_MAX_ENTITY_EXPANSIONS, } = process.env;
26
+ const MAX_OUTPUT_LENGTH = parseInt(TESTOMATIO_MAX_STACK_TRACE, 10) || 10000;
27
+ const MAX_ENTITY_EXPANSIONS = parseInt(TESTOMATIO_MAX_ENTITY_EXPANSIONS, 10) || 10000;
28
+ const ENTITY_EXPANSION_LIMIT_REGEXP = /Entity expansion limit exceeded/i;
26
29
  const options = {
27
30
  ignoreDeclaration: true,
28
31
  ignoreAttributes: false,
29
32
  alwaysCreateTextNode: false,
30
33
  attributeNamePrefix: '',
31
34
  parseTagValue: true,
35
+ processEntities: {
36
+ enabled: true,
37
+ maxEntitySize: 10000,
38
+ maxExpansionDepth: 10,
39
+ maxTotalExpansions: MAX_ENTITY_EXPANSIONS,
40
+ maxExpandedLength: 100000,
41
+ maxEntityCount: 10000,
42
+ },
32
43
  };
33
- const MAX_OUTPUT_LENGTH = parseInt(TESTOMATIO_MAX_STACK_TRACE, 10) || 10000;
34
44
  const reduceOptions = {};
35
45
  class XmlReader {
36
46
  constructor(opts = {}) {
@@ -84,7 +94,19 @@ class XmlReader {
84
94
  for (const regex of cutRegexes) {
85
95
  xmlData = xmlData.replace(regex, (_, p1, p2, p3) => `${p1}${p2.substring(0, MAX_OUTPUT_LENGTH)}${p3}`);
86
96
  }
87
- const jsonResult = this.parser.parse(xmlData);
97
+ let jsonResult;
98
+ try {
99
+ jsonResult = this.parser.parse(xmlData);
100
+ }
101
+ catch (error) {
102
+ if (ENTITY_EXPANSION_LIMIT_REGEXP.test(error.message)) {
103
+ throw new Error(`${error.message}\n\n` +
104
+ `XML report contains more entity references than the current limit (${MAX_ENTITY_EXPANSIONS}). ` +
105
+ 'If this XML report is trusted, increase the limit with TESTOMATIO_MAX_ENTITY_EXPANSIONS, for example:\n' +
106
+ `TESTOMATIO_MAX_ENTITY_EXPANSIONS=${MAX_ENTITY_EXPANSIONS * 2} npx report-xml "{pattern}" --lang={lang}`);
107
+ }
108
+ throw error;
109
+ }
88
110
  let jsonSuite;
89
111
  if (jsonResult.testsuites) {
90
112
  jsonSuite = jsonResult.testsuites;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@testomatio/reporter",
3
- "version": "2.7.6",
3
+ "version": "2.7.8",
4
4
  "description": "Testomatio Reporter Client",
5
5
  "engines": {
6
6
  "node": ">=18"
@@ -17,7 +17,6 @@
17
17
  "@aws-sdk/lib-storage": "^3.279.0",
18
18
  "@cucumber/cucumber": "^10.9.0",
19
19
  "@octokit/rest": "^21.1.1",
20
- "aws-sdk": "^2.1072.0",
21
20
  "callsite-record": "^4.1.4",
22
21
  "commander": "^12",
23
22
  "cross-spawn": "^7.0.3",
package/src/constants.js CHANGED
@@ -8,7 +8,7 @@ const TESTOMATIO_REQUEST_TIMEOUT = parseInt(process.env.TESTOMATIO_REQUEST_TIMEO
8
8
  if (TESTOMATIO_REQUEST_TIMEOUT) {
9
9
  console.log(`${APP_PREFIX} Request timeout is set to ${TESTOMATIO_REQUEST_TIMEOUT / 1000}s`);
10
10
  }
11
- const AXIOS_TIMEOUT = TESTOMATIO_REQUEST_TIMEOUT || 20 * 1000;
11
+ const REQUEST_TIMEOUT = TESTOMATIO_REQUEST_TIMEOUT || 20 * 1000;
12
12
  const SCREENSHOTS_ON_STEPS = process.env.TESTOMATIO_SCREENSHOTS_ON_STEPS == null
13
13
  || transformEnvVarToBoolean(process.env.TESTOMATIO_SCREENSHOTS_ON_STEPS);
14
14
 
@@ -44,13 +44,18 @@ const REPORTER_REQUEST_RETRIES = {
44
44
  withinTimeSeconds: Number(process.env.TESTOMATIO_MAX_REQUEST_RETRIES_WITHIN_TIME_SECONDS) || 60,
45
45
  };
46
46
 
47
+ function getCreateRunRequestTimeout() {
48
+ return Math.max(REQUEST_TIMEOUT, 80 * 1000);
49
+ }
50
+
47
51
  export {
48
52
  APP_PREFIX,
49
53
  TESTOMAT_TMP_STORAGE_DIR,
50
54
  CSV_HEADERS,
51
55
  STATUS,
52
56
  HTML_REPORT,
53
- AXIOS_TIMEOUT,
57
+ REQUEST_TIMEOUT,
58
+ getCreateRunRequestTimeout,
54
59
  testomatLogoURL,
55
60
  REPORTER_REQUEST_RETRIES,
56
61
  SCREENSHOTS_ON_STEPS,
@@ -4,7 +4,7 @@ import yaml from 'js-yaml';
4
4
  import { execSync } from 'child_process';
5
5
  import { Gaxios } from 'gaxios';
6
6
  import { minimatch } from 'minimatch';
7
- import { APP_PREFIX, AXIOS_TIMEOUT, REPORTER_REQUEST_RETRIES } from '../constants.js';
7
+ import { APP_PREFIX, REQUEST_TIMEOUT, REPORTER_REQUEST_RETRIES } from '../constants.js';
8
8
  import { generateFilterRequestParams } from '../utils/pipe_utils.js';
9
9
  import { parsePipeOptions } from '../utils/pipe_utils.js';
10
10
  import { config } from '../config.js';
@@ -76,7 +76,7 @@ class CoveragePipe { // or Changes for the future???
76
76
  // Create a new instance of gaxios with a custom config
77
77
  this.client = new Gaxios({
78
78
  baseURL: `${this.url.trim()}`,
79
- timeout: AXIOS_TIMEOUT,
79
+ timeout: REQUEST_TIMEOUT,
80
80
  proxy: proxy ? proxy.toString() : undefined,
81
81
  retry: true,
82
82
  retryConfig: {
@@ -2,7 +2,13 @@ import createDebugMessages from 'debug';
2
2
  import pc from 'picocolors';
3
3
  import { Gaxios } from 'gaxios';
4
4
  import JsonCycle from 'json-cycle';
5
- import { APP_PREFIX, STATUS, AXIOS_TIMEOUT, REPORTER_REQUEST_RETRIES } from '../constants.js';
5
+ import {
6
+ APP_PREFIX,
7
+ STATUS,
8
+ REQUEST_TIMEOUT,
9
+ getCreateRunRequestTimeout,
10
+ REPORTER_REQUEST_RETRIES,
11
+ } from '../constants.js';
6
12
  import {
7
13
  isValidUrl,
8
14
  foundedTestLog,
@@ -81,7 +87,7 @@ class TestomatioPipe {
81
87
  // Create a new instance of gaxios with a custom config
82
88
  this.client = new Gaxios({
83
89
  baseURL: `${this.url.trim()}`,
84
- timeout: AXIOS_TIMEOUT,
90
+ timeout: REQUEST_TIMEOUT,
85
91
  proxy: proxy ? proxy.toString() : undefined,
86
92
  retry: true,
87
93
  retryConfig: {
@@ -256,6 +262,7 @@ class TestomatioPipe {
256
262
  method: 'PUT',
257
263
  url: `/api/reporter/${this.runId}`,
258
264
  data: runParams,
265
+ timeout: getCreateRunRequestTimeout(),
259
266
  responseType: 'json',
260
267
  });
261
268
  if (resp.data.artifacts) setS3Credentials(resp.data.artifacts);
@@ -277,6 +284,7 @@ class TestomatioPipe {
277
284
  method: 'POST',
278
285
  url: '/api/reporter',
279
286
  data: runParams,
287
+ timeout: getCreateRunRequestTimeout(),
280
288
  maxContentLength: Infinity,
281
289
  responseType: 'json',
282
290
  });
@@ -294,14 +302,13 @@ class TestomatioPipe {
294
302
  process.env.runId = this.runId;
295
303
  debug('Run created', this.runId);
296
304
  } catch (err) {
305
+ if (!this.apiKey) console.error('Testomat.io API key is not set');
297
306
  const errorText = err.response?.data?.message || err.message;
298
307
  debug('Error creating run', err);
299
- console.log(errorText || err);
308
+ console.log(APP_PREFIX, errorText || err);
300
309
  if (err.response?.status === 403) this.#disablePipe();
301
- if (!this.apiKey) console.error('Testomat.io API key is not set');
302
- if (!this.apiKey?.startsWith('tstmt')) console.error('Testomat.io API key is invalid');
303
310
 
304
- if (process.env.DEBUG || process.env.TESTOMATIO_DEBUG) this.#logFailedResponse(err);
311
+ this.#logFailedResponse(err);
305
312
 
306
313
  console.error(
307
314
  APP_PREFIX,
@@ -532,8 +539,8 @@ class TestomatioPipe {
532
539
  );
533
540
  }
534
541
  } catch (err) {
535
- log.info('Error updating status, skipping...', err);
536
- if (process.env.DEBUG || process.env.TESTOMATIO_DEBUG) this.#logFailedResponse(err);
542
+ console.log(APP_PREFIX, 'Error updating status, skipping...', err);
543
+ this.#logFailedResponse(err);
537
544
  printCreateIssue();
538
545
  }
539
546
  debug('Run finished');
@@ -558,19 +565,26 @@ class TestomatioPipe {
558
565
  responseBody = hideTestomatioToken(responseBody);
559
566
 
560
567
  const statusCode = error.status || error.code || error.response?.status || '<unknown status code>';
561
- const method = error.response?.config.method || '<unknown method>';
562
- const url = error.response?.config.url || '<unknown url>';
568
+ const method = error.response?.config?.method || '<unknown method>';
569
+ const url = String(error.response?.config?.url || '<unknown url>');
570
+
571
+ let message = pc.yellow('⚠️ Request to Testomat.io failed:\n');
572
+ message += pc.bold(`${pc.red(statusCode)} ${method} ${pc.gray(url)}\n`);
573
+
574
+ if (statusCode === 403) {
575
+ message += `\t${pc.red('Please check your API token. It might be invalid or expired.')}\n`;
576
+ }
563
577
 
564
- let message = pc.yellow('\n⚠️ Request to Testomat.io failed:\n');
565
- message += pc.bold(`${pc.red(statusCode)} ${method} ${url}\n`);
566
578
  message += `\t${pc.bold('response: ')}${pc.gray(responseBody)}\n`;
567
579
 
568
580
  const requestBody = hideTestomatioToken(stringify(error.response?.config?.data));
569
- if (process.env.DEBUG || process.env.TESTOMATIO_DEBUG) {
581
+ if (process.env.DEBUG || process.env.TESTOMATIO_DEBUG || requestBody.length < 1000) {
582
+ // full body
570
583
  message += `\t${pc.bold('request: ')}${pc.gray(requestBody)}\n`;
571
584
  } else {
585
+ // cut body
572
586
  const requestBodyCut = requestBody.slice(0, 1000);
573
- message += `\t${pc.bold('request: ')}${pc.gray(`${requestBodyCut}.....`)}\n`;
587
+ message += `\t${pc.bold('request: ')}${pc.gray(`${requestBodyCut}...`)}\n`;
574
588
  message += '\trequest body is cut, run with TESTOMATIO_DEBUG=1 to see full body\n';
575
589
  }
576
590
 
package/src/xmlReader.js CHANGED
@@ -39,18 +39,29 @@ const {
39
39
  TESTOMATIO_RUN,
40
40
  TESTOMATIO_MARK_DETACHED,
41
41
  TESTOMATIO_LEGACY_NUNIT,
42
+ TESTOMATIO_MAX_ENTITY_EXPANSIONS,
42
43
  } = process.env;
43
44
 
45
+ const MAX_OUTPUT_LENGTH = parseInt(TESTOMATIO_MAX_STACK_TRACE, 10) || 10000;
46
+ const MAX_ENTITY_EXPANSIONS = parseInt(TESTOMATIO_MAX_ENTITY_EXPANSIONS, 10) || 10000;
47
+ const ENTITY_EXPANSION_LIMIT_REGEXP = /Entity expansion limit exceeded/i;
48
+
44
49
  const options = {
45
50
  ignoreDeclaration: true,
46
51
  ignoreAttributes: false,
47
52
  alwaysCreateTextNode: false,
48
53
  attributeNamePrefix: '',
49
54
  parseTagValue: true,
55
+ processEntities: {
56
+ enabled: true,
57
+ maxEntitySize: 10000,
58
+ maxExpansionDepth: 10,
59
+ maxTotalExpansions: MAX_ENTITY_EXPANSIONS,
60
+ maxExpandedLength: 100000,
61
+ maxEntityCount: 10000,
62
+ },
50
63
  };
51
64
 
52
- const MAX_OUTPUT_LENGTH = parseInt(TESTOMATIO_MAX_STACK_TRACE, 10) || 10000;
53
-
54
65
  const reduceOptions = {};
55
66
 
56
67
  class XmlReader {
@@ -113,7 +124,20 @@ class XmlReader {
113
124
  xmlData = xmlData.replace(regex, (_, p1, p2, p3) => `${p1}${p2.substring(0, MAX_OUTPUT_LENGTH)}${p3}`);
114
125
  }
115
126
 
116
- const jsonResult = this.parser.parse(xmlData);
127
+ let jsonResult;
128
+ try {
129
+ jsonResult = this.parser.parse(xmlData);
130
+ } catch (error) {
131
+ if (ENTITY_EXPANSION_LIMIT_REGEXP.test(error.message)) {
132
+ throw new Error(
133
+ `${error.message}\n\n` +
134
+ `XML report contains more entity references than the current limit (${MAX_ENTITY_EXPANSIONS}). ` +
135
+ 'If this XML report is trusted, increase the limit with TESTOMATIO_MAX_ENTITY_EXPANSIONS, for example:\n' +
136
+ `TESTOMATIO_MAX_ENTITY_EXPANSIONS=${MAX_ENTITY_EXPANSIONS * 2} npx report-xml "{pattern}" --lang={lang}`,
137
+ );
138
+ }
139
+ throw error;
140
+ }
117
141
  let jsonSuite;
118
142
 
119
143
  if (jsonResult.testsuites) {