Integrate PageSpeed Insights audits

This commit is contained in:
2026-06-04 22:12:59 +02:00
parent 99d61ac736
commit f0a948aec9
19 changed files with 3755 additions and 12 deletions

View File

@@ -70,6 +70,32 @@ function hasPattern(source: string, pattern: RegExp) {
return pattern.test(source);
}
function extractExportSource(source: string, name: string) {
const marker = `export const ${name} = `;
const declarationIndex = source.indexOf(marker);
assert.notEqual(declarationIndex, -1, `Expected declaration for ${name}`);
const openBraceIndex = source.indexOf("{", declarationIndex);
let depth = 0;
let end = -1;
for (let index = openBraceIndex; index < source.length; index += 1) {
const char = source[index];
if (char === "{") {
depth += 1;
} else if (char === "}") {
depth -= 1;
if (depth === 0) {
end = index;
break;
}
}
}
assert.notEqual(end, -1, `Expected balanced braces for ${name}`);
return source.slice(openBraceIndex, end + 1);
}
test("website enrichment mutation module exists and has runtime assertions", () => {
assert.equal(
existsSync(websiteEnrichmentPath),
@@ -531,3 +557,123 @@ test("website enrichment enforces TASK-8 crawler limits and runtime timeboxes",
"Default max crawl page count should be 5",
);
});
test("processLeadEnrichment schedules PageSpeed audit jobs after successful enrichment", () => {
const processBody = extractExportSource(actionSource, "processLeadEnrichment");
const persistIndex = processBody.indexOf(
"internal.websiteEnrichment.persistLeadEnrichmentResult",
);
const queueIndex = processBody.indexOf(
"internal.pageSpeed.queueLeadPageSpeedAudit",
persistIndex,
);
const finishIndex = processBody.indexOf(
"internal.websiteEnrichment.finishLeadEnrichmentRun",
persistIndex,
);
assert.notEqual(queueIndex, -1, "processLeadEnrichment should queue PageSpeed audits");
assert.notEqual(persistIndex, -1, "processLeadEnrichment should persist website enrichment result");
assert.notEqual(finishIndex, -1, "processLeadEnrichment should finish enrichment run");
assert.equal(
hasPattern(
processBody,
/runMutation\(\s*internal\.pageSpeed\.queueLeadPageSpeedAudit[\s\S]*leadId:\s*started\.lead\._id[\s\S]*parentRunId:\s*runId[\s\S]*\)/,
),
true,
"Queue call should pass lead ID and parent run ID",
);
assert.equal(queueIndex > persistIndex, true, "PageSpeed queueing should happen after persistence");
assert.equal(queueIndex < finishIndex, true, "PageSpeed queueing should happen before success finish");
});
test("processLeadEnrichment records warning on PageSpeed queue failure and continues", () => {
const processBody = extractExportSource(actionSource, "processLeadEnrichment");
assert.equal(
hasPattern(
processBody,
/try\s*\{[\s\S]*internal\.pageSpeed\.queueLeadPageSpeedAudit[\s\S]*\}\s*catch\s*\([^)]*\)\s*\{[\s\S]*api\.runs\.appendEvent[\s\S]*level:\s*"warning"/,
),
true,
"Queueing PageSpeed should be wrapped in warning-safe try/catch",
);
assert.equal(
hasPattern(
processBody,
/PageSpeed-Analyse konnte nicht in die Warteschlange gesetzt werden\./,
),
true,
"Warning event should describe queue failure",
);
});
test("processLeadEnrichment regression: queue PageSpeed on invalid URL failure when started lead exists", () => {
const processBody = extractExportSource(actionSource, "processLeadEnrichment");
const invalidUrlStart = processBody.indexOf("if (!rootUrl)");
assert.notEqual(invalidUrlStart, -1, "Invalid URL guard should exist");
const invalidUrlReturnNull = processBody.indexOf("return null;", invalidUrlStart);
assert.notEqual(
invalidUrlReturnNull,
-1,
"Invalid URL branch should return null",
);
const queueCallInInvalidUrl = processBody.indexOf(
"internal.pageSpeed.queueLeadPageSpeedAudit",
invalidUrlStart,
);
assert.equal(
queueCallInInvalidUrl > invalidUrlStart && queueCallInInvalidUrl < invalidUrlReturnNull,
true,
"Invalid URL failure path should queue PageSpeed before returning.",
);
const invalidUrlBranch = processBody.slice(invalidUrlStart, invalidUrlReturnNull);
assert.equal(
hasPattern(
invalidUrlBranch,
/leadId:\s*started\.lead\._id[\s\S]*?parentRunId:\s*runId/,
),
true,
"Invalid URL queue payload should use started.lead._id and parentRunId runId.",
);
});
test("processLeadEnrichment regression: queue PageSpeed in fatal catch path with started lead", () => {
const processBody = extractExportSource(actionSource, "processLeadEnrichment");
const outerCatchStart = processBody.lastIndexOf("catch (error)");
assert.notEqual(outerCatchStart, -1, "Outer catch block should exist");
const startedGuard = processBody.indexOf("if (started)", outerCatchStart);
assert.notEqual(startedGuard, -1, "Outer catch should guard lead patch by started check.");
const catchReturnNull = processBody.indexOf("return null;", outerCatchStart);
assert.notEqual(
catchReturnNull,
-1,
"Outer catch should return null on unrecoverable errors.",
);
const queueCallInCatch = processBody.indexOf(
"internal.pageSpeed.queueLeadPageSpeedAudit",
outerCatchStart,
);
assert.equal(
queueCallInCatch > outerCatchStart &&
queueCallInCatch > startedGuard &&
queueCallInCatch < catchReturnNull,
true,
"Fatal catch path should queue PageSpeed before returning, while started lead exists.",
);
const catchBlock = processBody.slice(outerCatchStart, catchReturnNull);
assert.equal(
hasPattern(
catchBlock,
/leadId:\s*started\.lead\._id[\s\S]*?parentRunId:\s*runId/,
),
true,
"Catch-path PageSpeed queue payload should use started.lead._id and parentRunId runId.",
);
});