From a67967aa63ce691a6ddfa6fdbba70787b7cb2ea4 Mon Sep 17 00:00:00 2001 From: Colin Rotherham Date: Tue, 20 Jun 2023 08:11:00 +0100 Subject: [PATCH] Update Puppeteer tests to use ES modules not window globals An import map has been added to resolve `govuk-frontend` to `/javascripts/all.bundle.min.mjs` when run inside Puppeteer `page.evaluate()` --- package-lock.json | 4 +--- .../src/views/layouts/_generic.njk | 4 ++++ .../govuk/components/button/button.test.js | 8 +++---- .../character-count/character-count.test.js | 7 ++---- .../error-summary/error-summary.test.js | 12 +++++----- .../src/govuk/components/globals.test.mjs | 20 ++++++----------- shared/helpers/package.json | 1 + shared/helpers/puppeteer.js | 22 ++++++------------- 8 files changed, 31 insertions(+), 47 deletions(-) diff --git a/package-lock.json b/package-lock.json index b4feb691b7..3dcfb43511 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,9 +14,6 @@ "shared/*", "docs/examples/*" ], - "dependencies": { - "puppeteer": "^20.7.2" - }, "devDependencies": { "@babel/core": "^7.22.5", "@babel/preset-env": "^7.22.5", @@ -27656,6 +27653,7 @@ "devDependencies": { "@axe-core/puppeteer": "^4.7.3", "cheerio": "^1.0.0-rc.12", + "govuk-frontend": "*", "govuk-frontend-config": "*", "govuk-frontend-lib": "*", "jest-axe": "^7.0.1", diff --git a/packages/govuk-frontend-review/src/views/layouts/_generic.njk b/packages/govuk-frontend-review/src/views/layouts/_generic.njk index f1d89284f3..8d46795098 100644 --- a/packages/govuk-frontend-review/src/views/layouts/_generic.njk +++ b/packages/govuk-frontend-review/src/views/layouts/_generic.njk @@ -4,6 +4,10 @@ {% block styles %}{% endblock %} + + {% endblock %} {% block bodyStart %} diff --git a/packages/govuk-frontend/src/govuk/components/button/button.test.js b/packages/govuk-frontend/src/govuk/components/button/button.test.js index 0e302fc02c..96c6f9c602 100644 --- a/packages/govuk-frontend/src/govuk/components/button/button.test.js +++ b/packages/govuk-frontend/src/govuk/components/button/button.test.js @@ -18,14 +18,12 @@ describe('/components/button', () => { it('does not prevent further JavaScript from running', async () => { await goTo(page, '/tests/boilerplate') - const result = await page.evaluate((component) => { - const namespace = 'GOVUKFrontend' in window - ? window.GOVUKFrontend - : {} + const result = await page.evaluate(async (exportName) => { + const namespace = await import('govuk-frontend') // `undefined` simulates the element being missing, // from an unchecked `document.querySelector` for example - new namespace[component](undefined).init() + new namespace[exportName](undefined).init() // If our component initialisation breaks, this won't run return true diff --git a/packages/govuk-frontend/src/govuk/components/character-count/character-count.test.js b/packages/govuk-frontend/src/govuk/components/character-count/character-count.test.js index c3c2e6af78..0c0e8e603a 100644 --- a/packages/govuk-frontend/src/govuk/components/character-count/character-count.test.js +++ b/packages/govuk-frontend/src/govuk/components/character-count/character-count.test.js @@ -648,17 +648,14 @@ describe('Character count', () => { // Override maxlength to 10 maxlength: 10 }, - initialiser ({ config, namespace }) { - const $component = document.querySelector('[data-module]') - + initialiser ($module) { // Set locale to Welsh, which expects translations for 'one', 'two', // 'few' 'many' and 'other' forms – with the default English strings // provided we only have translations for 'one' and 'other'. // // We want to make sure we handle this gracefully in case users have // an existing character count inside an incorrect locale. - $component.setAttribute('lang', 'cy') - new namespace.CharacterCount($component, config).init() + $module.setAttribute('lang', 'cy') } }) diff --git a/packages/govuk-frontend/src/govuk/components/error-summary/error-summary.test.js b/packages/govuk-frontend/src/govuk/components/error-summary/error-summary.test.js index ba2211abbd..9321e1a1e1 100644 --- a/packages/govuk-frontend/src/govuk/components/error-summary/error-summary.test.js +++ b/packages/govuk-frontend/src/govuk/components/error-summary/error-summary.test.js @@ -1,4 +1,4 @@ -const { goToComponent, goToExample, renderAndInitialise } = require('govuk-frontend-helpers/puppeteer') +const { goToComponent, goToExample, renderAndInitialise, goTo } = require('govuk-frontend-helpers/puppeteer') const { getExamples } = require('govuk-frontend-lib/files') describe('Error Summary', () => { @@ -82,14 +82,14 @@ describe('Error Summary', () => { describe('using JavaScript configuration, with no elements on the page', () => { it('does not prevent further JavaScript from running', async () => { - const result = await page.evaluate((component) => { - const namespace = 'GOVUKFrontend' in window - ? window.GOVUKFrontend - : {} + await goTo(page, '/tests/boilerplate') + + const result = await page.evaluate(async (exportName) => { + const namespace = await import('govuk-frontend') // `undefined` simulates the element being missing, // from an unchecked `document.querySelector` for example - new namespace[component](undefined).init() + new namespace[exportName](undefined).init() // If our component initialisation breaks, this won't run return true diff --git a/packages/govuk-frontend/src/govuk/components/globals.test.mjs b/packages/govuk-frontend/src/govuk/components/globals.test.mjs index 81c36a860b..79137a284c 100644 --- a/packages/govuk-frontend/src/govuk/components/globals.test.mjs +++ b/packages/govuk-frontend/src/govuk/components/globals.test.mjs @@ -7,21 +7,17 @@ describe('GOV.UK Frontend', () => { beforeEach(async () => { await goTo(page, '/') - // Exported via global (e.g GOVUKFrontend.initAll) - exported = await page.evaluate(() => 'GOVUKFrontend' in window - ? Object.keys(window.GOVUKFrontend) - : undefined + // Exports available via browser dynamic import + exported = await page.evaluate(async () => + Object.keys(await import('govuk-frontend')) ) }) it('exports `initAll` function', async () => { await goTo(page, '/') - const typeofInitAll = await page.evaluate((utility) => { - const namespace = 'GOVUKFrontend' in window - ? window.GOVUKFrontend - : {} - + const typeofInitAll = await page.evaluate(async (utility) => { + const namespace = await import('govuk-frontend') return typeof namespace[utility] }, 'initAll') @@ -53,10 +49,8 @@ describe('GOV.UK Frontend', () => { const components = exported .filter(method => !['initAll', 'version'].includes(method)) - const componentsWithoutInitFunctions = await page.evaluate((components) => { - const namespace = 'GOVUKFrontend' in window - ? window.GOVUKFrontend - : {} + const componentsWithoutInitFunctions = await page.evaluate(async (components) => { + const namespace = await import('govuk-frontend') return components.filter(component => { const prototype = namespace[component].prototype diff --git a/shared/helpers/package.json b/shared/helpers/package.json index ddc4a983d8..3dcf9b14d8 100644 --- a/shared/helpers/package.json +++ b/shared/helpers/package.json @@ -16,6 +16,7 @@ "devDependencies": { "@axe-core/puppeteer": "^4.7.3", "cheerio": "^1.0.0-rc.12", + "govuk-frontend": "*", "govuk-frontend-config": "*", "govuk-frontend-lib": "*", "jest-axe": "^7.0.1", diff --git a/shared/helpers/puppeteer.js b/shared/helpers/puppeteer.js index c593bd6d75..18e549a390 100644 --- a/shared/helpers/puppeteer.js +++ b/shared/helpers/puppeteer.js @@ -76,9 +76,8 @@ async function axe (page, overrides = {}) { * @param {object} options - Render and initialise options * @param {object} options.params - Nunjucks macro params * @param {object} [options.config] - Component instantiation config - * @param {(context: { config?: object, namespace: object }) => void} [options.initialiser] - A function that'll run in the - * browser to execute arbitrary initialisation. Receives an object with the - * passed configuration as `config` and the GOVUKFrontend global as `namespace` + * @param {($module: Element) => void} [options.initialiser] - A function that'll run in the + * browser to execute arbitrary initialisation * @returns {Promise} Puppeteer page object */ async function renderAndInitialise (page, componentName, options) { @@ -92,22 +91,15 @@ async function renderAndInitialise (page, componentName, options) { }, html) // Run a script to init the JavaScript component - await page.evaluate((componentClassName, options) => { - const $component = document.querySelector('[data-module]') - - // Check for window global - if (!('GOVUKFrontend' in window) || !window.GOVUKFrontend[componentClassName]) { - throw new Error(`Global 'window.GOVUKFrontend.${componentClassName}' not found`) - } + await page.evaluate(async (exportName, options) => { + const $module = document.querySelector('[data-module]') if (options.initialiser) { - return options.initialiser({ - config: options.config, - namespace: window.GOVUKFrontend - }) + options.initialiser($module) } - new window.GOVUKFrontend[componentClassName]($component, options.config).init() + const namespace = await import('govuk-frontend') + new namespace[exportName]($module, options.config).init() }, componentNameToClassName(componentName), options) return page