From a30c33e3edcaaa1cdf0a18472e282353b977da7c Mon Sep 17 00:00:00 2001 From: Tim Weise Date: Wed, 19 Apr 2023 16:01:09 +0200 Subject: [PATCH 01/16] =?UTF-8?q?docs:=20=F0=9F=93=9D=20fix=20typos=20and?= =?UTF-8?q?=20minor=20grammatical=20errors?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 85e12f5..e45edd8 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ For that, some kind of component might help which provides a sleek, but customiz That's where the Cookie Consent Banner comes in. In order to focus on the things that really matter, the Cookie Consent Banner supports us to fulfill that requirement. -It visualizes the available categories, like `technically required` and `analysis`, stores the decision of the user and provides an event-based API for you to handle appropriately. And of course, the consent data is stored locally in the vistors browser. +It visualizes the available categories, like `technically required` and `analysis`, stores the decision of the user and provides an event-based API for you to handle appropriately. And of course, the consent data is stored locally in the vistor's browser. ![](./assets/example.png) @@ -33,14 +33,14 @@ It visualizes the available categories, like `technically required` and `analysi ## :arrows_counterclockwise: Consent Flow -The consent banner has two tasks: Provide an UI Component with which visitors of your web application can choose which cookies they want to accept and to provide you an API to react on the choosen settings. +The consent banner has two tasks: Providing a UI Component to allow visitors of your web application to choose which cookies they want to accept, and the ability to react on the choosen settings via an API. -There are two typical scenarios. Either the external scripts, which set cookies are managed through a tag manager of your choice using the consent data, or the scripts are loaded or configured directly on code level. +There are two typical scenarios: Either the external scripts, which set cookies are managed through a tag manager of your choice using the consent data, or the scripts are loaded or configured directly on code level. ### Using a Tag Manager -The flow could look like this. Every script that sets cookies which require a consent from the visitor is blocked by default. -Instead, the Consent Banner is shown. Once the visitor updates it's preferences an event is triggered (`cookie_consent_preferences_updated`). +The flow could look like this: Every script that sets cookies which require a consent from the visitor is blocked by default. +Instead, the Consent Banner is shown. Once the visitor updates its preferences an event is triggered (`cookie_consent_preferences_updated`). Additionally the consent data is stored within a cookie in a format that can be parsed either programmatically or with a tag manager (e.g.: name: `cookies_accepted_categories`, value: `technically_required,analytics,marketing`). A tag manager could read the value of that `1st-Party Cookie` before any other script (tag) is loaded (e.g.: Fire trigger only `if Accepted Cookie Categories contains marketing`). ![](./assets/consentFlow.svg) @@ -51,9 +51,9 @@ Have a look on the Real World example using the React Component: [`packages/cook ## :spiral_notepad: Documentation -The Cookie Consent Banner supports multiple frontend frameworks, because it is build as an agnostic web component. +The Cookie Consent Banner supports multiple frontend frameworks, because it is built as an agnostic web component. For easier integration we also provide a wrapper component for React environments. -It's necessary to set at least the required properties for the component to work properly (see the provided examples). +It's necessary to set at least the required properties for the component in order to work properly (see the provided examples). ### Web Component – Vanilla JS From 496cfc97ddc85be196b58e739d648b85d6059b04 Mon Sep 17 00:00:00 2001 From: Tim Weise Date: Wed, 19 Apr 2023 16:29:15 +0200 Subject: [PATCH 02/16] =?UTF-8?q?chore:=20=F0=9F=9A=A8=20=20fix=20linter?= =?UTF-8?q?=20config?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 4 ++++ packages/cookie-consent-banner/.eslintrc | 5 +++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index ac4a763..6503b6b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -15,6 +15,10 @@ "typescriptreact", "html" ], + "eslint.workingDirectories": [ + "packages/cookie-consent-banner-react", + "packages/cookie-consent-banner", + ], "editor.formatOnSave": true, "[javascript]": { "editor.formatOnSave": false diff --git a/packages/cookie-consent-banner/.eslintrc b/packages/cookie-consent-banner/.eslintrc index 398d886..44fad3d 100644 --- a/packages/cookie-consent-banner/.eslintrc +++ b/packages/cookie-consent-banner/.eslintrc @@ -6,5 +6,6 @@ "rules": { "react/react-in-jsx-scope": "off", "react/no-unknown-property": "off" - } -} \ No newline at end of file + }, + "plugins": ["eslint-plugin-html"] +} From e78022234ea4cec9f51c2929f7ec51d1b6ffe519 Mon Sep 17 00:00:00 2001 From: Tim Weise Date: Wed, 19 Apr 2023 16:39:53 +0200 Subject: [PATCH 03/16] =?UTF-8?q?chore:=20=F0=9F=94=A7=20add=20prettier=20?= =?UTF-8?q?config=20on=20root?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .prettierrc | 1 + package.json | 1 + packages/cookie-consent-banner-react/package.json | 1 - packages/cookie-consent-banner/package.json | 1 - yarn.lock | 3 +-- 5 files changed, 3 insertions(+), 4 deletions(-) create mode 100644 .prettierrc diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..5f097e0 --- /dev/null +++ b/.prettierrc @@ -0,0 +1 @@ +"@porscheofficial/prettier-config-porschedigital" diff --git a/package.json b/package.json index 6b717ae..d1b0876 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "test:ci": "echo \"Root doesn't have any tests defined.\"" }, "devDependencies": { + "@porscheofficial/prettier-config-porschedigital": "2.3.0", "@types/node": "18.11.18", "typescript": "4.9.4" }, diff --git a/packages/cookie-consent-banner-react/package.json b/packages/cookie-consent-banner-react/package.json index c907146..d9c2ee1 100644 --- a/packages/cookie-consent-banner-react/package.json +++ b/packages/cookie-consent-banner-react/package.json @@ -44,7 +44,6 @@ }, "devDependencies": { "@porscheofficial/eslint-config-porschedigital-react": "2.3.0", - "@porscheofficial/prettier-config-porschedigital": "2.3.0", "@types/react": "18.0.27", "@types/react-dom": "18.0.10", "eslint": "8.32.0", diff --git a/packages/cookie-consent-banner/package.json b/packages/cookie-consent-banner/package.json index 6a2609c..eaceee6 100644 --- a/packages/cookie-consent-banner/package.json +++ b/packages/cookie-consent-banner/package.json @@ -48,7 +48,6 @@ }, "devDependencies": { "@porscheofficial/eslint-config-porschedigital-react": "2.3.0", - "@porscheofficial/prettier-config-porschedigital": "2.3.0", "@stencil/react-output-target": "0.4.0", "@types/jest": "27.5.2", "@types/puppeteer": "5.4.7", diff --git a/yarn.lock b/yarn.lock index d2442d2..9c01a8d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -789,7 +789,6 @@ __metadata: dependencies: "@porscheofficial/cookie-consent-banner": 3.1.2 "@porscheofficial/eslint-config-porschedigital-react": 2.3.0 - "@porscheofficial/prettier-config-porschedigital": 2.3.0 "@types/react": 18.0.27 "@types/react-dom": 18.0.10 eslint: 8.32.0 @@ -810,7 +809,6 @@ __metadata: resolution: "@porscheofficial/cookie-consent-banner@workspace:packages/cookie-consent-banner" dependencies: "@porscheofficial/eslint-config-porschedigital-react": 2.3.0 - "@porscheofficial/prettier-config-porschedigital": 2.3.0 "@stencil/core": 2.22.1 "@stencil/react-output-target": 0.4.0 "@types/jest": 27.5.2 @@ -6225,6 +6223,7 @@ __metadata: version: 0.0.0-use.local resolution: "root-workspace-0b6124@workspace:." dependencies: + "@porscheofficial/prettier-config-porschedigital": 2.3.0 "@types/node": 18.11.18 typescript: 4.9.4 languageName: unknown From 1150e1ea9f745ce033affbf7c7b2d402d214e31f Mon Sep 17 00:00:00 2001 From: Tim Weise Date: Wed, 19 Apr 2023 16:56:32 +0200 Subject: [PATCH 04/16] =?UTF-8?q?chore:=20=F0=9F=94=A7=20add=20default=20f?= =?UTF-8?q?ormatter=20to=20vscode=20config?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 1 + 1 file changed, 1 insertion(+) diff --git a/.vscode/settings.json b/.vscode/settings.json index 6503b6b..6df1b95 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -33,6 +33,7 @@ "editor.formatOnSave": false }, "editor.formatOnType": true, + "editor.defaultFormatter": "esbenp.prettier-vscode", "typescript.tsdk": "node_modules/typescript/lib", "editor.codeActionsOnSave": { "source.fixAll.eslint": true From 80e434e4b0f5c4af74b746b46241f0d8bbdeafcc Mon Sep 17 00:00:00 2001 From: Tim Weise Date: Thu, 20 Apr 2023 10:46:54 +0200 Subject: [PATCH 05/16] =?UTF-8?q?fix:=20=F0=9F=90=9B=20correctly=20parse?= =?UTF-8?q?=20cookie?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cookie-consent-banner/cookie-consent-banner.tsx | 5 ++--- .../cookie-consent-banner/src/utils/parseCookies.ts | 13 +++++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 packages/cookie-consent-banner/src/utils/parseCookies.ts diff --git a/packages/cookie-consent-banner/src/components/cookie-consent-banner/cookie-consent-banner.tsx b/packages/cookie-consent-banner/src/components/cookie-consent-banner/cookie-consent-banner.tsx index 1bc2cf2..853b45f 100644 --- a/packages/cookie-consent-banner/src/components/cookie-consent-banner/cookie-consent-banner.tsx +++ b/packages/cookie-consent-banner/src/components/cookie-consent-banner/cookie-consent-banner.tsx @@ -11,6 +11,7 @@ import { JSX, } from "@stencil/core"; import { CategoryItem } from "./types"; +import { getCookie } from "../../utils/parseCookies"; @Component({ tag: "cookie-consent-banner", @@ -128,9 +129,7 @@ export class CookieConsentBanner { let cookieValues: string[] = []; if (document.cookie) { - const cookieValueString = - `; ${document.cookie}`.split(`; ${this.cookieName}=`).pop() ?? - "".split(";").shift(); + const cookieValueString = getCookie(this.cookieName); cookieValues = cookieValueString ? cookieValueString.split(",") : []; } diff --git a/packages/cookie-consent-banner/src/utils/parseCookies.ts b/packages/cookie-consent-banner/src/utils/parseCookies.ts new file mode 100644 index 0000000..b16ff53 --- /dev/null +++ b/packages/cookie-consent-banner/src/utils/parseCookies.ts @@ -0,0 +1,13 @@ +export const parseCookies = () => + document.cookie + .split(";") + .reduce>((acc, curr) => { + const [key, value] = curr.split("="); + + // key and value may be surrounded by whitespace (space and tab characters) + const cookieKey = key.trim(); + const cookieValue= value.trim(); + return { ...acc, [cookieKey]: cookieValue }; + }, {}); + +export const getCookie = (cookieName: string) => parseCookies()[cookieName]; From cc810fd37f0cad4f7b4ae4af9cf62a0934a4d6cb Mon Sep 17 00:00:00 2001 From: Tim Weise Date: Mon, 24 Apr 2023 13:46:14 +0200 Subject: [PATCH 06/16] =?UTF-8?q?chore:=20=E2=9E=95=20add=20eslint-plugin-?= =?UTF-8?q?html=20dev=20dependency?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/cookie-consent-banner/package.json | 1 + yarn.lock | 67 +++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/packages/cookie-consent-banner/package.json b/packages/cookie-consent-banner/package.json index eaceee6..b791804 100644 --- a/packages/cookie-consent-banner/package.json +++ b/packages/cookie-consent-banner/package.json @@ -52,6 +52,7 @@ "@types/jest": "27.5.2", "@types/puppeteer": "5.4.7", "eslint": "8.32.0", + "eslint-plugin-html": "^7.1.0", "jest": "27.5.1", "jest-cli": "27.5.1", "prettier": "2.8.3", diff --git a/yarn.lock b/yarn.lock index 9c01a8d..f816175 100644 --- a/yarn.lock +++ b/yarn.lock @@ -814,6 +814,7 @@ __metadata: "@types/jest": 27.5.2 "@types/puppeteer": 5.4.7 eslint: 8.32.0 + eslint-plugin-html: ^7.1.0 jest: 27.5.1 jest-cli: 27.5.1 prettier: 2.8.3 @@ -2489,6 +2490,24 @@ __metadata: languageName: node linkType: hard +"dom-serializer@npm:^2.0.0": + version: 2.0.0 + resolution: "dom-serializer@npm:2.0.0" + dependencies: + domelementtype: ^2.3.0 + domhandler: ^5.0.2 + entities: ^4.2.0 + checksum: cd1810544fd8cdfbd51fa2c0c1128ec3a13ba92f14e61b7650b5de421b88205fd2e3f0cc6ace82f13334114addb90ed1c2f23074a51770a8e9c1273acbc7f3e6 + languageName: node + linkType: hard + +"domelementtype@npm:^2.3.0": + version: 2.3.0 + resolution: "domelementtype@npm:2.3.0" + checksum: ee837a318ff702622f383409d1f5b25dd1024b692ef64d3096ff702e26339f8e345820f29a68bcdcea8cfee3531776b3382651232fbeae95612d6f0a75efb4f6 + languageName: node + linkType: hard + "domexception@npm:^2.0.1": version: 2.0.1 resolution: "domexception@npm:2.0.1" @@ -2498,6 +2517,26 @@ __metadata: languageName: node linkType: hard +"domhandler@npm:^5.0.1, domhandler@npm:^5.0.2, domhandler@npm:^5.0.3": + version: 5.0.3 + resolution: "domhandler@npm:5.0.3" + dependencies: + domelementtype: ^2.3.0 + checksum: 0f58f4a6af63e6f3a4320aa446d28b5790a009018707bce2859dcb1d21144c7876482b5188395a188dfa974238c019e0a1e610d2fc269a12b2c192ea2b0b131c + languageName: node + linkType: hard + +"domutils@npm:^3.0.1": + version: 3.0.1 + resolution: "domutils@npm:3.0.1" + dependencies: + dom-serializer: ^2.0.0 + domelementtype: ^2.3.0 + domhandler: ^5.0.1 + checksum: 23aa7a840572d395220e173cb6263b0d028596e3950100520870a125af33ff819e6f609e1606d6f7d73bd9e7feb03bb404286e57a39063b5384c62b724d987b3 + languageName: node + linkType: hard + "dot-prop@npm:^5.1.0": version: 5.3.0 resolution: "dot-prop@npm:5.3.0" @@ -2563,6 +2602,13 @@ __metadata: languageName: node linkType: hard +"entities@npm:^4.2.0, entities@npm:^4.4.0": + version: 4.5.0 + resolution: "entities@npm:4.5.0" + checksum: 853f8ebd5b425d350bffa97dd6958143179a5938352ccae092c62d1267c4e392a039be1bae7d51b6e4ffad25f51f9617531fedf5237f15df302ccfb452cbf2d7 + languageName: node + linkType: hard + "env-paths@npm:^2.2.0": version: 2.2.1 resolution: "env-paths@npm:2.2.1" @@ -2756,6 +2802,15 @@ __metadata: languageName: node linkType: hard +"eslint-plugin-html@npm:^7.1.0": + version: 7.1.0 + resolution: "eslint-plugin-html@npm:7.1.0" + dependencies: + htmlparser2: ^8.0.1 + checksum: e92b0cf759c8d8aecff8fdea259fdc801fcff775096756d0b5a24f0c846012232fe74eaf44ea9b31b88e695605a8eff437e5fa440a4beed79c35dfaac190db79 + languageName: node + linkType: hard + "eslint-plugin-import@npm:2.27.5": version: 2.27.5 resolution: "eslint-plugin-import@npm:2.27.5" @@ -3663,6 +3718,18 @@ __metadata: languageName: node linkType: hard +"htmlparser2@npm:^8.0.1": + version: 8.0.2 + resolution: "htmlparser2@npm:8.0.2" + dependencies: + domelementtype: ^2.3.0 + domhandler: ^5.0.3 + domutils: ^3.0.1 + entities: ^4.4.0 + checksum: 29167a0f9282f181da8a6d0311b76820c8a59bc9e3c87009e21968264c2987d2723d6fde5a964d4b7b6cba663fca96ffb373c06d8223a85f52a6089ced942700 + languageName: node + linkType: hard + "http-cache-semantics@npm:^4.1.0": version: 4.1.0 resolution: "http-cache-semantics@npm:4.1.0" From 0b44f32e341fa37bf6be82d1d6c30111816704f3 Mon Sep 17 00:00:00 2001 From: Tim Weise Date: Mon, 24 Apr 2023 13:48:59 +0200 Subject: [PATCH 07/16] =?UTF-8?q?chore:=20=F0=9F=8F=B7=EF=B8=8F=20add=20ex?= =?UTF-8?q?plicit=20return=20types?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/cookie-consent-banner/src/utils/parseCookies.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/cookie-consent-banner/src/utils/parseCookies.ts b/packages/cookie-consent-banner/src/utils/parseCookies.ts index b16ff53..c2d6810 100644 --- a/packages/cookie-consent-banner/src/utils/parseCookies.ts +++ b/packages/cookie-consent-banner/src/utils/parseCookies.ts @@ -1,7 +1,9 @@ -export const parseCookies = () => +export type CookieMap = Record + +export const parseCookies = (): CookieMap => document.cookie .split(";") - .reduce>((acc, curr) => { + .reduce((acc, curr) => { const [key, value] = curr.split("="); // key and value may be surrounded by whitespace (space and tab characters) @@ -10,4 +12,4 @@ export const parseCookies = () => return { ...acc, [cookieKey]: cookieValue }; }, {}); -export const getCookie = (cookieName: string) => parseCookies()[cookieName]; +export const getCookie = (cookieName: string): string | undefined => parseCookies()[cookieName]; From 70952c1ece0fcf7ded10ad287bb11e4f52cfd74a Mon Sep 17 00:00:00 2001 From: Tim Weise Date: Mon, 24 Apr 2023 13:49:54 +0200 Subject: [PATCH 08/16] =?UTF-8?q?chore:=20=E2=9C=8F=EF=B8=8F=20=20invisibl?= =?UTF-8?q?e=20U+00a0=20char=20sneaked=20in?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/cookie-consent-banner/src/utils/parseCookies.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cookie-consent-banner/src/utils/parseCookies.ts b/packages/cookie-consent-banner/src/utils/parseCookies.ts index c2d6810..90395f0 100644 --- a/packages/cookie-consent-banner/src/utils/parseCookies.ts +++ b/packages/cookie-consent-banner/src/utils/parseCookies.ts @@ -12,4 +12,4 @@ export const parseCookies = (): CookieMap => return { ...acc, [cookieKey]: cookieValue }; }, {}); -export const getCookie = (cookieName: string): string | undefined => parseCookies()[cookieName]; +export const getCookie = (cookieName: string): string | undefined => parseCookies()[cookieName]; From d7736bdabbb3ec829085b606caf08e6f53ddcbbe Mon Sep 17 00:00:00 2001 From: Tim Weise Date: Mon, 24 Apr 2023 14:13:54 +0200 Subject: [PATCH 09/16] =?UTF-8?q?chore:=20=E2=9C=85=20add=20unit=20tests?= =?UTF-8?q?=20for=20parseCookies?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/utils/parseCookies.test.ts | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 packages/cookie-consent-banner/src/utils/parseCookies.test.ts diff --git a/packages/cookie-consent-banner/src/utils/parseCookies.test.ts b/packages/cookie-consent-banner/src/utils/parseCookies.test.ts new file mode 100644 index 0000000..278f1b8 --- /dev/null +++ b/packages/cookie-consent-banner/src/utils/parseCookies.test.ts @@ -0,0 +1,106 @@ +import { parseCookies, CookieMap } from "./parseCookies"; + +const mockDocumentCookie = (cookieString: string) => + Object.defineProperty(window.document, "cookie", { + writable: true, + value: cookieString, + }); + +describe("parseCookies", () => { + it("should work with one cookie", () => { + const cookieStringSingle = "first=someValue"; + const expectedParsed: CookieMap = { + first: "someValue", + }; + + mockDocumentCookie(cookieStringSingle); + + expect(parseCookies()).toMatchObject(expectedParsed); + }); + + it("should work with multiple cookies", () => { + const cookieStringSingle = "first=someValue;second=someValue;third=someValue"; + const expectedParsed: CookieMap = { + first: "someValue", + second: "someValue", + third: "someValue", + }; + + mockDocumentCookie(cookieStringSingle); + + expect(parseCookies()).toMatchObject(expectedParsed); + }); + + it("should trim leading spaces", () => { + const cookieStringWithLeadingSpaces = "first=someValue; second=someValue"; + const expectedParsed: CookieMap = { + first: "someValue", + second: "someValue", + }; + + mockDocumentCookie(cookieStringWithLeadingSpaces); + + expect(parseCookies()).toMatchObject(expectedParsed); + }); + + it("should trim trailing spaces", () => { + const cookieStringWithTrailingSpaces = "first=someValue ;second=someValue"; + const expectedParsed: CookieMap = { + first: "someValue", + second: "someValue", + }; + + mockDocumentCookie(cookieStringWithTrailingSpaces); + + expect(parseCookies()).toMatchObject(expectedParsed); + }); + + it("should trim leading and trailing spaces", () => { + const cookieStringLeadingAndTrailingSpaces = + " first=someValue ;second=someValue"; + const expectedParsed: CookieMap = { + first: "someValue", + second: "someValue", + }; + + mockDocumentCookie(cookieStringLeadingAndTrailingSpaces); + + expect(parseCookies()).toMatchObject(expectedParsed); + }); + + it("should trim leading tabs", () => { + const cookieStringWithLeadingTabs = "\tfirst=someValue;second=someValue"; + const expectedParsed: CookieMap = { + first: "someValue", + second: "someValue", + }; + + mockDocumentCookie(cookieStringWithLeadingTabs); + + expect(parseCookies()).toMatchObject(expectedParsed); + }); + + it("should trim trailing tabs", () => { + const cookieStringWithTrailingTabs = "first=someValue\t;second=someValue"; + const expectedParsed: CookieMap = { + first: "someValue", + second: "someValue", + }; + + mockDocumentCookie(cookieStringWithTrailingTabs); + + expect(parseCookies()).toMatchObject(expectedParsed); + }); + + it("should trim leading and trailing tabs", () => { + const cookieStringLeadingAndTrailingTabs = "\tfirst=someValue\t;second=someValue"; + const expectedParsed: CookieMap = { + first: "someValue", + second: "someValue", + }; + + mockDocumentCookie(cookieStringLeadingAndTrailingTabs); + + expect(parseCookies()).toMatchObject(expectedParsed); + }); +}); From cbdd8d5e890eb400cfee0816d670d3a71cb1f6cc Mon Sep 17 00:00:00 2001 From: Tim Weise Date: Mon, 24 Apr 2023 14:18:17 +0200 Subject: [PATCH 10/16] =?UTF-8?q?chore:=20=F0=9F=8E=A8=20fix=20code=20styl?= =?UTF-8?q?e=20with=20prettier?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/utils/parseCookies.test.ts | 6 ++++-- .../src/utils/parseCookies.ts | 21 +++++++++---------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/packages/cookie-consent-banner/src/utils/parseCookies.test.ts b/packages/cookie-consent-banner/src/utils/parseCookies.test.ts index 278f1b8..df17ee3 100644 --- a/packages/cookie-consent-banner/src/utils/parseCookies.test.ts +++ b/packages/cookie-consent-banner/src/utils/parseCookies.test.ts @@ -19,7 +19,8 @@ describe("parseCookies", () => { }); it("should work with multiple cookies", () => { - const cookieStringSingle = "first=someValue;second=someValue;third=someValue"; + const cookieStringSingle = + "first=someValue;second=someValue;third=someValue"; const expectedParsed: CookieMap = { first: "someValue", second: "someValue", @@ -93,7 +94,8 @@ describe("parseCookies", () => { }); it("should trim leading and trailing tabs", () => { - const cookieStringLeadingAndTrailingTabs = "\tfirst=someValue\t;second=someValue"; + const cookieStringLeadingAndTrailingTabs = + "\tfirst=someValue\t;second=someValue"; const expectedParsed: CookieMap = { first: "someValue", second: "someValue", diff --git a/packages/cookie-consent-banner/src/utils/parseCookies.ts b/packages/cookie-consent-banner/src/utils/parseCookies.ts index 90395f0..6bd9d98 100644 --- a/packages/cookie-consent-banner/src/utils/parseCookies.ts +++ b/packages/cookie-consent-banner/src/utils/parseCookies.ts @@ -1,15 +1,14 @@ -export type CookieMap = Record +export type CookieMap = Record; export const parseCookies = (): CookieMap => - document.cookie - .split(";") - .reduce((acc, curr) => { - const [key, value] = curr.split("="); + document.cookie.split(";").reduce((acc, curr) => { + const [key, value] = curr.split("="); - // key and value may be surrounded by whitespace (space and tab characters) - const cookieKey = key.trim(); - const cookieValue= value.trim(); - return { ...acc, [cookieKey]: cookieValue }; - }, {}); + // key and value may be surrounded by whitespace (space and tab characters) + const cookieKey = key.trim(); + const cookieValue = value.trim(); + return { ...acc, [cookieKey]: cookieValue }; + }, {}); -export const getCookie = (cookieName: string): string | undefined => parseCookies()[cookieName]; +export const getCookie = (cookieName: string): string | undefined => + parseCookies()[cookieName]; From 0e152ce48b3f8f38f77c8955dbd69871f525ed25 Mon Sep 17 00:00:00 2001 From: Tim Weise Date: Mon, 24 Apr 2023 14:22:20 +0200 Subject: [PATCH 11/16] =?UTF-8?q?chore:=20=F0=9F=8F=B7=EF=B8=8F=20=20add?= =?UTF-8?q?=20explicit=20return=20type=20in=20test=20mock=20fn?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/cookie-consent-banner/src/utils/parseCookies.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cookie-consent-banner/src/utils/parseCookies.test.ts b/packages/cookie-consent-banner/src/utils/parseCookies.test.ts index df17ee3..5ab9f7d 100644 --- a/packages/cookie-consent-banner/src/utils/parseCookies.test.ts +++ b/packages/cookie-consent-banner/src/utils/parseCookies.test.ts @@ -1,6 +1,6 @@ import { parseCookies, CookieMap } from "./parseCookies"; -const mockDocumentCookie = (cookieString: string) => +const mockDocumentCookie = (cookieString: string): Document => Object.defineProperty(window.document, "cookie", { writable: true, value: cookieString, From 4338fae752570f6abbc677058c3eeeab2ae02556 Mon Sep 17 00:00:00 2001 From: Tim Weise Date: Mon, 24 Apr 2023 15:16:35 +0200 Subject: [PATCH 12/16] =?UTF-8?q?chore:=20=E2=9C=85=20add=20e2e=20tests?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .vscode/settings.json | 3 +- .../cookie-consent-banner.test.ts | 114 ++++++++++++++++++ 2 files changed, 116 insertions(+), 1 deletion(-) create mode 100644 packages/cookie-consent-banner/src/components/cookie-consent-banner/cookie-consent-banner.test.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index 6df1b95..0590d6e 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,7 +5,8 @@ ".jsx", ".html", ".ts", - ".tsx" + ".tsx", + ".test.ts" ] }, "eslint.validate": [ diff --git a/packages/cookie-consent-banner/src/components/cookie-consent-banner/cookie-consent-banner.test.ts b/packages/cookie-consent-banner/src/components/cookie-consent-banner/cookie-consent-banner.test.ts new file mode 100644 index 0000000..e5c6bba --- /dev/null +++ b/packages/cookie-consent-banner/src/components/cookie-consent-banner/cookie-consent-banner.test.ts @@ -0,0 +1,114 @@ +import { E2EPage, newE2EPage } from "@stencil/core/testing"; + +const cookieBannerFullyConfigured = ` + + We use cookies and similar technologies to provide certain features, + enhance the user experience and deliver content that is relevant to your + interests. Depending on their purpose, analysis and marketing cookies may + be used in addition to technically necessary cookies. By clicking on + "Agree and continue", you declare your consent to the use of the + aforementioned cookies. + + Here + + you can make detailed settings or revoke your consent (in part if + necessary) with effect for the future. For further information, please + refer to our + Privacy Policy + . + +`; + +const clearCookies = async (page: E2EPage): Promise => { + const cookies = (await page.cookies()).map(({ name }) => { + return { + name, + }; + }); + await Promise.allSettled(cookies.map(async (cookie) => page.deleteCookie(cookie))); +}; + +describe("Cookie Consent Banner", () => { + let page: E2EPage; + + beforeEach(async () => { + page = await newE2EPage(); + await clearCookies(page); + }); + + it("should render", async () => { + await page.setContent(cookieBannerFullyConfigured); + + const cookieBanner = await page.find("cookie-consent-banner"); + + expect(cookieBanner).toBeDefined(); + expect(cookieBanner).toHaveClasses(["hydrated"]); + }); + + it("should be displayed if no cookies are set", async () => { + await page.setContent(cookieBannerFullyConfigured); + const cookieBannerInnerDiv = await page.find( + "cookie-consent-banner >>> .cc" + ); + + expect(cookieBannerInnerDiv).toBeDefined(); + }); + + it("should be displayed if cookies other than cookieName are set", async () => { + await page.setContent(cookieBannerFullyConfigured); + await page.setCookie({ + name: "someUnrelatedCookie", + value: "someValue", + domain: ".www.porsche.digital", + }); + const cookieBannerInnerDiv = await page.find( + "cookie-consent-banner >>> .cc" + ); + + expect(cookieBannerInnerDiv).toBeDefined(); + }); + + it("should not be displayed if cookieName cookie is set", async () => { + // default `cookieName` is cookies_accepted_categories + await page.setCookie({ + name: "cookies_accepted_categories", + value: "technically_required,analytics", + domain: ".www.porsche.digital", + }); + await page.setContent(cookieBannerFullyConfigured); + const cookieBannerInnerDiv = await page.find( + "cookie-consent-banner >>> .cc" + ); + + expect(cookieBannerInnerDiv).toBeNull(); + }); + + it("should not be displayed if cookieName cookie and other cookies are set", async () => { + // default `cookieName` is cookies_accepted_categories + await page.setCookie({ + name: "cookies_accepted_categories", + value: "technically_required,analytics", + domain: ".www.porsche.digital", + }); + + await page.setCookie({ + name: "someUnrelatedCookie", + value: "someValue", + domain: ".www.porsche.digital", + }); + await page.setContent(cookieBannerFullyConfigured); + const cookieBannerInnerDiv = await page.find( + "cookie-consent-banner >>> .cc" + ); + + expect(cookieBannerInnerDiv).toBeNull(); + }); +}); From 64b78834dc64f68318653479e1ae7206e26566a0 Mon Sep 17 00:00:00 2001 From: Tim Weise Date: Mon, 24 Apr 2023 15:33:08 +0200 Subject: [PATCH 13/16] =?UTF-8?q?chore:=20=E2=9C=85=20fix=20domains=20in?= =?UTF-8?q?=20e2e=20tests,=20rmv=20clearCookies?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../cookie-consent-banner.test.ts | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/packages/cookie-consent-banner/src/components/cookie-consent-banner/cookie-consent-banner.test.ts b/packages/cookie-consent-banner/src/components/cookie-consent-banner/cookie-consent-banner.test.ts index e5c6bba..c035b49 100644 --- a/packages/cookie-consent-banner/src/components/cookie-consent-banner/cookie-consent-banner.test.ts +++ b/packages/cookie-consent-banner/src/components/cookie-consent-banner/cookie-consent-banner.test.ts @@ -27,21 +27,11 @@ const cookieBannerFullyConfigured = ` `; -const clearCookies = async (page: E2EPage): Promise => { - const cookies = (await page.cookies()).map(({ name }) => { - return { - name, - }; - }); - await Promise.allSettled(cookies.map(async (cookie) => page.deleteCookie(cookie))); -}; - describe("Cookie Consent Banner", () => { let page: E2EPage; beforeEach(async () => { page = await newE2EPage(); - await clearCookies(page); }); it("should render", async () => { @@ -67,7 +57,7 @@ describe("Cookie Consent Banner", () => { await page.setCookie({ name: "someUnrelatedCookie", value: "someValue", - domain: ".www.porsche.digital", + domain: "localhost", }); const cookieBannerInnerDiv = await page.find( "cookie-consent-banner >>> .cc" @@ -81,7 +71,7 @@ describe("Cookie Consent Banner", () => { await page.setCookie({ name: "cookies_accepted_categories", value: "technically_required,analytics", - domain: ".www.porsche.digital", + domain: "localhost", }); await page.setContent(cookieBannerFullyConfigured); const cookieBannerInnerDiv = await page.find( @@ -96,13 +86,13 @@ describe("Cookie Consent Banner", () => { await page.setCookie({ name: "cookies_accepted_categories", value: "technically_required,analytics", - domain: ".www.porsche.digital", + domain: "localhost", }); await page.setCookie({ name: "someUnrelatedCookie", value: "someValue", - domain: ".www.porsche.digital", + domain: "localhost", }); await page.setContent(cookieBannerFullyConfigured); const cookieBannerInnerDiv = await page.find( From 66c1a62ebd1cd1799df5fbe03e2ee856ca7fa177 Mon Sep 17 00:00:00 2001 From: Tim Weise Date: Mon, 24 Apr 2023 15:36:57 +0200 Subject: [PATCH 14/16] =?UTF-8?q?chore:=20=F0=9F=94=A8=20add=20e2e=20optio?= =?UTF-8?q?n=20to=20test:ci?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/cookie-consent-banner/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cookie-consent-banner/package.json b/packages/cookie-consent-banner/package.json index b791804..76f9a88 100644 --- a/packages/cookie-consent-banner/package.json +++ b/packages/cookie-consent-banner/package.json @@ -18,7 +18,7 @@ "release:prepare": "standard-version", "test": "stencil test --spec --e2e", "test:watch": "stencil test --spec --e2e --watchAll", - "test:ci": "yarn prettier:ci && yarn eslint:ci && stencil test --spec --passWithNoTests" + "test:ci": "yarn prettier:ci && yarn eslint:ci && stencil test --spec --e2e --passWithNoTests" }, "main": "dist/index.cjs.js", "module": "dist/index.js", From 0be9664aef813f02afa1a6a20f886ab84120b299 Mon Sep 17 00:00:00 2001 From: Tim Weise Date: Mon, 24 Apr 2023 15:42:04 +0200 Subject: [PATCH 15/16] =?UTF-8?q?chore:=20=F0=9F=93=8C=20pin=20eslint-plug?= =?UTF-8?q?in-html?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/cookie-consent-banner/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cookie-consent-banner/package.json b/packages/cookie-consent-banner/package.json index 76f9a88..2b981b6 100644 --- a/packages/cookie-consent-banner/package.json +++ b/packages/cookie-consent-banner/package.json @@ -52,7 +52,7 @@ "@types/jest": "27.5.2", "@types/puppeteer": "5.4.7", "eslint": "8.32.0", - "eslint-plugin-html": "^7.1.0", + "eslint-plugin-html": "7.1.0", "jest": "27.5.1", "jest-cli": "27.5.1", "prettier": "2.8.3", From 2fdd70f7ba4092ec30e0642b3645912b6af64f97 Mon Sep 17 00:00:00 2001 From: Tim Weise Date: Tue, 25 Apr 2023 10:23:48 +0200 Subject: [PATCH 16/16] =?UTF-8?q?chore:=20=F0=9F=93=8C=20fix=20yarn=20lock?= =?UTF-8?q?=20with=20pinned=20eslint-plugin-html?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yarn.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/yarn.lock b/yarn.lock index f816175..a5542bf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -814,7 +814,7 @@ __metadata: "@types/jest": 27.5.2 "@types/puppeteer": 5.4.7 eslint: 8.32.0 - eslint-plugin-html: ^7.1.0 + eslint-plugin-html: 7.1.0 jest: 27.5.1 jest-cli: 27.5.1 prettier: 2.8.3 @@ -2802,7 +2802,7 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-html@npm:^7.1.0": +"eslint-plugin-html@npm:7.1.0": version: 7.1.0 resolution: "eslint-plugin-html@npm:7.1.0" dependencies: