diff --git a/src/core/best-practices.js b/src/core/best-practices.js
index ea48d5f2d1..b1877e6326 100644
--- a/src/core/best-practices.js
+++ b/src/core/best-practices.js
@@ -57,8 +57,13 @@ export function run() {
});
if (bps.length) {
if (bpSummary) {
- bpSummary.appendChild(html`
Best Practices Summary
`);
- if (summaryItems) bpSummary.appendChild(summaryItems);
+ const existingHeading = bpSummary.querySelector(
+ ":scope > :is(h1, h2, h3, h4, h5, h6)"
+ );
+ if (!existingHeading) {
+ bpSummary.prepend(html`Best Practices Summary
`);
+ }
+ if (summaryItems) bpSummary.append(summaryItems);
}
} else if (bpSummary) {
const msg = `Using best practices summary (#bp-summary) but no best practices found.`;
diff --git a/tests/spec/core/best-practices-spec.js b/tests/spec/core/best-practices-spec.js
index 6d4a1fdd77..0f4cd6461c 100644
--- a/tests/spec/core/best-practices-spec.js
+++ b/tests/spec/core/best-practices-spec.js
@@ -81,4 +81,29 @@ describe("Core — Best Practices", () => {
);
expect(bps.querySelectorAll("ul li")).toHaveSize(3);
});
+
+ it("does not duplicate heading when bp-summary already has one", async () => {
+ const body = `
+
+ `;
+ const ops = {
+ config: makeBasicConfig(),
+ body,
+ };
+ const doc = await makeRSDoc(ops);
+ const bpSummary = doc.getElementById("bp-summary");
+ const headings = bpSummary.querySelectorAll("h1, h2, h3, h4, h5, h6");
+ expect(headings).toHaveSize(1);
+ expect(headings[0].textContent).toContain("Custom Heading");
+
+ const listItems = bpSummary.querySelectorAll("ul li");
+ expect(listItems).toHaveSize(1);
+ expect(listItems[0].textContent.trim()).toBe("Best Practice 1: BP1");
+ });
});