@ciach/playwright-private-reporter 0.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.
Files changed (105) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +148 -0
  3. package/dist/cjs/bin/generate-report.d.ts +3 -0
  4. package/dist/cjs/bin/generate-report.d.ts.map +1 -0
  5. package/dist/cjs/bin/generate-report.js +6 -0
  6. package/dist/cjs/bin/generate-report.js.map +1 -0
  7. package/dist/cjs/cli/generateReport.d.ts +11 -0
  8. package/dist/cjs/cli/generateReport.d.ts.map +1 -0
  9. package/dist/cjs/cli/generateReport.js +56 -0
  10. package/dist/cjs/cli/generateReport.js.map +1 -0
  11. package/dist/cjs/config/withPrivateReporter.d.ts +4 -0
  12. package/dist/cjs/config/withPrivateReporter.d.ts.map +1 -0
  13. package/dist/cjs/config/withPrivateReporter.js +41 -0
  14. package/dist/cjs/config/withPrivateReporter.js.map +1 -0
  15. package/dist/cjs/history/diffRuns.d.ts +3 -0
  16. package/dist/cjs/history/diffRuns.d.ts.map +1 -0
  17. package/dist/cjs/history/diffRuns.js +16 -0
  18. package/dist/cjs/history/diffRuns.js.map +1 -0
  19. package/dist/cjs/history/loadPrevious.d.ts +4 -0
  20. package/dist/cjs/history/loadPrevious.d.ts.map +1 -0
  21. package/dist/cjs/history/loadPrevious.js +24 -0
  22. package/dist/cjs/history/loadPrevious.js.map +1 -0
  23. package/dist/cjs/index.d.ts +9 -0
  24. package/dist/cjs/index.d.ts.map +1 -0
  25. package/dist/cjs/index.js +21 -0
  26. package/dist/cjs/index.js.map +1 -0
  27. package/dist/cjs/package.json +1 -0
  28. package/dist/cjs/reporter/PrivateReporter.d.ts +16 -0
  29. package/dist/cjs/reporter/PrivateReporter.d.ts.map +1 -0
  30. package/dist/cjs/reporter/PrivateReporter.js +109 -0
  31. package/dist/cjs/reporter/PrivateReporter.js.map +1 -0
  32. package/dist/cjs/reporter/attachments.d.ts +9 -0
  33. package/dist/cjs/reporter/attachments.d.ts.map +1 -0
  34. package/dist/cjs/reporter/attachments.js +15 -0
  35. package/dist/cjs/reporter/attachments.js.map +1 -0
  36. package/dist/cjs/reporter/fingerprint.d.ts +12 -0
  37. package/dist/cjs/reporter/fingerprint.d.ts.map +1 -0
  38. package/dist/cjs/reporter/fingerprint.js +37 -0
  39. package/dist/cjs/reporter/fingerprint.js.map +1 -0
  40. package/dist/cjs/reporter/summary.d.ts +25 -0
  41. package/dist/cjs/reporter/summary.d.ts.map +1 -0
  42. package/dist/cjs/reporter/summary.js +105 -0
  43. package/dist/cjs/reporter/summary.js.map +1 -0
  44. package/dist/cjs/templates/summary.html.d.ts +3 -0
  45. package/dist/cjs/templates/summary.html.d.ts.map +1 -0
  46. package/dist/cjs/templates/summary.html.js +64 -0
  47. package/dist/cjs/templates/summary.html.js.map +1 -0
  48. package/dist/cjs/types/schema.d.ts +96 -0
  49. package/dist/cjs/types/schema.d.ts.map +1 -0
  50. package/dist/cjs/types/schema.js +3 -0
  51. package/dist/cjs/types/schema.js.map +1 -0
  52. package/dist/esm/bin/generate-report.d.ts +3 -0
  53. package/dist/esm/bin/generate-report.d.ts.map +1 -0
  54. package/dist/esm/bin/generate-report.js +4 -0
  55. package/dist/esm/bin/generate-report.js.map +1 -0
  56. package/dist/esm/cli/generateReport.d.ts +11 -0
  57. package/dist/esm/cli/generateReport.d.ts.map +1 -0
  58. package/dist/esm/cli/generateReport.js +54 -0
  59. package/dist/esm/cli/generateReport.js.map +1 -0
  60. package/dist/esm/config/withPrivateReporter.d.ts +4 -0
  61. package/dist/esm/config/withPrivateReporter.d.ts.map +1 -0
  62. package/dist/esm/config/withPrivateReporter.js +38 -0
  63. package/dist/esm/config/withPrivateReporter.js.map +1 -0
  64. package/dist/esm/history/diffRuns.d.ts +3 -0
  65. package/dist/esm/history/diffRuns.d.ts.map +1 -0
  66. package/dist/esm/history/diffRuns.js +13 -0
  67. package/dist/esm/history/diffRuns.js.map +1 -0
  68. package/dist/esm/history/loadPrevious.d.ts +4 -0
  69. package/dist/esm/history/loadPrevious.d.ts.map +1 -0
  70. package/dist/esm/history/loadPrevious.js +20 -0
  71. package/dist/esm/history/loadPrevious.js.map +1 -0
  72. package/dist/esm/index.d.ts +9 -0
  73. package/dist/esm/index.d.ts.map +1 -0
  74. package/dist/esm/index.js +8 -0
  75. package/dist/esm/index.js.map +1 -0
  76. package/dist/esm/package.json +1 -0
  77. package/dist/esm/reporter/PrivateReporter.d.ts +16 -0
  78. package/dist/esm/reporter/PrivateReporter.d.ts.map +1 -0
  79. package/dist/esm/reporter/PrivateReporter.js +105 -0
  80. package/dist/esm/reporter/PrivateReporter.js.map +1 -0
  81. package/dist/esm/reporter/attachments.d.ts +9 -0
  82. package/dist/esm/reporter/attachments.d.ts.map +1 -0
  83. package/dist/esm/reporter/attachments.js +11 -0
  84. package/dist/esm/reporter/attachments.js.map +1 -0
  85. package/dist/esm/reporter/fingerprint.d.ts +12 -0
  86. package/dist/esm/reporter/fingerprint.d.ts.map +1 -0
  87. package/dist/esm/reporter/fingerprint.js +32 -0
  88. package/dist/esm/reporter/fingerprint.js.map +1 -0
  89. package/dist/esm/reporter/summary.d.ts +25 -0
  90. package/dist/esm/reporter/summary.d.ts.map +1 -0
  91. package/dist/esm/reporter/summary.js +99 -0
  92. package/dist/esm/reporter/summary.js.map +1 -0
  93. package/dist/esm/templates/summary.html.d.ts +3 -0
  94. package/dist/esm/templates/summary.html.d.ts.map +1 -0
  95. package/dist/esm/templates/summary.html.js +61 -0
  96. package/dist/esm/templates/summary.html.js.map +1 -0
  97. package/dist/esm/types/schema.d.ts +96 -0
  98. package/dist/esm/types/schema.d.ts.map +1 -0
  99. package/dist/esm/types/schema.js +2 -0
  100. package/dist/esm/types/schema.js.map +1 -0
  101. package/examples/Jenkinsfile +82 -0
  102. package/examples/playwright.config.ts +19 -0
  103. package/package.json +78 -0
  104. package/schemas/failures.schema.json +82 -0
  105. package/schemas/run.schema.json +98 -0
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.normalizeErrorMessage = normalizeErrorMessage;
4
+ exports.extractFirstMeaningfulStack = extractFirstMeaningfulStack;
5
+ exports.createFailureFingerprint = createFailureFingerprint;
6
+ const node_crypto_1 = require("node:crypto");
7
+ function normalizeErrorMessage(message) {
8
+ if (!message) {
9
+ return 'Unknown error';
10
+ }
11
+ return message
12
+ .replace(/\b\d+ms\b/g, '<duration>')
13
+ .replace(/https?:\/\/\S+/g, '<url>')
14
+ .replace(/\/workspace\/[\w\-/\.]+/g, '<workspace-path>')
15
+ .trim();
16
+ }
17
+ function extractFirstMeaningfulStack(stack) {
18
+ if (!stack) {
19
+ return undefined;
20
+ }
21
+ return stack
22
+ .split('\n')
23
+ .map((line) => line.trim())
24
+ .find((line) => line.length > 0 && !line.startsWith('Error:'));
25
+ }
26
+ function createFailureFingerprint(parts) {
27
+ const payload = [
28
+ parts.testFile,
29
+ parts.titlePath.join(' › '),
30
+ parts.projectName ?? '',
31
+ parts.firstMeaningfulStack ?? '',
32
+ parts.normalizedMessage,
33
+ parts.stepTitle ?? '',
34
+ ].join('||');
35
+ return (0, node_crypto_1.createHash)('sha256').update(payload).digest('hex').slice(0, 16);
36
+ }
37
+ //# sourceMappingURL=fingerprint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fingerprint.js","sourceRoot":"","sources":["../../../src/reporter/fingerprint.ts"],"names":[],"mappings":";;AAWA,sDAUC;AAED,kEASC;AAED,4DAWC;AA7CD,6CAAyC;AAWzC,SAAgB,qBAAqB,CAAC,OAA2B;IAC/D,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,eAAe,CAAC;IACzB,CAAC;IAED,OAAO,OAAO;SACX,OAAO,CAAC,YAAY,EAAE,YAAY,CAAC;SACnC,OAAO,CAAC,iBAAiB,EAAE,OAAO,CAAC;SACnC,OAAO,CAAC,0BAA0B,EAAE,kBAAkB,CAAC;SACvD,IAAI,EAAE,CAAC;AACZ,CAAC;AAED,SAAgB,2BAA2B,CAAC,KAAyB;IACnE,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO,KAAK;SACT,KAAK,CAAC,IAAI,CAAC;SACX,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;SAC1B,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC;AACnE,CAAC;AAED,SAAgB,wBAAwB,CAAC,KAAuB;IAC9D,MAAM,OAAO,GAAG;QACd,KAAK,CAAC,QAAQ;QACd,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC;QAC3B,KAAK,CAAC,WAAW,IAAI,EAAE;QACvB,KAAK,CAAC,oBAAoB,IAAI,EAAE;QAChC,KAAK,CAAC,iBAAiB;QACvB,KAAK,CAAC,SAAS,IAAI,EAAE;KACtB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEb,OAAO,IAAA,wBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACzE,CAAC"}
@@ -0,0 +1,25 @@
1
+ import type { AttachmentRecord, FailureGroup, FailuresSummary, HistoryDiff, PrivateReporterOptions, RunCounts, RunSummary } from '../types/schema.js';
2
+ export type FailureInput = {
3
+ fingerprint: string;
4
+ title: string;
5
+ normalizedMessage: string;
6
+ firstMeaningfulStack?: string;
7
+ testFile: string;
8
+ projectName?: string;
9
+ status: FailureGroup['status'];
10
+ id: string;
11
+ titlePath: string[];
12
+ location?: string;
13
+ retry: number;
14
+ attachments: AttachmentRecord[];
15
+ };
16
+ export declare function createEmptyCounts(): RunCounts;
17
+ export declare function summarizeFailures(inputs: FailureInput[]): FailureGroup[];
18
+ export declare function buildRunSummary(params: {
19
+ options: PrivateReporterOptions;
20
+ counts: RunCounts;
21
+ groupedFailures: FailureGroup[];
22
+ historyDiff?: HistoryDiff;
23
+ }): RunSummary;
24
+ export declare function buildFailuresSummary(options: PrivateReporterOptions, groups: FailureGroup[]): FailuresSummary;
25
+ //# sourceMappingURL=summary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"summary.d.ts","sourceRoot":"","sources":["../../../src/reporter/summary.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAChB,YAAY,EACZ,eAAe,EACf,WAAW,EACX,sBAAsB,EACtB,SAAS,EACT,UAAU,EACX,MAAM,oBAAoB,CAAC;AAE5B,MAAM,MAAM,YAAY,GAAG;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,iBAAiB,EAAE,MAAM,CAAC;IAC1B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,YAAY,CAAC,QAAQ,CAAC,CAAC;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,gBAAgB,EAAE,CAAC;CACjC,CAAC;AAEF,wBAAgB,iBAAiB,IAAI,SAAS,CAS7C;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,YAAY,EAAE,CA0CxE;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE;IACtC,OAAO,EAAE,sBAAsB,CAAC;IAChC,MAAM,EAAE,SAAS,CAAC;IAClB,eAAe,EAAE,YAAY,EAAE,CAAC;IAChC,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B,GAAG,UAAU,CAwCb;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,sBAAsB,EAAE,MAAM,EAAE,YAAY,EAAE,GAAG,eAAe,CAO7G"}
@@ -0,0 +1,105 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createEmptyCounts = createEmptyCounts;
4
+ exports.summarizeFailures = summarizeFailures;
5
+ exports.buildRunSummary = buildRunSummary;
6
+ exports.buildFailuresSummary = buildFailuresSummary;
7
+ function createEmptyCounts() {
8
+ return {
9
+ passed: 0,
10
+ failed: 0,
11
+ skipped: 0,
12
+ flaky: 0,
13
+ timedOut: 0,
14
+ interrupted: 0,
15
+ };
16
+ }
17
+ function summarizeFailures(inputs) {
18
+ const grouped = new Map();
19
+ for (const failure of inputs) {
20
+ const existing = grouped.get(failure.fingerprint);
21
+ if (existing) {
22
+ existing.countInRun += 1;
23
+ existing.tests.push({
24
+ id: failure.id,
25
+ titlePath: failure.titlePath,
26
+ location: failure.location,
27
+ retry: failure.retry,
28
+ status: failure.status,
29
+ attachments: failure.attachments,
30
+ });
31
+ continue;
32
+ }
33
+ grouped.set(failure.fingerprint, {
34
+ fingerprint: failure.fingerprint,
35
+ title: failure.title,
36
+ normalizedMessage: failure.normalizedMessage,
37
+ firstMeaningfulStack: failure.firstMeaningfulStack,
38
+ testFile: failure.testFile,
39
+ projectName: failure.projectName,
40
+ status: failure.status,
41
+ countInRun: 1,
42
+ tests: [
43
+ {
44
+ id: failure.id,
45
+ titlePath: failure.titlePath,
46
+ location: failure.location,
47
+ retry: failure.retry,
48
+ status: failure.status,
49
+ attachments: failure.attachments,
50
+ },
51
+ ],
52
+ exampleAttachments: failure.attachments.slice(0, 3),
53
+ });
54
+ }
55
+ return [...grouped.values()].sort((left, right) => right.countInRun - left.countInRun);
56
+ }
57
+ function buildRunSummary(params) {
58
+ const buildUrlEnv = params.options.buildUrlEnv ?? 'BUILD_URL';
59
+ const buildIdEnv = params.options.buildIdEnv ?? 'BUILD_TAG';
60
+ const branchEnv = params.options.branchEnv ?? 'BRANCH_NAME';
61
+ const commitEnv = params.options.commitEnv ?? 'GIT_COMMIT';
62
+ const history = params.historyDiff;
63
+ const hasFailures = params.counts.failed + params.counts.timedOut + params.counts.interrupted > 0;
64
+ return {
65
+ schemaVersion: '1.0',
66
+ projectName: params.options.projectName,
67
+ generatedAt: new Date().toISOString(),
68
+ run: {
69
+ status: hasFailures ? 'failed' : 'passed',
70
+ buildId: process.env[buildIdEnv],
71
+ buildUrl: process.env[buildUrlEnv],
72
+ branch: process.env[branchEnv],
73
+ commit: process.env[commitEnv],
74
+ },
75
+ counts: params.counts,
76
+ projects: [],
77
+ history: {
78
+ enabled: Boolean(params.options.enableHistoryDiff),
79
+ previousBuildId: undefined,
80
+ newFailures: history?.newFailures.length ?? 0,
81
+ fixedFailures: history?.fixedFailures.length ?? 0,
82
+ stillFailing: history?.stillFailing.length ?? 0,
83
+ },
84
+ artifacts: {
85
+ blobReportDir: 'blob-report',
86
+ playwrightHtmlDir: 'playwright-report',
87
+ testResultsDir: 'test-results',
88
+ junitPath: 'junit/results.xml',
89
+ internalReportDir: 'internal-report',
90
+ },
91
+ failures: {
92
+ totalGroups: params.groupedFailures.length,
93
+ topFingerprint: params.groupedFailures[0]?.fingerprint,
94
+ },
95
+ };
96
+ }
97
+ function buildFailuresSummary(options, groups) {
98
+ return {
99
+ schemaVersion: '1.0',
100
+ projectName: options.projectName,
101
+ generatedAt: new Date().toISOString(),
102
+ groups,
103
+ };
104
+ }
105
+ //# sourceMappingURL=summary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"summary.js","sourceRoot":"","sources":["../../../src/reporter/summary.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { FailuresSummary, RunSummary } from '../types/schema.js';
2
+ export declare function renderSummaryHtml(run: RunSummary, failures: FailuresSummary): string;
3
+ //# sourceMappingURL=summary.html.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"summary.html.d.ts","sourceRoot":"","sources":["../../../src/templates/summary.html.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAWtE,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,UAAU,EAAE,QAAQ,EAAE,eAAe,GAAG,MAAM,CAsDpF"}
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.renderSummaryHtml = renderSummaryHtml;
4
+ function escapeHtml(value) {
5
+ return (value ?? '')
6
+ .replaceAll('&', '&amp;')
7
+ .replaceAll('<', '&lt;')
8
+ .replaceAll('>', '&gt;')
9
+ .replaceAll('"', '&quot;')
10
+ .replaceAll("'", '&#39;');
11
+ }
12
+ function renderSummaryHtml(run, failures) {
13
+ const failureItems = failures.groups
14
+ .slice(0, 10)
15
+ .map((group) => `
16
+ <li>
17
+ <strong>${escapeHtml(group.title)}</strong>
18
+ <div>Fingerprint: <code>${escapeHtml(group.fingerprint)}</code></div>
19
+ <div>Occurrences: ${group.countInRun}</div>
20
+ <div>${escapeHtml(group.normalizedMessage)}</div>
21
+ </li>`)
22
+ .join('');
23
+ return `<!DOCTYPE html>
24
+ <html lang="en">
25
+ <head>
26
+ <meta charset="utf-8" />
27
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
28
+ <title>${escapeHtml(run.projectName)} test summary</title>
29
+ <style>
30
+ body { font-family: Arial, sans-serif; margin: 2rem; color: #1f2937; }
31
+ .grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 1rem; }
32
+ .card { border: 1px solid #d1d5db; border-radius: 8px; padding: 1rem; background: #fff; }
33
+ code { background: #f3f4f6; padding: 0.1rem 0.3rem; border-radius: 4px; }
34
+ ul { padding-left: 1.25rem; }
35
+ </style>
36
+ </head>
37
+ <body>
38
+ <h1>${escapeHtml(run.projectName)} Playwright Summary</h1>
39
+ <p>Status: <strong>${escapeHtml(run.run.status)}</strong></p>
40
+ <div class="grid">
41
+ <div class="card"><div>Passed</div><strong>${run.counts.passed}</strong></div>
42
+ <div class="card"><div>Failed</div><strong>${run.counts.failed}</strong></div>
43
+ <div class="card"><div>Skipped</div><strong>${run.counts.skipped}</strong></div>
44
+ <div class="card"><div>Flaky</div><strong>${run.counts.flaky}</strong></div>
45
+ </div>
46
+ <h2>Build metadata</h2>
47
+ <ul>
48
+ <li>Build ID: ${escapeHtml(run.run.buildId)}</li>
49
+ <li>Branch: ${escapeHtml(run.run.branch)}</li>
50
+ <li>Commit: ${escapeHtml(run.run.commit)}</li>
51
+ <li>Build URL: ${run.run.buildUrl ? `<a href="${escapeHtml(run.run.buildUrl)}">${escapeHtml(run.run.buildUrl)}</a>` : 'n/a'}</li>
52
+ </ul>
53
+ <h2>Failure groups</h2>
54
+ <ul>${failureItems || '<li>No failing groups 🎉</li>'}</ul>
55
+ <h2>Artifacts</h2>
56
+ <ul>
57
+ <li><a href="../playwright-report/index.html">Merged Playwright HTML report</a></li>
58
+ <li><a href="../junit/results.xml">JUnit XML</a></li>
59
+ <li><a href="../test-results/">Test results attachments</a></li>
60
+ </ul>
61
+ </body>
62
+ </html>`;
63
+ }
64
+ //# sourceMappingURL=summary.html.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"summary.html.js","sourceRoot":"","sources":["../../../src/templates/summary.html.ts"],"names":[],"mappings":";;AAWA,8CAsDC;AA/DD,SAAS,UAAU,CAAC,KAAyB;IAC3C,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC;SACjB,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC;SACxB,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC;SACvB,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC;SACvB,UAAU,CAAC,GAAG,EAAE,QAAQ,CAAC;SACzB,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;AAC9B,CAAC;AAED,SAAgB,iBAAiB,CAAC,GAAe,EAAE,QAAyB;IAC1E,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM;SACjC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;SACZ,GAAG,CACF,CAAC,KAAK,EAAE,EAAE,CAAC;;oBAEG,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC;oCACP,UAAU,CAAC,KAAK,CAAC,WAAW,CAAC;8BACnC,KAAK,CAAC,UAAU;iBAC7B,UAAU,CAAC,KAAK,CAAC,iBAAiB,CAAC;cACtC,CACT;SACA,IAAI,CAAC,EAAE,CAAC,CAAC;IAEZ,OAAO;;;;;aAKI,UAAU,CAAC,GAAG,CAAC,WAAW,CAAC;;;;;;;;;;UAU9B,UAAU,CAAC,GAAG,CAAC,WAAW,CAAC;yBACZ,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC;;mDAEA,GAAG,CAAC,MAAM,CAAC,MAAM;mDACjB,GAAG,CAAC,MAAM,CAAC,MAAM;oDAChB,GAAG,CAAC,MAAM,CAAC,OAAO;kDACpB,GAAG,CAAC,MAAM,CAAC,KAAK;;;;sBAI5C,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC;oBAC7B,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC;oBAC1B,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,CAAC;uBACvB,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK;;;UAGvH,YAAY,IAAI,+BAA+B;;;;;;;;QAQjD,CAAC;AACT,CAAC"}
@@ -0,0 +1,96 @@
1
+ export type PrivateReporterOptions = {
2
+ projectName: string;
3
+ outputDir?: string;
4
+ summaryTitle?: string;
5
+ enableHistoryDiff?: boolean;
6
+ ci?: boolean;
7
+ buildUrlEnv?: string;
8
+ buildIdEnv?: string;
9
+ branchEnv?: string;
10
+ commitEnv?: string;
11
+ };
12
+ export type AttachmentRecord = {
13
+ name: string;
14
+ contentType?: string;
15
+ path?: string;
16
+ };
17
+ export type FailureTestRecord = {
18
+ id: string;
19
+ titlePath: string[];
20
+ location?: string;
21
+ retry: number;
22
+ status: 'failed' | 'timedOut' | 'interrupted' | 'flaky';
23
+ attachments: AttachmentRecord[];
24
+ };
25
+ export type FailureGroup = {
26
+ fingerprint: string;
27
+ title: string;
28
+ normalizedMessage: string;
29
+ firstMeaningfulStack?: string;
30
+ testFile: string;
31
+ projectName?: string;
32
+ status: FailureTestRecord['status'];
33
+ countInRun: number;
34
+ tests: FailureTestRecord[];
35
+ exampleAttachments: AttachmentRecord[];
36
+ history?: {
37
+ firstSeen?: string;
38
+ lastSeen?: string;
39
+ state: 'new' | 'still-failing' | 'fixed' | 'unknown';
40
+ };
41
+ };
42
+ export type RunCounts = {
43
+ passed: number;
44
+ failed: number;
45
+ skipped: number;
46
+ flaky: number;
47
+ timedOut: number;
48
+ interrupted: number;
49
+ };
50
+ export type RunSummary = {
51
+ schemaVersion: '1.0';
52
+ projectName: string;
53
+ generatedAt: string;
54
+ run: {
55
+ status: 'passed' | 'failed' | 'partial';
56
+ buildId?: string;
57
+ buildUrl?: string;
58
+ branch?: string;
59
+ commit?: string;
60
+ };
61
+ counts: RunCounts;
62
+ projects: Array<{
63
+ name: string;
64
+ counts: RunCounts;
65
+ }>;
66
+ history: {
67
+ enabled: boolean;
68
+ previousBuildId?: string;
69
+ newFailures: number;
70
+ fixedFailures: number;
71
+ stillFailing: number;
72
+ };
73
+ artifacts: {
74
+ blobReportDir: string;
75
+ playwrightHtmlDir: string;
76
+ testResultsDir: string;
77
+ junitPath: string;
78
+ internalReportDir: string;
79
+ };
80
+ failures: {
81
+ totalGroups: number;
82
+ topFingerprint?: string;
83
+ };
84
+ };
85
+ export type FailuresSummary = {
86
+ schemaVersion: '1.0';
87
+ projectName: string;
88
+ generatedAt: string;
89
+ groups: FailureGroup[];
90
+ };
91
+ export type HistoryDiff = {
92
+ newFailures: FailureGroup[];
93
+ fixedFailures: FailureGroup[];
94
+ stillFailing: FailureGroup[];
95
+ };
96
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/types/schema.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/types/schema.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=generate-report.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-report.d.ts","sourceRoot":"","sources":["../../../src/bin/generate-report.ts"],"names":[],"mappings":""}
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ import { runFromCli } from '../cli/generateReport.js';
3
+ void runFromCli();
4
+ //# sourceMappingURL=generate-report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate-report.js","sourceRoot":"","sources":["../../../src/bin/generate-report.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAEtD,KAAK,UAAU,EAAE,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { PrivateReporterOptions } from '../types/schema.js';
2
+ export type GenerateReportCliOptions = {
3
+ currentRunPath?: string;
4
+ currentFailuresPath?: string;
5
+ previousFailuresPath?: string;
6
+ outputDir?: string;
7
+ };
8
+ export declare function generateReport(reporterOptions: PrivateReporterOptions, cliOptions?: GenerateReportCliOptions): Promise<void>;
9
+ declare function runFromCli(): Promise<void>;
10
+ export { runFromCli };
11
+ //# sourceMappingURL=generateReport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generateReport.d.ts","sourceRoot":"","sources":["../../../src/cli/generateReport.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAmB,sBAAsB,EAAc,MAAM,oBAAoB,CAAC;AAE9F,MAAM,MAAM,wBAAwB,GAAG;IACrC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,wBAAsB,cAAc,CAClC,eAAe,EAAE,sBAAsB,EACvC,UAAU,GAAE,wBAA6B,GACxC,OAAO,CAAC,IAAI,CAAC,CAwCf;AAED,iBAAe,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CASzC;AAGD,OAAO,EAAE,UAAU,EAAE,CAAC"}
@@ -0,0 +1,54 @@
1
+ import { mkdir, readFile, writeFile } from 'node:fs/promises';
2
+ import { resolve } from 'node:path';
3
+ import { loadPreviousFailuresSummary } from '../history/loadPrevious.js';
4
+ import { diffFailureGroups } from '../history/diffRuns.js';
5
+ import { renderSummaryHtml } from '../templates/summary.html.js';
6
+ export async function generateReport(reporterOptions, cliOptions = {}) {
7
+ const currentRunPath = resolve(cliOptions.currentRunPath ?? 'artifacts/internal-report/run.json');
8
+ const currentFailuresPath = resolve(cliOptions.currentFailuresPath ?? 'artifacts/internal-report/failures.json');
9
+ const previousFailuresPath = cliOptions.previousFailuresPath
10
+ ? resolve(cliOptions.previousFailuresPath)
11
+ : undefined;
12
+ const outputDir = resolve(cliOptions.outputDir ?? 'artifacts/internal-report');
13
+ const runSummary = JSON.parse(await readFile(currentRunPath, 'utf8'));
14
+ const failuresSummary = JSON.parse(await readFile(currentFailuresPath, 'utf8'));
15
+ const previousFailures = previousFailuresPath
16
+ ? await loadPreviousFailuresSummary(previousFailuresPath)
17
+ : undefined;
18
+ const diff = previousFailures ? diffFailureGroups(failuresSummary.groups, previousFailures.groups) : undefined;
19
+ if (diff) {
20
+ runSummary.history.newFailures = diff.newFailures.length;
21
+ runSummary.history.fixedFailures = diff.fixedFailures.length;
22
+ runSummary.history.stillFailing = diff.stillFailing.length;
23
+ }
24
+ const markdown = [
25
+ `# ${reporterOptions.summaryTitle ?? reporterOptions.projectName} summary`,
26
+ '',
27
+ `- Status: ${runSummary.run.status}`,
28
+ `- Passed: ${runSummary.counts.passed}`,
29
+ `- Failed: ${runSummary.counts.failed}`,
30
+ `- Failure groups: ${failuresSummary.groups.length}`,
31
+ diff ? `- New failures: ${diff.newFailures.length}` : undefined,
32
+ diff ? `- Fixed failures: ${diff.fixedFailures.length}` : undefined,
33
+ ]
34
+ .filter(Boolean)
35
+ .join('\n');
36
+ await mkdir(outputDir, { recursive: true });
37
+ await Promise.all([
38
+ writeFile(resolve(outputDir, 'run.json'), JSON.stringify(runSummary, null, 2), 'utf8'),
39
+ writeFile(resolve(outputDir, 'summary.md'), markdown, 'utf8'),
40
+ writeFile(resolve(outputDir, 'summary.html'), renderSummaryHtml(runSummary, failuresSummary), 'utf8'),
41
+ ]);
42
+ }
43
+ async function runFromCli() {
44
+ const projectName = process.env.PRIVATE_REPORT_PROJECT_NAME ?? 'playwright-project';
45
+ await generateReport({
46
+ projectName,
47
+ outputDir: process.env.PRIVATE_REPORT_OUTPUT_DIR ?? 'artifacts',
48
+ summaryTitle: process.env.PRIVATE_REPORT_SUMMARY_TITLE,
49
+ enableHistoryDiff: process.env.PRIVATE_REPORT_ENABLE_HISTORY_DIFF === 'true',
50
+ });
51
+ }
52
+ // Export for CLI usage
53
+ export { runFromCli };
54
+ //# sourceMappingURL=generateReport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generateReport.js","sourceRoot":"","sources":["../../../src/cli/generateReport.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { PlaywrightTestConfig } from '@playwright/test';
2
+ import type { PrivateReporterOptions } from '../types/schema.js';
3
+ export declare function withPrivateReporter(baseConfig: PlaywrightTestConfig, options: PrivateReporterOptions): PlaywrightTestConfig;
4
+ //# sourceMappingURL=withPrivateReporter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"withPrivateReporter.d.ts","sourceRoot":"","sources":["../../../src/config/withPrivateReporter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAuB,MAAM,kBAAkB,CAAC;AAElF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAQjE,wBAAgB,mBAAmB,CACjC,UAAU,EAAE,oBAAoB,EAChC,OAAO,EAAE,sBAAsB,GAC9B,oBAAoB,CAqCtB"}
@@ -0,0 +1,38 @@
1
+ const DEFAULT_INTERNAL_REPORTER_PATH = '@ciach/playwright-private-reporter';
2
+ function hasReporter(reporters, name) {
3
+ return reporters.some((reporter) => reporter[0] === name);
4
+ }
5
+ export function withPrivateReporter(baseConfig, options) {
6
+ const outputDir = options.outputDir ?? 'artifacts';
7
+ const ci = options.ci ?? process.env.CI === 'true';
8
+ const reporters = Array.isArray(baseConfig.reporter)
9
+ ? [...baseConfig.reporter]
10
+ : baseConfig.reporter
11
+ ? [baseConfig.reporter]
12
+ : [];
13
+ if (ci && !hasReporter(reporters, 'blob')) {
14
+ reporters.unshift(['blob', { outputDir: 'blob-report' }]);
15
+ }
16
+ if (!hasReporter(reporters, 'junit')) {
17
+ reporters.push(['junit', { outputFile: 'junit/results.xml' }]);
18
+ }
19
+ if (!hasReporter(reporters, DEFAULT_INTERNAL_REPORTER_PATH)) {
20
+ reporters.push([DEFAULT_INTERNAL_REPORTER_PATH, options]);
21
+ }
22
+ if (!ci && !hasReporter(reporters, 'html') && !hasReporter(reporters, 'list')) {
23
+ reporters.unshift(['list']);
24
+ reporters.push(['html', { outputFolder: 'playwright-report', open: 'never' }]);
25
+ }
26
+ return {
27
+ ...baseConfig,
28
+ outputDir: baseConfig.outputDir ?? `${outputDir}/test-results`,
29
+ reporter: reporters,
30
+ use: {
31
+ trace: 'retain-on-failure',
32
+ screenshot: 'only-on-failure',
33
+ video: 'retain-on-failure',
34
+ ...baseConfig.use,
35
+ },
36
+ };
37
+ }
38
+ //# sourceMappingURL=withPrivateReporter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"withPrivateReporter.js","sourceRoot":"","sources":["../../../src/config/withPrivateReporter.ts"],"names":[],"mappings":"AAIA,MAAM,8BAA8B,GAAG,oCAAoC,CAAC;AAE5E,SAAS,WAAW,CAAC,SAAgC,EAAE,IAAY;IACjE,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;AAC5D,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,UAAgC,EAChC,OAA+B;IAE/B,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,WAAW,CAAC;IACnD,MAAM,EAAE,GAAG,OAAO,CAAC,EAAE,IAAI,OAAO,CAAC,GAAG,CAAC,EAAE,KAAK,MAAM,CAAC;IACnD,MAAM,SAAS,GAA0B,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC;QACzE,CAAC,CAAC,CAAC,GAAI,UAAU,CAAC,QAAkC,CAAC;QACrD,CAAC,CAAC,UAAU,CAAC,QAAQ;YACnB,CAAC,CAAC,CAAC,UAAU,CAAC,QAA+B,CAAC;YAC9C,CAAC,CAAC,EAAE,CAAC;IAET,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,SAAS,EAAE,MAAM,CAAC,EAAE,CAAC;QAC1C,SAAS,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC;IAC5D,CAAC;IAED,IAAI,CAAC,WAAW,CAAC,SAAS,EAAE,OAAO,CAAC,EAAE,CAAC;QACrC,SAAS,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,UAAU,EAAE,mBAAmB,EAAE,CAAC,CAAC,CAAC;IACjE,CAAC;IAED,IAAI,CAAC,WAAW,CAAC,SAAS,EAAE,8BAA8B,CAAC,EAAE,CAAC;QAC5D,SAAS,CAAC,IAAI,CAAC,CAAC,8BAA8B,EAAE,OAAO,CAAC,CAAC,CAAC;IAC5D,CAAC;IAED,IAAI,CAAC,EAAE,IAAI,CAAC,WAAW,CAAC,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,SAAS,EAAE,MAAM,CAAC,EAAE,CAAC;QAC9E,SAAS,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;QAC5B,SAAS,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,YAAY,EAAE,mBAAmB,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;IACjF,CAAC;IAED,OAAO;QACL,GAAG,UAAU;QACb,SAAS,EAAE,UAAU,CAAC,SAAS,IAAI,GAAG,SAAS,eAAe;QAC9D,QAAQ,EAAE,SAAS;QACnB,GAAG,EAAE;YACH,KAAK,EAAE,mBAAmB;YAC1B,UAAU,EAAE,iBAAiB;YAC7B,KAAK,EAAE,mBAAmB;YAC1B,GAAG,UAAU,CAAC,GAAG;SAClB;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { FailureGroup, HistoryDiff } from '../types/schema.js';
2
+ export declare function diffFailureGroups(current: FailureGroup[], previous: FailureGroup[]): HistoryDiff;
3
+ //# sourceMappingURL=diffRuns.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diffRuns.d.ts","sourceRoot":"","sources":["../../../src/history/diffRuns.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEpE,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,YAAY,EAAE,EAAE,QAAQ,EAAE,YAAY,EAAE,GAAG,WAAW,CAahG"}
@@ -0,0 +1,13 @@
1
+ export function diffFailureGroups(current, previous) {
2
+ const previousByFingerprint = new Map(previous.map((group) => [group.fingerprint, group]));
3
+ const currentByFingerprint = new Map(current.map((group) => [group.fingerprint, group]));
4
+ const newFailures = current.filter((group) => !previousByFingerprint.has(group.fingerprint));
5
+ const stillFailing = current.filter((group) => previousByFingerprint.has(group.fingerprint));
6
+ const fixedFailures = previous.filter((group) => !currentByFingerprint.has(group.fingerprint));
7
+ return {
8
+ newFailures,
9
+ fixedFailures,
10
+ stillFailing,
11
+ };
12
+ }
13
+ //# sourceMappingURL=diffRuns.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diffRuns.js","sourceRoot":"","sources":["../../../src/history/diffRuns.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,iBAAiB,CAAC,OAAuB,EAAE,QAAwB;IACjF,MAAM,qBAAqB,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IAC3F,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC;IAEzF,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,qBAAqB,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC;IAC7F,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,qBAAqB,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC;IAC7F,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,oBAAoB,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC;IAE/F,OAAO;QACL,WAAW;QACX,aAAa;QACb,YAAY;KACb,CAAC;AACJ,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { FailuresSummary, RunSummary } from '../types/schema.js';
2
+ export declare function loadPreviousRunSummary(path: string): Promise<RunSummary | undefined>;
3
+ export declare function loadPreviousFailuresSummary(path: string): Promise<FailuresSummary | undefined>;
4
+ //# sourceMappingURL=loadPrevious.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loadPrevious.d.ts","sourceRoot":"","sources":["../../../src/history/loadPrevious.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEtE,wBAAsB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAO1F;AAED,wBAAsB,2BAA2B,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,GAAG,SAAS,CAAC,CAOpG"}
@@ -0,0 +1,20 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ export async function loadPreviousRunSummary(path) {
3
+ try {
4
+ const raw = await readFile(path, 'utf8');
5
+ return JSON.parse(raw);
6
+ }
7
+ catch {
8
+ return undefined;
9
+ }
10
+ }
11
+ export async function loadPreviousFailuresSummary(path) {
12
+ try {
13
+ const raw = await readFile(path, 'utf8');
14
+ return JSON.parse(raw);
15
+ }
16
+ catch {
17
+ return undefined;
18
+ }
19
+ }
20
+ //# sourceMappingURL=loadPrevious.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loadPrevious.js","sourceRoot":"","sources":["../../../src/history/loadPrevious.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAI5C,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAAC,IAAY;IACvD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACzC,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAe,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAAC,IAAY;IAC5D,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACzC,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAoB,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC"}
@@ -0,0 +1,9 @@
1
+ export { withPrivateReporter } from './config/withPrivateReporter.js';
2
+ export { PrivateReporter } from './reporter/PrivateReporter.js';
3
+ export { createFailureFingerprint, extractFirstMeaningfulStack, normalizeErrorMessage } from './reporter/fingerprint.js';
4
+ export { generateReport } from './cli/generateReport.js';
5
+ export { diffFailureGroups } from './history/diffRuns.js';
6
+ export { loadPreviousFailuresSummary, loadPreviousRunSummary } from './history/loadPrevious.js';
7
+ export type { AttachmentRecord, FailureGroup, FailuresSummary, HistoryDiff, PrivateReporterOptions, RunSummary, } from './types/schema.js';
8
+ export { PrivateReporter as default } from './reporter/PrivateReporter.js';
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,EAAE,wBAAwB,EAAE,2BAA2B,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AACzH,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,2BAA2B,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AAChG,YAAY,EACV,gBAAgB,EAChB,YAAY,EACZ,eAAe,EACf,WAAW,EACX,sBAAsB,EACtB,UAAU,GACX,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,eAAe,IAAI,OAAO,EAAE,MAAM,+BAA+B,CAAC"}
@@ -0,0 +1,8 @@
1
+ export { withPrivateReporter } from './config/withPrivateReporter.js';
2
+ export { PrivateReporter } from './reporter/PrivateReporter.js';
3
+ export { createFailureFingerprint, extractFirstMeaningfulStack, normalizeErrorMessage } from './reporter/fingerprint.js';
4
+ export { generateReport } from './cli/generateReport.js';
5
+ export { diffFailureGroups } from './history/diffRuns.js';
6
+ export { loadPreviousFailuresSummary, loadPreviousRunSummary } from './history/loadPrevious.js';
7
+ export { PrivateReporter as default } from './reporter/PrivateReporter.js';
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,EAAE,wBAAwB,EAAE,2BAA2B,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AACzH,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,2BAA2B,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AAShG,OAAO,EAAE,eAAe,IAAI,OAAO,EAAE,MAAM,+BAA+B,CAAC"}
@@ -0,0 +1 @@
1
+ {"type":"module"}