@logicsync/pixelprobe 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.
- package/LICENSE +21 -0
- package/README.md +377 -0
- package/dist/bin/pixelprobe.d.ts +3 -0
- package/dist/bin/pixelprobe.d.ts.map +1 -0
- package/dist/bin/pixelprobe.js +218 -0
- package/dist/bin/pixelprobe.js.map +1 -0
- package/dist/browser/BrowserManager.d.ts +20 -0
- package/dist/browser/BrowserManager.d.ts.map +1 -0
- package/dist/browser/BrowserManager.js +64 -0
- package/dist/browser/BrowserManager.js.map +1 -0
- package/dist/browser/ViewportManager.d.ts +15 -0
- package/dist/browser/ViewportManager.d.ts.map +1 -0
- package/dist/browser/ViewportManager.js +65 -0
- package/dist/browser/ViewportManager.js.map +1 -0
- package/dist/cli/formatter.d.ts +4 -0
- package/dist/cli/formatter.d.ts.map +1 -0
- package/dist/cli/formatter.js +107 -0
- package/dist/cli/formatter.js.map +1 -0
- package/dist/comparator/DiffAggregator.d.ts +24 -0
- package/dist/comparator/DiffAggregator.d.ts.map +1 -0
- package/dist/comparator/DiffAggregator.js +94 -0
- package/dist/comparator/DiffAggregator.js.map +1 -0
- package/dist/comparator/LayoutComparator.d.ts +8 -0
- package/dist/comparator/LayoutComparator.d.ts.map +1 -0
- package/dist/comparator/LayoutComparator.js +68 -0
- package/dist/comparator/LayoutComparator.js.map +1 -0
- package/dist/comparator/PixelComparator.d.ts +9 -0
- package/dist/comparator/PixelComparator.d.ts.map +1 -0
- package/dist/comparator/PixelComparator.js +72 -0
- package/dist/comparator/PixelComparator.js.map +1 -0
- package/dist/comparator/StyleComparator.d.ts +8 -0
- package/dist/comparator/StyleComparator.d.ts.map +1 -0
- package/dist/comparator/StyleComparator.js +119 -0
- package/dist/comparator/StyleComparator.js.map +1 -0
- package/dist/core.d.ts +23 -0
- package/dist/core.d.ts.map +1 -0
- package/dist/core.js +211 -0
- package/dist/core.js.map +1 -0
- package/dist/extractor/ScreenshotCapturer.d.ts +20 -0
- package/dist/extractor/ScreenshotCapturer.d.ts.map +1 -0
- package/dist/extractor/ScreenshotCapturer.js +56 -0
- package/dist/extractor/ScreenshotCapturer.js.map +1 -0
- package/dist/extractor/SectionExtractor.d.ts +26 -0
- package/dist/extractor/SectionExtractor.d.ts.map +1 -0
- package/dist/extractor/SectionExtractor.js +92 -0
- package/dist/extractor/SectionExtractor.js.map +1 -0
- package/dist/extractor/StyleExtractor.d.ts +23 -0
- package/dist/extractor/StyleExtractor.d.ts.map +1 -0
- package/dist/extractor/StyleExtractor.js +88 -0
- package/dist/extractor/StyleExtractor.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/server.d.ts +3 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +203 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/reporter/HTMLReporter.d.ts +8 -0
- package/dist/reporter/HTMLReporter.d.ts.map +1 -0
- package/dist/reporter/HTMLReporter.js +219 -0
- package/dist/reporter/HTMLReporter.js.map +1 -0
- package/dist/reporter/JSONReporter.d.ts +17 -0
- package/dist/reporter/JSONReporter.d.ts.map +1 -0
- package/dist/reporter/JSONReporter.js +77 -0
- package/dist/reporter/JSONReporter.js.map +1 -0
- package/dist/types/comparison.d.ts +133 -0
- package/dist/types/comparison.d.ts.map +1 -0
- package/dist/types/comparison.js +3 -0
- package/dist/types/comparison.js.map +1 -0
- package/dist/types/config.d.ts +138 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +151 -0
- package/dist/types/config.js.map +1 -0
- package/package.json +72 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { STYLE_CATEGORIES } from "../types/config.js";
|
|
2
|
+
// Properties that have high visual impact when different
|
|
3
|
+
const CRITICAL_PROPERTIES = new Set([
|
|
4
|
+
"display",
|
|
5
|
+
"position",
|
|
6
|
+
"width",
|
|
7
|
+
"height",
|
|
8
|
+
"flex-direction",
|
|
9
|
+
"grid-template-columns",
|
|
10
|
+
"grid-template-rows",
|
|
11
|
+
"font-size",
|
|
12
|
+
"visibility",
|
|
13
|
+
"overflow",
|
|
14
|
+
]);
|
|
15
|
+
// Properties with moderate visual impact
|
|
16
|
+
const WARNING_PROPERTIES = new Set([
|
|
17
|
+
"margin",
|
|
18
|
+
"margin-top",
|
|
19
|
+
"margin-right",
|
|
20
|
+
"margin-bottom",
|
|
21
|
+
"margin-left",
|
|
22
|
+
"padding",
|
|
23
|
+
"padding-top",
|
|
24
|
+
"padding-right",
|
|
25
|
+
"padding-bottom",
|
|
26
|
+
"padding-left",
|
|
27
|
+
"font-family",
|
|
28
|
+
"font-weight",
|
|
29
|
+
"line-height",
|
|
30
|
+
"text-align",
|
|
31
|
+
"color",
|
|
32
|
+
"background-color",
|
|
33
|
+
"border",
|
|
34
|
+
"border-radius",
|
|
35
|
+
"gap",
|
|
36
|
+
"justify-content",
|
|
37
|
+
"align-items",
|
|
38
|
+
"flex-wrap",
|
|
39
|
+
"max-width",
|
|
40
|
+
"max-height",
|
|
41
|
+
"min-width",
|
|
42
|
+
"min-height",
|
|
43
|
+
]);
|
|
44
|
+
export class StyleComparator {
|
|
45
|
+
/**
|
|
46
|
+
* Compare computed styles from source and target elements.
|
|
47
|
+
*/
|
|
48
|
+
static compare(sourceStyles, targetStyles) {
|
|
49
|
+
const differences = [];
|
|
50
|
+
// Build a reverse map: property → category
|
|
51
|
+
const propertyCategory = new Map();
|
|
52
|
+
for (const [cat, props] of Object.entries(STYLE_CATEGORIES)) {
|
|
53
|
+
for (const prop of props) {
|
|
54
|
+
propertyCategory.set(prop, cat);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// Union of all properties from both
|
|
58
|
+
const allProperties = new Set([
|
|
59
|
+
...Object.keys(sourceStyles),
|
|
60
|
+
...Object.keys(targetStyles),
|
|
61
|
+
]);
|
|
62
|
+
for (const prop of allProperties) {
|
|
63
|
+
const sourceVal = normalizeValue(sourceStyles[prop] ?? "");
|
|
64
|
+
const targetVal = normalizeValue(targetStyles[prop] ?? "");
|
|
65
|
+
if (sourceVal !== targetVal) {
|
|
66
|
+
differences.push({
|
|
67
|
+
property: prop,
|
|
68
|
+
category: propertyCategory.get(prop) ?? "other",
|
|
69
|
+
sourceValue: sourceStyles[prop] ?? "(not set)",
|
|
70
|
+
targetValue: targetStyles[prop] ?? "(not set)",
|
|
71
|
+
severity: classifySeverity(prop),
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Sort by severity (critical first), then by property name
|
|
76
|
+
const severityOrder = {
|
|
77
|
+
critical: 0,
|
|
78
|
+
warning: 1,
|
|
79
|
+
info: 2,
|
|
80
|
+
};
|
|
81
|
+
differences.sort((a, b) => severityOrder[a.severity] - severityOrder[b.severity] ||
|
|
82
|
+
a.property.localeCompare(b.property));
|
|
83
|
+
return {
|
|
84
|
+
differences,
|
|
85
|
+
summary: {
|
|
86
|
+
total: differences.length,
|
|
87
|
+
critical: differences.filter((d) => d.severity === "critical").length,
|
|
88
|
+
warning: differences.filter((d) => d.severity === "warning").length,
|
|
89
|
+
info: differences.filter((d) => d.severity === "info").length,
|
|
90
|
+
},
|
|
91
|
+
sourceStyleCount: Object.keys(sourceStyles).length,
|
|
92
|
+
targetStyleCount: Object.keys(targetStyles).length,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
// ── Helpers ───────────────────────────────────────────────────────────
|
|
97
|
+
function classifySeverity(property) {
|
|
98
|
+
if (CRITICAL_PROPERTIES.has(property))
|
|
99
|
+
return "critical";
|
|
100
|
+
if (WARNING_PROPERTIES.has(property))
|
|
101
|
+
return "warning";
|
|
102
|
+
return "info";
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Normalize CSS values for comparison.
|
|
106
|
+
* E.g., "rgb(255, 0, 0)" vs "rgb(255,0,0)" should match.
|
|
107
|
+
*/
|
|
108
|
+
function normalizeValue(value) {
|
|
109
|
+
return value
|
|
110
|
+
.trim()
|
|
111
|
+
.toLowerCase()
|
|
112
|
+
.replace(/\s+/g, " ") // collapse whitespace
|
|
113
|
+
.replace(/,\s*/g, ", ") // normalize comma spacing
|
|
114
|
+
.replace(/\s*\/\s*/g, " / ") // normalize slash spacing
|
|
115
|
+
.replace(/0px/g, "0") // 0px → 0
|
|
116
|
+
.replace(/\.0+(?=\s|,|$|\))/g, "") // remove trailing .0
|
|
117
|
+
.replace(/rgba?\((\d+),\s*(\d+),\s*(\d+),\s*1\)/g, "rgb($1, $2, $3)"); // rgba(x,y,z,1) → rgb(x,y,z)
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=StyleComparator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StyleComparator.js","sourceRoot":"","sources":["../../src/comparator/StyleComparator.ts"],"names":[],"mappings":"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"}
|
package/dist/core.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ComparisonConfig, Breakpoint } from "./types/config.js";
|
|
2
|
+
import type { ComparisonResult, ProgressCallback, ElementInfo } from "./types/comparison.js";
|
|
3
|
+
export declare class WebSectionComparator {
|
|
4
|
+
private browserManager;
|
|
5
|
+
constructor(options?: {
|
|
6
|
+
headless?: boolean;
|
|
7
|
+
timeout?: number;
|
|
8
|
+
});
|
|
9
|
+
/**
|
|
10
|
+
* Run a full comparison across all breakpoints.
|
|
11
|
+
*/
|
|
12
|
+
compare(config: ComparisonConfig, onProgress?: ProgressCallback): Promise<ComparisonResult>;
|
|
13
|
+
/**
|
|
14
|
+
* Enumerate matching elements for a selector on a URL.
|
|
15
|
+
* Useful for disambiguation before comparing.
|
|
16
|
+
*/
|
|
17
|
+
enumerate(url: string, selector: string, breakpoint?: string): Promise<ElementInfo[]>;
|
|
18
|
+
/**
|
|
19
|
+
* List available breakpoint presets.
|
|
20
|
+
*/
|
|
21
|
+
listBreakpoints(): Breakpoint[];
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=core.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,gBAAgB,EAEhB,UAAU,EAEX,MAAM,mBAAmB,CAAC;AAE3B,OAAO,KAAK,EACV,gBAAgB,EAGhB,gBAAgB,EAChB,WAAW,EACZ,MAAM,uBAAuB,CAAC;AAM/B,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,cAAc,CAAiB;gBAE3B,OAAO,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE;IAI9D;;OAEG;IACG,OAAO,CACX,MAAM,EAAE,gBAAgB,EACxB,UAAU,CAAC,EAAE,gBAAgB,GAC5B,OAAO,CAAC,gBAAgB,CAAC;IAkI5B;;;OAGG;IACG,SAAS,CACb,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,EAChB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,WAAW,EAAE,CAAC;IAqBzB;;OAEG;IACH,eAAe;CAGhB"}
|
package/dist/core.js
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { ComparisonConfigSchema } from "./types/config.js";
|
|
3
|
+
import { BrowserManager } from "./browser/BrowserManager.js";
|
|
4
|
+
import { ViewportManager } from "./browser/ViewportManager.js";
|
|
5
|
+
import { SectionExtractor } from "./extractor/SectionExtractor.js";
|
|
6
|
+
import { DiffAggregator } from "./comparator/DiffAggregator.js";
|
|
7
|
+
export class WebSectionComparator {
|
|
8
|
+
browserManager;
|
|
9
|
+
constructor(options) {
|
|
10
|
+
this.browserManager = new BrowserManager(options);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Run a full comparison across all breakpoints.
|
|
14
|
+
*/
|
|
15
|
+
async compare(config, onProgress) {
|
|
16
|
+
const start = Date.now();
|
|
17
|
+
const id = randomUUID().slice(0, 8);
|
|
18
|
+
// Validate config
|
|
19
|
+
const validated = ComparisonConfigSchema.parse(config);
|
|
20
|
+
// Resolve breakpoints
|
|
21
|
+
const resolvedBreakpoints = ViewportManager.resolve(validated.breakpoints, validated.customBreakpoints);
|
|
22
|
+
const resolvedConfig = {
|
|
23
|
+
...validated,
|
|
24
|
+
resolvedBreakpoints,
|
|
25
|
+
};
|
|
26
|
+
onProgress?.({
|
|
27
|
+
phase: "init",
|
|
28
|
+
message: `Starting comparison with ${resolvedBreakpoints.length} breakpoints`,
|
|
29
|
+
progress: 0,
|
|
30
|
+
});
|
|
31
|
+
// Resolve separate selectors for source and target
|
|
32
|
+
const sourceSelector = validated.selector;
|
|
33
|
+
const targetSelector = validated.targetSelector ?? validated.selector;
|
|
34
|
+
try {
|
|
35
|
+
await this.browserManager.launch();
|
|
36
|
+
const breakpointResults = {};
|
|
37
|
+
for (let i = 0; i < resolvedBreakpoints.length; i++) {
|
|
38
|
+
const bp = resolvedBreakpoints[i];
|
|
39
|
+
const progressBase = Math.round(((i / resolvedBreakpoints.length) * 80) + 10);
|
|
40
|
+
onProgress?.({
|
|
41
|
+
phase: "extracting",
|
|
42
|
+
breakpoint: bp.name,
|
|
43
|
+
message: `Comparing at ${bp.name} (${bp.width}×${bp.height})`,
|
|
44
|
+
progress: progressBase,
|
|
45
|
+
});
|
|
46
|
+
// Create pages for this breakpoint
|
|
47
|
+
const sourcePage = await this.browserManager.createPage(bp);
|
|
48
|
+
const targetPage = await this.browserManager.createPage(bp);
|
|
49
|
+
try {
|
|
50
|
+
// Navigate both pages (each waits for its own selector)
|
|
51
|
+
await Promise.all([
|
|
52
|
+
this.browserManager.navigateAndWait(sourcePage, validated.sourceUrl, {
|
|
53
|
+
waitForSelector: validated.waitForSelector ?? sourceSelector,
|
|
54
|
+
waitForTimeout: validated.waitForTimeout,
|
|
55
|
+
}),
|
|
56
|
+
this.browserManager.navigateAndWait(targetPage, validated.targetUrl, {
|
|
57
|
+
waitForSelector: validated.waitForSelector ?? targetSelector,
|
|
58
|
+
waitForTimeout: validated.waitForTimeout,
|
|
59
|
+
}),
|
|
60
|
+
]);
|
|
61
|
+
// Run comparison for this breakpoint
|
|
62
|
+
const elementIdx = typeof validated.elementIndex === "number"
|
|
63
|
+
? validated.elementIndex
|
|
64
|
+
: 0;
|
|
65
|
+
const result = await DiffAggregator.compareBreakpoint(sourcePage, targetPage, bp, {
|
|
66
|
+
selector: sourceSelector,
|
|
67
|
+
targetSelector,
|
|
68
|
+
elementIndex: elementIdx,
|
|
69
|
+
styleCategories: validated.styleCategories,
|
|
70
|
+
pixelThreshold: validated.pixelThreshold,
|
|
71
|
+
includeVisual: validated.includeVisual,
|
|
72
|
+
includeStyles: validated.includeStyles,
|
|
73
|
+
includeLayout: validated.includeLayout,
|
|
74
|
+
});
|
|
75
|
+
breakpointResults[bp.name] = result;
|
|
76
|
+
}
|
|
77
|
+
finally {
|
|
78
|
+
// Always close contexts to free resources
|
|
79
|
+
await sourcePage.context().close();
|
|
80
|
+
await targetPage.context().close();
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
onProgress?.({
|
|
84
|
+
phase: "reporting",
|
|
85
|
+
message: "Generating report",
|
|
86
|
+
progress: 90,
|
|
87
|
+
});
|
|
88
|
+
const summary = computeSummary(breakpointResults);
|
|
89
|
+
const result = {
|
|
90
|
+
id,
|
|
91
|
+
timestamp: new Date().toISOString(),
|
|
92
|
+
config: {
|
|
93
|
+
sourceUrl: validated.sourceUrl,
|
|
94
|
+
targetUrl: validated.targetUrl,
|
|
95
|
+
selector: sourceSelector,
|
|
96
|
+
targetSelector: targetSelector !== sourceSelector ? targetSelector : undefined,
|
|
97
|
+
elementIndex: validated.elementIndex,
|
|
98
|
+
},
|
|
99
|
+
breakpoints: breakpointResults,
|
|
100
|
+
summary,
|
|
101
|
+
artifacts: {
|
|
102
|
+
diffImages: {},
|
|
103
|
+
sourceScreenshots: {},
|
|
104
|
+
targetScreenshots: {},
|
|
105
|
+
},
|
|
106
|
+
duration: Date.now() - start,
|
|
107
|
+
};
|
|
108
|
+
onProgress?.({
|
|
109
|
+
phase: "done",
|
|
110
|
+
message: "Comparison complete",
|
|
111
|
+
progress: 100,
|
|
112
|
+
});
|
|
113
|
+
return result;
|
|
114
|
+
}
|
|
115
|
+
finally {
|
|
116
|
+
await this.browserManager.close();
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Enumerate matching elements for a selector on a URL.
|
|
121
|
+
* Useful for disambiguation before comparing.
|
|
122
|
+
*/
|
|
123
|
+
async enumerate(url, selector, breakpoint) {
|
|
124
|
+
const bp = ViewportManager.resolve([breakpoint ?? "desktop"])[0];
|
|
125
|
+
try {
|
|
126
|
+
await this.browserManager.launch();
|
|
127
|
+
const page = await this.browserManager.createPage(bp);
|
|
128
|
+
try {
|
|
129
|
+
await this.browserManager.navigateAndWait(page, url, {
|
|
130
|
+
waitForSelector: selector,
|
|
131
|
+
});
|
|
132
|
+
return await SectionExtractor.enumerate(page, selector);
|
|
133
|
+
}
|
|
134
|
+
finally {
|
|
135
|
+
await page.context().close();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
finally {
|
|
139
|
+
await this.browserManager.close();
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* List available breakpoint presets.
|
|
144
|
+
*/
|
|
145
|
+
listBreakpoints() {
|
|
146
|
+
return ViewportManager.listPresets();
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
// ── Helpers ───────────────────────────────────────────────────────────
|
|
150
|
+
function computeSummary(breakpoints) {
|
|
151
|
+
const entries = Object.entries(breakpoints);
|
|
152
|
+
let totalStyleDiffs = 0;
|
|
153
|
+
let totalLayoutDiffs = 0;
|
|
154
|
+
let totalPixelDiff = 0;
|
|
155
|
+
let pixelDiffCount = 0;
|
|
156
|
+
let breakpointsWithDiffs = 0;
|
|
157
|
+
let worstBreakpoint = null;
|
|
158
|
+
let worstScore = 0;
|
|
159
|
+
for (const [name, result] of entries) {
|
|
160
|
+
if (result.error)
|
|
161
|
+
continue;
|
|
162
|
+
const hasDiffs = (result.styles?.summary.total ?? 0) > 0 ||
|
|
163
|
+
(result.layout?.summary.total ?? 0) > 0 ||
|
|
164
|
+
(result.visual?.diffPercentage ?? 0) > 0;
|
|
165
|
+
if (hasDiffs)
|
|
166
|
+
breakpointsWithDiffs++;
|
|
167
|
+
totalStyleDiffs += result.styles?.summary.total ?? 0;
|
|
168
|
+
totalLayoutDiffs += result.layout?.summary.total ?? 0;
|
|
169
|
+
if (result.visual) {
|
|
170
|
+
totalPixelDiff += result.visual.diffPercentage;
|
|
171
|
+
pixelDiffCount++;
|
|
172
|
+
}
|
|
173
|
+
// Score = weighted sum of issues
|
|
174
|
+
const score = (result.styles?.summary.critical ?? 0) * 10 +
|
|
175
|
+
(result.styles?.summary.warning ?? 0) * 3 +
|
|
176
|
+
(result.styles?.summary.info ?? 0) * 1 +
|
|
177
|
+
(result.layout?.summary.critical ?? 0) * 10 +
|
|
178
|
+
(result.layout?.summary.warning ?? 0) * 3 +
|
|
179
|
+
(result.visual?.diffPercentage ?? 0) * 2;
|
|
180
|
+
if (score > worstScore) {
|
|
181
|
+
worstScore = score;
|
|
182
|
+
worstBreakpoint = name;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
const avgPixelDiff = pixelDiffCount > 0
|
|
186
|
+
? Math.round((totalPixelDiff / pixelDiffCount) * 100) / 100
|
|
187
|
+
: 0;
|
|
188
|
+
// Determine overall severity
|
|
189
|
+
const hasCritical = entries.some(([, r]) => (r.styles?.summary.critical ?? 0) > 0 ||
|
|
190
|
+
(r.layout?.summary.critical ?? 0) > 0 ||
|
|
191
|
+
(r.visual?.diffPercentage ?? 0) > 5);
|
|
192
|
+
const hasWarning = entries.some(([, r]) => (r.styles?.summary.warning ?? 0) > 0 ||
|
|
193
|
+
(r.layout?.summary.warning ?? 0) > 0 ||
|
|
194
|
+
(r.visual?.diffPercentage ?? 0) > 1);
|
|
195
|
+
return {
|
|
196
|
+
totalBreakpoints: entries.length,
|
|
197
|
+
breakpointsWithDifferences: breakpointsWithDiffs,
|
|
198
|
+
totalStyleDifferences: totalStyleDiffs,
|
|
199
|
+
totalLayoutDifferences: totalLayoutDiffs,
|
|
200
|
+
averagePixelDiff: avgPixelDiff,
|
|
201
|
+
worstBreakpoint,
|
|
202
|
+
overallSeverity: hasCritical
|
|
203
|
+
? "critical"
|
|
204
|
+
: hasWarning
|
|
205
|
+
? "warning"
|
|
206
|
+
: breakpointsWithDiffs > 0
|
|
207
|
+
? "info"
|
|
208
|
+
: "pass",
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
//# sourceMappingURL=core.js.map
|
package/dist/core.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.js","sourceRoot":"","sources":["../src/core.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Locator, Page } from "playwright";
|
|
2
|
+
export interface ScreenshotOptions {
|
|
3
|
+
fullPage?: boolean;
|
|
4
|
+
padding?: number;
|
|
5
|
+
}
|
|
6
|
+
export declare class ScreenshotCapturer {
|
|
7
|
+
/**
|
|
8
|
+
* Capture a screenshot of a specific element.
|
|
9
|
+
*/
|
|
10
|
+
static captureElement(locator: Locator, options?: ScreenshotOptions): Promise<Buffer>;
|
|
11
|
+
/**
|
|
12
|
+
* Capture a screenshot of the full page.
|
|
13
|
+
*/
|
|
14
|
+
static captureFullPage(page: Page): Promise<Buffer>;
|
|
15
|
+
/**
|
|
16
|
+
* Capture element with surrounding context (padding around it).
|
|
17
|
+
*/
|
|
18
|
+
static captureElementWithContext(locator: Locator, padding?: number): Promise<Buffer>;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=ScreenshotCapturer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ScreenshotCapturer.d.ts","sourceRoot":"","sources":["../../src/extractor/ScreenshotCapturer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAEhD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,qBAAa,kBAAkB;IAC7B;;OAEG;WACU,cAAc,CACzB,OAAO,EAAE,OAAO,EAChB,OAAO,GAAE,iBAAsB,GAC9B,OAAO,CAAC,MAAM,CAAC;IAelB;;OAEG;WACU,eAAe,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC;IAUzD;;OAEG;WACU,yBAAyB,CACpC,OAAO,EAAE,OAAO,EAChB,OAAO,GAAE,MAAW,GACnB,OAAO,CAAC,MAAM,CAAC;CA8BnB"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
export class ScreenshotCapturer {
|
|
2
|
+
/**
|
|
3
|
+
* Capture a screenshot of a specific element.
|
|
4
|
+
*/
|
|
5
|
+
static async captureElement(locator, options = {}) {
|
|
6
|
+
// Scroll element into view first
|
|
7
|
+
await locator.scrollIntoViewIfNeeded();
|
|
8
|
+
// Small wait to ensure rendering is complete
|
|
9
|
+
await locator.page().waitForTimeout(100);
|
|
10
|
+
const screenshot = await locator.screenshot({
|
|
11
|
+
type: "png",
|
|
12
|
+
animations: "disabled",
|
|
13
|
+
});
|
|
14
|
+
return Buffer.from(screenshot);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Capture a screenshot of the full page.
|
|
18
|
+
*/
|
|
19
|
+
static async captureFullPage(page) {
|
|
20
|
+
const screenshot = await page.screenshot({
|
|
21
|
+
type: "png",
|
|
22
|
+
fullPage: true,
|
|
23
|
+
animations: "disabled",
|
|
24
|
+
});
|
|
25
|
+
return Buffer.from(screenshot);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Capture element with surrounding context (padding around it).
|
|
29
|
+
*/
|
|
30
|
+
static async captureElementWithContext(locator, padding = 20) {
|
|
31
|
+
await locator.scrollIntoViewIfNeeded();
|
|
32
|
+
await locator.page().waitForTimeout(100);
|
|
33
|
+
const box = await locator.boundingBox();
|
|
34
|
+
if (!box) {
|
|
35
|
+
throw new Error("Element has no bounding box (may be hidden)");
|
|
36
|
+
}
|
|
37
|
+
const page = locator.page();
|
|
38
|
+
const viewport = page.viewportSize();
|
|
39
|
+
if (!viewport) {
|
|
40
|
+
throw new Error("Page has no viewport size");
|
|
41
|
+
}
|
|
42
|
+
const clip = {
|
|
43
|
+
x: Math.max(0, box.x - padding),
|
|
44
|
+
y: Math.max(0, box.y - padding),
|
|
45
|
+
width: Math.min(viewport.width - Math.max(0, box.x - padding), box.width + padding * 2),
|
|
46
|
+
height: box.height + padding * 2,
|
|
47
|
+
};
|
|
48
|
+
const screenshot = await page.screenshot({
|
|
49
|
+
type: "png",
|
|
50
|
+
clip,
|
|
51
|
+
animations: "disabled",
|
|
52
|
+
});
|
|
53
|
+
return Buffer.from(screenshot);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=ScreenshotCapturer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ScreenshotCapturer.js","sourceRoot":"","sources":["../../src/extractor/ScreenshotCapturer.ts"],"names":[],"mappings":"AAOA,MAAM,OAAO,kBAAkB;IAC7B;;OAEG;IACH,MAAM,CAAC,KAAK,CAAC,cAAc,CACzB,OAAgB,EAChB,UAA6B,EAAE;QAE/B,iCAAiC;QACjC,MAAM,OAAO,CAAC,sBAAsB,EAAE,CAAC;QAEvC,6CAA6C;QAC7C,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC;QAEzC,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC;YAC1C,IAAI,EAAE,KAAK;YACX,UAAU,EAAE,UAAU;SACvB,CAAC,CAAC;QAEH,OAAO,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACjC,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,IAAU;QACrC,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC;YACvC,IAAI,EAAE,KAAK;YACX,QAAQ,EAAE,IAAI;YACd,UAAU,EAAE,UAAU;SACvB,CAAC,CAAC;QAEH,OAAO,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACjC,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,KAAK,CAAC,yBAAyB,CACpC,OAAgB,EAChB,UAAkB,EAAE;QAEpB,MAAM,OAAO,CAAC,sBAAsB,EAAE,CAAC;QACvC,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC;QAEzC,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,WAAW,EAAE,CAAC;QACxC,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;QACjE,CAAC;QAED,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;QAC5B,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;QACrC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;QAC/C,CAAC;QAED,MAAM,IAAI,GAAG;YACX,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,OAAO,CAAC;YAC/B,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,OAAO,CAAC;YAC/B,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,OAAO,CAAC,EAAE,GAAG,CAAC,KAAK,GAAG,OAAO,GAAG,CAAC,CAAC;YACvF,MAAM,EAAE,GAAG,CAAC,MAAM,GAAG,OAAO,GAAG,CAAC;SACjC,CAAC;QAEF,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC;YACvC,IAAI,EAAE,KAAK;YACX,IAAI;YACJ,UAAU,EAAE,UAAU;SACvB,CAAC,CAAC;QAEH,OAAO,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IACjC,CAAC;CACF"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Page } from "playwright";
|
|
2
|
+
import type { ElementInfo } from "../types/comparison.js";
|
|
3
|
+
export declare class SectionExtractor {
|
|
4
|
+
/**
|
|
5
|
+
* Find all elements matching a selector and return their info.
|
|
6
|
+
* Used for disambiguation when multiple elements match.
|
|
7
|
+
*/
|
|
8
|
+
static enumerate(page: Page, selector: string): Promise<ElementInfo[]>;
|
|
9
|
+
/**
|
|
10
|
+
* Get a specific element by selector and index.
|
|
11
|
+
* Returns the Playwright ElementHandle locator for further operations.
|
|
12
|
+
*/
|
|
13
|
+
static getElement(page: Page, selector: string, index?: number): Promise<{
|
|
14
|
+
info: ElementInfo;
|
|
15
|
+
locator: ReturnType<Page["locator"]>;
|
|
16
|
+
}>;
|
|
17
|
+
/**
|
|
18
|
+
* Validate that a selector matches at least one element.
|
|
19
|
+
*/
|
|
20
|
+
static validate(page: Page, selector: string): Promise<{
|
|
21
|
+
valid: boolean;
|
|
22
|
+
count: number;
|
|
23
|
+
error?: string;
|
|
24
|
+
}>;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=SectionExtractor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SectionExtractor.d.ts","sourceRoot":"","sources":["../../src/extractor/SectionExtractor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,KAAK,EAAE,WAAW,EAAe,MAAM,wBAAwB,CAAC;AAEvE,qBAAa,gBAAgB;IAC3B;;;OAGG;WACU,SAAS,CACpB,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,WAAW,EAAE,CAAC;IA0BzB;;;OAGG;WACU,UAAU,CACrB,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,MAAM,EAChB,KAAK,GAAE,MAAU,GAChB,OAAO,CAAC;QAAE,IAAI,EAAE,WAAW,CAAC;QAAC,OAAO,EAAE,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAA;KAAE,CAAC;IA+CvE;;OAEG;WACU,QAAQ,CACnB,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAgB9D"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
export class SectionExtractor {
|
|
2
|
+
/**
|
|
3
|
+
* Find all elements matching a selector and return their info.
|
|
4
|
+
* Used for disambiguation when multiple elements match.
|
|
5
|
+
*/
|
|
6
|
+
static async enumerate(page, selector) {
|
|
7
|
+
return await page.evaluate(({ sel }) => {
|
|
8
|
+
const elements = document.querySelectorAll(sel);
|
|
9
|
+
return Array.from(elements).map((el, index) => {
|
|
10
|
+
const rect = el.getBoundingClientRect();
|
|
11
|
+
const text = (el.textContent || "").trim().slice(0, 80);
|
|
12
|
+
return {
|
|
13
|
+
selector: sel,
|
|
14
|
+
index,
|
|
15
|
+
tagName: el.tagName.toLowerCase(),
|
|
16
|
+
textPreview: text.length === 80 ? text + "…" : text,
|
|
17
|
+
boundingBox: {
|
|
18
|
+
x: Math.round(rect.x),
|
|
19
|
+
y: Math.round(rect.y),
|
|
20
|
+
width: Math.round(rect.width),
|
|
21
|
+
height: Math.round(rect.height),
|
|
22
|
+
},
|
|
23
|
+
exists: true,
|
|
24
|
+
};
|
|
25
|
+
});
|
|
26
|
+
}, { sel: selector });
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Get a specific element by selector and index.
|
|
30
|
+
* Returns the Playwright ElementHandle locator for further operations.
|
|
31
|
+
*/
|
|
32
|
+
static async getElement(page, selector, index = 0) {
|
|
33
|
+
const locator = page.locator(selector).nth(index);
|
|
34
|
+
const count = await page.locator(selector).count();
|
|
35
|
+
if (count === 0) {
|
|
36
|
+
return {
|
|
37
|
+
info: {
|
|
38
|
+
selector,
|
|
39
|
+
index,
|
|
40
|
+
tagName: "unknown",
|
|
41
|
+
textPreview: "",
|
|
42
|
+
boundingBox: { x: 0, y: 0, width: 0, height: 0 },
|
|
43
|
+
exists: false,
|
|
44
|
+
},
|
|
45
|
+
locator,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
if (index >= count) {
|
|
49
|
+
throw new Error(`Element index ${index} out of range. Selector "${selector}" matched ${count} element(s).`);
|
|
50
|
+
}
|
|
51
|
+
const info = await locator.evaluate((el, idx) => {
|
|
52
|
+
const rect = el.getBoundingClientRect();
|
|
53
|
+
const text = (el.textContent || "").trim().slice(0, 80);
|
|
54
|
+
return {
|
|
55
|
+
selector: "", // filled below
|
|
56
|
+
index: idx,
|
|
57
|
+
tagName: el.tagName.toLowerCase(),
|
|
58
|
+
textPreview: text.length === 80 ? text + "…" : text,
|
|
59
|
+
boundingBox: {
|
|
60
|
+
x: Math.round(rect.x),
|
|
61
|
+
y: Math.round(rect.y),
|
|
62
|
+
width: Math.round(rect.width),
|
|
63
|
+
height: Math.round(rect.height),
|
|
64
|
+
},
|
|
65
|
+
exists: true,
|
|
66
|
+
};
|
|
67
|
+
}, index);
|
|
68
|
+
info.selector = selector;
|
|
69
|
+
return { info, locator };
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Validate that a selector matches at least one element.
|
|
73
|
+
*/
|
|
74
|
+
static async validate(page, selector) {
|
|
75
|
+
try {
|
|
76
|
+
const count = await page.locator(selector).count();
|
|
77
|
+
return {
|
|
78
|
+
valid: count > 0,
|
|
79
|
+
count,
|
|
80
|
+
error: count === 0 ? `No elements found matching "${selector}"` : undefined,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
return {
|
|
85
|
+
valid: false,
|
|
86
|
+
count: 0,
|
|
87
|
+
error: `Invalid selector "${selector}": ${err.message}`,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=SectionExtractor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SectionExtractor.js","sourceRoot":"","sources":["../../src/extractor/SectionExtractor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Locator } from "playwright";
|
|
2
|
+
import { type StyleCategory } from "../types/config.js";
|
|
3
|
+
import type { LayoutMetrics } from "../types/comparison.js";
|
|
4
|
+
export declare class StyleExtractor {
|
|
5
|
+
/**
|
|
6
|
+
* Extract computed styles for specific categories from an element.
|
|
7
|
+
*/
|
|
8
|
+
static extractStyles(locator: Locator, categories?: StyleCategory[]): Promise<Record<string, string>>;
|
|
9
|
+
/**
|
|
10
|
+
* Extract layout metrics (box model) from an element.
|
|
11
|
+
*/
|
|
12
|
+
static extractLayoutMetrics(locator: Locator): Promise<LayoutMetrics>;
|
|
13
|
+
/**
|
|
14
|
+
* Extract computed styles for ALL properties (not just categorized ones).
|
|
15
|
+
* Useful for deep analysis.
|
|
16
|
+
*/
|
|
17
|
+
static extractAllStyles(locator: Locator): Promise<Record<string, string>>;
|
|
18
|
+
/**
|
|
19
|
+
* Get the flat list of CSS properties for given categories.
|
|
20
|
+
*/
|
|
21
|
+
private static getProperties;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=StyleExtractor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StyleExtractor.d.ts","sourceRoot":"","sources":["../../src/extractor/StyleExtractor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAQ,OAAO,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAoB,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,KAAK,EAAE,aAAa,EAAc,MAAM,wBAAwB,CAAC;AAExE,qBAAa,cAAc;IACzB;;OAEG;WACU,aAAa,CACxB,OAAO,EAAE,OAAO,EAChB,UAAU,CAAC,EAAE,aAAa,EAAE,GAC3B,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAkBlC;;OAEG;WACU,oBAAoB,CAC/B,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,aAAa,CAAC;IAsCzB;;;OAGG;WACU,gBAAgB,CAC3B,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAclC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,aAAa;CAa7B"}
|