Skip to content

Commit

Permalink
Add single consent library
Browse files Browse the repository at this point in the history
- adds code to include and manage our use of the single consent API code
- init is called by the cookie banner code on every page, which determines which API endpoint to use (staging or prod) and creates the GovSingleConsent object
- useConsentApi is called across the code to check whether or not to use the consent API, this will be set in static
- the default callback for the consent object checks the returned response and if the user has consented, triggers the cookie-consent event, which will initialise analytics and hide the cookie banner
- setPreferences allows user consent to be set through the API
  • Loading branch information
andysellick committed Feb 8, 2024
1 parent 9845f33 commit a0e0dfa
Show file tree
Hide file tree
Showing 2 changed files with 277 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/* 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.useConsentApi()) {
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
this.consentApiObj = new GovSingleConsent(callback, this.url)
},

useConsentApi: function () {
if (window.GOVUK.useSingleConsentApi) {
return true
}
},

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) {
if (this.useConsentApi()) {
try {
switch (type) {
case 'accept':
this.consentApiObj.setConsents(GovSingleConsent.ACCEPT_ALL)
break
case 'reject':
this.consentApiObj.setConsents(GovSingleConsent.REJECT_ALL)
break
default:
this.consentApiObj.setConsents(options)
}
} catch (e) {
console.error('Single consent ' + type + ' error: ', e, window.location)
}
}
}
}
}(window))
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
/* 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('will not initialise', function () {
window.GOVUK.singleConsent.init()
expect(window.GOVUK.singleConsent.consentApiObj).not.toBeDefined()
})

it('confirms that it should do nothing', function () {
expect(window.GOVUK.singleConsent.useConsentApi()).toEqual(undefined)
})
})

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()
})

it('accepts a function with parameters for the callback', function () {
var test = {
testFunction: function () {}
}
spyOn(test, 'testFunction')
window.GOVUK.singleConsent.init(test.testFunction('this', 'works'))
expect(window.GOVUK.singleConsent.consentApiObj).toBeDefined()
expect(test.testFunction).toHaveBeenCalledWith('this', 'works')
})

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}')
})
})
})
})

0 comments on commit a0e0dfa

Please sign in to comment.