diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 51514d145e..59725d48fa 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -24,6 +24,7 @@ Changelog * Fix: Ensure that JS slugify function strips Unicode characters disallowed by Django slug validation (Atif Khan) * Fix: Do not show notices about root / unroutable pages when searching or filtering in the page explorer (Matt Westcott) * Fix: Resolve contrast issue for page deletion warning (Sanjeev Holla S) + * Fix: Make sure content metrics falls back to body element only when intended (Sage Abdullah) * Docs: Upgrade Sphinx to 7.3 (Matt Westcott) * Docs: Document how to customize date/time format settings (Vince Salvino) * Docs: Create a new documentation section for deployment and move fly.io deployment from the tutorial to this section (Vince Salvino) @@ -49,6 +50,7 @@ Changelog * Fix: Fix various instances of `USE_THOUSAND_SEPARATOR` formatting numbers where formatting is invalid (Sébastien Corbin, Matt Westcott) * Fix: Fix broken link to user search (Shlomo Markowitz) + * Fix: Make sure content metrics falls back to body element only when intended (Sage Abdullah) * Docs: Clarify process for UserViewSet customisation (Sage Abdullah) diff --git a/client/src/controllers/PreviewController.ts b/client/src/controllers/PreviewController.ts index 502c34c10e..e4ece271f3 100644 --- a/client/src/controllers/PreviewController.ts +++ b/client/src/controllers/PreviewController.ts @@ -22,7 +22,7 @@ const runContentChecks = async () => { axe.registerPlugin(wagtailPreviewPlugin); const contentMetrics = await getPreviewContentMetrics({ - targetElement: 'main, [role="main"], body', + targetElement: 'main, [role="main"]', }); // This requires Wagtail's preview plugin for axe to be registered in the diff --git a/client/src/includes/contentMetrics.test.ts b/client/src/includes/contentMetrics.test.ts index 9e55df2cd6..7437f7f30a 100644 --- a/client/src/includes/contentMetrics.test.ts +++ b/client/src/includes/contentMetrics.test.ts @@ -1,4 +1,8 @@ -import { getWordCount, getReadingTime } from './contentMetrics'; +import { + getWordCount, + getReadingTime, + contentMetricsPluginInstance, +} from './contentMetrics'; describe.each` text | lang | wordCount @@ -38,3 +42,50 @@ describe.each` expect(getReadingTime(lang, wordCount)).toBe(readingTime); }); }); + +describe('contentMetricsPluginInstance', () => { + let originalInnerText; + beforeAll(() => { + originalInnerText = Object.getOwnPropertyDescriptor( + HTMLElement.prototype, + 'innerText', + ); + }); + + beforeEach(() => { + document.body.innerHTML = ` +
+

Test content

+
+
Something else
+ `; + + // innerText is not implemented in JSDOM + // https://github.com/jsdom/jsdom/issues/1245 + Object.defineProperty(HTMLElement.prototype, 'innerText', { + configurable: true, + get() { + return this.textContent; + }, + }); + }); + + afterAll(() => { + Object.defineProperty(HTMLElement.prototype, 'innerText', { + configurable: true, + value: originalInnerText, + }); + }); + + it('should use the specified selector', () => { + const done = jest.fn(); + contentMetricsPluginInstance.getMetrics({ targetElement: 'main' }, done); + expect(done).toHaveBeenCalledWith({ wordCount: 2, readingTime: 0 }); + }); + + it('should fall back to the body element if the selector does not match any elements', () => { + const done = jest.fn(); + contentMetricsPluginInstance.getMetrics({ targetElement: 'article' }, done); + expect(done).toHaveBeenCalledWith({ wordCount: 4, readingTime: 0 }); + }); +}); diff --git a/client/src/includes/contentMetrics.ts b/client/src/includes/contentMetrics.ts index 97bc531153..cd2cae3cba 100644 --- a/client/src/includes/contentMetrics.ts +++ b/client/src/includes/contentMetrics.ts @@ -61,7 +61,9 @@ export const contentMetricsPluginInstance = { options: ContentMetricsOptions, done: (metrics: ContentMetrics) => void, ) { - const main = document.querySelector(options.targetElement); + const main = + document.querySelector(options.targetElement) || + document.body; // Fallback to the body only if the target element is not found const text = main?.innerText || ''; const lang = document.documentElement.lang || 'en'; const wordCount = getWordCount(lang, text); diff --git a/docs/releases/6.2.2.md b/docs/releases/6.2.2.md index 53779ce74a..e976175b75 100644 --- a/docs/releases/6.2.2.md +++ b/docs/releases/6.2.2.md @@ -16,6 +16,7 @@ depth: 1 * Fix various instances of `USE_THOUSAND_SEPARATOR` formatting numbers where formatting is invalid (Sébastien Corbin, Matt Westcott) * Fix broken link to user search (Shlomo Markowitz) + * Make sure content metrics falls back to body element only when intended (Sage Abdullah) ### Documentation diff --git a/docs/releases/6.3.md b/docs/releases/6.3.md index 55987491da..0671b9032b 100644 --- a/docs/releases/6.3.md +++ b/docs/releases/6.3.md @@ -39,6 +39,7 @@ This release adds formal support for Django 5.1. * Ensure that JS slugify function strips Unicode characters disallowed by Django slug validation (Atif Khan) * Do not show notices about root / unroutable pages when searching or filtering in the page explorer (Matt Westcott) * Resolve contrast issue for page deletion warning (Sanjeev Holla S) + * Make sure content metrics falls back to body element only when intended (Sage Abdullah) ### Documentation