From 90d86e1cbf41238431cc92c27091599ce8411dab Mon Sep 17 00:00:00 2001 From: Om Shivaprasad Wanere Date: Tue, 13 Jan 2026 21:06:32 +0530 Subject: [PATCH] Fix canonical audit to classify invalid URLs correctly --- core/audits/seo/canonical.js | 30 +++++++++++++++++++++----- core/test/audits/seo/canonical-test.js | 27 +++++++++++++++++++++++ 2 files changed, 52 insertions(+), 5 deletions(-) diff --git a/core/audits/seo/canonical.js b/core/audits/seo/canonical.js index 1a1868188e4b..a8f9617cc6f9 100644 --- a/core/audits/seo/canonical.js +++ b/core/audits/seo/canonical.js @@ -91,11 +91,31 @@ class Canonical extends Audit { if (!link.hrefRaw) continue; // Links that had an hrefRaw but didn't have a valid href were invalid, flag them - if (!link.href) invalidCanonicalLink = link; - // Links that had a valid href but didn't have a valid hrefRaw must have been relatively resolved, flag them - else if (!UrlUtils.isValid(link.hrefRaw)) relativeCanonicallink = link; - // Otherwise, it was a valid canonical URL - else uniqueCanonicalURLs.add(link.href); + // if (!link.href) invalidCanonicalLink = link; + // // Links that had a valid href but didn't have a valid hrefRaw must have been relatively resolved, flag them + // else if (!UrlUtils.isValid(link.hrefRaw)) relativeCanonicallink = link; + // // Otherwise, it was a valid canonical URL + // else uniqueCanonicalURLs.add(link.href); + + if (!link.href) { + invalidCanonicalLink = link; + } else { + let parsed; + try { + parsed = new URL(link.hrefRaw); + } catch { + invalidCanonicalLink = link; + continue; + } + + if (!parsed.origin || parsed.origin === 'null') { + relativeCanonicallink = link; + } else { + uniqueCanonicalURLs.add(link.href); + } + } + + } else if (link.rel === 'alternate') { if (link.href && link.hreflang) hreflangURLs.add(link.href); } diff --git a/core/test/audits/seo/canonical-test.js b/core/test/audits/seo/canonical-test.js index bf335317d7dc..51db4b277276 100644 --- a/core/test/audits/seo/canonical-test.js +++ b/core/test/audits/seo/canonical-test.js @@ -103,6 +103,33 @@ describe('SEO: Document has valid canonical link', () => { }); }); + it('fails when canonical url is invalid', async () => { + const mainDocumentUrl = 'https://example.com/'; + const mainResource = {url: mainDocumentUrl}; + const devtoolsLog = networkRecordsToDevtoolsLog([mainResource]); + + const artifacts = { + DevtoolsLog: devtoolsLog, + URL: {mainDocumentUrl}, + LinkElements: [ + link({ + rel: 'canonical', + source: 'headers', + href: null, + hrefRaw: 'example.com', + }), + ], + }; + + const context = createContext(); + const result = await Canonical.audit(artifacts, context); + + expect(result.score).toBe(0); + expect(result.explanation) + .toContain('Invalid URL'); +}); + + it('fails when canonical points to a different hreflang', () => { const mainDocumentUrl = 'https://example.com/'; const mainResource = {url: mainDocumentUrl};