mirror of
https://github.com/AgentDeskAI/browser-tools-mcp.git
synced 2025-11-21 04:28:48 +00:00
Refactor Lighthouse audit utilities and improve error handling
This commit is contained in:
parent
37269d1e2d
commit
0d995a3219
@ -2,8 +2,6 @@
|
|||||||
|
|
||||||
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||||
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
||||||
import path from "path";
|
|
||||||
import { z } from "zod";
|
|
||||||
// import { z } from "zod";
|
// import { z } from "zod";
|
||||||
// import fs from "fs";
|
// import fs from "fs";
|
||||||
|
|
||||||
@ -13,14 +11,14 @@ const server = new McpServer({
|
|||||||
version: "1.0.9",
|
version: "1.0.9",
|
||||||
});
|
});
|
||||||
|
|
||||||
// Define audit categories as constants to avoid importing from the types file
|
// Define audit categories as enum to match the server's AuditCategory enum
|
||||||
const AUDIT_CATEGORIES = {
|
enum AuditCategory {
|
||||||
ACCESSIBILITY: "accessibility",
|
ACCESSIBILITY = "accessibility",
|
||||||
PERFORMANCE: "performance",
|
PERFORMANCE = "performance",
|
||||||
SEO: "seo",
|
SEO = "seo",
|
||||||
BEST_PRACTICES: "best-practices",
|
BEST_PRACTICES = "best-practices",
|
||||||
PWA: "pwa",
|
PWA = "pwa",
|
||||||
};
|
}
|
||||||
|
|
||||||
// Function to get the port from the .port file
|
// Function to get the port from the .port file
|
||||||
// function getPort(): number {
|
// function getPort(): number {
|
||||||
@ -197,7 +195,7 @@ server.tool("wipeLogs", "Wipe all browser logs from memory", async () => {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add tool for accessibility audits
|
// Add tool for accessibility audits, launches a headless browser instance
|
||||||
server.tool(
|
server.tool(
|
||||||
"runAccessibilityAudit",
|
"runAccessibilityAudit",
|
||||||
"Run a WCAG-compliant accessibility audit on the current page",
|
"Run a WCAG-compliant accessibility audit on the current page",
|
||||||
@ -210,7 +208,7 @@ server.tool(
|
|||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
category: AUDIT_CATEGORIES.ACCESSIBILITY,
|
category: AuditCategory.ACCESSIBILITY,
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@ -248,7 +246,7 @@ server.tool(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// Add tool for performance audits
|
// Add tool for performance audits, launches a headless browser instance
|
||||||
server.tool(
|
server.tool(
|
||||||
"runPerformanceAudit",
|
"runPerformanceAudit",
|
||||||
"Run a performance audit on the current page",
|
"Run a performance audit on the current page",
|
||||||
@ -262,7 +260,7 @@ server.tool(
|
|||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
category: AUDIT_CATEGORIES.PERFORMANCE,
|
category: AuditCategory.PERFORMANCE,
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@ -3,11 +3,15 @@ import {
|
|||||||
AuditResult,
|
AuditResult,
|
||||||
AuditIssue,
|
AuditIssue,
|
||||||
LighthouseDetails,
|
LighthouseDetails,
|
||||||
ElementDetails,
|
|
||||||
ImpactLevel,
|
ImpactLevel,
|
||||||
AuditCategory,
|
AuditCategory,
|
||||||
} from "./types.js";
|
} from "./types.js";
|
||||||
import { runLighthouseOnExistingTab } from "./index.js";
|
import {
|
||||||
|
runLighthouseOnExistingTab,
|
||||||
|
mapAuditItemsToElements,
|
||||||
|
createAuditIssue,
|
||||||
|
createAuditMetadata,
|
||||||
|
} from "./index.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts simplified accessibility issues from Lighthouse results
|
* Extracts simplified accessibility issues from Lighthouse results
|
||||||
@ -44,56 +48,30 @@ export function extractAccessibilityIssues(
|
|||||||
failedAudits.forEach(({ ref, audit }) => {
|
failedAudits.forEach(({ ref, audit }) => {
|
||||||
const details = audit.details as LighthouseDetails;
|
const details = audit.details as LighthouseDetails;
|
||||||
|
|
||||||
// Extract actionable elements that need fixing
|
// Use the shared helper function to extract elements
|
||||||
const elements = (details?.items || []).map(
|
const elements = mapAuditItemsToElements(
|
||||||
(item: Record<string, unknown>) =>
|
details?.items || [],
|
||||||
({
|
detailed
|
||||||
selector:
|
|
||||||
((item.node as Record<string, unknown>)?.selector as string) ||
|
|
||||||
(item.selector as string) ||
|
|
||||||
"Unknown selector",
|
|
||||||
snippet:
|
|
||||||
((item.node as Record<string, unknown>)?.snippet as string) ||
|
|
||||||
(item.snippet as string) ||
|
|
||||||
"No snippet available",
|
|
||||||
explanation:
|
|
||||||
((item.node as Record<string, unknown>)
|
|
||||||
?.explanation as string) ||
|
|
||||||
(item.explanation as string) ||
|
|
||||||
"No explanation available",
|
|
||||||
url:
|
|
||||||
(item.url as string) ||
|
|
||||||
((item.node as Record<string, unknown>)?.url as string) ||
|
|
||||||
"",
|
|
||||||
size:
|
|
||||||
(item.totalBytes as number) ||
|
|
||||||
(item.transferSize as number) ||
|
|
||||||
0,
|
|
||||||
wastedMs: (item.wastedMs as number) || 0,
|
|
||||||
wastedBytes: (item.wastedBytes as number) || 0,
|
|
||||||
} as ElementDetails)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (elements.length > 0 || (audit.score || 0) < 1) {
|
if (elements.length > 0 || (audit.score || 0) < 1) {
|
||||||
const issue: AuditIssue = {
|
// Use the shared helper function to create an audit issue
|
||||||
id: audit.id,
|
const impact =
|
||||||
title: audit.title,
|
((details?.items?.[0] as Record<string, unknown>)
|
||||||
description: audit.description,
|
?.impact as string) || ImpactLevel.MODERATE;
|
||||||
score: audit.score || 0,
|
const issue = createAuditIssue(
|
||||||
details: detailed ? details : { type: details.type },
|
audit,
|
||||||
category: categoryName,
|
ref,
|
||||||
wcagReference: ref.relevantAudits || [],
|
details,
|
||||||
impact:
|
elements,
|
||||||
((details?.items?.[0] as Record<string, unknown>)
|
categoryName,
|
||||||
?.impact as string) || ImpactLevel.MODERATE,
|
impact
|
||||||
elements: detailed ? elements : elements.slice(0, 3),
|
);
|
||||||
failureSummary:
|
|
||||||
((details?.items?.[0] as Record<string, unknown>)
|
// Add detailed details if requested
|
||||||
?.failureSummary as string) ||
|
if (detailed) {
|
||||||
audit.explanation ||
|
issue.details = details;
|
||||||
"No failure summary available",
|
}
|
||||||
recommendations: [],
|
|
||||||
};
|
|
||||||
|
|
||||||
allIssues.push(issue);
|
allIssues.push(issue);
|
||||||
}
|
}
|
||||||
@ -124,19 +102,7 @@ export function extractAccessibilityIssues(
|
|||||||
categoryScores,
|
categoryScores,
|
||||||
issues: limitedIssues,
|
issues: limitedIssues,
|
||||||
...(detailed && {
|
...(detailed && {
|
||||||
auditMetadata: {
|
auditMetadata: createAuditMetadata(lhr),
|
||||||
fetchTime: lhr.fetchTime || new Date().toISOString(),
|
|
||||||
url: lhr.finalUrl || "Unknown URL",
|
|
||||||
deviceEmulation: "desktop",
|
|
||||||
categories: Object.keys(lhr.categories),
|
|
||||||
totalAudits: Object.keys(lhr.audits).length,
|
|
||||||
passedAudits: Object.values(lhr.audits).filter(
|
|
||||||
(audit) => audit.score === 1
|
|
||||||
).length,
|
|
||||||
failedAudits: Object.values(lhr.audits).filter(
|
|
||||||
(audit) => audit.score !== null && audit.score < 1
|
|
||||||
).length,
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,7 +4,13 @@ import {
|
|||||||
connectToHeadlessBrowser,
|
connectToHeadlessBrowser,
|
||||||
scheduleBrowserCleanup,
|
scheduleBrowserCleanup,
|
||||||
} from "../browser-utils.js";
|
} from "../browser-utils.js";
|
||||||
import { LighthouseConfig, AuditCategory } from "./types.js";
|
import {
|
||||||
|
LighthouseConfig,
|
||||||
|
AuditCategory,
|
||||||
|
AuditIssue,
|
||||||
|
LighthouseDetails,
|
||||||
|
ImpactLevel,
|
||||||
|
} from "./types.js";
|
||||||
|
|
||||||
// ===== Type Definitions =====
|
// ===== Type Definitions =====
|
||||||
|
|
||||||
@ -67,9 +73,11 @@ export async function runLighthouseOnExistingTab(
|
|||||||
): Promise<LighthouseResult> {
|
): Promise<LighthouseResult> {
|
||||||
console.log(`Starting Lighthouse ${categories.join(", ")} audit for: ${url}`);
|
console.log(`Starting Lighthouse ${categories.join(", ")} audit for: ${url}`);
|
||||||
|
|
||||||
if (!url) {
|
if (!url || url === "about:blank") {
|
||||||
console.error("URL is required for Lighthouse audit");
|
console.error("Invalid URL for Lighthouse audit");
|
||||||
throw new Error("URL is required for Lighthouse audit");
|
throw new Error(
|
||||||
|
"Cannot run audit on an empty page or about:blank. Please navigate to a valid URL first."
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -81,32 +89,53 @@ export async function runLighthouseOnExistingTab(
|
|||||||
|
|
||||||
// For performance audits, we want to load all resources
|
// For performance audits, we want to load all resources
|
||||||
// For accessibility or other audits, we can block non-essential resources
|
// For accessibility or other audits, we can block non-essential resources
|
||||||
const { port } = await connectToHeadlessBrowser(url, {
|
try {
|
||||||
blockResources: !isPerformanceAudit,
|
const { port } = await connectToHeadlessBrowser(url, {
|
||||||
// Don't pass an audit type - the blockResources flag is what matters
|
blockResources: !isPerformanceAudit,
|
||||||
});
|
// Don't pass an audit type - the blockResources flag is what matters
|
||||||
|
});
|
||||||
|
|
||||||
console.log(`Connected to browser on port: ${port}`);
|
console.log(`Connected to browser on port: ${port}`);
|
||||||
|
|
||||||
// Create Lighthouse config
|
// Create Lighthouse config
|
||||||
const { flags, config } = createLighthouseConfig(categories);
|
const { flags, config } = createLighthouseConfig(categories);
|
||||||
flags.port = port;
|
flags.port = port;
|
||||||
|
|
||||||
console.log(`Running Lighthouse with categories: ${categories.join(", ")}`);
|
console.log(
|
||||||
const runnerResult = await lighthouse(url, flags as Flags, config);
|
`Running Lighthouse with categories: ${categories.join(", ")}`
|
||||||
console.log("Lighthouse audit completed");
|
);
|
||||||
|
const runnerResult = await lighthouse(url, flags as Flags, config);
|
||||||
|
console.log("Lighthouse audit completed");
|
||||||
|
|
||||||
if (!runnerResult?.lhr) {
|
if (!runnerResult?.lhr) {
|
||||||
console.error("Lighthouse audit failed to produce results");
|
console.error("Lighthouse audit failed to produce results");
|
||||||
throw new Error("Lighthouse audit failed to produce results");
|
throw new Error("Lighthouse audit failed to produce results");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Schedule browser cleanup after a delay to allow for subsequent audits
|
||||||
|
scheduleBrowserCleanup();
|
||||||
|
|
||||||
|
// Return the result
|
||||||
|
const result = runnerResult.lhr;
|
||||||
|
return result;
|
||||||
|
} catch (browserError) {
|
||||||
|
// Check if the error is related to Chrome/Edge not being available
|
||||||
|
const errorMessage =
|
||||||
|
browserError instanceof Error
|
||||||
|
? browserError.message
|
||||||
|
: String(browserError);
|
||||||
|
if (
|
||||||
|
errorMessage.includes("Chrome could not be found") ||
|
||||||
|
errorMessage.includes("Failed to launch browser") ||
|
||||||
|
errorMessage.includes("spawn ENOENT")
|
||||||
|
) {
|
||||||
|
throw new Error(
|
||||||
|
"Chrome or Edge browser could not be found. Please ensure that Chrome or Edge is installed on your system to run audits."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// Re-throw other errors
|
||||||
|
throw browserError;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Schedule browser cleanup after a delay to allow for subsequent audits
|
|
||||||
scheduleBrowserCleanup();
|
|
||||||
|
|
||||||
// Return the result
|
|
||||||
const result = runnerResult.lhr;
|
|
||||||
return result;
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Lighthouse audit failed:", error);
|
console.error("Lighthouse audit failed:", error);
|
||||||
// Schedule browser cleanup even if the audit fails
|
// Schedule browser cleanup even if the audit fails
|
||||||
@ -123,3 +152,102 @@ export async function runLighthouseOnExistingTab(
|
|||||||
export * from "./accessibility.js";
|
export * from "./accessibility.js";
|
||||||
export * from "./performance.js";
|
export * from "./performance.js";
|
||||||
export * from "./types.js";
|
export * from "./types.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps Lighthouse audit items to ElementDetails objects
|
||||||
|
* @param items Array of audit items from Lighthouse
|
||||||
|
* @param detailed Whether to include all items or limit them
|
||||||
|
* @returns Array of ElementDetails objects
|
||||||
|
*/
|
||||||
|
export function mapAuditItemsToElements(
|
||||||
|
items: Record<string, unknown>[] = [],
|
||||||
|
detailed: boolean = false
|
||||||
|
): ElementDetails[] {
|
||||||
|
const elements = items.map(
|
||||||
|
(item: Record<string, unknown>) =>
|
||||||
|
({
|
||||||
|
selector:
|
||||||
|
((item.node as Record<string, unknown>)?.selector as string) ||
|
||||||
|
(item.selector as string) ||
|
||||||
|
"Unknown selector",
|
||||||
|
snippet:
|
||||||
|
((item.node as Record<string, unknown>)?.snippet as string) ||
|
||||||
|
(item.snippet as string) ||
|
||||||
|
"No snippet available",
|
||||||
|
explanation:
|
||||||
|
((item.node as Record<string, unknown>)?.explanation as string) ||
|
||||||
|
(item.explanation as string) ||
|
||||||
|
"No explanation available",
|
||||||
|
url:
|
||||||
|
(item.url as string) ||
|
||||||
|
((item.node as Record<string, unknown>)?.url as string) ||
|
||||||
|
"",
|
||||||
|
size: (item.totalBytes as number) || (item.transferSize as number) || 0,
|
||||||
|
wastedMs: (item.wastedMs as number) || 0,
|
||||||
|
wastedBytes: (item.wastedBytes as number) || 0,
|
||||||
|
} as ElementDetails)
|
||||||
|
);
|
||||||
|
|
||||||
|
return detailed ? elements : elements.slice(0, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an AuditIssue object from Lighthouse audit data
|
||||||
|
* @param audit The Lighthouse audit object
|
||||||
|
* @param ref The audit reference object
|
||||||
|
* @param details The audit details object
|
||||||
|
* @param elements Array of ElementDetails objects
|
||||||
|
* @param categoryName The category name
|
||||||
|
* @param impact The impact level (optional)
|
||||||
|
* @returns An AuditIssue object
|
||||||
|
*/
|
||||||
|
export function createAuditIssue(
|
||||||
|
audit: any,
|
||||||
|
ref: any,
|
||||||
|
details: LighthouseDetails,
|
||||||
|
elements: ElementDetails[],
|
||||||
|
categoryName: string,
|
||||||
|
impact?: string
|
||||||
|
): AuditIssue {
|
||||||
|
return {
|
||||||
|
id: audit.id,
|
||||||
|
title: audit.title,
|
||||||
|
description: audit.description,
|
||||||
|
score: audit.score || 0,
|
||||||
|
details: { type: details?.type || "unknown" },
|
||||||
|
category: categoryName,
|
||||||
|
wcagReference: ref.relevantAudits || [],
|
||||||
|
impact:
|
||||||
|
impact ||
|
||||||
|
((details?.items?.[0] as Record<string, unknown>)?.impact as string) ||
|
||||||
|
ImpactLevel.MODERATE,
|
||||||
|
elements: elements,
|
||||||
|
failureSummary:
|
||||||
|
((details?.items?.[0] as Record<string, unknown>)
|
||||||
|
?.failureSummary as string) ||
|
||||||
|
audit.explanation ||
|
||||||
|
"No failure summary available",
|
||||||
|
recommendations: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates audit metadata from Lighthouse results
|
||||||
|
* @param lhr The Lighthouse result object
|
||||||
|
* @returns Audit metadata object
|
||||||
|
*/
|
||||||
|
export function createAuditMetadata(lhr: LighthouseResult): any {
|
||||||
|
return {
|
||||||
|
fetchTime: lhr.fetchTime || new Date().toISOString(),
|
||||||
|
url: lhr.finalUrl || "Unknown URL",
|
||||||
|
deviceEmulation: "desktop",
|
||||||
|
categories: Object.keys(lhr.categories),
|
||||||
|
totalAudits: Object.keys(lhr.audits || {}).length,
|
||||||
|
passedAudits: Object.values(lhr.audits || {}).filter(
|
||||||
|
(audit) => audit.score === 1
|
||||||
|
).length,
|
||||||
|
failedAudits: Object.values(lhr.audits || {}).filter(
|
||||||
|
(audit) => audit.score !== null && audit.score < 1
|
||||||
|
).length,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
@ -7,7 +7,12 @@ import {
|
|||||||
ImpactLevel,
|
ImpactLevel,
|
||||||
AuditCategory,
|
AuditCategory,
|
||||||
} from "./types.js";
|
} from "./types.js";
|
||||||
import { runLighthouseOnExistingTab } from "./index.js";
|
import {
|
||||||
|
runLighthouseOnExistingTab,
|
||||||
|
mapAuditItemsToElements,
|
||||||
|
createAuditIssue,
|
||||||
|
createAuditMetadata,
|
||||||
|
} from "./index.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts performance issues from Lighthouse results
|
* Extracts performance issues from Lighthouse results
|
||||||
@ -21,8 +26,6 @@ export function extractPerformanceIssues(
|
|||||||
limit: number = 5,
|
limit: number = 5,
|
||||||
detailed: boolean = false
|
detailed: boolean = false
|
||||||
): Partial<AuditResult> {
|
): Partial<AuditResult> {
|
||||||
console.log("Processing performance audit results");
|
|
||||||
|
|
||||||
const allIssues: AuditIssue[] = [];
|
const allIssues: AuditIssue[] = [];
|
||||||
const categoryScores: { [key: string]: number } = {};
|
const categoryScores: { [key: string]: number } = {};
|
||||||
|
|
||||||
@ -67,8 +70,6 @@ export function extractPerformanceIssues(
|
|||||||
((item.audit.details as LighthouseDetails)?.items?.length || 0) > 0)
|
((item.audit.details as LighthouseDetails)?.items?.length || 0) > 0)
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log(`Found ${failedAudits.length} performance issues`);
|
|
||||||
|
|
||||||
if (failedAudits.length > 0) {
|
if (failedAudits.length > 0) {
|
||||||
failedAudits.forEach(({ ref, audit }) => {
|
failedAudits.forEach(({ ref, audit }) => {
|
||||||
try {
|
try {
|
||||||
@ -80,70 +81,28 @@ export function extractPerformanceIssues(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract actionable elements that need fixing
|
// Use the shared helper function to extract elements
|
||||||
const elements = (details.items || []).map(
|
const elements = mapAuditItemsToElements(
|
||||||
(item: Record<string, unknown>) => {
|
details.items || [],
|
||||||
try {
|
detailed
|
||||||
return {
|
|
||||||
selector:
|
|
||||||
((item.node as Record<string, unknown>)
|
|
||||||
?.selector as string) ||
|
|
||||||
(item.selector as string) ||
|
|
||||||
"Unknown selector",
|
|
||||||
snippet:
|
|
||||||
((item.node as Record<string, unknown>)
|
|
||||||
?.snippet as string) ||
|
|
||||||
(item.snippet as string) ||
|
|
||||||
"No snippet available",
|
|
||||||
explanation:
|
|
||||||
((item.node as Record<string, unknown>)
|
|
||||||
?.explanation as string) ||
|
|
||||||
(item.explanation as string) ||
|
|
||||||
"No explanation available",
|
|
||||||
url:
|
|
||||||
(item.url as string) ||
|
|
||||||
((item.node as Record<string, unknown>)?.url as string) ||
|
|
||||||
"",
|
|
||||||
size:
|
|
||||||
(item.totalBytes as number) ||
|
|
||||||
(item.transferSize as number) ||
|
|
||||||
0,
|
|
||||||
wastedMs: (item.wastedMs as number) || 0,
|
|
||||||
wastedBytes: (item.wastedBytes as number) || 0,
|
|
||||||
} as ElementDetails;
|
|
||||||
} catch (error) {
|
|
||||||
console.error(`Error processing element: ${error}`);
|
|
||||||
return {
|
|
||||||
selector: "Error processing element",
|
|
||||||
snippet: "Error",
|
|
||||||
explanation: "Error processing element details",
|
|
||||||
url: "",
|
|
||||||
size: 0,
|
|
||||||
wastedMs: 0,
|
|
||||||
wastedBytes: 0,
|
|
||||||
} as ElementDetails;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (elements.length > 0 || (audit.score || 0) < 0.9) {
|
if (elements.length > 0 || (audit.score || 0) < 0.9) {
|
||||||
const issue: AuditIssue = {
|
// Use the shared helper function to create an audit issue
|
||||||
id: audit.id,
|
const impact = getPerformanceImpact(audit.score || 0);
|
||||||
title: audit.title,
|
const issue = createAuditIssue(
|
||||||
description: audit.description,
|
audit,
|
||||||
score: audit.score || 0,
|
ref,
|
||||||
details: detailed ? details : { type: details.type || "unknown" },
|
details,
|
||||||
category: categoryName,
|
elements,
|
||||||
wcagReference: ref.relevantAudits || [],
|
categoryName,
|
||||||
impact: getPerformanceImpact(audit.score || 0),
|
impact
|
||||||
elements: detailed ? elements : elements.slice(0, 3),
|
);
|
||||||
failureSummary:
|
|
||||||
((details?.items?.[0] as Record<string, unknown>)
|
// Add detailed details if requested
|
||||||
?.failureSummary as string) ||
|
if (detailed) {
|
||||||
audit.explanation ||
|
issue.details = details;
|
||||||
"No failure summary available",
|
}
|
||||||
recommendations: [],
|
|
||||||
};
|
|
||||||
|
|
||||||
allIssues.push(issue);
|
allIssues.push(issue);
|
||||||
}
|
}
|
||||||
@ -160,26 +119,12 @@ export function extractPerformanceIssues(
|
|||||||
// Return only the specified number of issues
|
// Return only the specified number of issues
|
||||||
const limitedIssues = allIssues.slice(0, limit);
|
const limitedIssues = allIssues.slice(0, limit);
|
||||||
|
|
||||||
console.log(`Returning ${limitedIssues.length} performance issues`);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
score: categoryScores.performance || 0,
|
score: categoryScores.performance || 0,
|
||||||
categoryScores,
|
categoryScores,
|
||||||
issues: limitedIssues,
|
issues: limitedIssues,
|
||||||
...(detailed && {
|
...(detailed && {
|
||||||
auditMetadata: {
|
auditMetadata: createAuditMetadata(lhr),
|
||||||
fetchTime: lhr.fetchTime || new Date().toISOString(),
|
|
||||||
url: lhr.finalUrl || "Unknown URL",
|
|
||||||
deviceEmulation: "desktop",
|
|
||||||
categories: Object.keys(lhr.categories),
|
|
||||||
totalAudits: Object.keys(lhr.audits || {}).length,
|
|
||||||
passedAudits: Object.values(lhr.audits || {}).filter(
|
|
||||||
(audit) => audit.score === 1
|
|
||||||
).length,
|
|
||||||
failedAudits: Object.values(lhr.audits || {}).filter(
|
|
||||||
(audit) => audit.score !== null && audit.score < 1
|
|
||||||
).length,
|
|
||||||
},
|
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user