@trailmark/playwright 0.1.0

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 (94) hide show
  1. package/.trailmark/current-run.json +136 -0
  2. package/dist/artifacts/artifactManager.d.ts +31 -0
  3. package/dist/artifacts/artifactManager.d.ts.map +1 -0
  4. package/dist/artifacts/artifactManager.js +140 -0
  5. package/dist/artifacts/artifactManager.js.map +1 -0
  6. package/dist/artifacts/capture.d.ts +4 -0
  7. package/dist/artifacts/capture.d.ts.map +1 -0
  8. package/dist/artifacts/capture.js +16 -0
  9. package/dist/artifacts/capture.js.map +1 -0
  10. package/dist/artifacts/options.d.ts +11 -0
  11. package/dist/artifacts/options.d.ts.map +1 -0
  12. package/dist/artifacts/options.js +55 -0
  13. package/dist/artifacts/options.js.map +1 -0
  14. package/dist/artifacts/registry.d.ts +24 -0
  15. package/dist/artifacts/registry.d.ts.map +1 -0
  16. package/dist/artifacts/registry.js +99 -0
  17. package/dist/artifacts/registry.js.map +1 -0
  18. package/dist/constants.d.ts +2 -0
  19. package/dist/constants.d.ts.map +1 -0
  20. package/dist/constants.js +5 -0
  21. package/dist/constants.js.map +1 -0
  22. package/dist/fixture.d.ts +7 -0
  23. package/dist/fixture.d.ts.map +1 -0
  24. package/dist/fixture.js +193 -0
  25. package/dist/fixture.js.map +1 -0
  26. package/dist/index.d.ts +4 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +7 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/mode.d.ts +3 -0
  31. package/dist/mode.d.ts.map +1 -0
  32. package/dist/mode.js +9 -0
  33. package/dist/mode.js.map +1 -0
  34. package/dist/reporter/attachments.d.ts +4 -0
  35. package/dist/reporter/attachments.d.ts.map +1 -0
  36. package/dist/reporter/attachments.js +112 -0
  37. package/dist/reporter/attachments.js.map +1 -0
  38. package/dist/reporter/errors.d.ts +4 -0
  39. package/dist/reporter/errors.d.ts.map +1 -0
  40. package/dist/reporter/errors.js +11 -0
  41. package/dist/reporter/errors.js.map +1 -0
  42. package/dist/reporter/index.d.ts +33 -0
  43. package/dist/reporter/index.d.ts.map +1 -0
  44. package/dist/reporter/index.js +407 -0
  45. package/dist/reporter/index.js.map +1 -0
  46. package/dist/reporter/io.d.ts +15 -0
  47. package/dist/reporter/io.d.ts.map +1 -0
  48. package/dist/reporter/io.js +34 -0
  49. package/dist/reporter/io.js.map +1 -0
  50. package/dist/reporter/normalization.d.ts +13 -0
  51. package/dist/reporter/normalization.d.ts.map +1 -0
  52. package/dist/reporter/normalization.js +91 -0
  53. package/dist/reporter/normalization.js.map +1 -0
  54. package/dist/reporter/output.d.ts +5 -0
  55. package/dist/reporter/output.d.ts.map +1 -0
  56. package/dist/reporter/output.js +90 -0
  57. package/dist/reporter/output.js.map +1 -0
  58. package/dist/reporter/run.d.ts +4 -0
  59. package/dist/reporter/run.d.ts.map +1 -0
  60. package/dist/reporter/run.js +18 -0
  61. package/dist/reporter/run.js.map +1 -0
  62. package/dist/types.d.ts +48 -0
  63. package/dist/types.d.ts.map +1 -0
  64. package/dist/types.js +3 -0
  65. package/dist/types.js.map +1 -0
  66. package/integration/app/base.html +16 -0
  67. package/integration/app/extra.html +17 -0
  68. package/integration/playwright.config.ts +44 -0
  69. package/integration/specs/sample.spec.ts +15 -0
  70. package/integration/tmp/baseline.json +46 -0
  71. package/integration/tmp/report.json +97 -0
  72. package/package.json +35 -0
  73. package/src/artifacts/artifactManager.ts +178 -0
  74. package/src/artifacts/capture.ts +18 -0
  75. package/src/artifacts/options.ts +79 -0
  76. package/src/artifacts/registry.ts +143 -0
  77. package/src/constants.ts +1 -0
  78. package/src/fixture.ts +239 -0
  79. package/src/index.ts +3 -0
  80. package/src/mode.ts +7 -0
  81. package/src/reporter/attachments.ts +139 -0
  82. package/src/reporter/errors.ts +6 -0
  83. package/src/reporter/index.ts +572 -0
  84. package/src/reporter/io.ts +33 -0
  85. package/src/reporter/normalization.ts +122 -0
  86. package/src/reporter/output.ts +103 -0
  87. package/src/reporter/run.ts +17 -0
  88. package/src/types.ts +53 -0
  89. package/test/artifactManager.unit.test.ts +141 -0
  90. package/test/reporter.integration.test.ts +153 -0
  91. package/test/reporter.unit.test.ts +337 -0
  92. package/test-results/.last-run.json +4 -0
  93. package/trailmark-playwright-0.1.0.tgz +0 -0
  94. package/tsconfig.json +8 -0
