diff --git a/src/core/title.js b/src/core/title.js index 912df79c35..9d2c2b7b4e 100644 --- a/src/core/title.js +++ b/src/core/title.js @@ -51,7 +51,18 @@ export function run(conf) { } // Decorate the spec title - if (!h1Elem.id) h1Elem.id = "title"; + if (!h1Elem.id) { + const existing = document.getElementById("title"); + if (existing && existing !== h1Elem) { + const msg = + 'Another element already uses `id="title"`. ' + + "The spec's `

` will use a different id to avoid a collision."; + showError(msg, name, { elements: [existing] }); + h1Elem.id = "document-title"; + } else { + h1Elem.id = "title"; + } + } h1Elem.classList.add("title"); setDocumentTitle(conf, h1Elem); diff --git a/tests/spec/core/title-spec.js b/tests/spec/core/title-spec.js new file mode 100644 index 0000000000..745fbefc94 --- /dev/null +++ b/tests/spec/core/title-spec.js @@ -0,0 +1,57 @@ +"use strict"; + +import { + flushIframes, + makeDefaultBody, + makeRSDoc, + makeStandardOps, +} from "../SpecHelper.js"; + +describe("Core — Title", () => { + afterAll(flushIframes); + + it("uses id='document-title' when another element already uses id='title'", async () => { + const body = ` + not the title +

My Spec Title

+ ${makeDefaultBody()} + `; + const ops = makeStandardOps(null, body); + const doc = await makeRSDoc(ops); + + // The h1 should fall back to id="document-title" + const h1 = doc.querySelector("h1.title"); + expect(h1).toBeTruthy(); + expect(h1.id).toBe("document-title"); + + // The original id="title" element should still exist + const original = doc.getElementById("title"); + expect(original).toBeTruthy(); + expect(original.localName).toBe("span"); + + // An error should have been shown + const errors = doc.respec.errors.filter( + err => err.plugin === "core/title" + ); + expect(errors).toHaveSize(1); + expect(errors[0].message).toContain('id="title"'); + }); + + it("uses id='title' normally when there is no collision", async () => { + const body = ` +

My Spec Title

+ ${makeDefaultBody()} + `; + const ops = makeStandardOps(null, body); + const doc = await makeRSDoc(ops); + + const h1 = doc.querySelector("h1#title"); + expect(h1).toBeTruthy(); + expect(h1.id).toBe("title"); + + const errors = doc.respec.errors.filter( + err => err.plugin === "core/title" + ); + expect(errors).toHaveSize(0); + }); +});