@testomatio/reporter 2.15.0 → 2.17.0-beta

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.
@@ -34,7 +34,9 @@ const HOOK_EXECUTION_ORDER = {
34
34
  };
35
35
  // codeceptjs workers are self-contained
36
36
  data_storage_js_1.dataStorage.isFileStorage = false;
37
- const DATA_REGEXP = /[|\s]+?(\{".*\}|\[.*\])/;
37
+ // CodeceptJS appends the serialized data row of a data-driven test to its title
38
+ const DATA_REGEXP = / \| (\{.*\}|\[.*\]|null|"(?:\\.|[^"\\])*")((?:\s+@[a-zA-Z0-9-_]+)*)$/;
39
+ const PLACEHOLDER_REGEXP = /\$\{([\w_]+)\}/g;
38
40
  if (MAJOR_VERSION < 3) {
39
41
  console.log('🔴 This reporter works with CodeceptJS 3+, please update your tests');
40
42
  }
@@ -298,16 +300,37 @@ function stripExampleFromTitle(title) {
298
300
  const res = title.match(DATA_REGEXP);
299
301
  if (!res)
300
302
  return { title, example: null };
303
+ let example = null;
304
+ let exampleParsed = false;
301
305
  try {
302
- const example = JSON.parse(res[1]);
303
- title = title.replace(DATA_REGEXP, '').trim();
304
- return { title, example };
306
+ example = JSON.parse(res[1]);
307
+ exampleParsed = true;
305
308
  }
306
309
  catch (e) {
307
- // If JSON parsing fails, return title without example
308
- debug('Failed to parse example JSON:', res[1], e.message);
309
- return { title: title.replace(DATA_REGEXP, '').trim(), example: null };
310
+ try {
311
+ example = JSON.parse(res[1].slice(1, -1));
312
+ exampleParsed = true;
313
+ }
314
+ catch (e2) {
315
+ debug('Failed to parse example from title:', res[1]);
316
+ }
310
317
  }
318
+ let baseTitle = title.slice(0, res.index).trim();
319
+ if (exampleParsed) {
320
+ baseTitle = baseTitle.replace(PLACEHOLDER_REGEXP, (placeholder, key) => {
321
+ if (key === 'current')
322
+ return formatExample(example);
323
+ if (!Object.hasOwn(example ?? {}, key))
324
+ return placeholder;
325
+ return formatExample(example[key]);
326
+ });
327
+ }
328
+ return { title: `${baseTitle}${res[2]}`, example };
329
+ }
330
+ function formatExample(example) {
331
+ if (example !== null && typeof example === 'object')
332
+ return JSON.stringify(example);
333
+ return String(example);
311
334
  }
312
335
  function stripTagsFromTitle(title) {
313
336
  // Remove @tags from the end of titles (e.g., "Hooks Test Suite @hooks" -> "Hooks Test Suite")
@@ -36,6 +36,7 @@ declare class TestomatioPipe implements Pipe {
36
36
  store: any;
37
37
  title: any;
38
38
  sharedRun: boolean;
39
+ sharedRunShards: number;
39
40
  sharedRunTimeout: number;
40
41
  groupTitle: any;
41
42
  env: string;
@@ -76,11 +76,14 @@ class TestomatioPipe {
76
76
  this.store = store || {};
77
77
  this.title = params.title || process.env.TESTOMATIO_TITLE;
78
78
  this.sharedRun = !!process.env.TESTOMATIO_SHARED_RUN;
79
+ this.sharedRunShards = process.env.TESTOMATIO_SHARDS
80
+ ? parseInt(process.env.TESTOMATIO_SHARDS, 10) || undefined
81
+ : undefined;
79
82
  this.sharedRunTimeout = process.env.TESTOMATIO_SHARED_RUN_TIMEOUT
80
83
  ? parseInt(process.env.TESTOMATIO_SHARED_RUN_TIMEOUT, 10)
81
84
  : undefined;
82
- if (this.sharedRunTimeout && !this.sharedRun) {
83
- debug('Auto-enabling sharedRun because sharedRunTimeout is set');
85
+ if ((this.sharedRunTimeout || this.sharedRunShards) && !this.sharedRun) {
86
+ debug('Auto-enabling sharedRun because sharedRunTimeout or sharedRunShards is set');
84
87
  this.sharedRun = true;
85
88
  }
86
89
  if (!this.title && (this.sharedRun || this.sharedRunTimeout)) {
@@ -290,6 +293,7 @@ class TestomatioPipe {
290
293
  label: this.label,
291
294
  shared_run: this.sharedRun,
292
295
  shared_run_timeout: this.sharedRunTimeout,
296
+ shared_run_shards: this.sharedRunShards,
293
297
  kind: params.kind,
294
298
  status: params.status,
295
299
  configuration,
@@ -527,6 +531,8 @@ class TestomatioPipe {
527
531
  status_event = 'pass';
528
532
  if (status === constants_js_1.STATUS.FAILED)
529
533
  status_event = 'fail';
534
+ if (this.sharedRun)
535
+ status_event = 'finish';
530
536
  try {
531
537
  if (this.runId && !this.proceed) {
532
538
  await this.client.request({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@testomatio/reporter",
3
- "version": "2.15.0",
3
+ "version": "2.17.0-beta",
4
4
  "description": "Testomatio Reporter Client",
5
5
  "engines": {
6
6
  "node": ">=18"
@@ -34,7 +34,9 @@ const HOOK_EXECUTION_ORDER = {
34
34
  // codeceptjs workers are self-contained
35
35
  dataStorage.isFileStorage = false;
36
36
 
37
- const DATA_REGEXP = /[|\s]+?(\{".*\}|\[.*\])/;
37
+ // CodeceptJS appends the serialized data row of a data-driven test to its title
38
+ const DATA_REGEXP = / \| (\{.*\}|\[.*\]|null|"(?:\\.|[^"\\])*")((?:\s+@[a-zA-Z0-9-_]+)*)$/;
39
+ const PLACEHOLDER_REGEXP = /\$\{([\w_]+)\}/g;
38
40
 
39
41
  if (MAJOR_VERSION < 3) {
40
42
  console.log('🔴 This reporter works with CodeceptJS 3+, please update your tests');
@@ -349,15 +351,34 @@ function stripExampleFromTitle(title) {
349
351
  const res = title.match(DATA_REGEXP);
350
352
  if (!res) return { title, example: null };
351
353
 
354
+ let example = null;
355
+ let exampleParsed = false;
352
356
  try {
353
- const example = JSON.parse(res[1]);
354
- title = title.replace(DATA_REGEXP, '').trim();
355
- return { title, example };
357
+ example = JSON.parse(res[1]);
358
+ exampleParsed = true;
356
359
  } catch (e) {
357
- // If JSON parsing fails, return title without example
358
- debug('Failed to parse example JSON:', res[1], e.message);
359
- return { title: title.replace(DATA_REGEXP, '').trim(), example: null };
360
+ try {
361
+ example = JSON.parse(res[1].slice(1, -1));
362
+ exampleParsed = true;
363
+ } catch (e2) {
364
+ debug('Failed to parse example from title:', res[1]);
365
+ }
366
+ }
367
+
368
+ let baseTitle = title.slice(0, res.index).trim();
369
+ if (exampleParsed) {
370
+ baseTitle = baseTitle.replace(PLACEHOLDER_REGEXP, (placeholder, key) => {
371
+ if (key === 'current') return formatExample(example);
372
+ if (!Object.hasOwn(example ?? {}, key)) return placeholder;
373
+ return formatExample(example[key]);
374
+ });
360
375
  }
376
+ return { title: `${baseTitle}${res[2]}`, example };
377
+ }
378
+
379
+ function formatExample(example) {
380
+ if (example !== null && typeof example === 'object') return JSON.stringify(example);
381
+ return String(example);
361
382
  }
362
383
 
363
384
  function stripTagsFromTitle(title) {
@@ -88,12 +88,15 @@ class TestomatioPipe {
88
88
  this.store = store || {};
89
89
  this.title = params.title || process.env.TESTOMATIO_TITLE;
90
90
  this.sharedRun = !!process.env.TESTOMATIO_SHARED_RUN;
91
+ this.sharedRunShards = process.env.TESTOMATIO_SHARDS
92
+ ? parseInt(process.env.TESTOMATIO_SHARDS, 10) || undefined
93
+ : undefined;
91
94
  this.sharedRunTimeout = process.env.TESTOMATIO_SHARED_RUN_TIMEOUT
92
95
  ? parseInt(process.env.TESTOMATIO_SHARED_RUN_TIMEOUT, 10)
93
96
  : undefined;
94
97
 
95
- if (this.sharedRunTimeout && !this.sharedRun) {
96
- debug('Auto-enabling sharedRun because sharedRunTimeout is set');
98
+ if ((this.sharedRunTimeout || this.sharedRunShards) && !this.sharedRun) {
99
+ debug('Auto-enabling sharedRun because sharedRunTimeout or sharedRunShards is set');
97
100
  this.sharedRun = true;
98
101
  }
99
102
 
@@ -323,6 +326,7 @@ class TestomatioPipe {
323
326
  label: this.label,
324
327
  shared_run: this.sharedRun,
325
328
  shared_run_timeout: this.sharedRunTimeout,
329
+ shared_run_shards: this.sharedRunShards,
326
330
  kind: params.kind,
327
331
  status: params.status,
328
332
  configuration,
@@ -570,6 +574,7 @@ class TestomatioPipe {
570
574
  if (status === STATUS.FINISHED) status_event = 'finish';
571
575
  if (status === STATUS.PASSED) status_event = 'pass';
572
576
  if (status === STATUS.FAILED) status_event = 'fail';
577
+ if (this.sharedRun) status_event = 'finish';
573
578
 
574
579
  try {
575
580
  if (this.runId && !this.proceed) {