diff --git a/app/assets/javascripts/govuk_publishing_components/lib/single-consent-functions.js b/app/assets/javascripts/govuk_publishing_components/lib/single-consent-functions.js new file mode 100644 index 0000000000..af45fea0cd --- /dev/null +++ b/app/assets/javascripts/govuk_publishing_components/lib/single-consent-functions.js @@ -0,0 +1,65 @@ +/* global GovSingleConsent */ +// = require govuk-single-consent/dist/singleconsent.iife.js + +(function (root) { + 'use strict' + window.GOVUK = window.GOVUK || {} + + window.GOVUK.singleConsent = { + init: function (callback) { + if (!this.shouldUseConsentApi()) { + if (callback) { + callback() + } + return + } + callback = callback || this.apiCallBack + // determine where we are and set the consent api URL accordingly + if (!this.url) { + this.url = 'staging' + var environment = window.GOVUK.loadAnalytics.getEnvironment(window.GOVUK.analyticsGa4.core.trackFunctions.getHostname()) + if (environment && environment.name === 'production') { + this.url = 'production' + } + } + // create the consent API object + window.GOVUK.singleConsent.consentApiObj = new GovSingleConsent(callback, this.url) + }, + + shouldUseConsentApi: function () { + return window.GOVUK.useSingleConsentApi + }, + + apiCallBack: function (consents, consentsPreferencesSet, error) { + if (error) { + console.error('Single consent error: ', error, window.location) + return + } + if (consentsPreferencesSet) { + if (consents && consents.usage) { + window.GOVUK.triggerEvent(window, 'cookie-consent') + } + } + }, + + setPreferences: function (type, options) { + try { + if (!window.GOVUK.singleConsent.consentApiObj) { + this.init() + } + switch (type) { + case 'accept': + window.GOVUK.singleConsent.consentApiObj.setConsents(GovSingleConsent.ACCEPT_ALL) + break + case 'reject': + window.GOVUK.singleConsent.consentApiObj.setConsents(GovSingleConsent.REJECT_ALL) + break + default: + window.GOVUK.singleConsent.consentApiObj.setConsents(options) + } + } catch (e) { + console.error('Single consent ' + type + ' error: ' + e.message, window.location) + } + } + } +}(window)) diff --git a/spec/javascripts/govuk_publishing_components/lib/single-consent-functions-spec.js b/spec/javascripts/govuk_publishing_components/lib/single-consent-functions-spec.js new file mode 100644 index 0000000000..e044bce4f0 --- /dev/null +++ b/spec/javascripts/govuk_publishing_components/lib/single-consent-functions-spec.js @@ -0,0 +1,210 @@ +/* eslint-env jasmine */ + +describe('The single consent cookie code', function () { + var acceptAll = { + essential: true, + usage: true, + campaigns: true, + settings: true + } + var rejectAll = { + essential: true, + usage: false, + campaigns: false, + settings: false + } + var mix = { + essential: true, + usage: false, + campaigns: true, + settings: true + } + + beforeEach(function () { + spyOn(window.GOVUK, 'triggerEvent').and.callThrough() + spyOn(window.GOVUK.singleConsent, 'apiCallBack').and.callThrough() + jasmine.Ajax.install() + }) + + afterEach(function () { + jasmine.Ajax.uninstall() + delete window.GOVUK.singleConsent.consentApiObj + delete window.GOVUK.singleConsent.url + delete window.GOVUK.useSingleConsentApi + }) + + describe('if the single consent API should not be used', function () { + beforeEach(function () { + delete window.GOVUK.useSingleConsentApi + }) + + it('does nothing', function () { + window.GOVUK.singleConsent.init() + expect(window.GOVUK.singleConsent.consentApiObj).not.toBeDefined() + }) + + it('immediately calls anything passed as a callback', function () { + var test = { + testFunction: function () {} + } + spyOn(test, 'testFunction') + window.GOVUK.singleConsent.init(test.testFunction) + expect(window.GOVUK.singleConsent.consentApiObj).not.toBeDefined() + expect(test.testFunction).toHaveBeenCalled() + }) + }) + + describe('if the single consent API should be used', function () { + beforeEach(function () { + window.GOVUK.useSingleConsentApi = true + }) + + afterEach(function () { + delete window.GOVUK.useSingleConsentApi + }) + + it('does nothing if there is no unique user id', function () { + window.GOVUK.singleConsent.init() + expect(window.GOVUK.singleConsent.consentApiObj).toBeDefined() + expect(jasmine.Ajax.requests.count()).toEqual(0) + expect(window.GOVUK.singleConsent.apiCallBack).toHaveBeenCalledWith(null, false, null) + expect(window.GOVUK.triggerEvent).not.toHaveBeenCalled() + }) + + it('accepts a function for the callback', function () { + var test = { + testFunction: function () {} + } + spyOn(test, 'testFunction') + window.GOVUK.singleConsent.init(test.testFunction) + expect(test.testFunction).toHaveBeenCalled() + }) + + describe('when determining the environment', function () { + it('starts without a URL for the consent API', function () { + expect(window.GOVUK.singleConsent.url).toBeFalsy() + }) + + it('defaults to staging if the environment is not recognised', function () { + spyOn(window.GOVUK.analyticsGa4.core.trackFunctions, 'getHostname').and.returnValue('moo') + window.GOVUK.singleConsent.init() + expect(window.GOVUK.singleConsent.url).toEqual('staging') + }) + + it('switches to production when on production', function () { + spyOn(window.GOVUK.analyticsGa4.core.trackFunctions, 'getHostname').and.returnValue('www.gov.uk') + window.GOVUK.singleConsent.init() + expect(window.GOVUK.singleConsent.url).toEqual('production') + }) + }) + + describe('when there is a user id', function () { + beforeEach(function () { + window.GOVUK.cookie('gov_singleconsent_uid', '1234') + window.GOVUK.singleConsent.init() + }) + + afterEach(function () { + window.GOVUK.cookie('gov_singleconsent_uid', null) + }) + + it('does everything expected when full consent is given', function () { + window.GOVUK.singleConsent.setPreferences('accept') + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 200, + contentType: 'text/plain', + responseText: '{ "uid": "1234", "status": ' + JSON.stringify(acceptAll) + '}' + }) + + expect(window.GOVUK.singleConsent.consentApiObj).toBeDefined() + expect(window.GOVUK.singleConsent.apiCallBack).toHaveBeenCalledWith(acceptAll, true, null) + expect(window.GOVUK.triggerEvent).toHaveBeenCalled() + expect(window.GOVUK.cookie('cookies_policy')).toEqual('{"essential":true,"usage":true,"campaigns":true,"settings":true}') + }) + + it('does everything expected when consent is rejected', function () { + window.GOVUK.singleConsent.setPreferences('reject') + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 200, + contentType: 'text/plain', + responseText: '{ "uid": "1234", "status": ' + JSON.stringify(rejectAll) + '}' + }) + + expect(window.GOVUK.singleConsent.consentApiObj).toBeDefined() + expect(window.GOVUK.singleConsent.apiCallBack).toHaveBeenCalledWith(rejectAll, true, null) + expect(window.GOVUK.triggerEvent).not.toHaveBeenCalled() + expect(window.GOVUK.cookie('cookies_policy')).toEqual('{"essential":true,"usage":false,"campaigns":false,"settings":false}') + }) + + it('allows individual cookies to be set', function () { + window.GOVUK.singleConsent.setPreferences(false, mix) + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 200, + contentType: 'text/plain', + responseText: '{ "uid": "1234", "status": ' + JSON.stringify(mix) + '}' + }) + + expect(window.GOVUK.singleConsent.consentApiObj).toBeDefined() + expect(window.GOVUK.singleConsent.apiCallBack).toHaveBeenCalledWith(mix, true, null) + expect(window.GOVUK.triggerEvent).not.toHaveBeenCalled() + expect(window.GOVUK.cookie('cookies_policy')).toEqual('{"essential":true,"usage":false,"campaigns":true,"settings":true}') + }) + }) + + describe('when there is a problem', function () { + beforeEach(function () { + jasmine.clock().install() + window.GOVUK.cookie('gov_singleconsent_uid', '1234') + }) + + afterEach(function () { + jasmine.clock().uninstall() + window.GOVUK.cookie('gov_singleconsent_uid', null) + }) + + it('handles a timeout gracefully', function () { + window.GOVUK.singleConsent.init() + window.GOVUK.singleConsent.setPreferences('accept') + jasmine.Ajax.requests.mostRecent().responseTimeout() + expect(window.GOVUK.singleConsent.consentApiObj).toBeDefined() + expect(window.GOVUK.cookie('cookies_policy')).toEqual('{"essential":true,"usage":false,"campaigns":false,"settings":false}') + }) + + it('fails gracefully if pointed at an incorrect endpoint URL', function () { + window.GOVUK.singleConsent.init() + window.GOVUK.singleConsent.setPreferences('accept') + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 404, + contentType: 'text/plain', + responseText: 'error not found' + }) + expect(window.GOVUK.singleConsent.consentApiObj).toBeDefined() + expect(window.GOVUK.cookie('cookies_policy')).toEqual('{"essential":true,"usage":false,"campaigns":false,"settings":false}') + }) + + it('fails gracefully when the server errors', function () { + window.GOVUK.singleConsent.init() + window.GOVUK.singleConsent.setPreferences('accept') + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 500, + contentType: 'text/plain', + responseText: 'error not found' + }) + expect(window.GOVUK.singleConsent.consentApiObj).toBeDefined() + expect(window.GOVUK.cookie('cookies_policy')).toEqual('{"essential":true,"usage":false,"campaigns":false,"settings":false}') + }) + + it('fails gracefully when the response is not as expected', function () { + window.GOVUK.singleConsent.init() + window.GOVUK.singleConsent.setPreferences('accept') + jasmine.Ajax.requests.mostRecent().respondWith({ + status: 200, + contentType: 'text/plain', + responseText: 'surprise!' + }) + expect(window.GOVUK.singleConsent.consentApiObj).toBeDefined() + expect(window.GOVUK.cookie('cookies_policy')).toEqual('{"essential":true,"usage":false,"campaigns":false,"settings":false}') + }) + }) + }) +})