-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #592 from digital-land/551-cookie-banner
551 cookie banner
- Loading branch information
Showing
17 changed files
with
417 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
const cookieDefaults = { | ||
cookieNames: { | ||
preferenceCookie: 'cookies_preferences_set', | ||
policyCookie: 'cookies_policy' | ||
}, | ||
cookieExpiryDays: 365, | ||
cookiePath: '/', | ||
defaultPolicyValue: { essential: true, settings: true, usage: true, campaigns: true } | ||
} | ||
|
||
export default class CookieBanner { | ||
constructor (document) { | ||
this.document = document | ||
this.banner = this.document.querySelector('.js-app-c-cookie-banner') | ||
if (!this.banner) { | ||
console.warn('Cookie banner element not found') | ||
return | ||
} | ||
|
||
this.form = this.banner.querySelector('.js-app-c-cookie-banner__form') | ||
this.confirmationMessage = this.banner.querySelector('.js-app-c-cookie-banner__confirmation') | ||
this.confirmationDecision = this.banner.querySelector('.js-app-c-cookie-banner__confirmation-decision') | ||
this.acceptButton = this.banner.querySelector('.js-app-c-cookie-banner__accept') | ||
this.rejectButton = this.banner.querySelector('.js-app-c-cookie-banner__reject') | ||
this.hideButton = this.banner.querySelector('.js-app-c-cookie-banner__hide') | ||
|
||
this.init() | ||
} | ||
|
||
init () { | ||
if (this.getCookie(cookieDefaults.cookieNames.preferenceCookie) !== null) { | ||
this.hideCookieBanner() | ||
} | ||
|
||
this.acceptButton.addEventListener('click', this.accept.bind(this)) | ||
this.rejectButton.addEventListener('click', this.reject.bind(this)) | ||
this.hideButton.addEventListener('click', this.hideCookieBanner.bind(this)) | ||
} | ||
|
||
accept () { | ||
this.userCookiePolicyDecision(true) | ||
} | ||
|
||
reject () { | ||
this.userCookiePolicyDecision(false) | ||
} | ||
|
||
userCookiePolicyDecision (userAcceptedCookiePolicy = true) { | ||
this.setCookie( | ||
cookieDefaults.cookieNames.preferenceCookie, | ||
userAcceptedCookiePolicy, | ||
cookieDefaults.cookieExpiryDays) | ||
|
||
this.setCookie( | ||
cookieDefaults.cookieNames.policyCookie, | ||
userAcceptedCookiePolicy ? cookieDefaults.defaultPolicyValue : null, | ||
userAcceptedCookiePolicy ? cookieDefaults.cookieExpiryDays : 0 | ||
) | ||
|
||
this.showConfirmationMessage(userAcceptedCookiePolicy) | ||
} | ||
|
||
setCookie (name, value, days) { | ||
const expires = new Date() | ||
expires.setTime(expires.getTime() + (days * 24 * 60 * 60 * 1000)) | ||
this.document.cookie = `${name}=${JSON.stringify(value)};expires=${expires.toUTCString()};path=${cookieDefaults.cookiePath}` | ||
} | ||
|
||
getCookie (name) { | ||
const cookie = this.document.cookie | ||
.split('; ') | ||
.find(row => row.startsWith(name)) | ||
|
||
return cookie ? JSON.parse(cookie.split('=')[1]) : null | ||
} | ||
|
||
showConfirmationMessage (userAcceptedCookiePolicy = true) { | ||
this.form.classList.add('app-c-cookie-banner__form--hidden') | ||
this.form.setAttribute('aria-hidden', 'true') | ||
this.acceptButton.removeEventListener('click', this.accept.bind(this)) | ||
this.rejectButton.removeEventListener('click', this.reject.bind(this)) | ||
|
||
if (!userAcceptedCookiePolicy) this.confirmationDecision.textContent = 'rejected' | ||
this.confirmationMessage.classList.remove('app-c-cookie-banner__confirmation--hidden') | ||
this.confirmationMessage.setAttribute('aria-hidden', 'false') | ||
this.confirmationMessage.setAttribute('role', 'status') // Announce status to screen readers | ||
} | ||
|
||
hideCookieBanner () { | ||
if (this.banner) { | ||
this.banner.style.display = 'none' | ||
this.banner.setAttribute('aria-hidden', 'true') | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
.app-c-cookie-banner__form--hidden { | ||
display: none; | ||
} | ||
|
||
.app-c-cookie-banner__confirmation--hidden { | ||
display: none; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
{% from "govuk/components/cookie-banner/macro.njk" import govukCookieBanner %} | ||
|
||
{% if serviceType %} | ||
{% set serviceName = serviceType | getFullServiceName %} | ||
{% endif %} | ||
{% set cookiePagePath = '/cookies' %} | ||
{% set cookieHeader = "Cookies on " + serviceName %} | ||
|
||
{% set html %} | ||
<p class="govuk-body">We use some essential cookies to make this service work.</p> | ||
<p class="govuk-body">We’d also like to use analytics cookies so we can understand how you use the service and make improvements.</p> | ||
{% endset %} | ||
|
||
{% set acceptHtml %} | ||
<p class="govuk-body">You’ve <span class="js-app-c-cookie-banner__confirmation-decision">accepted</span> additional cookies. You can <a class="govuk-link" href="{{ cookiePagePath }}">change your cookie settings</a> at any time.</p> | ||
{% endset %} | ||
|
||
<div class="js-app-c-cookie-banner"> | ||
<div class="js-app-c-cookie-banner__form"> | ||
{{ govukCookieBanner({ | ||
ariaLabel: cookieHeader, | ||
messages: [ | ||
{ | ||
headingText: cookieHeader, | ||
html: html, | ||
actions: [ | ||
{ | ||
text: "Accept analytics cookies", | ||
type: "button", | ||
classes: "js-app-c-cookie-banner__accept" | ||
}, | ||
{ | ||
text: "Reject analytics cookies", | ||
type: "button", | ||
classes: "js-app-c-cookie-banner__reject" | ||
}, | ||
{ | ||
text: "View cookies", | ||
href: cookiePagePath | ||
} | ||
] | ||
} | ||
] | ||
}) }} | ||
</div> | ||
|
||
<div class="js-app-c-cookie-banner__confirmation app-c-cookie-banner__confirmation--hidden" aria-hidden="true"> | ||
{{ govukCookieBanner({ | ||
ariaLabel: cookieHeader, | ||
messages: [ | ||
{ | ||
html: acceptHtml, | ||
actions: [ | ||
{ | ||
text: "Hide cookie message", | ||
type: "button", | ||
classes: "js-app-c-cookie-banner__hide" | ||
} | ||
] | ||
} | ||
] | ||
}) }} | ||
</div> | ||
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import BasePage from './BasePage' | ||
|
||
export default class CookiesPage extends BasePage { | ||
constructor (page) { | ||
super(page, '/cookies') | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import { test, expect } from '@playwright/test' | ||
|
||
import CookiesPage from '../PageObjectModels/cookiesPage' | ||
import { beforeEach } from 'node:test' | ||
|
||
test.describe('Cookies page', () => { | ||
beforeEach(async ({ page }) => { | ||
await page.context().clearCookies() | ||
}) | ||
|
||
test('has title', async ({ page }) => { | ||
const cookiesPage = new CookiesPage(page) | ||
await cookiesPage.navigateHere() | ||
|
||
await expect(page).toHaveTitle('Cookie notice for Submit and update planning and housing data for England - Submit and update your planning data') | ||
}) | ||
|
||
test('Can find and select the accept cookies radio button and submit the form', async ({ page, context }) => { | ||
const cookiesPage = new CookiesPage(page) | ||
await cookiesPage.navigateHere() | ||
|
||
const acceptCookiesRadio = await page.locator('form input[name="accept_cookies"][value="true"]') | ||
await acceptCookiesRadio.click() | ||
await page.locator('form').evaluate(form => form.submit()) | ||
|
||
await expect(page).toHaveURL(cookiesPage.url) | ||
await expect(page.locator('.govuk-notification-banner__heading')).toHaveText('You’ve updated your cookie preferences') | ||
|
||
const cookies = await context.cookies() | ||
const cookiesPreferencesSet = cookies.find(cookie => cookie.name === 'cookies_preferences_set') | ||
const cookiesPolicy = cookies.find(cookie => cookie.name === 'cookies_policy') | ||
|
||
await expect(cookiesPreferencesSet).toBeDefined() | ||
await expect(cookiesPreferencesSet.value).toBe('true') | ||
await expect(cookiesPolicy).toBeDefined() | ||
await expect(cookiesPolicy.value).toBe(encodeURIComponent('{"essential":true,"settings":true,"usage":true,"campaigns":true}')) | ||
}) | ||
|
||
test('Can reject cookies', async ({ page, context }) => { | ||
const cookiesPage = new CookiesPage(page) | ||
await cookiesPage.navigateHere() | ||
|
||
const acceptCookiesRadio = await page.locator('form input[name="accept_cookies"][value="false"]') | ||
await acceptCookiesRadio.click() | ||
await page.locator('form').evaluate(form => form.submit()) | ||
|
||
await expect(page).toHaveURL(cookiesPage.url) | ||
await expect(page.locator('.govuk-notification-banner__heading')).toHaveText('You’ve updated your cookie preferences') | ||
|
||
const cookies = await context.cookies() | ||
const cookiesPreferencesSet = cookies.find(cookie => cookie.name === 'cookies_preferences_set') | ||
|
||
await expect(cookiesPreferencesSet).toBeDefined() | ||
await expect(cookiesPreferencesSet.value).toBe('false') | ||
}) | ||
}) |
Oops, something went wrong.