Skip to content
This repository has been archived by the owner on Jun 7, 2024. It is now read-only.

Commit

Permalink
fix(w3c/seo): update list of docs that required canonical link (spece…
Browse files Browse the repository at this point in the history
  • Loading branch information
marcoscaceres authored Dec 22, 2021
1 parent 85dc9aa commit 58c6c74
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 59 deletions.
4 changes: 2 additions & 2 deletions src/w3c/headers.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ const status2maturity = {
FPWD: "WD",
};

const publicationSpaces = {
export const publicationSpaces = {
"Member-SUBM": "/Submission",
finding: "/2001/tag/doc",
"draft-finding": "/2001/tag/doc",
Expand Down Expand Up @@ -203,7 +203,7 @@ export const registryTrackStatus = ["DRY", "CRY", "CRYD", "RY"];
export const cgStatus = ["CG-DRAFT", "CG-FINAL"];
export const bgStatus = ["BG-DRAFT", "BG-FINAL"];
export const cgbgStatus = [...cgStatus, ...bgStatus];
const noTrackStatus = [
export const noTrackStatus = [
"base",
...cgStatus,
...bgStatus,
Expand Down
54 changes: 24 additions & 30 deletions src/w3c/seo.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// Module w3c/seo
// Manages SEO information for documents
// e.g. set the canonical URL for the document if configured
import { html } from "../core/import-maps.js";
import { recTrackStatus } from "./headers.js";
import { resolveRef } from "../core/biblio.js";
import { showWarning } from "../core/utils.js";
export const name = "w3c/seo";
Expand All @@ -18,20 +20,24 @@ const status2rdf = {
RSCND: "w3p:RSCND",
};

export const requiresCanonicalLink = new Set([
...recTrackStatus,
"BG-FINAL",
"CG-FINAL",
"CRY",
"DRY",
"draft-finding",
"finding",
]);

export async function run(conf) {
// Don't include a canonical URL for documents
// that haven't been published.
if (!conf.canonicalURI) {
switch (conf.specStatus) {
case "CG-DRAFT":
case "BG-DRAFT":
case "unofficial":
return;
}
// Don't include a canonical URL for documents that haven't been published.
if (
(!conf.canonicalURI && !requiresCanonicalLink.has(conf.specStatus)) ||
!conf.shortName
) {
return;
}
const trLatestUri = conf.shortName
? `https://www.w3.org/TR/${conf.shortName}/`
: null;
switch (conf.canonicalURI) {
case "edDraft":
if (conf.edDraftURI) {
Expand All @@ -46,36 +52,24 @@ export async function run(conf) {
}
break;
case "TR":
if (trLatestUri) {
conf.canonicalURI = trLatestUri;
if (conf.latestVersion) {
conf.canonicalURI = conf.latestVersion;
} else {
const msg = `Canonical URI set to TR, but no shortName is set in configuration`;
showWarning(msg, name);
conf.canonicalURI = null;
}
break;
default:
if (conf.canonicalURI) {
try {
conf.canonicalURI = new URL(
conf.canonicalURI,
document.location.href
).href;
} catch (err) {
const msg = `CanonicalURI is an invalid URL: ${err.message}`;
showWarning(msg, name);
conf.canonicalURI = null;
}
} else if (trLatestUri) {
conf.canonicalURI = trLatestUri;
if (conf.latestVersion && !conf.canonicalURI) {
conf.canonicalURI = conf.latestVersion;
}
}
if (conf.canonicalURI) {
const linkElem = document.createElement("link");
linkElem.setAttribute("rel", "canonical");
linkElem.setAttribute("href", conf.canonicalURI);
const linkElem = html`<link rel="canonical" href="${conf.canonicalURI}" />`;
document.head.appendChild(linkElem);
}

if (conf.doJsonLd) {
await addJSONLDInfo(conf, document);
}
Expand Down
90 changes: 63 additions & 27 deletions tests/spec/w3c/seo-spec.js
Original file line number Diff line number Diff line change
@@ -1,57 +1,93 @@
"use strict";

import { flushIframes, makeRSDoc, makeStandardOps } from "../SpecHelper.js";
import { publicationSpaces } from "../../../src/w3c/headers.js";
import { requiresCanonicalLink } from "../../../src/w3c/seo.js";

function makeTest(uri) {
return doc => {
const canLink = doc.querySelector("link[rel='canonical']");
expect(canLink.href).toBe(uri);
};
}
describe("W3C - SEO", () => {
afterAll(flushIframes);

it("defaults to TR as canonical URI", async () => {
const test = makeTest("https://www.w3.org/TR/Foo/");
test(await makeRSDoc(makeStandardOps()));
const doc = await makeRSDoc(makeStandardOps({ specStatus: "REC" }));
const href = "https://www.w3.org/TR/Foo/";
expect(
doc.querySelector(`link[rel='canonical'][href='${href}']`)
).toBeTruthy();
});

it("sets the canonical URI to TR URI when so configured", async () => {
const test = makeTest("https://www.w3.org/TR/Foo/");
const ops = makeStandardOps();
ops.config.canonicalURI = "TR";
test(await makeRSDoc(ops));
const href = "https://www.w3.org/TR/Foo/";
const ops = makeStandardOps({ canonicalURI: "TR" });
const doc = await makeRSDoc(ops);
expect(
doc.querySelector(`link[rel='canonical'][href='${href}']`)
).toBeTruthy();
});

it("sets the canonical URI to editors draft when so configured", async () => {
const test = makeTest("https://foo.com/");
const ops = makeStandardOps();
ops.config.canonicalURI = "edDraft";
test(await makeRSDoc(ops));
it("sets the canonical URI to editors draft when configured with 'edDraft'", async () => {
const href = "https://foo.com/";
const ops = makeStandardOps({ canonicalURI: "edDraft" });
const doc = await makeRSDoc(ops);
expect(
doc.querySelector(`link[rel='canonical'][href='${href}']`)
).toBeTruthy();
});

it("shouldn't set any canonical URI if no shortname is defined", async () => {
const ops = makeStandardOps();
ops.config.shortName = undefined;
const ops = makeStandardOps({ shortName: undefined });
const doc = await makeRSDoc(ops);
expect(doc.querySelector("link[rel='canonical']")).toBeNull();
});

it("shouldn't set any canonical URI if it is a draft document", async () => {
const ops = makeStandardOps();
const draftStatuses = ["CG-DRAFT", "BG-DRAFT", "unofficial"];
for (const status of draftStatuses) {
ops.config.specStatus = status;
const ops = makeStandardOps({ specStatus: status });
const doc = await makeRSDoc(ops);
expect(doc.querySelector("link[rel='canonical']")).toBeNull();
expect(doc.querySelector("link[rel='canonical']"))
.withContext(draftStatuses)
.toBeNull();
}
});

it("sets the canonical URI if explicitly set", async () => {
const test = makeTest("https://example.com/");
const ops = makeStandardOps();
ops.config.canonicalURI = "https://example.com";
test(await makeRSDoc(ops));
it("doesn't adds a canonical link for drafts", async () => {
const draftStatuses = ["editor-draft-finding", "BG-DRAFT", "unofficial"];
for (const status of draftStatuses) {
const ops = makeStandardOps({ specStatus: status });
const doc = await makeRSDoc(ops);
expect(doc.querySelector("link[rel='canonical']"))
.withContext(draftStatuses)
.toBeNull();
}
});

it("handles tag documents correctly", async () => {
for (const specStatus of ["finding", "draft-finding"]) {
const ops = makeStandardOps({ specStatus });
const doc = await makeRSDoc(ops);
const path = publicationSpaces[specStatus];
const link = doc.querySelector("link[rel='canonical']");
expect(link.href).withContext(specStatus).toContain(path);
}
});

it("adds canonical link when if explicitly set", async () => {
const canonicalURI = "https://example.com/";
const ops = makeStandardOps({ canonicalURI });
const doc = await makeRSDoc(ops);
expect(
doc.querySelector(`link[rel='canonical'][href='${canonicalURI}']`)
).toBeTruthy();
});

it("adds canonicalURI links for types that require them", async () => {
for (const specStatus of requiresCanonicalLink) {
const ops = makeStandardOps({ specStatus });
const doc = await makeRSDoc(ops);
expect(doc.querySelector("link[rel='canonical']"))
.withContext(specStatus)
.toBeTruthy();
}
});

const body = `
Expand Down

0 comments on commit 58c6c74

Please sign in to comment.