@reportforge/playwright-pdf 0.21.0 → 0.22.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/README.md +28 -24
- package/SECURITY.md +2 -2
- package/dist/cli/index.js +65 -53
- package/dist/index.d.mts +19 -8
- package/dist/index.d.ts +19 -8
- package/dist/index.js +51 -39
- package/dist/index.mjs +51 -39
- package/dist/templates/partials/requirements-matrix.hbs +20 -4
- package/dist/templates/styles/base.css +23 -0
- package/package.json +1 -2
- package/CHANGELOG.md +0 -602
package/dist/index.js
CHANGED
|
@@ -10330,7 +10330,10 @@ var DEFAULT_OPTIONS = {
|
|
|
10330
10330
|
historySize: 10,
|
|
10331
10331
|
showTrend: true,
|
|
10332
10332
|
flakinessTopN: 5,
|
|
10333
|
-
slowTestThreshold: 10
|
|
10333
|
+
slowTestThreshold: 10,
|
|
10334
|
+
// Ticket-ID shape: @ODP-5328, REQ-001, JIRA-123. Tags matching this land in
|
|
10335
|
+
// the Requirements Traceability matrix; the rest fall to the tag summary.
|
|
10336
|
+
requirementTagPattern: "^@?[A-Z][A-Z0-9]*-\\d+$"
|
|
10334
10337
|
};
|
|
10335
10338
|
|
|
10336
10339
|
// src/templates/sections.ts
|
|
@@ -10559,6 +10562,14 @@ var ReporterOptionsSchema = external_exports.object({
|
|
|
10559
10562
|
remoteHistory: external_exports.boolean().default(false),
|
|
10560
10563
|
flakinessTopN: external_exports.number().int().min(0, "flakinessTopN must be 0 or greater").optional().default(DEFAULT_OPTIONS.flakinessTopN),
|
|
10561
10564
|
slowTestThreshold: external_exports.number().int().min(0, "slowTestThreshold must be 0 or greater").optional().default(DEFAULT_OPTIONS.slowTestThreshold),
|
|
10565
|
+
requirementTagPattern: external_exports.string().refine((v) => {
|
|
10566
|
+
try {
|
|
10567
|
+
new RegExp(v);
|
|
10568
|
+
return true;
|
|
10569
|
+
} catch {
|
|
10570
|
+
return false;
|
|
10571
|
+
}
|
|
10572
|
+
}, "requirementTagPattern must be a valid regular expression").optional().default(DEFAULT_OPTIONS.requirementTagPattern),
|
|
10562
10573
|
failureAnalysis: failureAnalysisConfigSchema,
|
|
10563
10574
|
capture: captureConfigSchema,
|
|
10564
10575
|
live: liveConfigSchema,
|
|
@@ -12638,6 +12649,7 @@ var PAGE_CONTENT_HEIGHT_PX = (A4_HEIGHT_MM - 2 * PAGE_MARGIN_Y_MM) * PX_PER_MM;
|
|
|
12638
12649
|
function isUnknownValue(v) {
|
|
12639
12650
|
return !v || v === "unknown";
|
|
12640
12651
|
}
|
|
12652
|
+
var NUMERIC_COLLATOR = new Intl.Collator(void 0, { numeric: true });
|
|
12641
12653
|
var SLOW_MEDIAN_FACTOR = 2;
|
|
12642
12654
|
function buildSuiteChartChunks(rows) {
|
|
12643
12655
|
const chunks = [];
|
|
@@ -12687,17 +12699,22 @@ var TemplateEngine = class {
|
|
|
12687
12699
|
setChartjsBundle(inline) {
|
|
12688
12700
|
this.chartjsInline = inline;
|
|
12689
12701
|
}
|
|
12690
|
-
render(data, template,
|
|
12702
|
+
render(data, template, opts = {}) {
|
|
12691
12703
|
const layoutPath = import_path3.default.join(this.templatesDir, "layouts", `${template}.hbs`);
|
|
12692
12704
|
if (!import_fs4.default.existsSync(layoutPath)) {
|
|
12693
12705
|
throw new Error(`[reportforge] Template layout not found: ${layoutPath}`);
|
|
12694
12706
|
}
|
|
12695
12707
|
const layoutSource = import_fs4.default.readFileSync(layoutPath, "utf8");
|
|
12696
12708
|
const compiledLayout = this.handlebars.compile(layoutSource);
|
|
12697
|
-
const ctx = this.
|
|
12709
|
+
const ctx = this.assembleContext(
|
|
12710
|
+
data,
|
|
12711
|
+
resolveSections(template, opts.sections),
|
|
12712
|
+
this.readStyle(`${template}.css`),
|
|
12713
|
+
opts
|
|
12714
|
+
);
|
|
12698
12715
|
return compiledLayout(ctx);
|
|
12699
12716
|
}
|
|
12700
|
-
renderFromPath(data, filePath,
|
|
12717
|
+
renderFromPath(data, filePath, opts = {}) {
|
|
12701
12718
|
if (!this.customTemplateCache.has(filePath)) {
|
|
12702
12719
|
if (!import_fs4.default.existsSync(filePath)) {
|
|
12703
12720
|
throw new Error(`[reportforge] Custom template not found: ${filePath}`);
|
|
@@ -12706,46 +12723,27 @@ var TemplateEngine = class {
|
|
|
12706
12723
|
this.customTemplateCache.set(filePath, this.handlebars.compile(source));
|
|
12707
12724
|
}
|
|
12708
12725
|
const compiledFn = this.customTemplateCache.get(filePath);
|
|
12709
|
-
return compiledFn(this.
|
|
12726
|
+
return compiledFn(this.assembleContext(data, allSectionsOn(), "", opts));
|
|
12710
12727
|
}
|
|
12711
|
-
|
|
12712
|
-
const sections = allSectionsOn();
|
|
12713
|
-
const slow = this.buildSlowTests(data);
|
|
12714
|
-
return {
|
|
12715
|
-
...data,
|
|
12716
|
-
projects: this.enrichProjects(data, slow, sections, slowTestThreshold ?? DEFAULT_OPTIONS.slowTestThreshold),
|
|
12717
|
-
options: deriveOptions(sections),
|
|
12718
|
-
sections,
|
|
12719
|
-
tagGroups: this.buildTagGroups(data),
|
|
12720
|
-
slowTests: slow.ranked,
|
|
12721
|
-
baseCSS: this.fontsBundleCss + "\n" + this.readStyle("base.css"),
|
|
12722
|
-
templateCSS: "",
|
|
12723
|
-
chartjsScript: this.buildChartjsScript(),
|
|
12724
|
-
watermarkPageHeightPx: PAGE_CONTENT_HEIGHT_PX,
|
|
12725
|
-
releaseGateTally: buildFailureTally(data.analysis),
|
|
12726
|
-
suiteChartLarge: data.charts.suiteResults.length > SUITE_CHART_SMALL_MAX,
|
|
12727
|
-
suiteChartChunks: data.charts.suiteResults.length > SUITE_CHART_SMALL_MAX ? buildSuiteChartChunks(data.charts.suiteResults) : []
|
|
12728
|
-
};
|
|
12729
|
-
}
|
|
12730
|
-
buildContext(data, template, userSections, slowTestThreshold) {
|
|
12731
|
-
const baseCSS = this.fontsBundleCss + "\n" + this.readStyle("base.css");
|
|
12732
|
-
const templateCSS = this.readStyle(`${template}.css`);
|
|
12733
|
-
const sections = resolveSections(template, userSections);
|
|
12728
|
+
assembleContext(data, sections, templateCSS, opts) {
|
|
12734
12729
|
const options = deriveOptions(sections);
|
|
12735
12730
|
const slow = this.buildSlowTests(data);
|
|
12731
|
+
const tags = this.buildTagGroups(data, opts.requirementTagPattern);
|
|
12736
12732
|
return {
|
|
12737
12733
|
...data,
|
|
12738
12734
|
projects: this.enrichProjects(
|
|
12739
12735
|
data,
|
|
12740
12736
|
slow,
|
|
12741
12737
|
sections,
|
|
12742
|
-
slowTestThreshold ?? DEFAULT_OPTIONS.slowTestThreshold
|
|
12738
|
+
opts.slowTestThreshold ?? DEFAULT_OPTIONS.slowTestThreshold
|
|
12743
12739
|
),
|
|
12744
12740
|
options,
|
|
12745
12741
|
sections,
|
|
12746
|
-
tagGroups:
|
|
12742
|
+
tagGroups: tags.all,
|
|
12743
|
+
requirementTagGroups: tags.requirements,
|
|
12744
|
+
categoryTagGroups: tags.categories,
|
|
12747
12745
|
slowTests: slow.ranked,
|
|
12748
|
-
baseCSS,
|
|
12746
|
+
baseCSS: this.fontsBundleCss + "\n" + this.readStyle("base.css"),
|
|
12749
12747
|
templateCSS,
|
|
12750
12748
|
chartjsScript: this.buildChartjsScript(),
|
|
12751
12749
|
watermarkPageHeightPx: PAGE_CONTENT_HEIGHT_PX,
|
|
@@ -12757,7 +12755,7 @@ var TemplateEngine = class {
|
|
|
12757
12755
|
buildChartjsScript() {
|
|
12758
12756
|
return this.chartjsInline ? `<script>${this.chartjsInline}</script>` : "<!-- Chart.js not bundled; charts disabled --><script>window.__chartsReady=true;</script>";
|
|
12759
12757
|
}
|
|
12760
|
-
buildTagGroups(data) {
|
|
12758
|
+
buildTagGroups(data, requirementTagPattern) {
|
|
12761
12759
|
const tagMap = /* @__PURE__ */ new Map();
|
|
12762
12760
|
for (const project of data.projects) {
|
|
12763
12761
|
for (const suite of this.flattenSuites(project.suites)) {
|
|
@@ -12772,11 +12770,20 @@ var TemplateEngine = class {
|
|
|
12772
12770
|
}
|
|
12773
12771
|
}
|
|
12774
12772
|
}
|
|
12775
|
-
|
|
12776
|
-
|
|
12777
|
-
|
|
12778
|
-
|
|
12779
|
-
|
|
12773
|
+
const regex = new RegExp(requirementTagPattern ?? DEFAULT_OPTIONS.requirementTagPattern);
|
|
12774
|
+
const requirements = [];
|
|
12775
|
+
const categories = [];
|
|
12776
|
+
for (const [tag, counts] of tagMap) {
|
|
12777
|
+
const row = {
|
|
12778
|
+
tag,
|
|
12779
|
+
...counts,
|
|
12780
|
+
coveragePct: counts.total > 0 ? Math.round(counts.passed / counts.total * 100) : 0
|
|
12781
|
+
};
|
|
12782
|
+
(regex.test(tag) ? requirements : categories).push(row);
|
|
12783
|
+
}
|
|
12784
|
+
requirements.sort((a, b) => NUMERIC_COLLATOR.compare(a.tag, b.tag));
|
|
12785
|
+
categories.sort((a, b) => b.total - a.total || a.tag.localeCompare(b.tag));
|
|
12786
|
+
return { all: [...requirements, ...categories], requirements, categories };
|
|
12780
12787
|
}
|
|
12781
12788
|
buildSlowTests(data) {
|
|
12782
12789
|
const tests = [];
|
|
@@ -13533,7 +13540,12 @@ var PdfGenerator = class {
|
|
|
13533
13540
|
}
|
|
13534
13541
|
const templateLabel = source.kind === "builtin" ? source.id : source.label;
|
|
13535
13542
|
logger.info(`Rendering template: ${templateLabel}`);
|
|
13536
|
-
const
|
|
13543
|
+
const renderOpts = {
|
|
13544
|
+
sections: options.sections,
|
|
13545
|
+
slowTestThreshold: options.slowTestThreshold,
|
|
13546
|
+
requirementTagPattern: options.requirementTagPattern
|
|
13547
|
+
};
|
|
13548
|
+
const html = source.kind === "builtin" ? this.templateEngine.render(renderData, source.id, renderOpts) : this.templateEngine.renderFromPath(renderData, source.absolutePath, renderOpts);
|
|
13537
13549
|
const tempHtmlPath = await this.htmlWriter.write(html);
|
|
13538
13550
|
const fileUrl = this.htmlWriter.toFileUrl(tempHtmlPath);
|
|
13539
13551
|
try {
|
|
@@ -14401,7 +14413,7 @@ var PdfReporter = class {
|
|
|
14401
14413
|
this.options = parseOptions(rawOptions);
|
|
14402
14414
|
setLogLevel(this.options.logLevel);
|
|
14403
14415
|
this.dataCollector = new DataCollector(this.options.capture);
|
|
14404
|
-
this.version = true ? "0.
|
|
14416
|
+
this.version = true ? "0.22.1" : "0.x";
|
|
14405
14417
|
logger.info(`@reportforge/playwright-pdf v${this.version} initialised`);
|
|
14406
14418
|
this.licenseClient = new LicenseClient({
|
|
14407
14419
|
licenseKey: this.options.licenseKey,
|
package/dist/index.mjs
CHANGED
|
@@ -10331,7 +10331,10 @@ var DEFAULT_OPTIONS = {
|
|
|
10331
10331
|
historySize: 10,
|
|
10332
10332
|
showTrend: true,
|
|
10333
10333
|
flakinessTopN: 5,
|
|
10334
|
-
slowTestThreshold: 10
|
|
10334
|
+
slowTestThreshold: 10,
|
|
10335
|
+
// Ticket-ID shape: @ODP-5328, REQ-001, JIRA-123. Tags matching this land in
|
|
10336
|
+
// the Requirements Traceability matrix; the rest fall to the tag summary.
|
|
10337
|
+
requirementTagPattern: "^@?[A-Z][A-Z0-9]*-\\d+$"
|
|
10335
10338
|
};
|
|
10336
10339
|
|
|
10337
10340
|
// src/templates/sections.ts
|
|
@@ -10560,6 +10563,14 @@ var ReporterOptionsSchema = external_exports.object({
|
|
|
10560
10563
|
remoteHistory: external_exports.boolean().default(false),
|
|
10561
10564
|
flakinessTopN: external_exports.number().int().min(0, "flakinessTopN must be 0 or greater").optional().default(DEFAULT_OPTIONS.flakinessTopN),
|
|
10562
10565
|
slowTestThreshold: external_exports.number().int().min(0, "slowTestThreshold must be 0 or greater").optional().default(DEFAULT_OPTIONS.slowTestThreshold),
|
|
10566
|
+
requirementTagPattern: external_exports.string().refine((v) => {
|
|
10567
|
+
try {
|
|
10568
|
+
new RegExp(v);
|
|
10569
|
+
return true;
|
|
10570
|
+
} catch {
|
|
10571
|
+
return false;
|
|
10572
|
+
}
|
|
10573
|
+
}, "requirementTagPattern must be a valid regular expression").optional().default(DEFAULT_OPTIONS.requirementTagPattern),
|
|
10563
10574
|
failureAnalysis: failureAnalysisConfigSchema,
|
|
10564
10575
|
capture: captureConfigSchema,
|
|
10565
10576
|
live: liveConfigSchema,
|
|
@@ -12639,6 +12650,7 @@ var PAGE_CONTENT_HEIGHT_PX = (A4_HEIGHT_MM - 2 * PAGE_MARGIN_Y_MM) * PX_PER_MM;
|
|
|
12639
12650
|
function isUnknownValue(v) {
|
|
12640
12651
|
return !v || v === "unknown";
|
|
12641
12652
|
}
|
|
12653
|
+
var NUMERIC_COLLATOR = new Intl.Collator(void 0, { numeric: true });
|
|
12642
12654
|
var SLOW_MEDIAN_FACTOR = 2;
|
|
12643
12655
|
function buildSuiteChartChunks(rows) {
|
|
12644
12656
|
const chunks = [];
|
|
@@ -12688,17 +12700,22 @@ var TemplateEngine = class {
|
|
|
12688
12700
|
setChartjsBundle(inline) {
|
|
12689
12701
|
this.chartjsInline = inline;
|
|
12690
12702
|
}
|
|
12691
|
-
render(data, template,
|
|
12703
|
+
render(data, template, opts = {}) {
|
|
12692
12704
|
const layoutPath = path9.join(this.templatesDir, "layouts", `${template}.hbs`);
|
|
12693
12705
|
if (!fs7.existsSync(layoutPath)) {
|
|
12694
12706
|
throw new Error(`[reportforge] Template layout not found: ${layoutPath}`);
|
|
12695
12707
|
}
|
|
12696
12708
|
const layoutSource = fs7.readFileSync(layoutPath, "utf8");
|
|
12697
12709
|
const compiledLayout = this.handlebars.compile(layoutSource);
|
|
12698
|
-
const ctx = this.
|
|
12710
|
+
const ctx = this.assembleContext(
|
|
12711
|
+
data,
|
|
12712
|
+
resolveSections(template, opts.sections),
|
|
12713
|
+
this.readStyle(`${template}.css`),
|
|
12714
|
+
opts
|
|
12715
|
+
);
|
|
12699
12716
|
return compiledLayout(ctx);
|
|
12700
12717
|
}
|
|
12701
|
-
renderFromPath(data, filePath,
|
|
12718
|
+
renderFromPath(data, filePath, opts = {}) {
|
|
12702
12719
|
if (!this.customTemplateCache.has(filePath)) {
|
|
12703
12720
|
if (!fs7.existsSync(filePath)) {
|
|
12704
12721
|
throw new Error(`[reportforge] Custom template not found: ${filePath}`);
|
|
@@ -12707,46 +12724,27 @@ var TemplateEngine = class {
|
|
|
12707
12724
|
this.customTemplateCache.set(filePath, this.handlebars.compile(source));
|
|
12708
12725
|
}
|
|
12709
12726
|
const compiledFn = this.customTemplateCache.get(filePath);
|
|
12710
|
-
return compiledFn(this.
|
|
12727
|
+
return compiledFn(this.assembleContext(data, allSectionsOn(), "", opts));
|
|
12711
12728
|
}
|
|
12712
|
-
|
|
12713
|
-
const sections = allSectionsOn();
|
|
12714
|
-
const slow = this.buildSlowTests(data);
|
|
12715
|
-
return {
|
|
12716
|
-
...data,
|
|
12717
|
-
projects: this.enrichProjects(data, slow, sections, slowTestThreshold ?? DEFAULT_OPTIONS.slowTestThreshold),
|
|
12718
|
-
options: deriveOptions(sections),
|
|
12719
|
-
sections,
|
|
12720
|
-
tagGroups: this.buildTagGroups(data),
|
|
12721
|
-
slowTests: slow.ranked,
|
|
12722
|
-
baseCSS: this.fontsBundleCss + "\n" + this.readStyle("base.css"),
|
|
12723
|
-
templateCSS: "",
|
|
12724
|
-
chartjsScript: this.buildChartjsScript(),
|
|
12725
|
-
watermarkPageHeightPx: PAGE_CONTENT_HEIGHT_PX,
|
|
12726
|
-
releaseGateTally: buildFailureTally(data.analysis),
|
|
12727
|
-
suiteChartLarge: data.charts.suiteResults.length > SUITE_CHART_SMALL_MAX,
|
|
12728
|
-
suiteChartChunks: data.charts.suiteResults.length > SUITE_CHART_SMALL_MAX ? buildSuiteChartChunks(data.charts.suiteResults) : []
|
|
12729
|
-
};
|
|
12730
|
-
}
|
|
12731
|
-
buildContext(data, template, userSections, slowTestThreshold) {
|
|
12732
|
-
const baseCSS = this.fontsBundleCss + "\n" + this.readStyle("base.css");
|
|
12733
|
-
const templateCSS = this.readStyle(`${template}.css`);
|
|
12734
|
-
const sections = resolveSections(template, userSections);
|
|
12729
|
+
assembleContext(data, sections, templateCSS, opts) {
|
|
12735
12730
|
const options = deriveOptions(sections);
|
|
12736
12731
|
const slow = this.buildSlowTests(data);
|
|
12732
|
+
const tags = this.buildTagGroups(data, opts.requirementTagPattern);
|
|
12737
12733
|
return {
|
|
12738
12734
|
...data,
|
|
12739
12735
|
projects: this.enrichProjects(
|
|
12740
12736
|
data,
|
|
12741
12737
|
slow,
|
|
12742
12738
|
sections,
|
|
12743
|
-
slowTestThreshold ?? DEFAULT_OPTIONS.slowTestThreshold
|
|
12739
|
+
opts.slowTestThreshold ?? DEFAULT_OPTIONS.slowTestThreshold
|
|
12744
12740
|
),
|
|
12745
12741
|
options,
|
|
12746
12742
|
sections,
|
|
12747
|
-
tagGroups:
|
|
12743
|
+
tagGroups: tags.all,
|
|
12744
|
+
requirementTagGroups: tags.requirements,
|
|
12745
|
+
categoryTagGroups: tags.categories,
|
|
12748
12746
|
slowTests: slow.ranked,
|
|
12749
|
-
baseCSS,
|
|
12747
|
+
baseCSS: this.fontsBundleCss + "\n" + this.readStyle("base.css"),
|
|
12750
12748
|
templateCSS,
|
|
12751
12749
|
chartjsScript: this.buildChartjsScript(),
|
|
12752
12750
|
watermarkPageHeightPx: PAGE_CONTENT_HEIGHT_PX,
|
|
@@ -12758,7 +12756,7 @@ var TemplateEngine = class {
|
|
|
12758
12756
|
buildChartjsScript() {
|
|
12759
12757
|
return this.chartjsInline ? `<script>${this.chartjsInline}</script>` : "<!-- Chart.js not bundled; charts disabled --><script>window.__chartsReady=true;</script>";
|
|
12760
12758
|
}
|
|
12761
|
-
buildTagGroups(data) {
|
|
12759
|
+
buildTagGroups(data, requirementTagPattern) {
|
|
12762
12760
|
const tagMap = /* @__PURE__ */ new Map();
|
|
12763
12761
|
for (const project of data.projects) {
|
|
12764
12762
|
for (const suite of this.flattenSuites(project.suites)) {
|
|
@@ -12773,11 +12771,20 @@ var TemplateEngine = class {
|
|
|
12773
12771
|
}
|
|
12774
12772
|
}
|
|
12775
12773
|
}
|
|
12776
|
-
|
|
12777
|
-
|
|
12778
|
-
|
|
12779
|
-
|
|
12780
|
-
|
|
12774
|
+
const regex = new RegExp(requirementTagPattern ?? DEFAULT_OPTIONS.requirementTagPattern);
|
|
12775
|
+
const requirements = [];
|
|
12776
|
+
const categories = [];
|
|
12777
|
+
for (const [tag, counts] of tagMap) {
|
|
12778
|
+
const row = {
|
|
12779
|
+
tag,
|
|
12780
|
+
...counts,
|
|
12781
|
+
coveragePct: counts.total > 0 ? Math.round(counts.passed / counts.total * 100) : 0
|
|
12782
|
+
};
|
|
12783
|
+
(regex.test(tag) ? requirements : categories).push(row);
|
|
12784
|
+
}
|
|
12785
|
+
requirements.sort((a, b) => NUMERIC_COLLATOR.compare(a.tag, b.tag));
|
|
12786
|
+
categories.sort((a, b) => b.total - a.total || a.tag.localeCompare(b.tag));
|
|
12787
|
+
return { all: [...requirements, ...categories], requirements, categories };
|
|
12781
12788
|
}
|
|
12782
12789
|
buildSlowTests(data) {
|
|
12783
12790
|
const tests = [];
|
|
@@ -13534,7 +13541,12 @@ var PdfGenerator = class {
|
|
|
13534
13541
|
}
|
|
13535
13542
|
const templateLabel = source.kind === "builtin" ? source.id : source.label;
|
|
13536
13543
|
logger.info(`Rendering template: ${templateLabel}`);
|
|
13537
|
-
const
|
|
13544
|
+
const renderOpts = {
|
|
13545
|
+
sections: options.sections,
|
|
13546
|
+
slowTestThreshold: options.slowTestThreshold,
|
|
13547
|
+
requirementTagPattern: options.requirementTagPattern
|
|
13548
|
+
};
|
|
13549
|
+
const html = source.kind === "builtin" ? this.templateEngine.render(renderData, source.id, renderOpts) : this.templateEngine.renderFromPath(renderData, source.absolutePath, renderOpts);
|
|
13538
13550
|
const tempHtmlPath = await this.htmlWriter.write(html);
|
|
13539
13551
|
const fileUrl = this.htmlWriter.toFileUrl(tempHtmlPath);
|
|
13540
13552
|
try {
|
|
@@ -14402,7 +14414,7 @@ var PdfReporter = class {
|
|
|
14402
14414
|
this.options = parseOptions(rawOptions);
|
|
14403
14415
|
setLogLevel(this.options.logLevel);
|
|
14404
14416
|
this.dataCollector = new DataCollector(this.options.capture);
|
|
14405
|
-
this.version = true ? "0.
|
|
14417
|
+
this.version = true ? "0.22.1" : "0.x";
|
|
14406
14418
|
logger.info(`@reportforge/playwright-pdf v${this.version} initialised`);
|
|
14407
14419
|
this.licenseClient = new LicenseClient({
|
|
14408
14420
|
licenseKey: this.options.licenseKey,
|
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
<div class="section">
|
|
3
3
|
<h2>Requirements Traceability</h2>
|
|
4
4
|
<p style="font-size:10px;color:var(--text-3);margin-bottom:12px;">
|
|
5
|
-
Tests grouped by
|
|
5
|
+
{{#if requirementTagGroups.length}}Tests grouped by requirement ID tags.{{else}}No requirement ID tags found.{{/if}}
|
|
6
|
+
Add <code>{ tag: '@REQ-001' }</code> to link tests to requirements.
|
|
6
7
|
</p>
|
|
8
|
+
{{#if requirementTagGroups.length}}
|
|
7
9
|
<table>
|
|
8
10
|
<thead>
|
|
9
11
|
<tr>
|
|
@@ -11,13 +13,13 @@
|
|
|
11
13
|
<th style="width:60px;">Tests</th>
|
|
12
14
|
<th style="width:60px;">Passed</th>
|
|
13
15
|
<th style="width:60px;">Failed</th>
|
|
14
|
-
<th style="width:120px;">
|
|
16
|
+
<th style="width:120px;">Pass Rate</th>
|
|
15
17
|
</tr>
|
|
16
18
|
</thead>
|
|
17
19
|
<tbody>
|
|
18
|
-
{{#each
|
|
20
|
+
{{#each requirementTagGroups}}
|
|
19
21
|
<tr class="no-break">
|
|
20
|
-
<td><code style="font-size:9.5px;">{{tag}}</code></td>
|
|
22
|
+
<td><code class="req-matrix__tag" style="font-size:9.5px;">{{tag}}</code></td>
|
|
21
23
|
<td>{{total}}</td>
|
|
22
24
|
<td style="color:var(--pass);font-weight:600;">{{passed}}</td>
|
|
23
25
|
<td style="color:{{#if failed}}var(--fail){{else}}var(--pass){{/if}};font-weight:600;">{{failed}}</td>
|
|
@@ -31,5 +33,19 @@
|
|
|
31
33
|
{{/each}}
|
|
32
34
|
</tbody>
|
|
33
35
|
</table>
|
|
36
|
+
{{/if}}
|
|
37
|
+
{{#if categoryTagGroups.length}}
|
|
38
|
+
<div class="tag-summary no-break">
|
|
39
|
+
<div class="tag-summary__label">Tag Summary</div>
|
|
40
|
+
<div class="tag-summary__items">
|
|
41
|
+
{{#each categoryTagGroups}}
|
|
42
|
+
<span class="tag-summary__item{{#if failed}} tag-summary__item--fail{{/if}}">
|
|
43
|
+
<code class="tag-summary__tag">{{tag}}</code>
|
|
44
|
+
<span class="tag-summary__counts">{{passed}}/{{total}}</span>
|
|
45
|
+
</span>
|
|
46
|
+
{{/each}}
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
{{/if}}
|
|
34
50
|
</div>
|
|
35
51
|
{{/if}}
|
|
@@ -891,6 +891,29 @@ code {
|
|
|
891
891
|
.coverage-bar__fill--mid { background: var(--timeout); }
|
|
892
892
|
.coverage-bar__fill--high { background: var(--pass); }
|
|
893
893
|
|
|
894
|
+
/* ── Requirements traceability: category tag summary ─────────────────────── */
|
|
895
|
+
/* Non-requirement tags (suite-level categories like @regression) collapse
|
|
896
|
+
into one compact row list instead of repeating identical matrix rows. */
|
|
897
|
+
.tag-summary {
|
|
898
|
+
margin-top: 10px; padding-top: 10px;
|
|
899
|
+
border-top: 1px solid var(--border);
|
|
900
|
+
}
|
|
901
|
+
.tag-summary__label {
|
|
902
|
+
font-family: 'Inter', system-ui, sans-serif; font-weight: 600;
|
|
903
|
+
font-size: 8.5px; letter-spacing: 0.8px; text-transform: uppercase;
|
|
904
|
+
color: var(--text-3); margin-bottom: 4px;
|
|
905
|
+
}
|
|
906
|
+
.tag-summary__items { max-width: 340px; }
|
|
907
|
+
.tag-summary__item {
|
|
908
|
+
display: flex; justify-content: space-between; align-items: center;
|
|
909
|
+
padding: 3.5px 2px;
|
|
910
|
+
border-bottom: 1px solid var(--border);
|
|
911
|
+
}
|
|
912
|
+
.tag-summary__item:last-child { border-bottom: none; }
|
|
913
|
+
.tag-summary__tag { font-size: 9.5px; color: var(--text-1); background: none; border: none; padding: 0; }
|
|
914
|
+
.tag-summary__counts { font-size: 8.5px; font-weight: 600; color: var(--pass); }
|
|
915
|
+
.tag-summary__item--fail .tag-summary__counts { color: var(--fail); }
|
|
916
|
+
|
|
894
917
|
/* ── Environment table — full ci-environment mode (fullEnvironment), shared ─── */
|
|
895
918
|
.env-table {
|
|
896
919
|
background: var(--surface);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reportforge/playwright-pdf",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.1",
|
|
4
4
|
"description": "Playwright Test reporter that generates designed PDF reports: minimal, detailed, and executive templates with CI/CD integrations",
|
|
5
5
|
"license": "Elastic-2.0",
|
|
6
6
|
"author": "ReportForge",
|
|
@@ -51,7 +51,6 @@
|
|
|
51
51
|
"dist",
|
|
52
52
|
"ci-templates",
|
|
53
53
|
"README.md",
|
|
54
|
-
"CHANGELOG.md",
|
|
55
54
|
"LICENSE",
|
|
56
55
|
"SECURITY.md"
|
|
57
56
|
],
|