@reportforge/playwright-pdf 0.2.2 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/README.md +3 -0
- package/dist/demo/cli.js +11558 -0
- package/dist/index.d.mts +5 -2
- package/dist/index.d.ts +5 -2
- package/dist/index.js +60 -53
- package/dist/index.mjs +60 -53
- package/package.json +4 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Reporter, FullConfig, Suite, TestCase, TestResult, FullResult } from '@playwright/test/reporter';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
declare const TEMPLATE_IDS: readonly ["minimal", "detailed", "executive"];
|
|
4
|
+
type TemplateId = (typeof TEMPLATE_IDS)[number];
|
|
4
5
|
/**
|
|
5
6
|
* License plan. Subscription is the only product — every active license is the
|
|
6
7
|
* same plan. The "no license" case is represented by the absence of a
|
|
@@ -219,9 +220,11 @@ interface ReporterOptions {
|
|
|
219
220
|
*/
|
|
220
221
|
interface LicenseInfo {
|
|
221
222
|
plan: LicensePlan;
|
|
222
|
-
source: 'jwt-online' | 'jwt-cache';
|
|
223
|
+
source: 'jwt-online' | 'jwt-cache' | 'demo';
|
|
223
224
|
expiry: Date;
|
|
224
225
|
key: string;
|
|
226
|
+
/** Raw Ed25519-signed JWT from the server. Absent only in demo mode. */
|
|
227
|
+
jwt?: string;
|
|
225
228
|
machinesUsed?: number;
|
|
226
229
|
machineLimit?: number;
|
|
227
230
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Reporter, FullConfig, Suite, TestCase, TestResult, FullResult } from '@playwright/test/reporter';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
declare const TEMPLATE_IDS: readonly ["minimal", "detailed", "executive"];
|
|
4
|
+
type TemplateId = (typeof TEMPLATE_IDS)[number];
|
|
4
5
|
/**
|
|
5
6
|
* License plan. Subscription is the only product — every active license is the
|
|
6
7
|
* same plan. The "no license" case is represented by the absence of a
|
|
@@ -219,9 +220,11 @@ interface ReporterOptions {
|
|
|
219
220
|
*/
|
|
220
221
|
interface LicenseInfo {
|
|
221
222
|
plan: LicensePlan;
|
|
222
|
-
source: 'jwt-online' | 'jwt-cache';
|
|
223
|
+
source: 'jwt-online' | 'jwt-cache' | 'demo';
|
|
223
224
|
expiry: Date;
|
|
224
225
|
key: string;
|
|
226
|
+
/** Raw Ed25519-signed JWT from the server. Absent only in demo mode. */
|
|
227
|
+
jwt?: string;
|
|
225
228
|
machinesUsed?: number;
|
|
226
229
|
machineLimit?: number;
|
|
227
230
|
}
|
package/dist/index.js
CHANGED
|
@@ -10740,6 +10740,7 @@ var LicenseClient = class {
|
|
|
10740
10740
|
plan: "subscription",
|
|
10741
10741
|
source: "jwt-online",
|
|
10742
10742
|
key: normalizedKey,
|
|
10743
|
+
jwt: result.jwt,
|
|
10743
10744
|
expiry: new Date(payload.exp * 1e3),
|
|
10744
10745
|
machinesUsed: result.machinesUsed,
|
|
10745
10746
|
machineLimit: result.machineLimit
|
|
@@ -10822,6 +10823,7 @@ function toLicenseInfo(payload, cached, normalizedKey, source) {
|
|
|
10822
10823
|
plan: "subscription",
|
|
10823
10824
|
source,
|
|
10824
10825
|
key: normalizedKey,
|
|
10826
|
+
jwt: cached.jwt,
|
|
10825
10827
|
expiry: new Date(payload.exp * 1e3),
|
|
10826
10828
|
// Surface the snapshot from the last activate/refresh. Undefined for
|
|
10827
10829
|
// caches written by older reporter versions before these fields were
|
|
@@ -10839,6 +10841,32 @@ init_cjs_shims();
|
|
|
10839
10841
|
|
|
10840
10842
|
// src/collector/SuiteWalker.ts
|
|
10841
10843
|
init_cjs_shims();
|
|
10844
|
+
|
|
10845
|
+
// src/collector/stats-utils.ts
|
|
10846
|
+
init_cjs_shims();
|
|
10847
|
+
function statsFromTests(tests) {
|
|
10848
|
+
return {
|
|
10849
|
+
total: tests.length,
|
|
10850
|
+
passed: tests.filter((t) => t.status === "passed").length,
|
|
10851
|
+
failed: tests.filter((t) => t.status === "failed" || t.status === "timedOut").length,
|
|
10852
|
+
skipped: tests.filter((t) => t.status === "skipped").length,
|
|
10853
|
+
flaky: tests.filter((t) => t.status === "flaky").length
|
|
10854
|
+
};
|
|
10855
|
+
}
|
|
10856
|
+
function aggregateStats(parts) {
|
|
10857
|
+
return parts.reduce(
|
|
10858
|
+
(acc, s) => ({
|
|
10859
|
+
total: acc.total + s.total,
|
|
10860
|
+
passed: acc.passed + s.passed,
|
|
10861
|
+
failed: acc.failed + s.failed,
|
|
10862
|
+
skipped: acc.skipped + s.skipped,
|
|
10863
|
+
flaky: acc.flaky + s.flaky
|
|
10864
|
+
}),
|
|
10865
|
+
{ total: 0, passed: 0, failed: 0, skipped: 0, flaky: 0 }
|
|
10866
|
+
);
|
|
10867
|
+
}
|
|
10868
|
+
|
|
10869
|
+
// src/collector/SuiteWalker.ts
|
|
10842
10870
|
var SuiteWalker = class {
|
|
10843
10871
|
build(rootSuite, resultMap) {
|
|
10844
10872
|
return rootSuite.suites.map(
|
|
@@ -10849,15 +10877,15 @@ var SuiteWalker = class {
|
|
|
10849
10877
|
const suites = projectSuite.suites.map(
|
|
10850
10878
|
(s) => this.buildSuite(s, resultMap)
|
|
10851
10879
|
);
|
|
10852
|
-
const stats =
|
|
10880
|
+
const stats = aggregateStats(suites.map((s) => s.stats));
|
|
10853
10881
|
return { name: projectSuite.title || "default", suites, stats };
|
|
10854
10882
|
}
|
|
10855
10883
|
buildSuite(suite, resultMap) {
|
|
10856
10884
|
const childSuites = suite.suites.map((s) => this.buildSuite(s, resultMap));
|
|
10857
10885
|
const tests = suite.tests.map((t) => this.buildTest(t, resultMap));
|
|
10858
|
-
const stats =
|
|
10886
|
+
const stats = aggregateStats([
|
|
10859
10887
|
...childSuites.map((s) => s.stats),
|
|
10860
|
-
|
|
10888
|
+
statsFromTests(tests)
|
|
10861
10889
|
]);
|
|
10862
10890
|
return {
|
|
10863
10891
|
title: suite.title,
|
|
@@ -10894,27 +10922,6 @@ var SuiteWalker = class {
|
|
|
10894
10922
|
if (actual === "failed" && expected === "failed") return "passed";
|
|
10895
10923
|
return "failed";
|
|
10896
10924
|
}
|
|
10897
|
-
statsFromTests(tests) {
|
|
10898
|
-
return {
|
|
10899
|
-
total: tests.length,
|
|
10900
|
-
passed: tests.filter((t) => t.status === "passed").length,
|
|
10901
|
-
failed: tests.filter((t) => t.status === "failed" || t.status === "timedOut").length,
|
|
10902
|
-
skipped: tests.filter((t) => t.status === "skipped").length,
|
|
10903
|
-
flaky: tests.filter((t) => t.status === "flaky").length
|
|
10904
|
-
};
|
|
10905
|
-
}
|
|
10906
|
-
aggregateStats(parts) {
|
|
10907
|
-
return parts.reduce(
|
|
10908
|
-
(acc, s) => ({
|
|
10909
|
-
total: acc.total + s.total,
|
|
10910
|
-
passed: acc.passed + s.passed,
|
|
10911
|
-
failed: acc.failed + s.failed,
|
|
10912
|
-
skipped: acc.skipped + s.skipped,
|
|
10913
|
-
flaky: acc.flaky + s.flaky
|
|
10914
|
-
}),
|
|
10915
|
-
{ total: 0, passed: 0, failed: 0, skipped: 0, flaky: 0 }
|
|
10916
|
-
);
|
|
10917
|
-
}
|
|
10918
10925
|
};
|
|
10919
10926
|
|
|
10920
10927
|
// src/utils/env.ts
|
|
@@ -11250,7 +11257,7 @@ var ShardMerger = class {
|
|
|
11250
11257
|
}
|
|
11251
11258
|
return Array.from(projectMap.entries()).map(([name, projectSuites]) => {
|
|
11252
11259
|
const suites = this.mergeFileSuites(projectSuites);
|
|
11253
|
-
const stats =
|
|
11260
|
+
const stats = aggregateStats(suites.map((s) => s.stats));
|
|
11254
11261
|
return { name, suites, stats };
|
|
11255
11262
|
});
|
|
11256
11263
|
}
|
|
@@ -11271,9 +11278,9 @@ var ShardMerger = class {
|
|
|
11271
11278
|
const suitePath = [ref.title ?? ""];
|
|
11272
11279
|
const tests = allSpecs.map((spec) => this.specToTestNode(spec, projectName, suitePath));
|
|
11273
11280
|
const childSuiteNodes = this.buildDescribeSuites(allChildSuites, projectName, suitePath);
|
|
11274
|
-
const stats =
|
|
11281
|
+
const stats = aggregateStats([
|
|
11275
11282
|
...childSuiteNodes.map((s) => s.stats),
|
|
11276
|
-
|
|
11283
|
+
statsFromTests(tests)
|
|
11277
11284
|
]);
|
|
11278
11285
|
return {
|
|
11279
11286
|
title: ref.title ?? ref.file ?? "unknown",
|
|
@@ -11290,9 +11297,9 @@ var ShardMerger = class {
|
|
|
11290
11297
|
const suitePath = [...parentPath, suite.title];
|
|
11291
11298
|
const tests = suite.specs.map((spec) => this.specToTestNode(spec, projectName, suitePath));
|
|
11292
11299
|
const childSuites = this.buildDescribeSuites(suite.suites ?? [], projectName, suitePath);
|
|
11293
|
-
const stats =
|
|
11300
|
+
const stats = aggregateStats([
|
|
11294
11301
|
...childSuites.map((s) => s.stats),
|
|
11295
|
-
|
|
11302
|
+
statsFromTests(tests)
|
|
11296
11303
|
]);
|
|
11297
11304
|
return {
|
|
11298
11305
|
title: suite.title,
|
|
@@ -11447,27 +11454,6 @@ var ShardMerger = class {
|
|
|
11447
11454
|
suiteResults
|
|
11448
11455
|
};
|
|
11449
11456
|
}
|
|
11450
|
-
statsFromTests(tests) {
|
|
11451
|
-
return {
|
|
11452
|
-
total: tests.length,
|
|
11453
|
-
passed: tests.filter((t) => t.status === "passed").length,
|
|
11454
|
-
failed: tests.filter((t) => t.status === "failed" || t.status === "timedOut").length,
|
|
11455
|
-
skipped: tests.filter((t) => t.status === "skipped").length,
|
|
11456
|
-
flaky: tests.filter((t) => t.status === "flaky").length
|
|
11457
|
-
};
|
|
11458
|
-
}
|
|
11459
|
-
aggregateStats(parts) {
|
|
11460
|
-
return parts.reduce(
|
|
11461
|
-
(acc, s) => ({
|
|
11462
|
-
total: acc.total + s.total,
|
|
11463
|
-
passed: acc.passed + s.passed,
|
|
11464
|
-
failed: acc.failed + s.failed,
|
|
11465
|
-
skipped: acc.skipped + s.skipped,
|
|
11466
|
-
flaky: acc.flaky + s.flaky
|
|
11467
|
-
}),
|
|
11468
|
-
{ total: 0, passed: 0, failed: 0, skipped: 0, flaky: 0 }
|
|
11469
|
-
);
|
|
11470
|
-
}
|
|
11471
11457
|
};
|
|
11472
11458
|
|
|
11473
11459
|
// src/pdf/PdfGenerator.ts
|
|
@@ -12137,10 +12123,31 @@ var PdfGenerator = class {
|
|
|
12137
12123
|
*
|
|
12138
12124
|
* @param data - Assembled `ReportData` (projects, stats, failures, charts).
|
|
12139
12125
|
* @param options - Validated reporter options.
|
|
12140
|
-
* @param
|
|
12126
|
+
* @param licenseInfo - Verified license. JWT must be present and valid for
|
|
12127
|
+
* non-demo sources; `source: 'demo'` is the only allowed JWT-free path.
|
|
12141
12128
|
* @returns Absolute paths of written PDF files.
|
|
12142
12129
|
*/
|
|
12143
|
-
async generateAll(data, options,
|
|
12130
|
+
async generateAll(data, options, licenseInfo) {
|
|
12131
|
+
if (false) {
|
|
12132
|
+
if (licenseInfo.expiry <= /* @__PURE__ */ new Date()) {
|
|
12133
|
+
throw new Error("[reportforge] Demo license expired \u2014 PDF generation skipped.");
|
|
12134
|
+
}
|
|
12135
|
+
} else {
|
|
12136
|
+
if (!licenseInfo.jwt) {
|
|
12137
|
+
throw new Error("[reportforge] License JWT missing \u2014 PDF generation skipped.");
|
|
12138
|
+
}
|
|
12139
|
+
if (!LICENSE_PUBLIC_KEY_PEM) {
|
|
12140
|
+
throw new Error("[reportforge] LICENSE_PUBLIC_KEY_PEM missing \u2014 cannot verify license JWT.");
|
|
12141
|
+
}
|
|
12142
|
+
try {
|
|
12143
|
+
const payload = new JwtVerifier(LICENSE_PUBLIC_KEY_PEM).verify(licenseInfo.jwt);
|
|
12144
|
+
if (payload.exp * 1e3 <= Date.now()) {
|
|
12145
|
+
throw new Error("JWT expired");
|
|
12146
|
+
}
|
|
12147
|
+
} catch (err) {
|
|
12148
|
+
throw new Error(`[reportforge] License JWT verification failed: ${err.message}`);
|
|
12149
|
+
}
|
|
12150
|
+
}
|
|
12144
12151
|
const sources = this.resolveTemplateSources(options);
|
|
12145
12152
|
const isMulti = sources.length > 1;
|
|
12146
12153
|
for (const source of sources) {
|
|
@@ -12670,7 +12677,7 @@ var PdfReporter = class {
|
|
|
12670
12677
|
this.dataCollector = new DataCollector();
|
|
12671
12678
|
this.pdfGenerator = new PdfGenerator();
|
|
12672
12679
|
this.options = parseOptions(rawOptions);
|
|
12673
|
-
const version = true ? "0.
|
|
12680
|
+
const version = true ? "0.3.1" : "0.x";
|
|
12674
12681
|
logger.info(`@reportforge/playwright-pdf v${version} initialised`);
|
|
12675
12682
|
this.licenseClient = new LicenseClient({
|
|
12676
12683
|
licenseKey: this.options.licenseKey,
|
package/dist/index.mjs
CHANGED
|
@@ -10741,6 +10741,7 @@ var LicenseClient = class {
|
|
|
10741
10741
|
plan: "subscription",
|
|
10742
10742
|
source: "jwt-online",
|
|
10743
10743
|
key: normalizedKey,
|
|
10744
|
+
jwt: result.jwt,
|
|
10744
10745
|
expiry: new Date(payload.exp * 1e3),
|
|
10745
10746
|
machinesUsed: result.machinesUsed,
|
|
10746
10747
|
machineLimit: result.machineLimit
|
|
@@ -10823,6 +10824,7 @@ function toLicenseInfo(payload, cached, normalizedKey, source) {
|
|
|
10823
10824
|
plan: "subscription",
|
|
10824
10825
|
source,
|
|
10825
10826
|
key: normalizedKey,
|
|
10827
|
+
jwt: cached.jwt,
|
|
10826
10828
|
expiry: new Date(payload.exp * 1e3),
|
|
10827
10829
|
// Surface the snapshot from the last activate/refresh. Undefined for
|
|
10828
10830
|
// caches written by older reporter versions before these fields were
|
|
@@ -10840,6 +10842,32 @@ init_esm_shims();
|
|
|
10840
10842
|
|
|
10841
10843
|
// src/collector/SuiteWalker.ts
|
|
10842
10844
|
init_esm_shims();
|
|
10845
|
+
|
|
10846
|
+
// src/collector/stats-utils.ts
|
|
10847
|
+
init_esm_shims();
|
|
10848
|
+
function statsFromTests(tests) {
|
|
10849
|
+
return {
|
|
10850
|
+
total: tests.length,
|
|
10851
|
+
passed: tests.filter((t) => t.status === "passed").length,
|
|
10852
|
+
failed: tests.filter((t) => t.status === "failed" || t.status === "timedOut").length,
|
|
10853
|
+
skipped: tests.filter((t) => t.status === "skipped").length,
|
|
10854
|
+
flaky: tests.filter((t) => t.status === "flaky").length
|
|
10855
|
+
};
|
|
10856
|
+
}
|
|
10857
|
+
function aggregateStats(parts) {
|
|
10858
|
+
return parts.reduce(
|
|
10859
|
+
(acc, s) => ({
|
|
10860
|
+
total: acc.total + s.total,
|
|
10861
|
+
passed: acc.passed + s.passed,
|
|
10862
|
+
failed: acc.failed + s.failed,
|
|
10863
|
+
skipped: acc.skipped + s.skipped,
|
|
10864
|
+
flaky: acc.flaky + s.flaky
|
|
10865
|
+
}),
|
|
10866
|
+
{ total: 0, passed: 0, failed: 0, skipped: 0, flaky: 0 }
|
|
10867
|
+
);
|
|
10868
|
+
}
|
|
10869
|
+
|
|
10870
|
+
// src/collector/SuiteWalker.ts
|
|
10843
10871
|
var SuiteWalker = class {
|
|
10844
10872
|
build(rootSuite, resultMap) {
|
|
10845
10873
|
return rootSuite.suites.map(
|
|
@@ -10850,15 +10878,15 @@ var SuiteWalker = class {
|
|
|
10850
10878
|
const suites = projectSuite.suites.map(
|
|
10851
10879
|
(s) => this.buildSuite(s, resultMap)
|
|
10852
10880
|
);
|
|
10853
|
-
const stats =
|
|
10881
|
+
const stats = aggregateStats(suites.map((s) => s.stats));
|
|
10854
10882
|
return { name: projectSuite.title || "default", suites, stats };
|
|
10855
10883
|
}
|
|
10856
10884
|
buildSuite(suite, resultMap) {
|
|
10857
10885
|
const childSuites = suite.suites.map((s) => this.buildSuite(s, resultMap));
|
|
10858
10886
|
const tests = suite.tests.map((t) => this.buildTest(t, resultMap));
|
|
10859
|
-
const stats =
|
|
10887
|
+
const stats = aggregateStats([
|
|
10860
10888
|
...childSuites.map((s) => s.stats),
|
|
10861
|
-
|
|
10889
|
+
statsFromTests(tests)
|
|
10862
10890
|
]);
|
|
10863
10891
|
return {
|
|
10864
10892
|
title: suite.title,
|
|
@@ -10895,27 +10923,6 @@ var SuiteWalker = class {
|
|
|
10895
10923
|
if (actual === "failed" && expected === "failed") return "passed";
|
|
10896
10924
|
return "failed";
|
|
10897
10925
|
}
|
|
10898
|
-
statsFromTests(tests) {
|
|
10899
|
-
return {
|
|
10900
|
-
total: tests.length,
|
|
10901
|
-
passed: tests.filter((t) => t.status === "passed").length,
|
|
10902
|
-
failed: tests.filter((t) => t.status === "failed" || t.status === "timedOut").length,
|
|
10903
|
-
skipped: tests.filter((t) => t.status === "skipped").length,
|
|
10904
|
-
flaky: tests.filter((t) => t.status === "flaky").length
|
|
10905
|
-
};
|
|
10906
|
-
}
|
|
10907
|
-
aggregateStats(parts) {
|
|
10908
|
-
return parts.reduce(
|
|
10909
|
-
(acc, s) => ({
|
|
10910
|
-
total: acc.total + s.total,
|
|
10911
|
-
passed: acc.passed + s.passed,
|
|
10912
|
-
failed: acc.failed + s.failed,
|
|
10913
|
-
skipped: acc.skipped + s.skipped,
|
|
10914
|
-
flaky: acc.flaky + s.flaky
|
|
10915
|
-
}),
|
|
10916
|
-
{ total: 0, passed: 0, failed: 0, skipped: 0, flaky: 0 }
|
|
10917
|
-
);
|
|
10918
|
-
}
|
|
10919
10926
|
};
|
|
10920
10927
|
|
|
10921
10928
|
// src/utils/env.ts
|
|
@@ -11251,7 +11258,7 @@ var ShardMerger = class {
|
|
|
11251
11258
|
}
|
|
11252
11259
|
return Array.from(projectMap.entries()).map(([name, projectSuites]) => {
|
|
11253
11260
|
const suites = this.mergeFileSuites(projectSuites);
|
|
11254
|
-
const stats =
|
|
11261
|
+
const stats = aggregateStats(suites.map((s) => s.stats));
|
|
11255
11262
|
return { name, suites, stats };
|
|
11256
11263
|
});
|
|
11257
11264
|
}
|
|
@@ -11272,9 +11279,9 @@ var ShardMerger = class {
|
|
|
11272
11279
|
const suitePath = [ref.title ?? ""];
|
|
11273
11280
|
const tests = allSpecs.map((spec) => this.specToTestNode(spec, projectName, suitePath));
|
|
11274
11281
|
const childSuiteNodes = this.buildDescribeSuites(allChildSuites, projectName, suitePath);
|
|
11275
|
-
const stats =
|
|
11282
|
+
const stats = aggregateStats([
|
|
11276
11283
|
...childSuiteNodes.map((s) => s.stats),
|
|
11277
|
-
|
|
11284
|
+
statsFromTests(tests)
|
|
11278
11285
|
]);
|
|
11279
11286
|
return {
|
|
11280
11287
|
title: ref.title ?? ref.file ?? "unknown",
|
|
@@ -11291,9 +11298,9 @@ var ShardMerger = class {
|
|
|
11291
11298
|
const suitePath = [...parentPath, suite.title];
|
|
11292
11299
|
const tests = suite.specs.map((spec) => this.specToTestNode(spec, projectName, suitePath));
|
|
11293
11300
|
const childSuites = this.buildDescribeSuites(suite.suites ?? [], projectName, suitePath);
|
|
11294
|
-
const stats =
|
|
11301
|
+
const stats = aggregateStats([
|
|
11295
11302
|
...childSuites.map((s) => s.stats),
|
|
11296
|
-
|
|
11303
|
+
statsFromTests(tests)
|
|
11297
11304
|
]);
|
|
11298
11305
|
return {
|
|
11299
11306
|
title: suite.title,
|
|
@@ -11448,27 +11455,6 @@ var ShardMerger = class {
|
|
|
11448
11455
|
suiteResults
|
|
11449
11456
|
};
|
|
11450
11457
|
}
|
|
11451
|
-
statsFromTests(tests) {
|
|
11452
|
-
return {
|
|
11453
|
-
total: tests.length,
|
|
11454
|
-
passed: tests.filter((t) => t.status === "passed").length,
|
|
11455
|
-
failed: tests.filter((t) => t.status === "failed" || t.status === "timedOut").length,
|
|
11456
|
-
skipped: tests.filter((t) => t.status === "skipped").length,
|
|
11457
|
-
flaky: tests.filter((t) => t.status === "flaky").length
|
|
11458
|
-
};
|
|
11459
|
-
}
|
|
11460
|
-
aggregateStats(parts) {
|
|
11461
|
-
return parts.reduce(
|
|
11462
|
-
(acc, s) => ({
|
|
11463
|
-
total: acc.total + s.total,
|
|
11464
|
-
passed: acc.passed + s.passed,
|
|
11465
|
-
failed: acc.failed + s.failed,
|
|
11466
|
-
skipped: acc.skipped + s.skipped,
|
|
11467
|
-
flaky: acc.flaky + s.flaky
|
|
11468
|
-
}),
|
|
11469
|
-
{ total: 0, passed: 0, failed: 0, skipped: 0, flaky: 0 }
|
|
11470
|
-
);
|
|
11471
|
-
}
|
|
11472
11458
|
};
|
|
11473
11459
|
|
|
11474
11460
|
// src/pdf/PdfGenerator.ts
|
|
@@ -12138,10 +12124,31 @@ var PdfGenerator = class {
|
|
|
12138
12124
|
*
|
|
12139
12125
|
* @param data - Assembled `ReportData` (projects, stats, failures, charts).
|
|
12140
12126
|
* @param options - Validated reporter options.
|
|
12141
|
-
* @param
|
|
12127
|
+
* @param licenseInfo - Verified license. JWT must be present and valid for
|
|
12128
|
+
* non-demo sources; `source: 'demo'` is the only allowed JWT-free path.
|
|
12142
12129
|
* @returns Absolute paths of written PDF files.
|
|
12143
12130
|
*/
|
|
12144
|
-
async generateAll(data, options,
|
|
12131
|
+
async generateAll(data, options, licenseInfo) {
|
|
12132
|
+
if (false) {
|
|
12133
|
+
if (licenseInfo.expiry <= /* @__PURE__ */ new Date()) {
|
|
12134
|
+
throw new Error("[reportforge] Demo license expired \u2014 PDF generation skipped.");
|
|
12135
|
+
}
|
|
12136
|
+
} else {
|
|
12137
|
+
if (!licenseInfo.jwt) {
|
|
12138
|
+
throw new Error("[reportforge] License JWT missing \u2014 PDF generation skipped.");
|
|
12139
|
+
}
|
|
12140
|
+
if (!LICENSE_PUBLIC_KEY_PEM) {
|
|
12141
|
+
throw new Error("[reportforge] LICENSE_PUBLIC_KEY_PEM missing \u2014 cannot verify license JWT.");
|
|
12142
|
+
}
|
|
12143
|
+
try {
|
|
12144
|
+
const payload = new JwtVerifier(LICENSE_PUBLIC_KEY_PEM).verify(licenseInfo.jwt);
|
|
12145
|
+
if (payload.exp * 1e3 <= Date.now()) {
|
|
12146
|
+
throw new Error("JWT expired");
|
|
12147
|
+
}
|
|
12148
|
+
} catch (err) {
|
|
12149
|
+
throw new Error(`[reportforge] License JWT verification failed: ${err.message}`);
|
|
12150
|
+
}
|
|
12151
|
+
}
|
|
12145
12152
|
const sources = this.resolveTemplateSources(options);
|
|
12146
12153
|
const isMulti = sources.length > 1;
|
|
12147
12154
|
for (const source of sources) {
|
|
@@ -12671,7 +12678,7 @@ var PdfReporter = class {
|
|
|
12671
12678
|
this.dataCollector = new DataCollector();
|
|
12672
12679
|
this.pdfGenerator = new PdfGenerator();
|
|
12673
12680
|
this.options = parseOptions(rawOptions);
|
|
12674
|
-
const version = true ? "0.
|
|
12681
|
+
const version = true ? "0.3.1" : "0.x";
|
|
12675
12682
|
logger.info(`@reportforge/playwright-pdf v${version} initialised`);
|
|
12676
12683
|
this.licenseClient = new LicenseClient({
|
|
12677
12684
|
licenseKey: this.options.licenseKey,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reportforge/playwright-pdf",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Enterprise-ready PDF reports for Playwright Test — minimal, detailed, and executive templates with CI/CD integrations",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "ReportForge",
|
|
@@ -33,6 +33,9 @@
|
|
|
33
33
|
"require": "./dist/index.js"
|
|
34
34
|
}
|
|
35
35
|
},
|
|
36
|
+
"bin": {
|
|
37
|
+
"reportforge-demo": "./dist/demo/cli.js"
|
|
38
|
+
},
|
|
36
39
|
"publishConfig": {
|
|
37
40
|
"access": "public"
|
|
38
41
|
},
|