diff --git a/__tests__/accessiblity-audit.test.js b/__tests__/accessiblity-audit.test.js index 73b0421aa4..2cd660d8a6 100644 --- a/__tests__/accessiblity-audit.test.js +++ b/__tests__/accessiblity-audit.test.js @@ -6,6 +6,7 @@ async function analyze (page, path) { await goTo(page, path) const axe = new AxePuppeteer(page) + .setLegacyMode(true) // Share single page via iframe .include('body') // axe reports there is "no label associated with the text field", when there is one. .exclude('#app-site-search__input') @@ -16,6 +17,8 @@ async function analyze (page, path) { .exclude('.govuk-skip-link') // axe reports that the back to top button is not inside a landmark, which is intentional. .exclude('.app-back-to-top') + // axe reports that the Browsersync banner is not inside a landmark, which is intentional. + .exclude('#__bs_notify__') // axe reports that the frame "does not have a main landmark" and example

headings // violate "Heading levels should only increase by one", which is intentional. // https://github.com/alphagov/govuk-design-system/pull/2442#issuecomment-1326600528 diff --git a/__tests__/cookie-banner.test.js b/__tests__/cookie-banner.test.js index ff6731c916..06242c1aac 100644 --- a/__tests__/cookie-banner.test.js +++ b/__tests__/cookie-banner.test.js @@ -17,7 +17,7 @@ describe('Cookie banner', () => { const cookieParam = { name: 'design_system_cookies_policy', value: JSON.stringify({ analytics: true, version: 1 }), - url: `http://localhost:${configPaths.testPort}` + url: `http://localhost:${configPaths.port}` } async function setup (page) { diff --git a/__tests__/cookies-page.test.js b/__tests__/cookies-page.test.js index 3403fc09ff..f437b47bd8 100644 --- a/__tests__/cookies-page.test.js +++ b/__tests__/cookies-page.test.js @@ -19,7 +19,7 @@ describe('Cookies page', () => { beforeEach(async () => { await page.deleteCookie({ name: 'design_system_cookies_policy', - url: `http://localhost:${configPaths.testPort}` + url: `http://localhost:${configPaths.port}` }) await page.setJavaScriptEnabled(true) diff --git a/config/paths.json b/config/paths.json index 6fd592cad2..4273f4b20e 100644 --- a/config/paths.json +++ b/config/paths.json @@ -15,6 +15,5 @@ "views": "views/", "layouts": "views/layouts/", "partials": "views/partials/", - "port": 3000, - "testPort": 3333 + "port": 3000 } diff --git a/jest-puppeteer.config.js b/jest-puppeteer.config.js index 86cd7b2023..777858e26a 100644 --- a/jest-puppeteer.config.js +++ b/jest-puppeteer.config.js @@ -1,9 +1,34 @@ const configPaths = require('./lib/paths.js') +/** + * @type {import('jest-environment-puppeteer').JestPuppeteerConfig} + */ module.exports = { browserContext: 'incognito', + + /** + * Puppeteer launch options + */ + launch: { + /** + * Allow headless mode switching using `HEADLESS=false` + * but default to `new` to skip deprecation warning + * + * {@link https://developer.chrome.com/articles/new-headless/} + */ + headless: process.env.HEADLESS !== 'false' + ? 'new' + : false + }, + + /** + * Development server options + */ server: { command: 'npm run serve', - port: configPaths.testPort + port: configPaths.port, + + // Skip when already running + usedPortAction: 'ignore' } } diff --git a/jest.config.mjs b/jest.config.mjs index 366f55689b..8c5da8eb13 100644 --- a/jest.config.mjs +++ b/jest.config.mjs @@ -1,6 +1,21 @@ +import jestPuppeteerConfig from './jest-puppeteer.config.js' + +// Detect when browser has been launched headless +const { headless } = jestPuppeteerConfig.launch + +/** + * Jest config + * + * @type {import('@jest/types').Config.InitialOptions} + */ export default { preset: 'jest-puppeteer', + // Reduce CPU usage during project test runs + maxWorkers: headless + ? '50%' // Matches Jest default (50%) via `--watch` + : 1, // Use only 1x browser window when headless + // Custom matchers setupFilesAfterEnv: ['./config/jest/matchers.js'], diff --git a/lib/puppeteer-helpers.js b/lib/puppeteer-helpers.js index d7feed91f0..086ccb421a 100644 --- a/lib/puppeteer-helpers.js +++ b/lib/puppeteer-helpers.js @@ -1,7 +1,5 @@ const configPaths = require('../lib/paths.js') -const PORT = configPaths.testPort - /** * Navigate to path * @@ -10,7 +8,7 @@ const PORT = configPaths.testPort * @returns {Promise} Puppeteer page object */ async function goTo (page, path) { - const { href } = new URL(path, `http://localhost:${PORT}`) + const { href } = new URL(path, `http://localhost:${configPaths.port}`) // Navigate to blank page first to fix same page // hash fragment changes (window.location.hash) diff --git a/package-lock.json b/package-lock.json index c90fe81443..12dad7384b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -55,7 +55,7 @@ "metalsmith-renamer": "^0.5.217", "nunjucks": "^3.2.4", "outdent": "^0.8.0", - "puppeteer": "^19.10.1", + "puppeteer": "^20.2.0", "rollup": "^3.21.7", "sitemap": "^7.1.1", "slash": "^3.0.0", @@ -2731,13 +2731,14 @@ } }, "node_modules/@puppeteer/browsers": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-0.5.0.tgz", - "integrity": "sha512-Uw6oB7VvmPRLE4iKsjuOh8zgDabhNX67dzo8U/BB0f9527qx+4eeUs+korU98OhG5C4ubg7ufBgVi63XYwS6TQ==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.3.0.tgz", + "integrity": "sha512-an3QdbNPkuU6qpxpbssxAbjRLJcF+eP4L8UqIY3+6n0sbaVxw5pz7PiCLy9g32XEZuoamUlV5ZQPnA6FxvkIHA==", "dev": true, "dependencies": { "debug": "4.3.4", "extract-zip": "2.0.1", + "http-proxy-agent": "5.0.0", "https-proxy-agent": "5.0.1", "progress": "2.0.3", "proxy-from-env": "1.1.0", @@ -2749,7 +2750,7 @@ "browsers": "lib/cjs/main-cli.js" }, "engines": { - "node": ">=14.1.0" + "node": ">=16.0.0" }, "peerDependencies": { "typescript": ">= 4.7.4" @@ -4877,9 +4878,9 @@ "dev": true }, "node_modules/chromium-bidi": { - "version": "0.4.6", - "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.6.tgz", - "integrity": "sha512-TQOkWRaLI/IWvoP8XC+7jO4uHTIiAUiklXU1T0qszlUFEai9LgKXIBXy3pOS3EnQZ3bQtMbKUPkug0fTAEHCSw==", + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.9.tgz", + "integrity": "sha512-u3DC6XwgLCA9QJ5ak1voPslCmacQdulZNCPsI3qNXxSnEcZS7DFIbww+5RM2bznMEje7cc0oydavRLRvOIZtHw==", "dev": true, "dependencies": { "mitt": "3.0.0" @@ -5555,9 +5556,9 @@ } }, "node_modules/devtools-protocol": { - "version": "0.0.1107588", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1107588.tgz", - "integrity": "sha512-yIR+pG9x65Xko7bErCUSQaDLrO/P1p3JUzEk7JCU4DowPcGHkTGUGQapcfcLc4qj0UaALwZ+cr0riFgiqpixcg==", + "version": "0.0.1120988", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1120988.tgz", + "integrity": "sha512-39fCpE3Z78IaIPChJsP6Lhmkbf4dWXOmzLk/KFTdRkNk/0JymRIfUynDVRndV9HoDz8PyalK1UH21ST/ivwW5Q==", "dev": true }, "node_modules/diff": { @@ -12012,40 +12013,32 @@ } }, "node_modules/puppeteer": { - "version": "19.10.1", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-19.10.1.tgz", - "integrity": "sha512-HqpY8sWqz28JfyZE8cGG9kBPgASD7iRHn/ryWLvVLXE10poR5AyU/mMsLmL175qoYl/chwMTN2pxKSz7HobaCg==", + "version": "20.2.1", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-20.2.1.tgz", + "integrity": "sha512-XWHlNCJf1u+i5AzakXj1PlNOTYcFcAwAunQj/urFKzKaZ7WTChlAo710W+TlEE2SJKshEZTwilMDDkVvwadLTQ==", "dev": true, "hasInstallScript": true, "dependencies": { - "@puppeteer/browsers": "0.5.0", + "@puppeteer/browsers": "1.3.0", "cosmiconfig": "8.1.3", - "https-proxy-agent": "5.0.1", - "progress": "2.0.3", - "proxy-from-env": "1.1.0", - "puppeteer-core": "19.10.1" + "puppeteer-core": "20.2.1" } }, "node_modules/puppeteer-core": { - "version": "19.10.1", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-19.10.1.tgz", - "integrity": "sha512-vD4ojslBtnIWd56IQIEADIcAWrNel/Qt7YGlAxcSNB0b33U3tYe0A+0FLmPNgSa7UTlCOCCVEmzXi5QlDtLGjQ==", + "version": "20.2.1", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.2.1.tgz", + "integrity": "sha512-HmNMcL+g9ght0nCzS5BmEvom2IVhp1/xhlQ9O+fmihQx0EYwYUqgCQhs8Hbv7IapiqKhahKCC8PKfCNTXXsKbQ==", "dev": true, "dependencies": { - "@puppeteer/browsers": "0.5.0", - "chromium-bidi": "0.4.6", + "@puppeteer/browsers": "1.3.0", + "chromium-bidi": "0.4.9", "cross-fetch": "3.1.5", "debug": "4.3.4", - "devtools-protocol": "0.0.1107588", - "extract-zip": "2.0.1", - "https-proxy-agent": "5.0.1", - "proxy-from-env": "1.1.0", - "tar-fs": "2.1.1", - "unbzip2-stream": "1.4.3", + "devtools-protocol": "0.0.1120988", "ws": "8.13.0" }, "engines": { - "node": ">=14.14.0" + "node": ">=16.0.0" }, "peerDependencies": { "typescript": ">= 4.7.4" @@ -17434,13 +17427,14 @@ "optional": true }, "@puppeteer/browsers": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-0.5.0.tgz", - "integrity": "sha512-Uw6oB7VvmPRLE4iKsjuOh8zgDabhNX67dzo8U/BB0f9527qx+4eeUs+korU98OhG5C4ubg7ufBgVi63XYwS6TQ==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-1.3.0.tgz", + "integrity": "sha512-an3QdbNPkuU6qpxpbssxAbjRLJcF+eP4L8UqIY3+6n0sbaVxw5pz7PiCLy9g32XEZuoamUlV5ZQPnA6FxvkIHA==", "dev": true, "requires": { "debug": "4.3.4", "extract-zip": "2.0.1", + "http-proxy-agent": "5.0.0", "https-proxy-agent": "5.0.1", "progress": "2.0.3", "proxy-from-env": "1.1.0", @@ -19094,9 +19088,9 @@ "dev": true }, "chromium-bidi": { - "version": "0.4.6", - "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.6.tgz", - "integrity": "sha512-TQOkWRaLI/IWvoP8XC+7jO4uHTIiAUiklXU1T0qszlUFEai9LgKXIBXy3pOS3EnQZ3bQtMbKUPkug0fTAEHCSw==", + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.4.9.tgz", + "integrity": "sha512-u3DC6XwgLCA9QJ5ak1voPslCmacQdulZNCPsI3qNXxSnEcZS7DFIbww+5RM2bznMEje7cc0oydavRLRvOIZtHw==", "dev": true, "requires": { "mitt": "3.0.0" @@ -19608,9 +19602,9 @@ "dev": true }, "devtools-protocol": { - "version": "0.0.1107588", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1107588.tgz", - "integrity": "sha512-yIR+pG9x65Xko7bErCUSQaDLrO/P1p3JUzEk7JCU4DowPcGHkTGUGQapcfcLc4qj0UaALwZ+cr0riFgiqpixcg==", + "version": "0.0.1120988", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1120988.tgz", + "integrity": "sha512-39fCpE3Z78IaIPChJsP6Lhmkbf4dWXOmzLk/KFTdRkNk/0JymRIfUynDVRndV9HoDz8PyalK1UH21ST/ivwW5Q==", "dev": true }, "diff": { @@ -24276,17 +24270,14 @@ "dev": true }, "puppeteer": { - "version": "19.10.1", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-19.10.1.tgz", - "integrity": "sha512-HqpY8sWqz28JfyZE8cGG9kBPgASD7iRHn/ryWLvVLXE10poR5AyU/mMsLmL175qoYl/chwMTN2pxKSz7HobaCg==", + "version": "20.2.1", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-20.2.1.tgz", + "integrity": "sha512-XWHlNCJf1u+i5AzakXj1PlNOTYcFcAwAunQj/urFKzKaZ7WTChlAo710W+TlEE2SJKshEZTwilMDDkVvwadLTQ==", "dev": true, "requires": { - "@puppeteer/browsers": "0.5.0", + "@puppeteer/browsers": "1.3.0", "cosmiconfig": "8.1.3", - "https-proxy-agent": "5.0.1", - "progress": "2.0.3", - "proxy-from-env": "1.1.0", - "puppeteer-core": "19.10.1" + "puppeteer-core": "20.2.1" }, "dependencies": { "argparse": { @@ -24331,21 +24322,16 @@ } }, "puppeteer-core": { - "version": "19.10.1", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-19.10.1.tgz", - "integrity": "sha512-vD4ojslBtnIWd56IQIEADIcAWrNel/Qt7YGlAxcSNB0b33U3tYe0A+0FLmPNgSa7UTlCOCCVEmzXi5QlDtLGjQ==", + "version": "20.2.1", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-20.2.1.tgz", + "integrity": "sha512-HmNMcL+g9ght0nCzS5BmEvom2IVhp1/xhlQ9O+fmihQx0EYwYUqgCQhs8Hbv7IapiqKhahKCC8PKfCNTXXsKbQ==", "dev": true, "requires": { - "@puppeteer/browsers": "0.5.0", - "chromium-bidi": "0.4.6", + "@puppeteer/browsers": "1.3.0", + "chromium-bidi": "0.4.9", "cross-fetch": "3.1.5", "debug": "4.3.4", - "devtools-protocol": "0.0.1107588", - "extract-zip": "2.0.1", - "https-proxy-agent": "5.0.1", - "proxy-from-env": "1.1.0", - "tar-fs": "2.1.1", - "unbzip2-stream": "1.4.3", + "devtools-protocol": "0.0.1120988", "ws": "8.13.0" }, "dependencies": { diff --git a/package.json b/package.json index 4e91a92136..5c838cf22f 100644 --- a/package.json +++ b/package.json @@ -74,7 +74,7 @@ "metalsmith-renamer": "^0.5.217", "nunjucks": "^3.2.4", "outdent": "^0.8.0", - "puppeteer": "^19.10.1", + "puppeteer": "^20.2.0", "rollup": "^3.21.7", "sitemap": "^7.1.1", "slash": "^3.0.0", diff --git a/tasks/serve.js b/tasks/serve.js index 1ddfbdf07d..b7e3db5f75 100644 --- a/tasks/serve.js +++ b/tasks/serve.js @@ -9,6 +9,6 @@ const paths = require('../lib/paths.js') const app = connect().use(serveStatic(paths.public)) const server = createServer(app) -server.listen(paths.testPort, () => { - console.log(`Server started at http://localhost:${paths.testPort}`) +server.listen(paths.port, () => { + console.log(`Server started at http://localhost:${paths.port}`) })