From 7b63774b918b0da83b6e7adb47fc4a6f673bbd54 Mon Sep 17 00:00:00 2001 From: Jani Kraner Date: Tue, 17 Dec 2024 15:07:17 +0000 Subject: [PATCH 1/7] Rewrite errorBanner as ES module --- app/assets/javascripts/errorBanner.js | 17 -------- app/assets/javascripts/esm/error-banner.mjs | 43 +++++++++++++++++++ rollup.config.mjs | 1 - ...orBanner.test.js => error-banner.test.mjs} | 13 +++--- 4 files changed, 49 insertions(+), 25 deletions(-) delete mode 100644 app/assets/javascripts/errorBanner.js create mode 100644 app/assets/javascripts/esm/error-banner.mjs rename tests/javascripts/{errorBanner.test.js => error-banner.test.mjs} (79%) diff --git a/app/assets/javascripts/errorBanner.js b/app/assets/javascripts/errorBanner.js deleted file mode 100644 index 7b7f94cd38..0000000000 --- a/app/assets/javascripts/errorBanner.js +++ /dev/null @@ -1,17 +0,0 @@ -(function (window) { - "use strict"; - - /* - This module is intended to be used to show and hide an error banner based on a javascript trigger. You should make - sure the banner has an appropriate aria-live attribute, and a tabindex of -1 so that screenreaders and keyboard users - are alerted to the change respectively. - - This may behave in unexpected ways if you have more than one element with the `govuk-error-summary` class on your page. - */ - window.GOVUK.ErrorBanner = { - hideBanner: () => $('.govuk-error-summary').addClass('govuk-!-display-none'), - showBanner: () => $('.govuk-error-summary') - .removeClass('govuk-!-display-none') - .trigger('focus'), - }; -})(window); diff --git a/app/assets/javascripts/esm/error-banner.mjs b/app/assets/javascripts/esm/error-banner.mjs new file mode 100644 index 0000000000..ef989e59cd --- /dev/null +++ b/app/assets/javascripts/esm/error-banner.mjs @@ -0,0 +1,43 @@ +import { isSupported } from 'govuk-frontend'; + +// This new way of writing Javascript components is based on the GOV.UK Frontend skeleton Javascript coding standard +// that uses ES2015 Classes - +// https://github.com/alphagov/govuk-frontend/blob/main/docs/contributing/coding-standards/js.md#skeleton +// +// It replaces the previously used way of setting methods on the component's `prototype`. +// We use a class declaration way of defining classes - +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/class +// +// More on ES2015 Classes at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes + +class ErrorBanner { + /* + This module is intended to be used to show and hide an error banner based on a javascript trigger. You should make + sure the banner has an appropriate aria-live attribute, and a tabindex of -1 so that screenreaders and keyboard users + are alerted to the change respectively. + + This may behave in unexpected ways if you have more than one element with the `govuk-error-summary` class on your page. + */ + constructor() { + if (!isSupported()) { + return this; + } + // yes some pages have more than one error summary on the page + // depending on if there's no JS or no webuth support + this.errorSummaryArray = document.querySelectorAll('.govuk-error-summary'); + } + hideBanner() { + this.errorSummaryArray.forEach(errorSummary => { + errorSummary.classList.add('govuk-!-display-none'); + }); + } + showBanner() { + this.errorSummaryArray.forEach(errorSummary => { + errorSummary.classList.remove('govuk-!-display-none'); + // is works as before but it feels strange to apply focus to all + errorSummary.focus(); + }); + } +} + +export default ErrorBanner; diff --git a/rollup.config.mjs b/rollup.config.mjs index fb481a69d5..e2dd645126 100644 --- a/rollup.config.mjs +++ b/rollup.config.mjs @@ -102,7 +102,6 @@ export default [ paths.src + 'javascripts/registerSecurityKey.js', paths.src + 'javascripts/authenticateSecurityKey.js', paths.src + 'javascripts/updateStatus.js', - paths.src + 'javascripts/errorBanner.js', paths.src + 'javascripts/homepage.js', paths.src + 'javascripts/removeInPresenceOf.js', paths.src + 'javascripts/main.js', diff --git a/tests/javascripts/errorBanner.test.js b/tests/javascripts/error-banner.test.mjs similarity index 79% rename from tests/javascripts/errorBanner.test.js rename to tests/javascripts/error-banner.test.mjs index ade1621fa1..2d3485f799 100644 --- a/tests/javascripts/errorBanner.test.js +++ b/tests/javascripts/error-banner.test.mjs @@ -1,9 +1,8 @@ -beforeAll(() => { - require('../../app/assets/javascripts/errorBanner.js') -}); +import ErrorBanner from "../../app/assets/javascripts/esm/error-banner.mjs"; -afterAll(() => { - require('./support/teardown.js'); +beforeAll(() => { + // add class to mimic IRL + document.body.classList.add('govuk-frontend-supported') }); describe("Error Banner", () => { @@ -16,7 +15,7 @@ describe("Error Banner", () => { document.body.innerHTML = ` `; - window.GOVUK.ErrorBanner.hideBanner(); + new ErrorBanner().hideBanner(); expect(document.querySelector('.govuk-error-summary').classList).toContain('govuk-!-display-none') }); }); @@ -27,7 +26,7 @@ describe("Error Banner", () => { `; - window.GOVUK.ErrorBanner.showBanner('Some Err'); + new ErrorBanner().showBanner('Some Err'); }); test("Will show the element", () => { From b056c2cd700ba44f74e589bf6354b25508df85a9 Mon Sep 17 00:00:00 2001 From: Jani Kraner Date: Wed, 18 Dec 2024 12:47:37 +0000 Subject: [PATCH 2/7] Rewrite authenticateSecurityKey as ES Module --- .../javascripts/authenticateSecurityKey.js | 74 --------------- app/assets/javascripts/esm/all-esm.mjs | 6 ++ .../esm/authenticate-security-key.mjs | 94 +++++++++++++++++++ rollup.config.mjs | 1 - 4 files changed, 100 insertions(+), 75 deletions(-) delete mode 100644 app/assets/javascripts/authenticateSecurityKey.js create mode 100644 app/assets/javascripts/esm/authenticate-security-key.mjs diff --git a/app/assets/javascripts/authenticateSecurityKey.js b/app/assets/javascripts/authenticateSecurityKey.js deleted file mode 100644 index 033e100795..0000000000 --- a/app/assets/javascripts/authenticateSecurityKey.js +++ /dev/null @@ -1,74 +0,0 @@ -(function (window) { - "use strict"; - - window.GOVUK.NotifyModules.AuthenticateSecurityKey = function () { - this.start = function (component) { - $(component) - .on('click', function (event) { - event.preventDefault(); - - // hide any existing error prompt - window.GOVUK.ErrorBanner.hideBanner(); - - fetch('/webauthn/authenticate') - .then(response => { - if (!response.ok) { - throw Error(response.statusText); - } - - return response.arrayBuffer(); - }) - .then(data => { - var options = window.CBOR.decode(data); - // triggers browser dialogue to login with authenticator - return window.navigator.credentials.get(options); - }) - .then(credential => { - const currentURL = new URL(window.location.href); - - // create authenticateURL from admin hostname plus /webauthn/authenticate path - const authenticateURL = new URL('/webauthn/authenticate', window.location.href); - - const nextUrl = currentURL.searchParams.get('next'); - if (nextUrl) { - // takes nextUrl from the query string on the current browser URL - // (which should be /two-factor-webauthn) and pass it through to - // the POST. put it in a query string so it's consistent with how - // the other login flows manage it - authenticateURL.searchParams.set('next', nextUrl); - } - - return fetch(authenticateURL, { - method: 'POST', - headers: { 'X-CSRFToken': component.data('csrfToken') }, - body: window.CBOR.encode({ - credentialId: new Uint8Array(credential.rawId), - authenticatorData: new Uint8Array(credential.response.authenticatorData), - signature: new Uint8Array(credential.response.signature), - clientDataJSON: new Uint8Array(credential.response.clientDataJSON), - }) - }); - }) - .then(response => { - if (!response.ok) { - throw Error(response.statusText); - } - - return response.arrayBuffer(); - }) - .then(cbor => { - return Promise.resolve(window.CBOR.decode(cbor)); - }) - .then(data => { - window.location.assign(data.redirect_url); - }) - .catch(error => { - console.error(error); - // some browsers will show an error dialogue for some - // errors; to be safe we always display an error message on the page. - window.GOVUK.ErrorBanner.showBanner(); - }); - }); - }; - }; -}) (window); diff --git a/app/assets/javascripts/esm/all-esm.mjs b/app/assets/javascripts/esm/all-esm.mjs index f575ece78b..e575710930 100644 --- a/app/assets/javascripts/esm/all-esm.mjs +++ b/app/assets/javascripts/esm/all-esm.mjs @@ -6,6 +6,7 @@ import FocusBanner from './focus-banner.mjs'; import ColourPreview from './colour-preview.mjs'; import FileUpload from './file-upload.mjs'; import Autofocus from './autofocus.mjs'; +import AuthenticateSecurityKey from './authenticate-security-key.mjs'; // Modules from 3rd party vendors import morphdom from 'morphdom'; @@ -37,6 +38,11 @@ if ($autoFocus) { new Autofocus($autoFocus); } +const $authenticateSecurityKey = document.querySelector('[data-notify-module="authenticate-security-key"]'); +if ($authenticateSecurityKey) { + new AuthenticateSecurityKey($authenticateSecurityKey); +} + const focusBanner = new FocusBanner(); // ES modules do not export to global so in order to diff --git a/app/assets/javascripts/esm/authenticate-security-key.mjs b/app/assets/javascripts/esm/authenticate-security-key.mjs new file mode 100644 index 0000000000..0dea5383fb --- /dev/null +++ b/app/assets/javascripts/esm/authenticate-security-key.mjs @@ -0,0 +1,94 @@ +import { isSupported } from 'govuk-frontend'; +import ErrorBanner from './error-banner.mjs'; + +// This new way of writing Javascript components is based on the GOV.UK Frontend skeleton Javascript coding standard +// that uses ES2015 Classes - +// https://github.com/alphagov/govuk-frontend/blob/main/docs/contributing/coding-standards/js.md#skeleton +// +// It replaces the previously used way of setting methods on the component's `prototype`. +// We use a class declaration way of defining classes - +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/class +// +// More on ES2015 Classes at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes + +class AuthenticateSecurityKey { + constructor($module) { + if (!isSupported()) { + return this; + } + this.authenticatePath = '/webauthn/authenticate'; + this.$module = $module; + + this.$module.addEventListener("click", () => { + new ErrorBanner().hideBanner(); + this.getAuthentication(); + }); + } + getAuthentication() { + fetch(this.authenticatePath) + .then(response => { + if (!response.ok) { + throw Error(response.statusText); + } + + return response.arrayBuffer(); + }) + .then(data => { + var options = window.CBOR.decode(data); + // triggers browser dialogue to login with authenticator + return window.navigator.credentials.get(options); + }) + .then(credential => { + const currentURL = new URL(window.location.href); + + // create authenticateURL from admin hostname plus /webauthn/authenticate path + const authenticateURL = new URL(this.authenticatePath, window.location.href); + + const nextUrl = currentURL.searchParams.get('next'); + if (nextUrl) { + // takes nextUrl from the query string on the current browser URL + // (which should be /two-factor-webauthn) and pass it through to + // the POST. put it in a query string so it's consistent with how + // the other login flows manage it + authenticateURL.searchParams.set('next', nextUrl); + } + + return this.postWebAuthnCreateResponse( + credential, this.$module.dataset.csrfToken + ); + }) + .then(response => { + if (!response.ok) { + throw Error(response.statusText); + } + + return response.arrayBuffer(); + }) + .then(cbor => { + return Promise.resolve(window.CBOR.decode(cbor)); + }) + .then(data => { + window.location.assign(data.redirect_url); + }) + .catch(error => { + console.error(error); + // some browsers will show an error dialogue for some + // errors; to be safe we always display an error message on the page. + new ErrorBanner().showBanner(); + }); + } + postWebAuthnCreateResponse(credential, csrf_token) { + return fetch(this.authenticatePath, { + method: 'POST', + headers: { 'X-CSRFToken': csrf_token }, + body: window.CBOR.encode({ + credentialId: new Uint8Array(credential.rawId), + authenticatorData: new Uint8Array(credential.response.authenticatorData), + signature: new Uint8Array(credential.response.signature), + clientDataJSON: new Uint8Array(credential.response.clientDataJSON), + }) + }); + } +} + +export default AuthenticateSecurityKey; diff --git a/rollup.config.mjs b/rollup.config.mjs index e2dd645126..ecc756ff2e 100644 --- a/rollup.config.mjs +++ b/rollup.config.mjs @@ -100,7 +100,6 @@ export default [ paths.src + 'javascripts/addBrandingOptionsForm.js', paths.src + 'javascripts/setAuthTypeForm.js', paths.src + 'javascripts/registerSecurityKey.js', - paths.src + 'javascripts/authenticateSecurityKey.js', paths.src + 'javascripts/updateStatus.js', paths.src + 'javascripts/homepage.js', paths.src + 'javascripts/removeInPresenceOf.js', From 2caf0c1361ef3f7593ed6986a54b71d3e5d1cb2c Mon Sep 17 00:00:00 2001 From: Jani Kraner Date: Wed, 18 Dec 2024 12:47:58 +0000 Subject: [PATCH 3/7] Rewrite registerSecurityKey as ES Module --- app/assets/javascripts/esm/all-esm.mjs | 6 ++ .../javascripts/esm/register-security-key.mjs | 72 +++++++++++++++++++ app/assets/javascripts/registerSecurityKey.js | 58 --------------- rollup.config.mjs | 1 - 4 files changed, 78 insertions(+), 59 deletions(-) create mode 100644 app/assets/javascripts/esm/register-security-key.mjs delete mode 100644 app/assets/javascripts/registerSecurityKey.js diff --git a/app/assets/javascripts/esm/all-esm.mjs b/app/assets/javascripts/esm/all-esm.mjs index e575710930..ab736adc76 100644 --- a/app/assets/javascripts/esm/all-esm.mjs +++ b/app/assets/javascripts/esm/all-esm.mjs @@ -7,6 +7,7 @@ import ColourPreview from './colour-preview.mjs'; import FileUpload from './file-upload.mjs'; import Autofocus from './autofocus.mjs'; import AuthenticateSecurityKey from './authenticate-security-key.mjs'; +import RegisterSecurityKey from './register-security-key.mjs'; // Modules from 3rd party vendors import morphdom from 'morphdom'; @@ -43,6 +44,11 @@ if ($authenticateSecurityKey) { new AuthenticateSecurityKey($authenticateSecurityKey); } +const $registerSecurityKey = document.querySelector('[data-notify-module="register-security-key"]'); +if ($registerSecurityKey) { + new RegisterSecurityKey($registerSecurityKey); +} + const focusBanner = new FocusBanner(); // ES modules do not export to global so in order to diff --git a/app/assets/javascripts/esm/register-security-key.mjs b/app/assets/javascripts/esm/register-security-key.mjs new file mode 100644 index 0000000000..c3df26c991 --- /dev/null +++ b/app/assets/javascripts/esm/register-security-key.mjs @@ -0,0 +1,72 @@ +import { isSupported } from 'govuk-frontend'; +import ErrorBanner from './error-banner.mjs'; + +// This new way of writing Javascript components is based on the GOV.UK Frontend skeleton Javascript coding standard +// that uses ES2015 Classes - +// https://github.com/alphagov/govuk-frontend/blob/main/docs/contributing/coding-standards/js.md#skeleton +// +// It replaces the previously used way of setting methods on the component's `prototype`. +// We use a class declaration way of defining classes - +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/class +// +// More on ES2015 Classes at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes + +class RegisterSecurityKey { + constructor($module) { + if (!isSupported()) { + return this; + } + this.registerPath = '/webauthn/register'; + this.$module = $module; + + this.$module.addEventListener("click", () => { + new ErrorBanner().hideBanner(); + this.getAuthentication(); + }); + } + getAuthentication() { + fetch(this.registerPath) + .then((response) => { + if (!response.ok) { + throw Error(response.statusText); + } + + return response.arrayBuffer(); + }) + .then((data) => { + var options = window.CBOR.decode(data); + // triggers browser dialogue to select authenticator + return window.navigator.credentials.create(options); + }) + .then((credential) => { + return this.postWebAuthnCreateResponse( + credential.response, this.$module.dataset.csrfToken + ); + }) + .then((response) => { + if (!response.ok) { + throw Error(response.statusText); + } + + window.location.reload(); + }) + .catch((error) => { + console.error(error); + // some browsers will show an error dialogue for some + // errors; to be safe we always display an error message on the page. + new ErrorBanner().showBanner(); + }); + } + postWebAuthnCreateResponse(response, csrf_token) { + return fetch(this.registerPath, { + method: 'POST', + headers: { 'X-CSRFToken': csrf_token }, + body: window.CBOR.encode({ + attestationObject: new Uint8Array(response.attestationObject), + clientDataJSON: new Uint8Array(response.clientDataJSON), + }) + }); + } +} + +export default RegisterSecurityKey; diff --git a/app/assets/javascripts/registerSecurityKey.js b/app/assets/javascripts/registerSecurityKey.js deleted file mode 100644 index 5dafd03718..0000000000 --- a/app/assets/javascripts/registerSecurityKey.js +++ /dev/null @@ -1,58 +0,0 @@ -(function(window) { - "use strict"; - - window.GOVUK.NotifyModules.RegisterSecurityKey = function() { - this.start = function(component) { - $(component) - .on('click', function(event) { - event.preventDefault(); - - // hide any existing error prompt - window.GOVUK.ErrorBanner.hideBanner(); - - fetch('/webauthn/register') - .then((response) => { - if (!response.ok) { - throw Error(response.statusText); - } - - return response.arrayBuffer(); - }) - .then((data) => { - var options = window.CBOR.decode(data); - // triggers browser dialogue to select authenticator - return window.navigator.credentials.create(options); - }) - .then((credential) => { - return postWebAuthnCreateResponse( - credential.response, component.data('csrfToken') - ); - }) - .then((response) => { - if (!response.ok) { - throw Error(response.statusText); - } - - window.location.reload(); - }) - .catch((error) => { - console.error(error); - // some browsers will show an error dialogue for some - // errors; to be safe we always display an error message on the page. - window.GOVUK.ErrorBanner.showBanner(); - }); - }); - }; - }; - - function postWebAuthnCreateResponse(response, csrf_token) { - return fetch('/webauthn/register', { - method: 'POST', - headers: { 'X-CSRFToken': csrf_token }, - body: window.CBOR.encode({ - attestationObject: new Uint8Array(response.attestationObject), - clientDataJSON: new Uint8Array(response.clientDataJSON), - }) - }); - } -})(window); diff --git a/rollup.config.mjs b/rollup.config.mjs index ecc756ff2e..dab8b34a0c 100644 --- a/rollup.config.mjs +++ b/rollup.config.mjs @@ -99,7 +99,6 @@ export default [ paths.src + 'javascripts/templateFolderForm.js', paths.src + 'javascripts/addBrandingOptionsForm.js', paths.src + 'javascripts/setAuthTypeForm.js', - paths.src + 'javascripts/registerSecurityKey.js', paths.src + 'javascripts/updateStatus.js', paths.src + 'javascripts/homepage.js', paths.src + 'javascripts/removeInPresenceOf.js', From b40469a7b3351f0e27b7806f070f11eddd299faf Mon Sep 17 00:00:00 2001 From: Jani Kraner Date: Thu, 19 Dec 2024 16:05:27 +0000 Subject: [PATCH 4/7] replace cbor-js with cbor 2 new package, esm --- .../javascripts/esm/authenticate-security-key.mjs | 7 ++++--- .../javascripts/esm/register-security-key.mjs | 5 +++-- package-lock.json | 13 ++++++++----- package.json | 2 +- rollup.config.mjs | 2 -- 5 files changed, 16 insertions(+), 13 deletions(-) diff --git a/app/assets/javascripts/esm/authenticate-security-key.mjs b/app/assets/javascripts/esm/authenticate-security-key.mjs index 0dea5383fb..5bbbd589e0 100644 --- a/app/assets/javascripts/esm/authenticate-security-key.mjs +++ b/app/assets/javascripts/esm/authenticate-security-key.mjs @@ -1,5 +1,6 @@ import { isSupported } from 'govuk-frontend'; import ErrorBanner from './error-banner.mjs'; +import { decode, encode } from 'cbor2'; // This new way of writing Javascript components is based on the GOV.UK Frontend skeleton Javascript coding standard // that uses ES2015 Classes - @@ -34,7 +35,7 @@ class AuthenticateSecurityKey { return response.arrayBuffer(); }) .then(data => { - var options = window.CBOR.decode(data); + var options = decode(new Uint8Array(data)); // triggers browser dialogue to login with authenticator return window.navigator.credentials.get(options); }) @@ -65,7 +66,7 @@ class AuthenticateSecurityKey { return response.arrayBuffer(); }) .then(cbor => { - return Promise.resolve(window.CBOR.decode(cbor)); + return Promise.resolve(decode(new Uint8Array(cbor))); }) .then(data => { window.location.assign(data.redirect_url); @@ -81,7 +82,7 @@ class AuthenticateSecurityKey { return fetch(this.authenticatePath, { method: 'POST', headers: { 'X-CSRFToken': csrf_token }, - body: window.CBOR.encode({ + body: encode({ credentialId: new Uint8Array(credential.rawId), authenticatorData: new Uint8Array(credential.response.authenticatorData), signature: new Uint8Array(credential.response.signature), diff --git a/app/assets/javascripts/esm/register-security-key.mjs b/app/assets/javascripts/esm/register-security-key.mjs index c3df26c991..480c3e03e4 100644 --- a/app/assets/javascripts/esm/register-security-key.mjs +++ b/app/assets/javascripts/esm/register-security-key.mjs @@ -1,5 +1,6 @@ import { isSupported } from 'govuk-frontend'; import ErrorBanner from './error-banner.mjs'; +import { decode, encode } from 'cbor2'; // This new way of writing Javascript components is based on the GOV.UK Frontend skeleton Javascript coding standard // that uses ES2015 Classes - @@ -34,7 +35,7 @@ class RegisterSecurityKey { return response.arrayBuffer(); }) .then((data) => { - var options = window.CBOR.decode(data); + var options = decode(new Uint8Array(data)); // triggers browser dialogue to select authenticator return window.navigator.credentials.create(options); }) @@ -61,7 +62,7 @@ class RegisterSecurityKey { return fetch(this.registerPath, { method: 'POST', headers: { 'X-CSRFToken': csrf_token }, - body: window.CBOR.encode({ + body: encode({ attestationObject: new Uint8Array(response.attestationObject), clientDataJSON: new Uint8Array(response.clientDataJSON), }) diff --git a/package-lock.json b/package-lock.json index a636da3ea8..7fb66429bf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "0.0.1", "license": "MIT", "dependencies": { - "cbor-js": "0.1.0", + "cbor2": "^1.8.0", "govuk-frontend": "5.7.1", "jquery": "3.5.0", "morphdom": "2.6.1", @@ -3879,10 +3879,13 @@ } ] }, - "node_modules/cbor-js": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/cbor-js/-/cbor-js-0.1.0.tgz", - "integrity": "sha512-7sQ/TvDZPl7csT1Sif9G0+MA0I0JOVah8+wWlJVQdVEgIbCzlN/ab3x+uvMNsc34TUvO6osQTAmB2ls80JX6tw==" + "node_modules/cbor2": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/cbor2/-/cbor2-1.8.0.tgz", + "integrity": "sha512-CsrHAWXBDEUlc2VsIfLveHZlAmsle8QH8sDIoBqBsq5GuP37FasoRklcnLCxKY+wT+IdQlI2eSRAgP1SZKjChg==", + "engines": { + "node": ">=18" + } }, "node_modules/chalk": { "version": "2.4.2", diff --git a/package.json b/package.json index 1e818cd21f..63b0c92d74 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "license": "MIT", "homepage": "https://github.com/alphagov/notifications-admin#readme", "dependencies": { - "cbor-js": "0.1.0", + "cbor2": "^1.8.0", "govuk-frontend": "5.7.1", "jquery": "3.5.0", "morphdom": "2.6.1", diff --git a/rollup.config.mjs b/rollup.config.mjs index dab8b34a0c..9c062b831d 100644 --- a/rollup.config.mjs +++ b/rollup.config.mjs @@ -80,7 +80,6 @@ export default [ paths.npm + 'query-command-supported/dist/queryCommandSupported.min.js', paths.npm + 'timeago/jquery.timeago.js', paths.npm + 'textarea-caret/index.js', - paths.npm + 'cbor-js/cbor.js', paths.src + 'javascripts/modules.js', paths.src + 'javascripts/govuk-frontend-toolkit/show-hide-content.js', paths.src + 'javascripts/stick-to-window-when-scrolling.js', @@ -110,7 +109,6 @@ export default [ }, moduleContext: { './node_modules/jquery/dist/jquery.min.js': 'window', - './node_modules/cbor-js/cbor.js': 'window', }, plugins: [ nodeResolve(), From a141163c042ff614d7388630b7c63600458f1f66 Mon Sep 17 00:00:00 2001 From: Jani Kraner Date: Fri, 20 Dec 2024 15:37:32 +0000 Subject: [PATCH 5/7] register test --- ...ityKey.test.js => register-security-key.test.mjs} | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) rename tests/javascripts/{registerSecurityKey.test.js => register-security-key.test.mjs} (94%) diff --git a/tests/javascripts/registerSecurityKey.test.js b/tests/javascripts/register-security-key.test.mjs similarity index 94% rename from tests/javascripts/registerSecurityKey.test.js rename to tests/javascripts/register-security-key.test.mjs index 0a38b27393..a69e35e493 100644 --- a/tests/javascripts/registerSecurityKey.test.js +++ b/tests/javascripts/register-security-key.test.mjs @@ -1,9 +1,9 @@ -const helpers = require('./support/helpers.js') +import RegisterSecurityKey from '../../app/assets/javascripts/esm/register-security-key.mjs'; +import { jest } from '@jest/globals'; +import * as helpers from './support/helpers'; beforeAll(() => { - window.CBOR = require('../../node_modules/cbor-js/cbor.js') - require('../../app/assets/javascripts/registerSecurityKey.js') - + document.body.classList.add('govuk-frontend-supported'); // populate missing values to allow consistent jest.spyOn() window.fetch = () => {} window.navigator.credentials = { create: () => { } } @@ -14,7 +14,7 @@ beforeAll(() => { }) afterAll(() => { - require('./support/teardown.js') + // require('./support/teardown.js') // restore window attributes to their original undefined state delete window.fetch @@ -44,7 +44,7 @@ describe('Register security key', () => { ` button = document.querySelector('[data-notify-module="register-security-key"]') - window.GOVUK.notifyModules.start() + new RegisterSecurityKey(button); }) afterEach(() => { From 8eaeb477465704d4d3d31f82c028ad61faf8adaa Mon Sep 17 00:00:00 2001 From: Jani Kraner Date: Fri, 20 Dec 2024 15:37:46 +0000 Subject: [PATCH 6/7] authenticate-test --- ...yKey.test.js => authenticate-security-key.test.mjs} | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) rename tests/javascripts/{authenticateSecurityKey.test.js => authenticate-security-key.test.mjs} (96%) diff --git a/tests/javascripts/authenticateSecurityKey.test.js b/tests/javascripts/authenticate-security-key.test.mjs similarity index 96% rename from tests/javascripts/authenticateSecurityKey.test.js rename to tests/javascripts/authenticate-security-key.test.mjs index 0f31d29371..3ace6c018f 100644 --- a/tests/javascripts/authenticateSecurityKey.test.js +++ b/tests/javascripts/authenticate-security-key.test.mjs @@ -1,8 +1,9 @@ -const helpers = require('./support/helpers.js') +import RegisterSecurityKey from '../../app/assets/javascripts/esm/authenticate-security-key.mjs'; +import { jest } from '@jest/globals'; +import * as helpers from './support/helpers'; beforeAll(() => { - window.CBOR = require('../../node_modules/cbor-js/cbor.js') - require('../../app/assets/javascripts/authenticateSecurityKey.js') + document.body.classList.add('govuk-frontend-supported'); // populate missing values to allow consistent jest.spyOn() window.fetch = () => { } @@ -14,7 +15,6 @@ beforeAll(() => { }) afterAll(() => { - require('./support/teardown.js') // restore window attributes to their original undefined state delete window.fetch @@ -42,7 +42,7 @@ describe('Authenticate with security key', () => { ` button = document.querySelector('[data-notify-module="authenticate-security-key"]') - window.GOVUK.notifyModules.start() + new RegisterSecurityKey(button); }) afterEach(() => { From a68ad01c0807fad71ad1d2f07a57dd7b789dc814 Mon Sep 17 00:00:00 2001 From: Jani Kraner Date: Mon, 30 Dec 2024 16:16:33 +0000 Subject: [PATCH 7/7] mess with cbor and jest --- babel.config.js | 3 +- package-lock.json | 291 ++++++++---------- package.json | 15 +- .../register-security-key.test.mjs | 37 ++- tests/javascripts/support/setup.js | 8 + 5 files changed, 170 insertions(+), 184 deletions(-) diff --git a/babel.config.js b/babel.config.js index 9eebbf7fd6..8d508f7a3d 100644 --- a/babel.config.js +++ b/babel.config.js @@ -1,7 +1,8 @@ module.exports = { env: { test: { - presets: ['@babel/preset-env'] + presets: ['@babel/preset-env'], + plugins: ['@babel/plugin-transform-class-properties', '@babel/plugin-transform-private-methods'] } } }; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 7fb66429bf..a994d704b8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,8 @@ }, "devDependencies": { "@babel/core": "7.25.2", + "@babel/plugin-transform-class-properties": "^7.25.9", + "@babel/plugin-transform-private-methods": "^7.25.9", "@babel/preset-env": "7.4.2", "@eslint/js": "9.15.0", "@rollup/plugin-multi-entry": "6.0.1", @@ -60,12 +62,13 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", - "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", + "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", "dev": true, "dependencies": { - "@babel/highlight": "^7.24.7", + "@babel/helper-validator-identifier": "^7.25.9", + "js-tokens": "^4.0.0", "picocolors": "^1.0.0" }, "engines": { @@ -112,27 +115,28 @@ } }, "node_modules/@babel/generator": { - "version": "7.25.6", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.6.tgz", - "integrity": "sha512-VPC82gr1seXOpkjAAKoLhP50vx4vGNlF4msF64dSFq1P8RfB+QAuJWGHPXXPc8QyfVWwwB/TNNU4+ayZmHNbZw==", + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.3.tgz", + "integrity": "sha512-6FF/urZvD0sTeO7k6/B15pMLC4CHUv1426lzr3N01aHJTl046uCAh9LXW/fzeXXjPNCJ6iABW5XaWOsIZB93aQ==", "dev": true, "dependencies": { - "@babel/types": "^7.25.6", + "@babel/parser": "^7.26.3", + "@babel/types": "^7.26.3", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^2.5.1" + "jsesc": "^3.0.2" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz", - "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz", + "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==", "dev": true, "dependencies": { - "@babel/types": "^7.24.7" + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -167,6 +171,27 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.9.tgz", + "integrity": "sha512-UTZQMvt0d/rSz6KI+qdu7GQze5TIajwTS++GUozlw8VBJDEOAqSXwm1WvmYEZwqdqSGQshRocPDqrt4HBZB3fQ==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.25.9", + "@babel/helper-member-expression-to-functions": "^7.25.9", + "@babel/helper-optimise-call-expression": "^7.25.9", + "@babel/helper-replace-supers": "^7.25.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", + "@babel/traverse": "^7.25.9", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, "node_modules/@babel/helper-create-regexp-features-plugin": { "version": "7.25.2", "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.2.tgz", @@ -197,13 +222,13 @@ } }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.8.tgz", - "integrity": "sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz", + "integrity": "sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==", "dev": true, "dependencies": { - "@babel/traverse": "^7.24.8", - "@babel/types": "^7.24.8" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -241,21 +266,21 @@ } }, "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.7.tgz", - "integrity": "sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz", + "integrity": "sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==", "dev": true, "dependencies": { - "@babel/types": "^7.24.7" + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", - "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.9.tgz", + "integrity": "sha512-kSMlyUVdWe25rEsRGviIgOWnoT/nfABVWlqt9N19/dIPWViAOW2s9wznP5tURbs/IDuNk4gPy3YdYRgH3uxhBw==", "dev": true, "engines": { "node": ">=6.9.0" @@ -279,14 +304,14 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.0.tgz", - "integrity": "sha512-q688zIvQVYtZu+i2PsdIu/uWGRpfxzr5WESsfpShfZECkO+d2o+WROWezCi/Q6kJ0tfPa5+pUGUlfx2HhrA3Bg==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.9.tgz", + "integrity": "sha512-IiDqTOTBQy0sWyeXyGSC5TBJpGFXBkRynjBeXsvbhQFKj2viwJC76Epz35YLU1fpe/Am6Vppb7W7zM4fPQzLsQ==", "dev": true, "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.24.8", - "@babel/helper-optimise-call-expression": "^7.24.7", - "@babel/traverse": "^7.25.0" + "@babel/helper-member-expression-to-functions": "^7.25.9", + "@babel/helper-optimise-call-expression": "^7.25.9", + "@babel/traverse": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -309,31 +334,31 @@ } }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.7.tgz", - "integrity": "sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz", + "integrity": "sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==", "dev": true, "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.24.8", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", - "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", + "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", - "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", "dev": true, "engines": { "node": ">=6.9.0" @@ -375,28 +400,13 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/highlight": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", - "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.24.7", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/parser": { - "version": "7.25.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.6.tgz", - "integrity": "sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q==", + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.3.tgz", + "integrity": "sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==", "dev": true, "dependencies": { - "@babel/types": "^7.25.6" + "@babel/types": "^7.26.3" }, "bin": { "parser": "bin/babel-parser.js" @@ -779,6 +789,22 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.9.tgz", + "integrity": "sha512-bbMAII8GRSkcd0h0b4X+36GksxuheLFjP65ul9w6C3KgAamI3JqErNgSrosX6ZPj+Mpim5VvEbawXxJCyEUV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-transform-classes": { "version": "7.25.4", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.4.tgz", @@ -1063,6 +1089,22 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.9.tgz", + "integrity": "sha512-D/JUozNpQLAPUVusvqMxyvjzllRaF8/nSrP1s2YGQT/W4LHK4xxsMcHjhOGTS01mp9Hda8nswb+FblLdJornQw==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.25.9", + "@babel/helper-plugin-utils": "^7.25.9" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-transform-regenerator": { "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.7.tgz", @@ -1255,30 +1297,30 @@ } }, "node_modules/@babel/template": { - "version": "7.25.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", - "integrity": "sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==", + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", + "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/parser": "^7.25.0", - "@babel/types": "^7.25.0" + "@babel/code-frame": "^7.25.9", + "@babel/parser": "^7.25.9", + "@babel/types": "^7.25.9" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.25.6", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.6.tgz", - "integrity": "sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ==", + "version": "7.26.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.4.tgz", + "integrity": "sha512-fH+b7Y4p3yqvApJALCPJcwb0/XaOSgtK4pzV6WVjPR5GLFQBRI7pfoX2V2iM48NXvX07NUxxm1Vw98YjqTcU5w==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.25.6", - "@babel/parser": "^7.25.6", - "@babel/template": "^7.25.0", - "@babel/types": "^7.25.6", + "@babel/code-frame": "^7.26.2", + "@babel/generator": "^7.26.3", + "@babel/parser": "^7.26.3", + "@babel/template": "^7.25.9", + "@babel/types": "^7.26.3", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -1296,14 +1338,13 @@ } }, "node_modules/@babel/types": { - "version": "7.25.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.6.tgz", - "integrity": "sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==", + "version": "7.26.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.3.tgz", + "integrity": "sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.24.8", - "@babel/helper-validator-identifier": "^7.24.7", - "to-fast-properties": "^2.0.0" + "@babel/helper-string-parser": "^7.25.9", + "@babel/helper-validator-identifier": "^7.25.9" }, "engines": { "node": ">=6.9.0" @@ -3196,18 +3237,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/anymatch": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", @@ -3887,20 +3916,6 @@ "node": ">=18" } }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/char-regex": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", @@ -4047,21 +4062,6 @@ "node": ">=0.10.0" } }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, "node_modules/colord": { "version": "2.9.3", "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", @@ -4932,15 +4932,6 @@ "node": ">=6" } }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/escodegen": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", @@ -5880,15 +5871,6 @@ "node": ">=6" } }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/has-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", @@ -8259,15 +8241,15 @@ } }, "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", "dev": true, "bin": { "jsesc": "bin/jsesc" }, "engines": { - "node": ">=4" + "node": ">=6" } }, "node_modules/json-buffer": { @@ -11655,18 +11637,6 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/supports-hyperlinks": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.1.0.tgz", @@ -11845,15 +11815,6 @@ "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", "dev": true }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/to-object-path": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", diff --git a/package.json b/package.json index 63b0c92d74..95dc19eb59 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,8 @@ }, "devDependencies": { "@babel/core": "7.25.2", + "@babel/plugin-transform-class-properties": "^7.25.9", + "@babel/plugin-transform-private-methods": "^7.25.9", "@babel/preset-env": "7.4.2", "@eslint/js": "9.15.0", "@rollup/plugin-multi-entry": "6.0.1", @@ -69,11 +71,20 @@ "url": "https://www.notifications.service.gov.uk" }, "transform": { - "^.+\\mjs$": "babel-jest" + "^.+\\.(m)?js$": "babel-jest" }, + "transformIgnorePatterns": [ + "/node_modules/(?!cbor2)" + ], "testMatch": [ "/**/?(*.)(test).{js,mjs}" ], "testEnvironment": "jsdom" - } + }, + "//": "used by babel-jest for cbor2 transpilation", + "browserslist": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] } diff --git a/tests/javascripts/register-security-key.test.mjs b/tests/javascripts/register-security-key.test.mjs index a69e35e493..5b3453729a 100644 --- a/tests/javascripts/register-security-key.test.mjs +++ b/tests/javascripts/register-security-key.test.mjs @@ -1,21 +1,25 @@ import RegisterSecurityKey from '../../app/assets/javascripts/esm/register-security-key.mjs'; import { jest } from '@jest/globals'; import * as helpers from './support/helpers'; +import { encode, decode } from 'cbor2'; +import ErrorBanner from '../../app/assets/javascripts/esm/error-banner.mjs'; + +jest.mock('../../app/assets/javascripts/esm/error-banner.mjs'); + +let errorBanner beforeAll(() => { document.body.classList.add('govuk-frontend-supported'); // populate missing values to allow consistent jest.spyOn() window.fetch = () => {} window.navigator.credentials = { create: () => { } } - window.GOVUK.ErrorBanner = { - showBanner: () => { }, - hideBanner: () => { } - }; + // window.GOVUK.ErrorBanner = { + // showBanner: () => { }, + // hideBanner: () => { } + // }; }) afterAll(() => { - // require('./support/teardown.js') - // restore window attributes to their original undefined state delete window.fetch delete window.navigator.credentials @@ -38,6 +42,8 @@ describe('Register security key', () => { // you might need to comment this out to debug some failures jest.spyOn(console, 'error').mockImplementation(() => {}) + errorBanner = new ErrorBanner() + document.body.innerHTML = `