Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions src/server/lib/audit/page-analyzer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,26 @@ describe("analyzeHtml parity with the DOM reference", () => {
});
});

describe("analyzeHtml link resolution", () => {
const linkTargets = (html: string) =>
analyzeHtml(html, PAGE_URL, 200, 0).links.map((link) => link.targetUrl);

it("resolves relative links against <base href>", () => {
expect(
linkTargets(
`<html><head><base href="https://example.com/en/"></head>
<body><a href="guide">Guide</a></body></html>`,
),
).toEqual(["https://example.com/en/guide"]);
});

it("resolves relative links against the page URL without a <base>", () => {
expect(
linkTargets(`<html><body><a href="guide">Guide</a></body></html>`),
).toEqual(["https://example.com/blog/guide"]);
});
});

describe("analyzeHtml extraction caps", () => {
it("caps links and images per page", () => {
const links = Array.from(
Expand Down
11 changes: 10 additions & 1 deletion src/server/lib/audit/page-analyzer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ export function analyzeHtml(
let ogImage: string | null = null;
let hasStructuredData = false;
const hreflangTags: string[] = [];
// Resolution base for relative link targets. HTML lets a document override
// it with <base href>, which sits in <head> and so is always parsed before
// the links it governs; the first <base> with an href wins.
let linkBase: string | null = null;

const h1s: string[] = [];
const headingOrder: number[] = [];
Expand Down Expand Up @@ -113,7 +117,7 @@ export function analyzeHtml(
const { href, rel, text } = openAnchor;
openAnchor = null;
if (linksByTarget.size >= MAX_EXTRACTED_LINKS) return;
const resolved = normalizeUrl(href, pageUrl);
const resolved = normalizeUrl(href, linkBase ?? pageUrl);
if (!resolved || linksByTarget.has(resolved)) return;
const anchor = text
.join("")
Expand Down Expand Up @@ -157,6 +161,11 @@ export function analyzeHtml(
case "link":
handleLinkTag(attribs);
break;
case "base":
if (linkBase === null && attribs["href"]) {
linkBase = normalizeUrl(attribs["href"], pageUrl);
}
break;
case "img":
if (images.length < MAX_EXTRACTED_IMAGES) {
images.push({
Expand Down