ghost-qa 1.3.1 → 2.0.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/README.md +88 -32
- package/SKILL.md +83 -80
- package/dist/bin/ghost-qa.d.ts +11 -3
- package/dist/bin/ghost-qa.d.ts.map +1 -1
- package/dist/bin/ghost-qa.js +498 -405
- package/dist/bin/ghost-qa.js.map +1 -1
- package/dist/src/engine/audit-runner.d.ts +6 -5
- package/dist/src/engine/audit-runner.d.ts.map +1 -1
- package/dist/src/engine/audit-runner.js +117 -60
- package/dist/src/engine/audit-runner.js.map +1 -1
- package/dist/src/engine/browser-session.d.ts +3 -3
- package/dist/src/engine/browser-session.d.ts.map +1 -1
- package/dist/src/engine/browser-session.js +18 -7
- package/dist/src/engine/browser-session.js.map +1 -1
- package/dist/src/engine/compare.d.ts +37 -0
- package/dist/src/engine/compare.d.ts.map +1 -0
- package/dist/src/engine/compare.js +63 -0
- package/dist/src/engine/compare.js.map +1 -0
- package/dist/src/engine/health-score.d.ts +14 -0
- package/dist/src/engine/health-score.d.ts.map +1 -0
- package/dist/src/engine/health-score.js +74 -0
- package/dist/src/engine/health-score.js.map +1 -0
- package/dist/src/engine/version.d.ts +14 -0
- package/dist/src/engine/version.d.ts.map +1 -0
- package/dist/src/engine/version.js +43 -0
- package/dist/src/engine/version.js.map +1 -0
- package/dist/src/index.d.ts +6 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +6 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/mcp/server.d.ts +25 -5
- package/dist/src/mcp/server.d.ts.map +1 -1
- package/dist/src/mcp/server.js +45 -7
- package/dist/src/mcp/server.js.map +1 -1
- package/dist/src/reporter/agent-diagnostic.d.ts +6 -0
- package/dist/src/reporter/agent-diagnostic.d.ts.map +1 -1
- package/dist/src/reporter/agent-diagnostic.js +53 -3
- package/dist/src/reporter/agent-diagnostic.js.map +1 -1
- package/dist/src/reporter/html-report.d.ts.map +1 -1
- package/dist/src/reporter/html-report.js +79 -4
- package/dist/src/reporter/html-report.js.map +1 -1
- package/dist/src/reporter/terminal-summary.d.ts.map +1 -1
- package/dist/src/reporter/terminal-summary.js +6 -0
- package/dist/src/reporter/terminal-summary.js.map +1 -1
- package/dist/src/traps/a11y-trap.d.ts +23 -0
- package/dist/src/traps/a11y-trap.d.ts.map +1 -1
- package/dist/src/traps/a11y-trap.js +185 -0
- package/dist/src/traps/a11y-trap.js.map +1 -1
- package/dist/src/traps/console-trap.d.ts +3 -1
- package/dist/src/traps/console-trap.d.ts.map +1 -1
- package/dist/src/traps/console-trap.js +41 -0
- package/dist/src/traps/console-trap.js.map +1 -1
- package/dist/src/traps/layout-trap.d.ts +31 -0
- package/dist/src/traps/layout-trap.d.ts.map +1 -1
- package/dist/src/traps/layout-trap.js +173 -0
- package/dist/src/traps/layout-trap.js.map +1 -1
- package/dist/src/traps/links-trap.d.ts +34 -0
- package/dist/src/traps/links-trap.d.ts.map +1 -0
- package/dist/src/traps/links-trap.js +136 -0
- package/dist/src/traps/links-trap.js.map +1 -0
- package/dist/src/traps/network-trap.d.ts +4 -1
- package/dist/src/traps/network-trap.d.ts.map +1 -1
- package/dist/src/traps/network-trap.js +29 -2
- package/dist/src/traps/network-trap.js.map +1 -1
- package/dist/src/traps/perf-trap.d.ts +18 -0
- package/dist/src/traps/perf-trap.d.ts.map +1 -1
- package/dist/src/traps/perf-trap.js +148 -8
- package/dist/src/traps/perf-trap.js.map +1 -1
- package/dist/src/traps/seo-trap.d.ts +30 -0
- package/dist/src/traps/seo-trap.d.ts.map +1 -0
- package/dist/src/traps/seo-trap.js +98 -0
- package/dist/src/traps/seo-trap.js.map +1 -0
- package/dist/src/traps/theme-trap.d.ts +32 -0
- package/dist/src/traps/theme-trap.d.ts.map +1 -0
- package/dist/src/traps/theme-trap.js +109 -0
- package/dist/src/traps/theme-trap.js.map +1 -0
- package/dist/src/types.d.ts +55 -3
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.js +30 -2
- package/dist/src/types.js.map +1 -1
- package/package.json +99 -91
|
@@ -3,6 +3,8 @@ import { type QAIssue, type ViewportName } from '../types.js';
|
|
|
3
3
|
export interface ResourceSize {
|
|
4
4
|
url: string;
|
|
5
5
|
transferBytes: number;
|
|
6
|
+
/** Resource Timing initiatorType (img, script, link, fetch…). */
|
|
7
|
+
kind?: string;
|
|
6
8
|
}
|
|
7
9
|
export interface PerfMetrics {
|
|
8
10
|
domContentLoadedMs: number;
|
|
@@ -16,17 +18,33 @@ export interface PerfMetrics {
|
|
|
16
18
|
/** Long Tasks API (Chromium): tasks > 50ms that freeze the main thread. */
|
|
17
19
|
longTaskCount: number;
|
|
18
20
|
longTaskTotalMs: number;
|
|
21
|
+
/** Time to first byte (navigation responseStart). */
|
|
22
|
+
ttfbMs: number;
|
|
23
|
+
/** First Contentful Paint. */
|
|
24
|
+
fcpMs: number;
|
|
25
|
+
/** Largest Contentful Paint (observed, buffered). */
|
|
26
|
+
lcpMs: number;
|
|
27
|
+
/** Cumulative Layout Shift (layout-shift entries, buffered). */
|
|
28
|
+
cls: number;
|
|
29
|
+
/** Deepest DOM nesting level. */
|
|
30
|
+
maxDomDepth: number;
|
|
19
31
|
}
|
|
20
32
|
export declare const EMPTY_PERF_METRICS: PerfMetrics;
|
|
21
33
|
export declare const PERF_THRESHOLDS: {
|
|
22
34
|
readonly domContentLoadedMs: 3000;
|
|
23
35
|
readonly loadMs: 5000;
|
|
24
36
|
readonly singleResourceBytes: 1000000;
|
|
37
|
+
readonly unoptimizedResourceBytes: 500000;
|
|
25
38
|
readonly totalTransferBytes: 3000000;
|
|
26
39
|
readonly renderBlockingCount: 5;
|
|
27
40
|
readonly domNodeCount: 1500;
|
|
41
|
+
readonly domDepth: 32;
|
|
28
42
|
readonly longTaskCount: 5;
|
|
29
43
|
readonly longTaskTotalMs: 500;
|
|
44
|
+
readonly ttfbMs: 800;
|
|
45
|
+
readonly fcpMs: 1800;
|
|
46
|
+
readonly lcpMs: 2500;
|
|
47
|
+
readonly cls: 0.1;
|
|
30
48
|
};
|
|
31
49
|
/**
|
|
32
50
|
* Pure evaluator: Navigation/Resource Timing facts in, perf issues out.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"perf-trap.d.ts","sourceRoot":"","sources":["../../../src/traps/perf-trap.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAa,KAAK,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAEzE,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,aAAa,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"perf-trap.d.ts","sourceRoot":"","sources":["../../../src/traps/perf-trap.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAa,KAAK,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAEzE,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,aAAa,EAAE,MAAM,CAAC;IACtB,iEAAiE;IACjE,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,WAAW;IAC1B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,kBAAkB,EAAE,YAAY,EAAE,CAAC;IACnC,sFAAsF;IACtF,mBAAmB,EAAE,MAAM,CAAC;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,2EAA2E;IAC3E,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAC;IACf,8BAA8B;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,qDAAqD;IACrD,KAAK,EAAE,MAAM,CAAC;IACd,gEAAgE;IAChE,GAAG,EAAE,MAAM,CAAC;IACZ,iCAAiC;IACjC,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,kBAAkB,EAAE,WAehC,CAAC;AAEF,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;CAelB,CAAC;AAKX;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,WAAW,EACpB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,YAAY,GACrB,OAAO,EAAE,CAqMX;AA6HD,wEAAwE;AACxE,qBAAa,QAAQ;IACnB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAe;gBAE5B,QAAQ,EAAE,YAAY;IAI5B,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;CAS7D"}
|
|
@@ -9,16 +9,27 @@ export const EMPTY_PERF_METRICS = {
|
|
|
9
9
|
domNodeCount: 0,
|
|
10
10
|
longTaskCount: 0,
|
|
11
11
|
longTaskTotalMs: 0,
|
|
12
|
+
ttfbMs: 0,
|
|
13
|
+
fcpMs: 0,
|
|
14
|
+
lcpMs: 0,
|
|
15
|
+
cls: 0,
|
|
16
|
+
maxDomDepth: 0,
|
|
12
17
|
};
|
|
13
18
|
export const PERF_THRESHOLDS = {
|
|
14
19
|
domContentLoadedMs: 3_000,
|
|
15
20
|
loadMs: 5_000,
|
|
16
21
|
singleResourceBytes: 1_000_000,
|
|
22
|
+
unoptimizedResourceBytes: 500_000,
|
|
17
23
|
totalTransferBytes: 3_000_000,
|
|
18
24
|
renderBlockingCount: 5,
|
|
19
25
|
domNodeCount: 1_500,
|
|
26
|
+
domDepth: 32,
|
|
20
27
|
longTaskCount: 5,
|
|
21
28
|
longTaskTotalMs: 500,
|
|
29
|
+
ttfbMs: 800,
|
|
30
|
+
fcpMs: 1_800,
|
|
31
|
+
lcpMs: 2_500,
|
|
32
|
+
cls: 0.1,
|
|
22
33
|
};
|
|
23
34
|
const kb = (bytes) => `${Math.round(bytes / 1024)}KB`;
|
|
24
35
|
const ms = (value) => `${Math.round(value)}ms`;
|
|
@@ -48,17 +59,85 @@ export function evaluatePerfMetrics(metrics, route, viewport) {
|
|
|
48
59
|
}));
|
|
49
60
|
}
|
|
50
61
|
for (const resource of metrics.oversizedResources.slice(0, 5)) {
|
|
51
|
-
if (resource.transferBytes
|
|
52
|
-
|
|
62
|
+
if (resource.transferBytes > PERF_THRESHOLDS.singleResourceBytes) {
|
|
63
|
+
issues.push(makeIssue({
|
|
64
|
+
category: 'performance',
|
|
65
|
+
severity: 'major',
|
|
66
|
+
type: 'oversized-resource',
|
|
67
|
+
message: `Oversized resource (${kb(resource.transferBytes)}): ${resource.url}. Compress, resize, lazy-load or code-split it — a single asset should stay under ${kb(PERF_THRESHOLDS.singleResourceBytes)}.`,
|
|
68
|
+
route,
|
|
69
|
+
viewport,
|
|
70
|
+
url: resource.url,
|
|
71
|
+
details: { transferBytes: resource.transferBytes },
|
|
72
|
+
}));
|
|
73
|
+
}
|
|
74
|
+
else if (resource.transferBytes > PERF_THRESHOLDS.unoptimizedResourceBytes &&
|
|
75
|
+
(resource.kind === 'img' || resource.kind === 'script' || resource.kind === 'link')) {
|
|
76
|
+
issues.push(makeIssue({
|
|
77
|
+
category: 'performance',
|
|
78
|
+
severity: 'minor',
|
|
79
|
+
type: 'unoptimized-resource',
|
|
80
|
+
message: `Unoptimized payload (${kb(resource.transferBytes)}, ${resource.kind}): ${resource.url}. Images/scripts over ${kb(PERF_THRESHOLDS.unoptimizedResourceBytes)} should be compressed, resized to display size, modern-formatted (WebP/AVIF) or code-split.`,
|
|
81
|
+
route,
|
|
82
|
+
viewport,
|
|
83
|
+
url: resource.url,
|
|
84
|
+
details: { transferBytes: resource.transferBytes, kind: resource.kind },
|
|
85
|
+
}));
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (metrics.ttfbMs > PERF_THRESHOLDS.ttfbMs) {
|
|
53
89
|
issues.push(makeIssue({
|
|
54
90
|
category: 'performance',
|
|
55
|
-
severity: 'major',
|
|
56
|
-
type: '
|
|
57
|
-
message: `
|
|
91
|
+
severity: metrics.ttfbMs > PERF_THRESHOLDS.ttfbMs * 2 ? 'major' : 'minor',
|
|
92
|
+
type: 'slow-ttfb',
|
|
93
|
+
message: `Slow time-to-first-byte: ${ms(metrics.ttfbMs)} (budget ${ms(PERF_THRESHOLDS.ttfbMs)}). Profile server rendering, middleware and database calls — no client optimisation can hide a slow first byte.`,
|
|
94
|
+
route,
|
|
95
|
+
viewport,
|
|
96
|
+
details: { ttfbMs: Math.round(metrics.ttfbMs) },
|
|
97
|
+
}));
|
|
98
|
+
}
|
|
99
|
+
if (metrics.fcpMs > PERF_THRESHOLDS.fcpMs) {
|
|
100
|
+
issues.push(makeIssue({
|
|
101
|
+
category: 'performance',
|
|
102
|
+
severity: metrics.fcpMs > PERF_THRESHOLDS.fcpMs * 1.7 ? 'major' : 'minor',
|
|
103
|
+
type: 'slow-fcp',
|
|
104
|
+
message: `Slow First Contentful Paint: ${ms(metrics.fcpMs)} (budget ${ms(PERF_THRESHOLDS.fcpMs)}). Reduce render-blocking CSS/JS and inline critical styles.`,
|
|
105
|
+
route,
|
|
106
|
+
viewport,
|
|
107
|
+
details: { fcpMs: Math.round(metrics.fcpMs) },
|
|
108
|
+
}));
|
|
109
|
+
}
|
|
110
|
+
if (metrics.lcpMs > PERF_THRESHOLDS.lcpMs) {
|
|
111
|
+
issues.push(makeIssue({
|
|
112
|
+
category: 'performance',
|
|
113
|
+
severity: metrics.lcpMs > 4_000 ? 'critical' : 'major',
|
|
114
|
+
type: 'slow-lcp',
|
|
115
|
+
message: `Slow Largest Contentful Paint: ${ms(metrics.lcpMs)} (budget ${ms(PERF_THRESHOLDS.lcpMs)}). Optimise the hero element: preload it, serve responsive image sizes, and remove render-blocking work ahead of it.`,
|
|
116
|
+
route,
|
|
117
|
+
viewport,
|
|
118
|
+
details: { lcpMs: Math.round(metrics.lcpMs) },
|
|
119
|
+
}));
|
|
120
|
+
}
|
|
121
|
+
if (metrics.cls > PERF_THRESHOLDS.cls) {
|
|
122
|
+
issues.push(makeIssue({
|
|
123
|
+
category: 'performance',
|
|
124
|
+
severity: metrics.cls > 0.25 ? 'critical' : 'major',
|
|
125
|
+
type: 'high-cls',
|
|
126
|
+
message: `High Cumulative Layout Shift: ${metrics.cls.toFixed(3)} (budget ${PERF_THRESHOLDS.cls}). Reserve space for images/ads/embeds with width/height or aspect-ratio so content stops jumping while it loads.`,
|
|
58
127
|
route,
|
|
59
128
|
viewport,
|
|
60
|
-
|
|
61
|
-
|
|
129
|
+
details: { cls: Math.round(metrics.cls * 1000) / 1000 },
|
|
130
|
+
}));
|
|
131
|
+
}
|
|
132
|
+
if (metrics.maxDomDepth > PERF_THRESHOLDS.domDepth) {
|
|
133
|
+
issues.push(makeIssue({
|
|
134
|
+
category: 'performance',
|
|
135
|
+
severity: 'minor',
|
|
136
|
+
type: 'deep-dom',
|
|
137
|
+
message: `Deeply nested DOM: ${metrics.maxDomDepth} levels (budget ${PERF_THRESHOLDS.domDepth}). Flatten wrapper-div pyramids — deep trees slow style recalculation, layout and hydration.`,
|
|
138
|
+
route,
|
|
139
|
+
viewport,
|
|
140
|
+
details: { maxDomDepth: metrics.maxDomDepth },
|
|
62
141
|
}));
|
|
63
142
|
}
|
|
64
143
|
if (metrics.totalTransferBytes > PERF_THRESHOLDS.totalTransferBytes) {
|
|
@@ -124,7 +203,11 @@ async function probePerf() {
|
|
|
124
203
|
const bytes = resource.transferSize || resource.encodedBodySize || 0;
|
|
125
204
|
totalTransferBytes += bytes;
|
|
126
205
|
if (bytes > 250_000) {
|
|
127
|
-
oversizedResources.push({
|
|
206
|
+
oversizedResources.push({
|
|
207
|
+
url: resource.name.slice(0, 200),
|
|
208
|
+
transferBytes: bytes,
|
|
209
|
+
kind: resource.initiatorType || 'other',
|
|
210
|
+
});
|
|
128
211
|
}
|
|
129
212
|
}
|
|
130
213
|
oversizedResources.sort((a, b) => b.transferBytes - a.transferBytes);
|
|
@@ -164,6 +247,58 @@ async function probePerf() {
|
|
|
164
247
|
catch {
|
|
165
248
|
/* Long Tasks API unsupported in this browser */
|
|
166
249
|
}
|
|
250
|
+
// Core Web Vitals: paint timing is synchronous; LCP/CLS need buffered
|
|
251
|
+
// PerformanceObserver entries (same pattern as longtask above).
|
|
252
|
+
const paint = performance.getEntriesByType('paint');
|
|
253
|
+
const fcp = paint.find((entry) => entry.name === 'first-contentful-paint');
|
|
254
|
+
let lcpMs = 0;
|
|
255
|
+
let cls = 0;
|
|
256
|
+
try {
|
|
257
|
+
const vitals = await new Promise((resolvePromise) => {
|
|
258
|
+
let lcp = 0;
|
|
259
|
+
let shift = 0;
|
|
260
|
+
const observers = [];
|
|
261
|
+
try {
|
|
262
|
+
const lcpObserver = new PerformanceObserver((list) => {
|
|
263
|
+
for (const entry of list.getEntries())
|
|
264
|
+
lcp = Math.max(lcp, entry.startTime);
|
|
265
|
+
});
|
|
266
|
+
lcpObserver.observe({ type: 'largest-contentful-paint', buffered: true });
|
|
267
|
+
observers.push(lcpObserver);
|
|
268
|
+
const clsObserver = new PerformanceObserver((list) => {
|
|
269
|
+
for (const entry of list.getEntries()) {
|
|
270
|
+
const shiftEntry = entry;
|
|
271
|
+
if (!shiftEntry.hadRecentInput)
|
|
272
|
+
shift += shiftEntry.value ?? 0;
|
|
273
|
+
}
|
|
274
|
+
});
|
|
275
|
+
clsObserver.observe({ type: 'layout-shift', buffered: true });
|
|
276
|
+
observers.push(clsObserver);
|
|
277
|
+
setTimeout(() => {
|
|
278
|
+
observers.forEach((o) => o.disconnect());
|
|
279
|
+
resolvePromise({ lcp, cls: shift });
|
|
280
|
+
}, 30);
|
|
281
|
+
}
|
|
282
|
+
catch {
|
|
283
|
+
resolvePromise({ lcp, cls: shift });
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
lcpMs = vitals.lcp;
|
|
287
|
+
cls = vitals.cls;
|
|
288
|
+
}
|
|
289
|
+
catch {
|
|
290
|
+
/* Web Vitals APIs unsupported in this browser */
|
|
291
|
+
}
|
|
292
|
+
let maxDomDepth = 0;
|
|
293
|
+
const walkDepth = (el, depth) => {
|
|
294
|
+
if (depth > maxDomDepth)
|
|
295
|
+
maxDomDepth = depth;
|
|
296
|
+
if (depth > 64)
|
|
297
|
+
return;
|
|
298
|
+
for (const child of Array.from(el.children))
|
|
299
|
+
walkDepth(child, depth + 1);
|
|
300
|
+
};
|
|
301
|
+
walkDepth(document.documentElement, 1);
|
|
167
302
|
return {
|
|
168
303
|
domContentLoadedMs: nav ? nav.domContentLoadedEventEnd : 0,
|
|
169
304
|
loadMs: nav ? nav.loadEventEnd || nav.responseEnd : 0,
|
|
@@ -174,6 +309,11 @@ async function probePerf() {
|
|
|
174
309
|
domNodeCount: document.querySelectorAll('*').length,
|
|
175
310
|
longTaskCount,
|
|
176
311
|
longTaskTotalMs,
|
|
312
|
+
ttfbMs: nav ? nav.responseStart : 0,
|
|
313
|
+
fcpMs: fcp ? fcp.startTime : 0,
|
|
314
|
+
lcpMs,
|
|
315
|
+
cls,
|
|
316
|
+
maxDomDepth,
|
|
177
317
|
};
|
|
178
318
|
}
|
|
179
319
|
/** Runs the in-page perf probe against a live page and evaluates it. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"perf-trap.js","sourceRoot":"","sources":["../../../src/traps/perf-trap.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"perf-trap.js","sourceRoot":"","sources":["../../../src/traps/perf-trap.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Page } from 'playwright';
|
|
2
|
+
import { type QAIssue, type ViewportName } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Trap 7 — SEO, Metadata & Social Graph.
|
|
5
|
+
*
|
|
6
|
+
* What search engines and link unfurlers see, audited on the live DOM
|
|
7
|
+
* (post-hydration, exactly as a crawler rendering the page would).
|
|
8
|
+
*/
|
|
9
|
+
export interface SeoMetrics {
|
|
10
|
+
title: string;
|
|
11
|
+
hasDescription: boolean;
|
|
12
|
+
hasLang: boolean;
|
|
13
|
+
hasViewportMeta: boolean;
|
|
14
|
+
hasCanonical: boolean;
|
|
15
|
+
ogTitle: boolean;
|
|
16
|
+
ogDescription: boolean;
|
|
17
|
+
ogImage: boolean;
|
|
18
|
+
/** id attribute values used more than once. */
|
|
19
|
+
duplicateIds: string[];
|
|
20
|
+
}
|
|
21
|
+
export declare const EMPTY_SEO_METRICS: SeoMetrics;
|
|
22
|
+
export declare const TITLE_MIN_LENGTH = 10;
|
|
23
|
+
export declare const TITLE_MAX_LENGTH = 60;
|
|
24
|
+
export declare function evaluateSeoMetrics(metrics: SeoMetrics, route: string, viewport: ViewportName): QAIssue[];
|
|
25
|
+
export declare class SeoTrap {
|
|
26
|
+
private readonly viewport;
|
|
27
|
+
constructor(viewport: ViewportName);
|
|
28
|
+
collect(page: Page, route: string): Promise<QAIssue[]>;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=seo-trap.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seo-trap.d.ts","sourceRoot":"","sources":["../../../src/traps/seo-trap.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAa,KAAK,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAEzE;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,OAAO,CAAC;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,eAAe,EAAE,OAAO,CAAC;IACzB,YAAY,EAAE,OAAO,CAAC;IACtB,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,OAAO,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,+CAA+C;IAC/C,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,eAAO,MAAM,iBAAiB,EAAE,UAU/B,CAAC;AAEF,eAAO,MAAM,gBAAgB,KAAK,CAAC;AACnC,eAAO,MAAM,gBAAgB,KAAK,CAAC;AAEnC,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,UAAU,EACnB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,YAAY,GACrB,OAAO,EAAE,CAoDX;AAsBD,qBAAa,OAAO;IAClB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAe;gBAE5B,QAAQ,EAAE,YAAY;IAI5B,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;CAS7D"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { makeIssue } from '../types.js';
|
|
2
|
+
export const EMPTY_SEO_METRICS = {
|
|
3
|
+
title: '',
|
|
4
|
+
hasDescription: false,
|
|
5
|
+
hasLang: false,
|
|
6
|
+
hasViewportMeta: false,
|
|
7
|
+
hasCanonical: false,
|
|
8
|
+
ogTitle: false,
|
|
9
|
+
ogDescription: false,
|
|
10
|
+
ogImage: false,
|
|
11
|
+
duplicateIds: [],
|
|
12
|
+
};
|
|
13
|
+
export const TITLE_MIN_LENGTH = 10;
|
|
14
|
+
export const TITLE_MAX_LENGTH = 60;
|
|
15
|
+
export function evaluateSeoMetrics(metrics, route, viewport) {
|
|
16
|
+
const issues = [];
|
|
17
|
+
const push = (severity, type, message) => issues.push(makeIssue({ category: 'seo', severity, type, message, route, viewport }));
|
|
18
|
+
const title = metrics.title.trim();
|
|
19
|
+
if (title.length === 0) {
|
|
20
|
+
push('major', 'missing-document-title', 'Missing <title>: search results, tabs and screen readers all start here. Add a unique descriptive title per route.');
|
|
21
|
+
}
|
|
22
|
+
else if (title.length < TITLE_MIN_LENGTH) {
|
|
23
|
+
push('minor', 'title-too-short', `<title> is only ${title.length} characters ("${title}"). Aim for ${TITLE_MIN_LENGTH}–${TITLE_MAX_LENGTH} descriptive characters.`);
|
|
24
|
+
}
|
|
25
|
+
else if (title.length > TITLE_MAX_LENGTH) {
|
|
26
|
+
push('minor', 'title-too-long', `<title> is ${title.length} characters — it will be truncated in search results (~${TITLE_MAX_LENGTH} shown). Shorten it and move detail into the description.`);
|
|
27
|
+
}
|
|
28
|
+
if (!metrics.hasDescription) {
|
|
29
|
+
push('minor', 'missing-meta-description', 'Missing <meta name="description">: search engines will improvise a snippet from page text. Add a 120–160 character summary.');
|
|
30
|
+
}
|
|
31
|
+
if (!metrics.hasLang) {
|
|
32
|
+
push('minor', 'missing-html-lang', 'Missing lang attribute on <html> (e.g. <html lang="en">) — hurts both SEO locale signals and screen-reader pronunciation.');
|
|
33
|
+
}
|
|
34
|
+
if (!metrics.hasViewportMeta) {
|
|
35
|
+
push('major', 'missing-viewport-meta', 'Missing <meta name="viewport">: mobile search ranking and rendering both depend on it. Add content="width=device-width, initial-scale=1".');
|
|
36
|
+
}
|
|
37
|
+
if (!metrics.hasCanonical) {
|
|
38
|
+
push('minor', 'missing-canonical', 'Missing <link rel="canonical">: duplicate URLs (query params, trailing slashes) can split ranking. Point canonical at the clean route URL.');
|
|
39
|
+
}
|
|
40
|
+
const missingOg = [
|
|
41
|
+
!metrics.ogTitle && 'og:title',
|
|
42
|
+
!metrics.ogDescription && 'og:description',
|
|
43
|
+
!metrics.ogImage && 'og:image',
|
|
44
|
+
].filter(Boolean);
|
|
45
|
+
if (missingOg.length > 0) {
|
|
46
|
+
push('minor', 'missing-opengraph', `Missing OpenGraph tags: ${missingOg.join(', ')}. Links shared to Slack/X/LinkedIn will unfurl with no (or scraped) preview. Add the full og: set.`);
|
|
47
|
+
}
|
|
48
|
+
for (const id of metrics.duplicateIds.slice(0, 5)) {
|
|
49
|
+
issues.push(makeIssue({
|
|
50
|
+
category: 'seo',
|
|
51
|
+
severity: 'major',
|
|
52
|
+
type: 'duplicate-id',
|
|
53
|
+
message: `Duplicate id attribute in the live DOM: #${id} appears more than once. ids must be unique — anchors, aria-labelledby and getElementById all silently target the first match.`,
|
|
54
|
+
route,
|
|
55
|
+
viewport,
|
|
56
|
+
details: { id },
|
|
57
|
+
selector: `#${id}`,
|
|
58
|
+
}));
|
|
59
|
+
}
|
|
60
|
+
return issues;
|
|
61
|
+
}
|
|
62
|
+
/** In-page probe: metadata facts from the live (post-hydration) DOM. */
|
|
63
|
+
function probeSeo() {
|
|
64
|
+
const meta = (selector) => Boolean(document.querySelector(selector));
|
|
65
|
+
const idCounts = new Map();
|
|
66
|
+
document.querySelectorAll('[id]').forEach((el) => {
|
|
67
|
+
if (el.id)
|
|
68
|
+
idCounts.set(el.id, (idCounts.get(el.id) ?? 0) + 1);
|
|
69
|
+
});
|
|
70
|
+
return {
|
|
71
|
+
title: document.title ?? '',
|
|
72
|
+
hasDescription: meta('meta[name="description"]'),
|
|
73
|
+
hasLang: (document.documentElement.getAttribute('lang') ?? '').trim().length > 0,
|
|
74
|
+
hasViewportMeta: meta('meta[name="viewport"]'),
|
|
75
|
+
hasCanonical: meta('link[rel="canonical"]'),
|
|
76
|
+
ogTitle: meta('meta[property="og:title"]'),
|
|
77
|
+
ogDescription: meta('meta[property="og:description"]'),
|
|
78
|
+
ogImage: meta('meta[property="og:image"]'),
|
|
79
|
+
duplicateIds: [...idCounts.entries()].filter(([, count]) => count > 1).map(([id]) => id),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
export class SeoTrap {
|
|
83
|
+
viewport;
|
|
84
|
+
constructor(viewport) {
|
|
85
|
+
this.viewport = viewport;
|
|
86
|
+
}
|
|
87
|
+
async collect(page, route) {
|
|
88
|
+
let metrics;
|
|
89
|
+
try {
|
|
90
|
+
metrics = await page.evaluate(probeSeo);
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return [];
|
|
94
|
+
}
|
|
95
|
+
return evaluateSeoMetrics(metrics, route, this.viewport);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=seo-trap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seo-trap.js","sourceRoot":"","sources":["../../../src/traps/seo-trap.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { Page } from 'playwright';
|
|
2
|
+
import { contrastRatio } from './a11y-trap.js';
|
|
3
|
+
import { type ColorScheme, type QAIssue, type ViewportName } from '../types.js';
|
|
4
|
+
/**
|
|
5
|
+
* Trap 8 — Dark / Light Theme Emulation.
|
|
6
|
+
*
|
|
7
|
+
* The page is rendered twice per viewport, once per emulated colour scheme
|
|
8
|
+
* (`colorScheme: 'light' | 'dark'` media emulation). Under each scheme the
|
|
9
|
+
* trap recomputes real foreground/background contrast on visible text: the
|
|
10
|
+
* classic invisible-dark-mode bug (near-black text on a near-black
|
|
11
|
+
* background when the OS flips to dark) shows up as a theme-contrast
|
|
12
|
+
* finding tagged with the failing scheme.
|
|
13
|
+
*/
|
|
14
|
+
export interface ThemeContrastFailure {
|
|
15
|
+
descriptor: string;
|
|
16
|
+
selector: string;
|
|
17
|
+
ratio: number;
|
|
18
|
+
required: number;
|
|
19
|
+
}
|
|
20
|
+
export interface ThemeMetrics {
|
|
21
|
+
failures: ThemeContrastFailure[];
|
|
22
|
+
}
|
|
23
|
+
export declare const EMPTY_THEME_METRICS: ThemeMetrics;
|
|
24
|
+
export declare function evaluateThemeMetrics(metrics: ThemeMetrics, route: string, viewport: ViewportName, colorScheme: ColorScheme): QAIssue[];
|
|
25
|
+
export declare class ThemeTrap {
|
|
26
|
+
private readonly viewport;
|
|
27
|
+
private readonly colorScheme;
|
|
28
|
+
constructor(viewport: ViewportName, colorScheme: ColorScheme);
|
|
29
|
+
collect(page: Page, route: string): Promise<QAIssue[]>;
|
|
30
|
+
}
|
|
31
|
+
export { contrastRatio };
|
|
32
|
+
//# sourceMappingURL=theme-trap.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme-trap.d.ts","sourceRoot":"","sources":["../../../src/traps/theme-trap.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAa,KAAK,WAAW,EAAE,KAAK,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3F;;;;;;;;;GASG;AACH,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,oBAAoB,EAAE,CAAC;CAClC;AAED,eAAO,MAAM,mBAAmB,EAAE,YAA+B,CAAC;AAElE,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,YAAY,EACrB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,YAAY,EACtB,WAAW,EAAE,WAAW,GACvB,OAAO,EAAE,CAgBX;AAwED,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAe;IACxC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAc;gBAE9B,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW;IAKtD,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;CAS7D;AAED,OAAO,EAAE,aAAa,EAAE,CAAC"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { contrastRatio } from './a11y-trap.js';
|
|
2
|
+
import { makeIssue } from '../types.js';
|
|
3
|
+
export const EMPTY_THEME_METRICS = { failures: [] };
|
|
4
|
+
export function evaluateThemeMetrics(metrics, route, viewport, colorScheme) {
|
|
5
|
+
return metrics.failures.slice(0, 5).map((failure) => makeIssue({
|
|
6
|
+
category: 'theme',
|
|
7
|
+
severity: 'major',
|
|
8
|
+
type: 'theme-contrast',
|
|
9
|
+
message: `Invisible/low-contrast text in ${colorScheme} mode: ${failure.descriptor} has contrast ${failure.ratio}:1 (needs ${failure.required}:1) ` +
|
|
10
|
+
`when the OS colour scheme is ${colorScheme}. Use theme-aware tokens (CSS variables / dark: variants) instead of hard-coded colours.`,
|
|
11
|
+
route,
|
|
12
|
+
viewport,
|
|
13
|
+
colorScheme,
|
|
14
|
+
details: { element: failure.descriptor, ratio: failure.ratio, required: failure.required, colorScheme },
|
|
15
|
+
selector: failure.selector,
|
|
16
|
+
}));
|
|
17
|
+
}
|
|
18
|
+
/** In-page probe: computed-contrast failures under the emulated scheme. */
|
|
19
|
+
function probeTheme() {
|
|
20
|
+
const describe = (el) => {
|
|
21
|
+
const tag = el.tagName.toLowerCase();
|
|
22
|
+
const id = el.id ? `#${el.id}` : '';
|
|
23
|
+
const text = (el.textContent ?? '').replace(/\s+/g, ' ').trim().slice(0, 40);
|
|
24
|
+
return `${tag}${id}${text ? ` "${text}"` : ''}`;
|
|
25
|
+
};
|
|
26
|
+
const visible = (el) => {
|
|
27
|
+
const style = window.getComputedStyle(el);
|
|
28
|
+
return style.display !== 'none' && style.visibility !== 'hidden';
|
|
29
|
+
};
|
|
30
|
+
const parseRgb = (value) => {
|
|
31
|
+
const match = value.match(/rgba?\(([^)]+)\)/);
|
|
32
|
+
if (!match)
|
|
33
|
+
return null;
|
|
34
|
+
const parts = match[1].split(',').map((p) => Number.parseFloat(p));
|
|
35
|
+
if (parts.length < 3 || parts.some((n) => Number.isNaN(n)))
|
|
36
|
+
return null;
|
|
37
|
+
return [parts[0], parts[1], parts[2], parts.length > 3 ? parts[3] : 1];
|
|
38
|
+
};
|
|
39
|
+
const luminance = (rgb) => {
|
|
40
|
+
const linear = (channel) => {
|
|
41
|
+
const s = channel / 255;
|
|
42
|
+
return s <= 0.03928 ? s / 12.92 : Math.pow((s + 0.055) / 1.055, 2.4);
|
|
43
|
+
};
|
|
44
|
+
return 0.2126 * linear(rgb[0]) + 0.7152 * linear(rgb[1]) + 0.0722 * linear(rgb[2]);
|
|
45
|
+
};
|
|
46
|
+
const effectiveBackground = (el) => {
|
|
47
|
+
let node = el;
|
|
48
|
+
while (node) {
|
|
49
|
+
const bg = parseRgb(window.getComputedStyle(node).backgroundColor);
|
|
50
|
+
if (bg && bg[3] > 0)
|
|
51
|
+
return [bg[0], bg[1], bg[2]];
|
|
52
|
+
node = node.parentElement;
|
|
53
|
+
}
|
|
54
|
+
// No painted background anywhere: browsers still paint the default
|
|
55
|
+
// white canvas (pages that never opt into dark styling render
|
|
56
|
+
// identically in both schemes). Real dark-mode bugs set a dark
|
|
57
|
+
// background via media query, which the walk above finds.
|
|
58
|
+
return [255, 255, 255];
|
|
59
|
+
};
|
|
60
|
+
const failures = [];
|
|
61
|
+
for (const el of Array.from(document.querySelectorAll('body *')).slice(0, 400)) {
|
|
62
|
+
if (failures.length >= 8)
|
|
63
|
+
break;
|
|
64
|
+
const html = el;
|
|
65
|
+
const ownText = Array.from(html.childNodes).some((n) => n.nodeType === Node.TEXT_NODE && (n.textContent ?? '').trim().length > 0);
|
|
66
|
+
if (!ownText || !visible(el))
|
|
67
|
+
continue;
|
|
68
|
+
const style = window.getComputedStyle(html);
|
|
69
|
+
const fg = parseRgb(style.color);
|
|
70
|
+
if (!fg)
|
|
71
|
+
continue;
|
|
72
|
+
const bg = effectiveBackground(el);
|
|
73
|
+
const l1 = luminance([fg[0], fg[1], fg[2]]);
|
|
74
|
+
const l2 = luminance(bg);
|
|
75
|
+
const ratio = (Math.max(l1, l2) + 0.05) / (Math.min(l1, l2) + 0.05);
|
|
76
|
+
const fontSize = Number.parseFloat(style.fontSize) || 16;
|
|
77
|
+
const bold = Number.parseInt(style.fontWeight, 10) >= 700 || style.fontWeight === 'bold';
|
|
78
|
+
const required = fontSize >= 24 || (fontSize >= 18.66 && bold) ? 3 : 4.5;
|
|
79
|
+
if (ratio < required) {
|
|
80
|
+
failures.push({
|
|
81
|
+
descriptor: describe(el),
|
|
82
|
+
selector: describe(el),
|
|
83
|
+
ratio: Math.round(ratio * 100) / 100,
|
|
84
|
+
required,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return { failures };
|
|
89
|
+
}
|
|
90
|
+
export class ThemeTrap {
|
|
91
|
+
viewport;
|
|
92
|
+
colorScheme;
|
|
93
|
+
constructor(viewport, colorScheme) {
|
|
94
|
+
this.viewport = viewport;
|
|
95
|
+
this.colorScheme = colorScheme;
|
|
96
|
+
}
|
|
97
|
+
async collect(page, route) {
|
|
98
|
+
let metrics;
|
|
99
|
+
try {
|
|
100
|
+
metrics = await page.evaluate(probeTheme);
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return [];
|
|
104
|
+
}
|
|
105
|
+
return evaluateThemeMetrics(metrics, route, this.viewport, this.colorScheme);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
export { contrastRatio };
|
|
109
|
+
//# sourceMappingURL=theme-trap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme-trap.js","sourceRoot":"","sources":["../../../src/traps/theme-trap.ts"],"names":[],"mappings":"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"}
|