@@ -0,0 +1,136 @@
1
+ {
2
+ "generatedAt": "2026-02-08T20:11:55.646Z",
3
+ "mode": "check",
4
+ "configHash": "bf23043ed4b93b2119d6c9048bc54afdcfa1b9b9",
5
+ "run": {
6
+ "version": 1,
7
+ "startedAt": "2026-02-08T20:11:53.970Z",
8
+ "tool": {
9
+ "name": "trailmark",
10
+ "version": "0.1.0",
11
+ "scanner": "@axe-core/playwright"
12
+ },
13
+ "findings": [
14
+ {
15
+ "issueId": "afbdf52e9915d0b0e73041501018ec09de569a5b",
16
+ "relaxedIssueId": "85362a09993122b59cdcb30d0d1682654e2bf705",
17
+ "ruleId": "image-alt",
18
+ "impact": "critical",
19
+ "tags": [
20
+ "cat.text-alternatives",
21
+ "wcag2a",
22
+ "wcag111",
23
+ "section508",
24
+ "section508.22.a",
25
+ "TTv5",
26
+ "TT7.a",
27
+ "TT7.b",
28
+ "EN-301-549",
29
+ "EN-9.1.1.1",
30
+ "ACT",
31
+ "RGAAv4",
32
+ "RGAA-1.1.1"
33
+ ],
34
+ "help": "Images must have alternative text",
35
+ "helpUrl": "https://dequeuniversity.com/rules/axe/4.11/image-alt?application=playwright",
36
+ "pageUrl": "file:///Users/dmitrijsminajevs/dev/axe/packages/trailmark-playwright/integration/app/base.html",
37
+ "pageKey": "sample-app/page.html",
38
+ "target": [
39
+ "img"
40
+ ],
41
+ "selectorHint": "img",
42
+ "targetHash": "affe482b172ca2ef1a2ef338d49db47e91b1f05e",
43
+ "nodeHtml": "<img data-testid=\"hero-image\" src=\"hero.jpg\">",
44
+ "failureSummary": "Fix any of the following:\n Element does not have an alt attribute\n aria-label attribute does not exist or is empty\n aria-labelledby attribute does not exist, references elements that do not exist or references elements that are empty\n Element has no title attribute\n Element's default semantics were not overridden with role=\"none\" or role=\"presentation\"",
45
+ "failureHint": "fix any of the following: element does not have an alt attribute aria-label attribute does not exist or is empty aria-labelledby attribute does not exist, references elements that do not exist or references elements that are empty element has no title attribute elements default semantics were not overridden with role=none or role=presentation",
46
+ "meta": {
47
+ "testId": "b92766bcf73bd5c029a8-4f0088c96308a9a97a42",
48
+ "testTitle": "trailmark sample app scan",
49
+ "testFile": "/Users/dmitrijsminajevs/dev/axe/packages/trailmark-playwright/integration/specs/sample.spec.ts",
50
+ "projectName": "chromium"
51
+ },
52
+ "occurrenceId": "3473dff9eb8fb607ca9dcb0f558fb82305e1a033",
53
+ "occurredAt": "2026-02-08T20:11:55.607Z"
54
+ }
55
+ ],
56
+ "scanErrors": [],
57
+ "metadata": {
58
+ "sourceRuns": 1,
59
+ "artifactRunIds": [
60
+ "20260208T201155296Z"
61
+ ],
62
+ "artifactWarnings": [],
63
+ "artifactIndex": {
64
+ "byOccurrenceId": {},
65
+ "byIssueId": {}
66
+ },
67
+ "scanCount": 1,
68
+ "skippedScanCount": 0
69
+ },
70
+ "finishedAt": "2026-02-08T20:11:55.643Z"
71
+ },
72
+ "diff": {
73
+ "newFindings": [],
74
+ "existing": [
75
+ {
76
+ "finding": {
77
+ "issueId": "afbdf52e9915d0b0e73041501018ec09de569a5b",
78
+ "relaxedIssueId": "85362a09993122b59cdcb30d0d1682654e2bf705",
79
+ "ruleId": "image-alt",
80
+ "impact": "critical",
81
+ "tags": [
82
+ "cat.text-alternatives",
83
+ "wcag2a",
84
+ "wcag111",
85
+ "section508",
86
+ "section508.22.a",
87
+ "TTv5",
88
+ "TT7.a",
89
+ "TT7.b",
90
+ "EN-301-549",
91
+ "EN-9.1.1.1",
92
+ "ACT",
93
+ "RGAAv4",
94
+ "RGAA-1.1.1"
95
+ ],
96
+ "help": "Images must have alternative text",
97
+ "helpUrl": "https://dequeuniversity.com/rules/axe/4.11/image-alt?application=playwright",
98
+ "pageUrl": "file:///Users/dmitrijsminajevs/dev/axe/packages/trailmark-playwright/integration/app/base.html",
99
+ "pageKey": "sample-app/page.html",
100
+ "target": [
101
+ "img"
102
+ ],
103
+ "selectorHint": "img",
104
+ "targetHash": "affe482b172ca2ef1a2ef338d49db47e91b1f05e",
105
+ "nodeHtml": "<img data-testid=\"hero-image\" src=\"hero.jpg\">",
106
+ "failureSummary": "Fix any of the following:\n Element does not have an alt attribute\n aria-label attribute does not exist or is empty\n aria-labelledby attribute does not exist, references elements that do not exist or references elements that are empty\n Element has no title attribute\n Element's default semantics were not overridden with role=\"none\" or role=\"presentation\"",
107
+ "failureHint": "fix any of the following: element does not have an alt attribute aria-label attribute does not exist or is empty aria-labelledby attribute does not exist, references elements that do not exist or references elements that are empty element has no title attribute elements default semantics were not overridden with role=none or role=presentation",
108
+ "meta": {
109
+ "testId": "b92766bcf73bd5c029a8-4f0088c96308a9a97a42",
110
+ "testTitle": "trailmark sample app scan",
111
+ "testFile": "/Users/dmitrijsminajevs/dev/axe/packages/trailmark-playwright/integration/specs/sample.spec.ts",
112
+ "projectName": "chromium"
113
+ },
114
+ "occurrenceId": "3473dff9eb8fb607ca9dcb0f558fb82305e1a033",
115
+ "occurredAt": "2026-02-08T20:11:55.607Z"
116
+ },
117
+ "matchedBy": "exact",
118
+ "baselineIssueId": "afbdf52e9915d0b0e73041501018ec09de569a5b",
119
+ "baselineScopeKey": "chromium"
120
+ }
121
+ ],
122
+ "resolved": [],
123
+ "blockingNew": [],
124
+ "stats": {
125
+ "totalCurrent": 1,
126
+ "totalBaseline": 1,
127
+ "newCount": 0,
128
+ "existingCount": 1,
129
+ "resolvedCount": 0,
130
+ "newByImpact": {}
131
+ }
132
+ },
133
+ "reportPath": "/Users/dmitrijsminajevs/dev/axe/packages/trailmark-playwright/integration/tmp/report.json",
134
+ "warnings": [],
135
+ "errors": []
136
+ }
@@ -0,0 +1,31 @@
1
+ import { Page } from "@playwright/test";
2
+ import { TrailmarkAttachment, TrailmarkFinding } from "@trailmark/core";
3
+ import { ResolvedTrailmarkArtifactOptions } from "./options";
4
+ export declare function sanitizeArtifactSegment(input: string, maxLength?: number): string;
5
+ export declare function createArtifactRunId(date?: Date): string;
6
+ export interface ArtifactManagerOptions extends ResolvedTrailmarkArtifactOptions {
7
+ runId: string;
8
+ }
9
+ export interface ArtifactCaptureContext {
10
+ page: Page;
11
+ finding: TrailmarkFinding;
12
+ }
13
+ export interface ArtifactCaptureResult {
14
+ attachments: TrailmarkAttachment[];
15
+ skipped: boolean;
16
+ }
17
+ export declare class ArtifactManager {
18
+ private readonly options;
19
+ private readonly runDir;
20
+ private readonly stemCounters;
21
+ private capturedIssues;
22
+ private limitWarningEmitted;
23
+ private readonly warnings;
24
+ constructor(options: ArtifactManagerOptions);
25
+ getRunId(): string;
26
+ getWarnings(): string[];
27
+ private nextStem;
28
+ private canCaptureIssue;
29
+ captureForIssue(context: ArtifactCaptureContext): Promise<ArtifactCaptureResult>;
30
+ }
31
+ //# sourceMappingURL=artifactManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifactManager.d.ts","sourceRoot":"","sources":["../../src/artifacts/artifactManager.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAA;AACvC,OAAO,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAEvE,OAAO,EAAE,gCAAgC,EAAE,MAAM,WAAW,CAAA;AAU5D,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,SAAK,GAAG,MAAM,CAY7E;AAWD,wBAAgB,mBAAmB,CAAC,IAAI,GAAE,IAAiB,GAAG,MAAM,CAGnE;AAED,MAAM,WAAW,sBAAuB,SAAQ,gCAAgC;IAC9E,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,IAAI,CAAA;IACV,OAAO,EAAE,gBAAgB,CAAA;CAC1B;AAED,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,mBAAmB,EAAE,CAAA;IAClC,OAAO,EAAE,OAAO,CAAA;CACjB;AAED,qBAAa,eAAe;IAWd,OAAO,CAAC,QAAQ,CAAC,OAAO;IAVpC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAQ;IAE/B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA4B;IAEzD,OAAO,CAAC,cAAc,CAAI;IAE1B,OAAO,CAAC,mBAAmB,CAAQ;IAEnC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAe;gBAEX,OAAO,EAAE,sBAAsB;IAO5D,QAAQ,IAAI,MAAM;IAIlB,WAAW,IAAI,MAAM,EAAE;IAIvB,OAAO,CAAC,QAAQ;IAkBhB,OAAO,CAAC,eAAe;IAmBjB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,qBAAqB,CAAC;CAyDvF"}
@@ -0,0 +1,140 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ArtifactManager = void 0;
7
+ exports.sanitizeArtifactSegment = sanitizeArtifactSegment;
8
+ exports.createArtifactRunId = createArtifactRunId;
9
+ const node_fs_1 = require("node:fs");
10
+ const node_path_1 = __importDefault(require("node:path"));
11
+ const capture_1 = require("./capture");
12
+ function impactKey(impact) {
13
+ if (!impact) {
14
+ return "unknown";
15
+ }
16
+ return String(impact).toLowerCase();
17
+ }
18
+ function sanitizeArtifactSegment(input, maxLength = 60) {
19
+ const cleaned = input
20
+ .toLowerCase()
21
+ .replace(/[^a-z0-9._-]+/g, "_")
22
+ .replace(/_+/g, "_")
23
+ .replace(/^_+|_+$/g, "");
24
+ if (!cleaned) {
25
+ return "unknown";
26
+ }
27
+ return cleaned.slice(0, maxLength);
28
+ }
29
+ function toPosixPath(filePath) {
30
+ return filePath.split(node_path_1.default.sep).join(node_path_1.default.posix.sep);
31
+ }
32
+ function toRelativeArtifactPath(absolutePath) {
33
+ const relative = node_path_1.default.relative(process.cwd(), absolutePath);
34
+ return toPosixPath(relative);
35
+ }
36
+ function createArtifactRunId(date = new Date()) {
37
+ const iso = date.toISOString();
38
+ return iso.replace(/[-:.]/g, "").replace(".000", "");
39
+ }
40
+ class ArtifactManager {
41
+ constructor(options) {
42
+ this.options = options;
43
+ this.stemCounters = new Map();
44
+ this.capturedIssues = 0;
45
+ this.limitWarningEmitted = false;
46
+ this.warnings = [];
47
+ this.runDir = node_path_1.default.resolve(options.outputDir, options.runId);
48
+ if (options.enabled && (options.includeViewport || options.includeElement)) {
49
+ (0, node_fs_1.mkdirSync)(this.runDir, { recursive: true });
50
+ }
51
+ }
52
+ getRunId() {
53
+ return this.options.runId;
54
+ }
55
+ getWarnings() {
56
+ return [...this.warnings];
57
+ }
58
+ nextStem(finding) {
59
+ const baseStem = [
60
+ sanitizeArtifactSegment(impactKey(finding.impact)),
61
+ sanitizeArtifactSegment(finding.ruleId),
62
+ sanitizeArtifactSegment(finding.pageKey),
63
+ sanitizeArtifactSegment(finding.issueId.slice(0, 12)),
64
+ ].join("__");
65
+ const currentCount = (this.stemCounters.get(baseStem) ?? 0) + 1;
66
+ this.stemCounters.set(baseStem, currentCount);
67
+ if (currentCount === 1) {
68
+ return baseStem;
69
+ }
70
+ return `${baseStem}__${currentCount}`;
71
+ }
72
+ canCaptureIssue() {
73
+ if (!this.options.enabled) {
74
+ return false;
75
+ }
76
+ if (this.capturedIssues < this.options.limitPerRun) {
77
+ return true;
78
+ }
79
+ if (!this.limitWarningEmitted) {
80
+ this.limitWarningEmitted = true;
81
+ this.warnings.push(`trailmark: artifact capture limit reached (${this.options.limitPerRun}); skipping remaining captures.`);
82
+ }
83
+ return false;
84
+ }
85
+ async captureForIssue(context) {
86
+ if (!this.canCaptureIssue()) {
87
+ return { attachments: [], skipped: true };
88
+ }
89
+ this.capturedIssues += 1;
90
+ const attachments = [];
91
+ const stem = this.nextStem(context.finding);
92
+ if (this.options.includeViewport) {
93
+ const outputPath = node_path_1.default.join(this.runDir, `${stem}__viewport.png`);
94
+ try {
95
+ await (0, capture_1.captureViewportScreenshot)(context.page, outputPath);
96
+ attachments.push({
97
+ kind: "viewport",
98
+ path: toRelativeArtifactPath(outputPath),
99
+ });
100
+ }
101
+ catch (error) {
102
+ attachments.push({
103
+ kind: "viewport",
104
+ error: error instanceof Error ? error.message : String(error),
105
+ });
106
+ }
107
+ }
108
+ if (this.options.includeElement) {
109
+ const selector = context.finding.target[0] ?? context.finding.selectorHint;
110
+ if (!selector) {
111
+ attachments.push({
112
+ kind: "element",
113
+ error: "No selector available for element screenshot capture.",
114
+ });
115
+ }
116
+ else {
117
+ const outputPath = node_path_1.default.join(this.runDir, `${stem}__element.png`);
118
+ try {
119
+ await (0, capture_1.captureElementScreenshot)(context.page, selector, outputPath);
120
+ attachments.push({
121
+ kind: "element",
122
+ path: toRelativeArtifactPath(outputPath),
123
+ });
124
+ }
125
+ catch (error) {
126
+ attachments.push({
127
+ kind: "element",
128
+ error: error instanceof Error ? error.message : String(error),
129
+ });
130
+ }
131
+ }
132
+ }
133
+ return {
134
+ attachments,
135
+ skipped: false,
136
+ };
137
+ }
138
+ }
139
+ exports.ArtifactManager = ArtifactManager;
140
+ //# sourceMappingURL=artifactManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifactManager.js","sourceRoot":"","sources":["../../src/artifacts/artifactManager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { Page } from "@playwright/test";
2
+ export declare function captureViewportScreenshot(page: Page, outputPath: string): Promise<void>;
3
+ export declare function captureElementScreenshot(page: Page, selector: string, outputPath: string): Promise<void>;
4
+ //# sourceMappingURL=capture.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capture.d.ts","sourceRoot":"","sources":["../../src/artifacts/capture.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAA;AAEvC,wBAAsB,yBAAyB,CAAC,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAK7F;AAED,wBAAsB,wBAAwB,CAC5C,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CAIf"}
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.captureViewportScreenshot = captureViewportScreenshot;
4
+ exports.captureElementScreenshot = captureElementScreenshot;
5
+ async function captureViewportScreenshot(page, outputPath) {
6
+ await page.screenshot({
7
+ path: outputPath,
8
+ fullPage: true,
9
+ });
10
+ }
11
+ async function captureElementScreenshot(page, selector, outputPath) {
12
+ await page.locator(selector).first().screenshot({
13
+ path: outputPath,
14
+ });
15
+ }
16
+ //# sourceMappingURL=capture.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capture.js","sourceRoot":"","sources":["../../src/artifacts/capture.ts"],"names":[],"mappings":";;AAEA,8DAKC;AAED,4DAQC;AAfM,KAAK,UAAU,yBAAyB,CAAC,IAAU,EAAE,UAAkB;IAC5E,MAAM,IAAI,CAAC,UAAU,CAAC;QACpB,IAAI,EAAE,UAAU;QAChB,QAAQ,EAAE,IAAI;KACf,CAAC,CAAA;AACJ,CAAC;AAEM,KAAK,UAAU,wBAAwB,CAC5C,IAAU,EACV,QAAgB,EAChB,UAAkB;IAElB,MAAM,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,KAAK,EAAE,CAAC,UAAU,CAAC;QAC9C,IAAI,EAAE,UAAU;KACjB,CAAC,CAAA;AACJ,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { TrailmarkArtifactCaptureMode, TrailmarkArtifactOptions, TrailmarkMode } from "../types";
2
+ export interface ResolvedTrailmarkArtifactOptions {
3
+ enabled: boolean;
4
+ outputDir: string;
5
+ limitPerRun: number;
6
+ capture: TrailmarkArtifactCaptureMode;
7
+ includeViewport: boolean;
8
+ includeElement: boolean;
9
+ }
10
+ export declare function resolveArtifactOptions(mode: TrailmarkMode, options: TrailmarkArtifactOptions | undefined, env?: NodeJS.ProcessEnv): ResolvedTrailmarkArtifactOptions;
11
+ //# sourceMappingURL=options.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"options.d.ts","sourceRoot":"","sources":["../../src/artifacts/options.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,4BAA4B,EAAE,wBAAwB,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAEhG,MAAM,WAAW,gCAAgC;IAC/C,OAAO,EAAE,OAAO,CAAA;IAChB,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,EAAE,4BAA4B,CAAA;IACrC,eAAe,EAAE,OAAO,CAAA;IACxB,cAAc,EAAE,OAAO,CAAA;CACxB;AA+CD,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,aAAa,EACnB,OAAO,EAAE,wBAAwB,GAAG,SAAS,EAC7C,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,gCAAgC,CAkBlC"}
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveArtifactOptions = resolveArtifactOptions;
4
+ const DEFAULT_OUTPUT_DIR = ".trailmark/artifacts";
5
+ const DEFAULT_LIMIT_PER_RUN = 50;
6
+ function parseBoolean(value) {
7
+ if (!value) {
8
+ return undefined;
9
+ }
10
+ const normalized = value.trim().toLowerCase();
11
+ if (normalized === "1" || normalized === "true") {
12
+ return true;
13
+ }
14
+ if (normalized === "0" || normalized === "false") {
15
+ return false;
16
+ }
17
+ return undefined;
18
+ }
19
+ function parsePositiveInteger(value) {
20
+ if (!value) {
21
+ return undefined;
22
+ }
23
+ const parsed = Number.parseInt(value, 10);
24
+ if (!Number.isFinite(parsed) || parsed <= 0) {
25
+ return undefined;
26
+ }
27
+ return parsed;
28
+ }
29
+ function parseCaptureMode(value) {
30
+ if (!value) {
31
+ return undefined;
32
+ }
33
+ if (value === "new-only" || value === "all") {
34
+ return value;
35
+ }
36
+ return undefined;
37
+ }
38
+ function resolveArtifactOptions(mode, options, env = process.env) {
39
+ // const defaultEnabled = mode === "check"
40
+ const defaultEnabled = false;
41
+ const envEnabled = parseBoolean(env.TRAILMARK_ARTIFACTS_ENABLED);
42
+ const envIncludeViewport = parseBoolean(env.TRAILMARK_ARTIFACTS_INCLUDE_VIEWPORT);
43
+ const envIncludeElement = parseBoolean(env.TRAILMARK_ARTIFACTS_INCLUDE_ELEMENT);
44
+ const envLimitPerRun = parsePositiveInteger(env.TRAILMARK_ARTIFACTS_LIMIT_PER_RUN);
45
+ const envCaptureMode = parseCaptureMode(env.TRAILMARK_ARTIFACTS_CAPTURE);
46
+ return {
47
+ enabled: options?.enabled ?? envEnabled ?? defaultEnabled,
48
+ outputDir: options?.outputDir ?? env.TRAILMARK_ARTIFACTS_OUTPUT_DIR ?? DEFAULT_OUTPUT_DIR,
49
+ limitPerRun: options?.limitPerRun ?? envLimitPerRun ?? DEFAULT_LIMIT_PER_RUN,
50
+ capture: options?.capture ?? envCaptureMode ?? "new-only",
51
+ includeViewport: options?.includeViewport ?? envIncludeViewport ?? true,
52
+ includeElement: options?.includeElement ?? envIncludeElement ?? true,
53
+ };
54
+ }
55
+ //# sourceMappingURL=options.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"options.js","sourceRoot":"","sources":["../../src/artifacts/options.ts"],"names":[],"mappings":";;AAwDA,wDAsBC;AAnED,MAAM,kBAAkB,GAAG,sBAAsB,CAAA;AACjD,MAAM,qBAAqB,GAAG,EAAE,CAAA;AAEhC,SAAS,YAAY,CAAC,KAAyB;IAC7C,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;IAC7C,IAAI,UAAU,KAAK,GAAG,IAAI,UAAU,KAAK,MAAM,EAAE,CAAC;QAChD,OAAO,IAAI,CAAA;IACb,CAAC;IAED,IAAI,UAAU,KAAK,GAAG,IAAI,UAAU,KAAK,OAAO,EAAE,CAAC;QACjD,OAAO,KAAK,CAAA;IACd,CAAC;IAED,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,SAAS,oBAAoB,CAAC,KAAyB;IACrD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;IACzC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,IAAI,CAAC,EAAE,CAAC;QAC5C,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,OAAO,MAAM,CAAA;AACf,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAyB;IACjD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,IAAI,KAAK,KAAK,UAAU,IAAI,KAAK,KAAK,KAAK,EAAE,CAAC;QAC5C,OAAO,KAAK,CAAA;IACd,CAAC;IAED,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,SAAgB,sBAAsB,CACpC,IAAmB,EACnB,OAA6C,EAC7C,MAAyB,OAAO,CAAC,GAAG;IAEpC,0CAA0C;IAC1C,MAAM,cAAc,GAAG,KAAK,CAAA;IAE5B,MAAM,UAAU,GAAG,YAAY,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAA;IAChE,MAAM,kBAAkB,GAAG,YAAY,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAA;IACjF,MAAM,iBAAiB,GAAG,YAAY,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAA;IAC/E,MAAM,cAAc,GAAG,oBAAoB,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAA;IAClF,MAAM,cAAc,GAAG,gBAAgB,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAA;IAExE,OAAO;QACL,OAAO,EAAE,OAAO,EAAE,OAAO,IAAI,UAAU,IAAI,cAAc;QACzD,SAAS,EAAE,OAAO,EAAE,SAAS,IAAI,GAAG,CAAC,8BAA8B,IAAI,kBAAkB;QACzF,WAAW,EAAE,OAAO,EAAE,WAAW,IAAI,cAAc,IAAI,qBAAqB;QAC5E,OAAO,EAAE,OAAO,EAAE,OAAO,IAAI,cAAc,IAAI,UAAU;QACzD,eAAe,EAAE,OAAO,EAAE,eAAe,IAAI,kBAAkB,IAAI,IAAI;QACvE,cAAc,EAAE,OAAO,EAAE,cAAc,IAAI,iBAAiB,IAAI,IAAI;KACrE,CAAA;AACH,CAAC"}
@@ -0,0 +1,24 @@
1
+ import { BaselineFile, TrailmarkAttachment, TrailmarkFinding } from "@trailmark/core";
2
+ import { TrailmarkArtifactCaptureMode } from "../types";
3
+ export declare class CaptureDecisionRegistry {
4
+ private readonly captureMode;
5
+ private readonly seenIssueKeys;
6
+ private readonly baselineByExact;
7
+ private readonly baselineByRelaxed;
8
+ private readonly matchedBaselineExactKeys;
9
+ constructor(captureMode: TrailmarkArtifactCaptureMode, baseline: BaselineFile | undefined);
10
+ shouldCaptureIssue(finding: TrailmarkFinding): boolean;
11
+ }
12
+ export declare class ArtifactRegistry {
13
+ private readonly occurrenceOrdinalByIssueKey;
14
+ private readonly attachmentsByOccurrenceId;
15
+ registerOccurrence(finding: TrailmarkFinding): {
16
+ occurrenceId: string;
17
+ issueKey: string;
18
+ };
19
+ registerAttachments(occurrenceId: string, attachments: TrailmarkAttachment[]): void;
20
+ attachmentIndex(): {
21
+ byOccurrenceId: Record<string, TrailmarkAttachment[]>;
22
+ };
23
+ }
24
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/artifacts/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,YAAY,EACZ,mBAAmB,EACnB,gBAAgB,EAKjB,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,4BAA4B,EAAE,MAAM,UAAU,CAAA;AA2CvD,qBAAa,uBAAuB;IAUhC,OAAO,CAAC,QAAQ,CAAC,WAAW;IAT9B,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAoB;IAElD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA4B;IAE5D,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAA8B;IAEhE,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAoB;gBAG1C,WAAW,EAAE,4BAA4B,EAC1D,QAAQ,EAAE,YAAY,GAAG,SAAS;IAOpC,kBAAkB,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO;CA8BvD;AAED,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,2BAA2B,CAA4B;IAExE,OAAO,CAAC,QAAQ,CAAC,yBAAyB,CAA2C;IAErF,kBAAkB,CAAC,OAAO,EAAE,gBAAgB,GAAG;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE;IAoBzF,mBAAmB,CAAC,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,mBAAmB,EAAE,GAAG,IAAI;IAInF,eAAe,IAAI;QAAE,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,EAAE,CAAC,CAAA;KAAE;CAU7E"}
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ArtifactRegistry = exports.CaptureDecisionRegistry = void 0;
4
+ const core_1 = require("@trailmark/core");
5
+ function makeBaselineExactKey(entry) {
6
+ return (0, core_1.scopedIssueKey)(entry.issueId, (0, core_1.scopeKeyFromBaselineEntry)(entry));
7
+ }
8
+ function makeFindingExactKey(finding) {
9
+ return (0, core_1.scopedIssueKey)(finding.issueId, (0, core_1.scopeKeyFromMeta)(finding.meta));
10
+ }
11
+ function makeFindingRelaxedKey(finding) {
12
+ return (0, core_1.scopedIssueKey)(finding.relaxedIssueId, (0, core_1.scopeKeyFromMeta)(finding.meta));
13
+ }
14
+ function makeRelaxedMap(baselineEntries) {
15
+ const map = new Map();
16
+ for (const entry of baselineEntries) {
17
+ const key = (0, core_1.scopedIssueKey)(entry.relaxedIssueId, (0, core_1.scopeKeyFromBaselineEntry)(entry));
18
+ const list = map.get(key) ?? [];
19
+ list.push(entry);
20
+ map.set(key, list);
21
+ }
22
+ for (const entries of map.values()) {
23
+ entries.sort((left, right) => makeBaselineExactKey(left).localeCompare(makeBaselineExactKey(right)));
24
+ }
25
+ return map;
26
+ }
27
+ function pickUnmatched(entries, matchedExactKeys) {
28
+ if (!entries || entries.length === 0) {
29
+ return undefined;
30
+ }
31
+ return entries.find((entry) => !matchedExactKeys.has(makeBaselineExactKey(entry)));
32
+ }
33
+ class CaptureDecisionRegistry {
34
+ constructor(captureMode, baseline) {
35
+ this.captureMode = captureMode;
36
+ this.seenIssueKeys = new Set();
37
+ this.matchedBaselineExactKeys = new Set();
38
+ const entries = Object.values(baseline?.findings ?? {});
39
+ this.baselineByExact = new Map(entries.map((entry) => [makeBaselineExactKey(entry), entry]));
40
+ this.baselineByRelaxed = makeRelaxedMap(entries);
41
+ }
42
+ shouldCaptureIssue(finding) {
43
+ const findingExactKey = makeFindingExactKey(finding);
44
+ if (this.seenIssueKeys.has(findingExactKey)) {
45
+ return false;
46
+ }
47
+ this.seenIssueKeys.add(findingExactKey);
48
+ if (this.captureMode === "all") {
49
+ return true;
50
+ }
51
+ const exact = this.baselineByExact.get(findingExactKey);
52
+ if (exact) {
53
+ this.matchedBaselineExactKeys.add(makeBaselineExactKey(exact));
54
+ return false;
55
+ }
56
+ const relaxed = pickUnmatched(this.baselineByRelaxed.get(makeFindingRelaxedKey(finding)), this.matchedBaselineExactKeys);
57
+ if (relaxed) {
58
+ this.matchedBaselineExactKeys.add(makeBaselineExactKey(relaxed));
59
+ return false;
60
+ }
61
+ return true;
62
+ }
63
+ }
64
+ exports.CaptureDecisionRegistry = CaptureDecisionRegistry;
65
+ class ArtifactRegistry {
66
+ constructor() {
67
+ this.occurrenceOrdinalByIssueKey = new Map();
68
+ this.attachmentsByOccurrenceId = new Map();
69
+ }
70
+ registerOccurrence(finding) {
71
+ const issueKey = makeFindingExactKey(finding);
72
+ const ordinal = (this.occurrenceOrdinalByIssueKey.get(issueKey) ?? 0) + 1;
73
+ this.occurrenceOrdinalByIssueKey.set(issueKey, ordinal);
74
+ const occurrenceId = (0, core_1.hashObject)({
75
+ issueKey,
76
+ issueId: finding.issueId,
77
+ pageKey: finding.pageKey,
78
+ testId: finding.meta?.testId,
79
+ projectName: finding.meta?.projectName,
80
+ ordinal,
81
+ });
82
+ return {
83
+ occurrenceId,
84
+ issueKey,
85
+ };
86
+ }
87
+ registerAttachments(occurrenceId, attachments) {
88
+ this.attachmentsByOccurrenceId.set(occurrenceId, attachments);
89
+ }
90
+ attachmentIndex() {
91
+ const byOccurrenceId = {};
92
+ for (const key of Array.from(this.attachmentsByOccurrenceId.keys()).sort((a, b) => a.localeCompare(b))) {
93
+ byOccurrenceId[key] = this.attachmentsByOccurrenceId.get(key) ?? [];
94
+ }
95
+ return { byOccurrenceId };
96
+ }
97
+ }
98
+ exports.ArtifactRegistry = ArtifactRegistry;
99
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/artifacts/registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare const TRAILMARK_ATTACHMENT_NAME = "trailmark-run";
2
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,yBAAyB,kBAAkB,CAAA"}
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TRAILMARK_ATTACHMENT_NAME = void 0;
4
+ exports.TRAILMARK_ATTACHMENT_NAME = "trailmark-run";
5
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,yBAAyB,GAAG,eAAe,CAAA"}
@@ -0,0 +1,7 @@
1
+ import { expect } from "@playwright/test";
2
+ import { TrailmarkFixture } from "./types";
3
+ export declare const test: import("@playwright/test").TestType<import("@playwright/test").PlaywrightTestArgs & import("@playwright/test").PlaywrightTestOptions & {
4
+ trailmark: TrailmarkFixture;
5
+ }, import("@playwright/test").PlaywrightWorkerArgs & import("@playwright/test").PlaywrightWorkerOptions>;
6
+ export { expect };
7
+ //# sourceMappingURL=fixture.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fixture.d.ts","sourceRoot":"","sources":["../src/fixture.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAgB,MAAM,kBAAkB,CAAA;AAcvD,OAAO,EAAyC,gBAAgB,EAAiB,MAAM,SAAS,CAAA;AAqFhG,eAAO,MAAM,IAAI;eAA4B,gBAAgB;wGAuI3D,CAAA;AAEF,OAAO,EAAE,MAAM,EAAE,CAAA"}