From 4f858c91e5e8a2151da10c1b5c8105786dbb8e92 Mon Sep 17 00:00:00 2001 From: Maxim Tsoy Date: Thu, 25 Aug 2022 12:44:26 +0200 Subject: [PATCH] New rules (#26) * Unblock scrolling in sourcepoint * Fix aws rule * Run popup detection steps sequentially * Handle multiple CMPs on the same page (opt-out is still executed for only one of them) * Expand the klaro rule * Fix cookieconsent rule * Add a bunch of detection rules (no opt-out yet) * some test fixes * Indicate which CMP was found in the extension * Add opt-out rules for complianz, cookie information, primebox, tarteaucitron and wp-cookie-notice * Conditional JSON rules * Add opt-out rules for Moove * Add opt-out rules for Termly * Fix termly and tests for Moove * Add opt-out rules for jquery.cookiebar plugin * Opt-out rules for UK Cookie Consent * Add rules for eu cookie law and Mediavine * Add rules for EZoic * Test fixes * remove outdated rule * Add rules for DSGVO Tools * Sort out different complianz flavors * Stabilize mediavine opt-in * Fix rule for vodafone * Fix complianz test * Add iubenda * Limit conditionals to visible and exists rules * Fix sourcepoint rule * Add rules for usercentrics-banner * clarify the "if" docs --- addon/background.ts | 22 ++++--- lib/cmps/all.ts | 2 + lib/cmps/base.ts | 61 ++++++++++------- lib/cmps/klaro.ts | 66 +++++++++++++++++++ lib/cmps/sourcepoint-frame.ts | 17 ++--- lib/cmps/sourcepoint-top.ts | 5 ++ lib/rules.ts | 9 ++- lib/web.ts | 60 ++++++++++------- package-lock.json | 28 ++++---- readme.md | 29 ++++++++ rules/autoconsent/aws-amazon.json | 7 +- rules/autoconsent/complianz-banner.json | 13 ++++ rules/autoconsent/complianz-categories.json | 17 +++++ rules/autoconsent/complianz-notice.json | 14 ++++ rules/autoconsent/complianz-optin.json | 20 ++++++ rules/autoconsent/cookie-notice.json | 4 +- rules/autoconsent/cookieconsent.json | 8 --- rules/autoconsent/cookieinformation.json | 14 ++++ rules/autoconsent/destatis-de.json | 8 --- rules/autoconsent/dsgvo.json | 16 +++++ rules/autoconsent/eu-cookie-law.json | 20 ++++++ rules/autoconsent/ezoic.json | 19 ++++++ rules/autoconsent/iubenda.json | 23 +++++++ rules/autoconsent/jquery-cookiebar.json | 25 +++++++ rules/autoconsent/klaro.json | 10 --- rules/autoconsent/mediavine.json | 20 ++++++ rules/autoconsent/moove.json | 28 ++++++++ rules/autoconsent/primebox.json | 19 ++++++ rules/autoconsent/tarteaucitron.json | 18 +++++ rules/autoconsent/termly.json | 31 +++++++++ rules/autoconsent/testcmp.json | 5 +- rules/autoconsent/uk-cookie-consent.json | 15 +++++ ...rcentrics-1.json => usercentrics-api.json} | 4 +- rules/autoconsent/usercentrics-button.json | 14 ++++ rules/autoconsent/vodafone-de.json | 10 +-- rules/autoconsent/wp-cookie-notice.json | 12 ++++ tests/complianz-banner.spec.ts | 9 +++ tests/complianz-categories.spec.ts | 14 ++++ ...nsent.spec.ts => complianz-notice.spec.ts} | 3 +- tests/complianz-optin.spec.ts | 6 ++ tests/consentmanager.spec.ts | 2 +- ...ienotice.spec.ts => cookie-notice.spec.ts} | 0 tests/cookieinformation.spec.ts | 10 +++ tests/destatis.spec.ts | 7 -- tests/dsgvo.spec.ts | 6 ++ tests/eu-cookie-law.spec.ts | 6 ++ tests/ezoic.spec.ts | 8 +++ tests/iubenda.spec.ts | 8 +++ tests/jquery-cookiebar.spec.ts | 6 ++ tests/klaro.spec.ts | 8 ++- tests/mediavine.spec.ts | 8 +++ tests/moove.spec.ts | 13 ++++ tests/onetrust.spec.ts | 4 +- tests/primebox.spec.ts | 8 +++ tests/tarteaucitron.spec.ts | 9 +++ tests/tealium.spec.ts | 2 +- tests/termly.spec.ts | 7 ++ tests/trustarc.spec.ts | 10 +-- tests/uk-cookie-consent.spec.ts | 7 ++ ...ics-1.spec.ts => usercentrics-api.spec.ts} | 5 +- tests/usercentrics-button.spec.ts | 8 +++ tests/wp-cookie-notice.spec.ts | 8 +++ 62 files changed, 731 insertions(+), 144 deletions(-) create mode 100644 lib/cmps/klaro.ts create mode 100644 rules/autoconsent/complianz-banner.json create mode 100644 rules/autoconsent/complianz-categories.json create mode 100644 rules/autoconsent/complianz-notice.json create mode 100644 rules/autoconsent/complianz-optin.json delete mode 100644 rules/autoconsent/cookieconsent.json create mode 100644 rules/autoconsent/cookieinformation.json delete mode 100644 rules/autoconsent/destatis-de.json create mode 100644 rules/autoconsent/dsgvo.json create mode 100644 rules/autoconsent/eu-cookie-law.json create mode 100644 rules/autoconsent/ezoic.json create mode 100644 rules/autoconsent/iubenda.json create mode 100644 rules/autoconsent/jquery-cookiebar.json delete mode 100644 rules/autoconsent/klaro.json create mode 100644 rules/autoconsent/mediavine.json create mode 100644 rules/autoconsent/moove.json create mode 100644 rules/autoconsent/primebox.json create mode 100644 rules/autoconsent/tarteaucitron.json create mode 100644 rules/autoconsent/termly.json create mode 100644 rules/autoconsent/uk-cookie-consent.json rename rules/autoconsent/{usercentrics-1.json => usercentrics-api.json} (75%) create mode 100644 rules/autoconsent/usercentrics-button.json create mode 100644 rules/autoconsent/wp-cookie-notice.json create mode 100644 tests/complianz-banner.spec.ts create mode 100644 tests/complianz-categories.spec.ts rename tests/{cookieconsent.spec.ts => complianz-notice.spec.ts} (67%) create mode 100644 tests/complianz-optin.spec.ts rename tests/{cookienotice.spec.ts => cookie-notice.spec.ts} (100%) create mode 100644 tests/cookieinformation.spec.ts delete mode 100644 tests/destatis.spec.ts create mode 100644 tests/dsgvo.spec.ts create mode 100644 tests/eu-cookie-law.spec.ts create mode 100644 tests/ezoic.spec.ts create mode 100644 tests/iubenda.spec.ts create mode 100644 tests/jquery-cookiebar.spec.ts create mode 100644 tests/mediavine.spec.ts create mode 100644 tests/moove.spec.ts create mode 100644 tests/primebox.spec.ts create mode 100644 tests/tarteaucitron.spec.ts create mode 100644 tests/termly.spec.ts create mode 100644 tests/uk-cookie-consent.spec.ts rename tests/{usercentrics-1.spec.ts => usercentrics-api.spec.ts} (59%) create mode 100644 tests/usercentrics-button.spec.ts create mode 100644 tests/wp-cookie-notice.spec.ts diff --git a/addon/background.ts b/addon/background.ts index 98345854..ee465cd7 100644 --- a/addon/background.ts +++ b/addon/background.ts @@ -69,6 +69,7 @@ async function evalInTab(tabId: number, frameId: number, code: string): Promise< return window.eval(code); } catch (e) { // ignore CSP errors + console.warn('eval error', code, e); return; } }, @@ -85,27 +86,28 @@ if (manifestVersion === 2) { function showOptOutStatus( tabId: number, - status: "success" | "complete" | "working" | "available" | "verified" | "idle" + status: "success" | "complete" | "working" | "available" | "verified" | "idle", + cmp = '', ) { let title = ""; let icon = "icons/cookie-idle.png"; if (status === "success") { - title = "Opt out successful!"; + title = `Opt out successful! (${cmp})`; icon = "icons/party.png"; } else if (status === "complete") { - title = "Opt out complete!"; + title = `Opt out complete! (${cmp})`; icon = "icons/tick.png"; } else if (status === "working") { - title = "Processing..."; + title = `Processing... (${cmp})`; icon = "icons/cog.png"; } else if (status === "verified") { - title = "Verified"; + title = `Verified (${cmp})`; icon = "icons/verified.png"; } else if (status === "idle") { title = "Idle"; icon = "icons/cookie-idle.png"; } else if (status === "available") { - title = "Click to opt out"; + title = `Click to opt out (${cmp})`; icon = "icons/cookie.png"; } enableLogs && console.log('Setting action state to', status); @@ -164,7 +166,7 @@ chrome.runtime.onMessage.addListener( }); break; case "popupFound": - showOptOutStatus(tabId, "available"); + showOptOutStatus(tabId, "available", msg.cmp); storageSet({ [`detected${tabId}`]: frameId, }); @@ -172,7 +174,7 @@ chrome.runtime.onMessage.addListener( case "optOutResult": case "optInResult": if (msg.result) { - showOptOutStatus(tabId, "working"); + showOptOutStatus(tabId, "working", msg.cmp); if (msg.scheduleSelfTest) { await storageSet({ [`selfTest${tabId}`]: frameId, @@ -182,11 +184,11 @@ chrome.runtime.onMessage.addListener( break; case "selfTestResult": if (msg.result) { - showOptOutStatus(tabId, "verified"); + showOptOutStatus(tabId, "verified", msg.cmp); } break; case "autoconsentDone": { - showOptOutStatus(tabId, "success"); + showOptOutStatus(tabId, "success", msg.cmp); // sometimes self-test needs to be done in another frame const selfTestKey = `selfTest${tabId}`; const selfTestFrameId = (await chrome.storage.local.get(selfTestKey))?.[selfTestKey]; diff --git a/lib/cmps/all.ts b/lib/cmps/all.ts index cbe720a1..dc002532 100644 --- a/lib/cmps/all.ts +++ b/lib/cmps/all.ts @@ -9,6 +9,7 @@ import Evidon from './evidon'; import { AutoConsentCMPRule } from '../rules'; import Onetrust from './onetrust'; import { AutoCMP } from '../types'; +import Klaro from './klaro'; const rules: AutoCMP[] = [ new TrustArcTop(), @@ -19,6 +20,7 @@ const rules: AutoCMP[] = [ new ConsentManager(), new Evidon(), new Onetrust(), + new Klaro(), ]; export function createAutoCMP(config: AutoConsentCMPRule): AutoConsentCMP { diff --git a/lib/cmps/base.ts b/lib/cmps/base.ts index d2efc0ed..3422807b 100644 --- a/lib/cmps/base.ts +++ b/lib/cmps/base.ts @@ -114,6 +114,19 @@ async function evaluateRuleStep(rule: AutoConsentRuleStep) { if (rule.hide) { results.push(hide(rule.hide, rule.method)); } + if (rule.if) { + if (!rule.if.exists && !rule.if.visible) { + console.error('invalid conditional rule', rule.if); + return false; + } + const condition = await evaluateRuleStep(rule.if); + enableLogs && console.log('Condition is', condition); + if (condition) { + results.push(_runRulesSequentially(rule.then)); + } else if (rule.else) { + results.push(_runRulesSequentially(rule.else)); + } + } if (results.length === 0) { enableLogs && console.warn('Unrecognized rule', rule); @@ -125,6 +138,24 @@ async function evaluateRuleStep(rule: AutoConsentRuleStep) { return all.reduce((a, b) => a && b, true); } +async function _runRulesParallel(rules: AutoConsentRuleStep[]): Promise { + const results = rules.map(rule => evaluateRuleStep(rule)); + const detections = await Promise.all(results); + return detections.every(r => !!r); +} + +async function _runRulesSequentially(rules: AutoConsentRuleStep[]): Promise { + for (const rule of rules) { + enableLogs && console.log('Running rule...', rule); + const result = await evaluateRuleStep(rule); + enableLogs && console.log('...rule result', result); + if (!result && !rule.optional) { + return false; + } + } + return true; +} + export class AutoConsentCMP extends AutoConsentCMPBase { constructor(public config: AutoConsentCMPRule) { @@ -144,34 +175,16 @@ export class AutoConsentCMP extends AutoConsentCMPBase { return this.config.prehideSelectors; } - async _runRulesParallel(rules: AutoConsentRuleStep[]): Promise { - const results = rules.map(rule => evaluateRuleStep(rule)); - const detections = await Promise.all(results); - return detections.every(r => !!r); - } - - async _runRulesSequentially(rules: AutoConsentRuleStep[]): Promise { - for (const rule of rules) { - enableLogs && console.log('Running rule...', rule); - const result = await evaluateRuleStep(rule); - enableLogs && console.log('...rule result', result); - if (!result && !rule.optional) { - return false; - } - } - return true; - } - async detectCmp() { if (this.config.detectCmp) { - return this._runRulesParallel(this.config.detectCmp); + return _runRulesParallel(this.config.detectCmp); } return false; } async detectPopup() { if (this.config.detectPopup) { - return this._runRulesParallel(this.config.detectPopup); + return _runRulesSequentially(this.config.detectPopup); } return false; } @@ -179,7 +192,7 @@ export class AutoConsentCMP extends AutoConsentCMPBase { async optOut() { if (this.config.optOut) { enableLogs && console.log('Initiated optOut()', this.config.optOut); - return this._runRulesSequentially(this.config.optOut); + return _runRulesSequentially(this.config.optOut); } return false; } @@ -187,21 +200,21 @@ export class AutoConsentCMP extends AutoConsentCMPBase { async optIn() { if (this.config.optIn) { enableLogs && console.log('Initiated optIn()', this.config.optIn); - return this._runRulesSequentially(this.config.optIn); + return _runRulesSequentially(this.config.optIn); } return false; } async openCmp() { if (this.config.openCmp) { - return this._runRulesSequentially(this.config.openCmp); + return _runRulesSequentially(this.config.openCmp); } return false; } async test() { if (this.hasSelfTest) { - return this._runRulesSequentially(this.config.test); + return _runRulesSequentially(this.config.test); } return super.test(); } diff --git a/lib/cmps/klaro.ts b/lib/cmps/klaro.ts new file mode 100644 index 00000000..911a3d99 --- /dev/null +++ b/lib/cmps/klaro.ts @@ -0,0 +1,66 @@ +import { click, doEval, elementExists, elementVisible, waitForElement } from "../rule-executors"; +import AutoConsentCMPBase from "./base"; + +export default class Klaro extends AutoConsentCMPBase { + + prehideSelectors = [".klaro"] + settingsOpen = false; + + constructor() { + super("Klaro"); + } + + get hasSelfTest(): boolean { + return true; + } + + get isIntermediate(): boolean { + return false; + } + + async detectCmp() { + if (elementExists('.klaro > .cookie-modal')) { + this.settingsOpen = true; + return true; + } + return elementExists(".klaro > .cookie-notice"); + } + + async detectPopup() { + return elementVisible(".klaro > .cookie-notice,.klaro > .cookie-modal", 'any'); + } + + async optOut() { + if (click('.klaro .cn-decline')) { + return true; + } + + if (!this.settingsOpen) { + click('.klaro .cn-learn-more'); + await waitForElement('.klaro > .cookie-modal', 2000); + this.settingsOpen = true; + } + + if (click('.klaro .cn-decline')) { + return true; + } + + click('.cm-purpose:not(.cm-toggle-all) > input:not(.half-checked)', true); + return click('.cm-btn-accept'); + } + + async optIn() { + if (click('.klaro .cm-btn-accept-all')) { + return true; + } + if (this.settingsOpen) { + click('.cm-purpose:not(.cm-toggle-all) > input.half-checked', true); + return click('.cm-btn-accept'); + } + return click('.klaro .cookie-notice .cm-btn-success'); + } + + async test() { + return await doEval('klaro.getManager().config.services.every(c => c.required || !klaro.getManager().consents[c.name])'); + } +} diff --git a/lib/cmps/sourcepoint-frame.ts b/lib/cmps/sourcepoint-frame.ts index b2657441..1e15251b 100644 --- a/lib/cmps/sourcepoint-frame.ts +++ b/lib/cmps/sourcepoint-frame.ts @@ -32,7 +32,7 @@ export default class SourcePoint extends AutoConsentCMPBase { return true; } return (url.pathname === '/index.html' || url.pathname === '/privacy-manager/index.html') - && url.searchParams.has('message_id') && url.searchParams.has('requestUUID'); + && (url.searchParams.has('message_id') || url.searchParams.has('requestUUID') || url.searchParams.has('consentUUID')); } async detectPopup() { @@ -57,16 +57,17 @@ export default class SourcePoint extends AutoConsentCMPBase { async optOut() { if (!this.isManagerOpen()) { - const actionable = await waitForElement('button.sp_choice_type_12,button.sp_choice_type_13'); + const actionable = await waitForElement('.sp_choice_type_12,.sp_choice_type_13'); if (!actionable) { return false; } - if (!elementExists("button.sp_choice_type_12")) { + if (!elementExists(".sp_choice_type_12")) { // do not sell button - return click("button.sp_choice_type_13"); + return click(".sp_choice_type_13"); } - click("button.sp_choice_type_12"); + click(".sp_choice_type_12"); + // the page may navigate at this point but that's okay await waitFor( () => location.pathname === "/privacy-manager/index.html", 200, @@ -88,9 +89,8 @@ export default class SourcePoint extends AutoConsentCMPBase { await wait(1000); return click(rejectSelector1); } else if (path === 1) { - return click(rejectSelector2); + click(rejectSelector2); } else if (path === 2) { - // TODO: check if this is still working await waitForElement('.pm-features', 10000); click('.checked > span', true); @@ -99,6 +99,7 @@ export default class SourcePoint extends AutoConsentCMPBase { } catch (e) { enableLogs && console.warn(e); } - return click('.sp_choice_type_SAVE_AND_EXIT'); + click('.sp_choice_type_SAVE_AND_EXIT'); + return true; } } diff --git a/lib/cmps/sourcepoint-top.ts b/lib/cmps/sourcepoint-top.ts index fe1daee1..5c719ce8 100644 --- a/lib/cmps/sourcepoint-top.ts +++ b/lib/cmps/sourcepoint-top.ts @@ -35,6 +35,11 @@ export default class SourcePoint extends AutoConsentCMPBase { } async optOut() { + // unblock scrolling + const container = document.querySelector('.sp-message-open'); + if (container) { + container.classList.remove('sp-message-open'); + } return true; } diff --git a/lib/rules.ts b/lib/rules.ts index 974e0329..b27baf6f 100644 --- a/lib/rules.ts +++ b/lib/rules.ts @@ -28,7 +28,8 @@ export type AutoConsentRuleStep = { optional?: boolean } & Partial< Partial & Partial & Partial & - Partial; + Partial & + Partial; export type ElementExistsRule = { exists: string; @@ -80,3 +81,9 @@ export type HideRule = { hide: string[]; method?: HideMethod; }; + +export type IfRule = { + if: Partial & Partial; + then: AutoConsentRuleStep[]; + else?: AutoConsentRuleStep[]; +}; diff --git a/lib/web.ts b/lib/web.ts index 8e805297..4ffde085 100644 --- a/lib/web.ts +++ b/lib/web.ts @@ -107,16 +107,36 @@ export default class AutoConsent { async _start() { enableLogs && console.log(`Detecting CMPs on ${window.location.href}`) - const cmp = await this.findCmp(this.config.detectRetries); - if (cmp) { - enableLogs && console.log("detected CMP:", cmp.name, window.location.href); - this.sendContentMessage({ - type: 'cmpDetected', - url: location.href, - cmp: cmp.name, - }); // notify the browser - const isOpen = await this.waitForPopup(cmp); - if (!isOpen) { + const cmps = await this.findCmp(this.config.detectRetries); + if (cmps.length > 0) { + const popupLookups: Promise[] = []; + for (const cmp of cmps) { + enableLogs && console.log("detected CMP:", cmp.name, window.location.href); + this.sendContentMessage({ + type: 'cmpDetected', + url: location.href, + cmp: cmp.name, + }); // notify the browser + popupLookups.push(this.waitForPopup(cmp).then((isOpen) => { + if (isOpen) { + if (!this.foundCmp) { + this.foundCmp = cmp; + } + this.sendContentMessage({ + type: 'popupFound', + cmp: cmp.name, + url: location.href, + }); // notify the browser + return true; + } else { + return Promise.reject(`${cmp.name} popup not found`); + } + })); + } + + const somethingOpen = await Promise.any(popupLookups).catch(() => false); + + if (!somethingOpen) { enableLogs && console.log('no popup found'); if (this.config.enablePrehide) { undoPrehide(); @@ -124,13 +144,6 @@ export default class AutoConsent { return false; } - this.foundCmp = cmp; - this.sendContentMessage({ - type: 'popupFound', - cmp: cmp.name, - url: location.href, - }); // notify the browser - if (this.config.autoAction === 'optOut') { return await this.doOptOut(); } else if (this.config.autoAction === 'optIn') { @@ -148,8 +161,7 @@ export default class AutoConsent { } } - async findCmp(retries: number): Promise { - let foundCmp: AutoCMP = null; + async findCmp(retries: number): Promise { const allFoundCmps: AutoCMP[] = []; for (const cmp of this.rules) { @@ -161,9 +173,6 @@ export default class AutoConsent { if (result) { enableLogs && console.log(`Found CMP: ${cmp.name}`); allFoundCmps.push(cmp); - if (!foundCmp) { - foundCmp = cmp; - } } } catch (e) { enableLogs && console.warn(`error detecting ${cmp.name}`, e); @@ -182,7 +191,7 @@ export default class AutoConsent { }); } - if (!foundCmp && retries > 0) { + if (allFoundCmps.length === 0 && retries > 0) { return new Promise((resolve) => { setTimeout(async () => { const result = this.findCmp(retries - 1); @@ -191,7 +200,7 @@ export default class AutoConsent { }); } - return foundCmp; + return allFoundCmps; } async doOptOut(): Promise { @@ -236,6 +245,7 @@ export default class AutoConsent { } else { enableLogs && console.log(`CMP ${this.foundCmp.name}: opt in on ${window.location.href}`); optInResult = await this.foundCmp.optIn(); + enableLogs && console.log(`${this.foundCmp.name}: opt in result ${optInResult}`); } if (this.config.enablePrehide) { @@ -286,7 +296,7 @@ export default class AutoConsent { if (!isOpen && retries > 0) { return new Promise((resolve) => setTimeout(() => resolve(this.waitForPopup(cmp, retries - 1, interval)), interval)); } - enableLogs && console.log(`popup is ${isOpen ? 'open' : 'not open'}`); + enableLogs && console.log(cmp.name, `popup is ${isOpen ? 'open' : 'not open'}`); return isOpen; } diff --git a/package-lock.json b/package-lock.json index e19a8953..eaa81337 100644 --- a/package-lock.json +++ b/package-lock.json @@ -239,13 +239,13 @@ } }, "node_modules/@playwright/test": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.22.2.tgz", - "integrity": "sha512-cCl96BEBGPtptFz7C2FOSN3PrTnJ3rPpENe+gYCMx4GNNDlN4tmo2D89y13feGKTMMAIVrXfSQ/UmaQKLy1XLA==", + "version": "1.24.2", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.24.2.tgz", + "integrity": "sha512-Q4X224pRHw4Dtkk5PoNJplZCokLNvVbXD9wDQEMrHcEuvWpJWEQDeJ9gEwkZ3iCWSFSWBshIX177B231XW4wOQ==", "dev": true, "dependencies": { "@types/node": "*", - "playwright-core": "1.22.2" + "playwright-core": "1.24.2" }, "bin": { "playwright": "cli.js" @@ -3061,9 +3061,9 @@ } }, "node_modules/playwright-core": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.22.2.tgz", - "integrity": "sha512-w/hc/Ld0RM4pmsNeE6aL/fPNWw8BWit2tg+TfqJ3+p59c6s3B6C8mXvXrIPmfQEobkcFDc+4KirNzOQ+uBSP1Q==", + "version": "1.24.2", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.24.2.tgz", + "integrity": "sha512-zfAoDoPY/0sDLsgSgLZwWmSCevIg1ym7CppBwllguVBNiHeixZkc1AdMuYUPZC6AdEYc4CxWEyLMBTw2YcmRrA==", "dev": true, "bin": { "playwright": "cli.js" @@ -4114,13 +4114,13 @@ } }, "@playwright/test": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.22.2.tgz", - "integrity": "sha512-cCl96BEBGPtptFz7C2FOSN3PrTnJ3rPpENe+gYCMx4GNNDlN4tmo2D89y13feGKTMMAIVrXfSQ/UmaQKLy1XLA==", + "version": "1.24.2", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.24.2.tgz", + "integrity": "sha512-Q4X224pRHw4Dtkk5PoNJplZCokLNvVbXD9wDQEMrHcEuvWpJWEQDeJ9gEwkZ3iCWSFSWBshIX177B231XW4wOQ==", "dev": true, "requires": { "@types/node": "*", - "playwright-core": "1.22.2" + "playwright-core": "1.24.2" } }, "@rollup/plugin-json": { @@ -6212,9 +6212,9 @@ "dev": true }, "playwright-core": { - "version": "1.22.2", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.22.2.tgz", - "integrity": "sha512-w/hc/Ld0RM4pmsNeE6aL/fPNWw8BWit2tg+TfqJ3+p59c6s3B6C8mXvXrIPmfQEobkcFDc+4KirNzOQ+uBSP1Q==", + "version": "1.24.2", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.24.2.tgz", + "integrity": "sha512-zfAoDoPY/0sDLsgSgLZwWmSCevIg1ym7CppBwllguVBNiHeixZkc1AdMuYUPZC6AdEYc4CxWEyLMBTw2YcmRrA==", "dev": true }, "prelude-ls": { diff --git a/readme.md b/readme.md index 14bcb07b..0ffbd6e4 100644 --- a/readme.md +++ b/readme.md @@ -106,6 +106,17 @@ Returns true if elements returned from `document.querySelectorAll(selector)` are ``` Waits until `selector` exists in the page. After `timeout` ms the step fails. +### Wait for visibility + +```json +{ + "waitForVisible": "selector", + "timeout": 1000, + "check": "any" | "all" | "none" +} +``` +Waits until element is visible in the page. After `timeout` ms the step fails. + ### Click an element ```json { @@ -152,6 +163,24 @@ Hide the elements matched by the selectors. `method` defines how elements are hi Evaluates `code` in the context of the page. The rule is considered successful if it *evaluates to a truthy value*. Eval rules are not 100% reliable because they can be blocked by a CSP policy on the page. Therefore, they should only be used as a last resort when none of the other rules are sufficient. +### Conditionals + +```json +{ + "if": { "exists": "selector" }, + "then": [ + { "click": ".button1" }, + { "click": ".button3" } + ], + "else": [ + { "click": ".button2" } + ] +} +``` + +Allows to do conditional branching in JSON rules. The `if` section can contain either a "visible" or "exists" rule. Depending on the result of that rule, `then` or `else` sequences will be executed. `else` section is optional. +The "if" rule is considered successful as long as all rules inside the chosen branch are successful. The other branch, as well as the result of the condition itself, do not affect the result of the whole rule. + ### Optional actions Any rule can include the `"optional": true` to ignore failure. diff --git a/rules/autoconsent/aws-amazon.json b/rules/autoconsent/aws-amazon.json index 31620c05..ed6ddddd 100644 --- a/rules/autoconsent/aws-amazon.json +++ b/rules/autoconsent/aws-amazon.json @@ -9,7 +9,12 @@ "click": "button[data-id=awsccc-cb-btn-customize]" }, { - "eval": "Array.from(document.querySelectorAll('input[aria-checked=true')).forEach(e => e.click()) || true" + "waitFor": "input[aria-checked]" + }, + { + "click": "input[aria-checked=true]", + "all": true, + "optional": true }, { "click": "button[data-id=awsccc-cs-btn-save]" diff --git a/rules/autoconsent/complianz-banner.json b/rules/autoconsent/complianz-banner.json new file mode 100644 index 00000000..bbd64149 --- /dev/null +++ b/rules/autoconsent/complianz-banner.json @@ -0,0 +1,13 @@ +{ + "name": "Complianz banner", + "prehideSelectors": ["#cmplz-cookiebanner-container"], + "detectCmp": [{ "exists": "#cmplz-cookiebanner-container .cmplz-cookiebanner" }], + "detectPopup": [{ "visible": "#cmplz-cookiebanner-container .cmplz-cookiebanner", "check": "any" }], + "optIn": [ + { "waitForThenClick": ".cmplz-cookiebanner .cmplz-accept" } + ], + "optOut": [ + { "waitForThenClick": ".cmplz-cookiebanner .cmplz-deny" } + ], + "test": [ { "eval": "document.cookie.includes('cmplz_banner-status=dismissed')" } ] +} \ No newline at end of file diff --git a/rules/autoconsent/complianz-categories.json b/rules/autoconsent/complianz-categories.json new file mode 100644 index 00000000..ed9a6946 --- /dev/null +++ b/rules/autoconsent/complianz-categories.json @@ -0,0 +1,17 @@ +{ + "name": "Complianz categories", + "prehideSelectors": [".cc-type-categories[aria-describedby=\"cookieconsent:desc\"]"], + "detectCmp": [{ "exists": ".cc-type-categories[aria-describedby=\"cookieconsent:desc\"]" }], + "detectPopup": [{ "visible": ".cc-type-categories[aria-describedby=\"cookieconsent:desc\"]" }], + "optIn": [ + { "click": ".cc-accept-all", "optional": true }, + { "click": ".cc-allow", "optional": true }, + { "click": ".cc-dismiss", "optional": true } + ], + "optOut": [ + { "click": ".cc-dismiss" } + ], + "test": [ + { "eval": "!!document.cookie.match(/cmplz_[^=]+=deny/)" } + ] +} \ No newline at end of file diff --git a/rules/autoconsent/complianz-notice.json b/rules/autoconsent/complianz-notice.json new file mode 100644 index 00000000..44eed4cb --- /dev/null +++ b/rules/autoconsent/complianz-notice.json @@ -0,0 +1,14 @@ +{ + "name": "Complianz notice", + "prehideSelectors": [".cc-type-info[aria-describedby=\"cookieconsent:desc\"]"], + "detectCmp": [{ "exists": ".cc-type-info[aria-describedby=\"cookieconsent:desc\"]" }], + "detectPopup": [{ "visible": ".cc-type-info[aria-describedby=\"cookieconsent:desc\"]" }], + "optIn": [ + { "click": ".cc-accept-all", "optional": true }, + { "click": ".cc-allow", "optional": true }, + { "click": ".cc-dismiss", "optional": true } + ], + "optOut": [ + { "hide": ["[aria-describedby=\"cookieconsent:desc\"]"] } + ] +} \ No newline at end of file diff --git a/rules/autoconsent/complianz-optin.json b/rules/autoconsent/complianz-optin.json new file mode 100644 index 00000000..9a1097a5 --- /dev/null +++ b/rules/autoconsent/complianz-optin.json @@ -0,0 +1,20 @@ +{ + "name": "Complianz optin", + "prehideSelectors": [".cc-type-opt-in[aria-describedby=\"cookieconsent:desc\"]"], + "detectCmp": [{ "exists": ".cc-type-opt-in[aria-describedby=\"cookieconsent:desc\"]" }], + "detectPopup": [{ "visible": ".cc-type-opt-in[aria-describedby=\"cookieconsent:desc\"]" }], + "optIn": [ + { "click": ".cc-accept-all", "optional": true }, + { "click": ".cc-allow", "optional": true }, + { "click": ".cc-dismiss", "optional": true } + ], + "optOut": [ + { "click": ".cc-settings" }, + { "waitForVisible": "[aria-label=\"cookies preferences popup\"]" }, + { "click": "[aria-label=\"cookies preferences popup\"] input[type=checkbox]:not([disabled])", "all": true }, + { "click": "[aria-label=\"cookies preferences popup\"] [aria-label=\"Accept Selected\"]" } + ], + "test": [ + { "eval": "!!document.cookie.match(/cookieconsent_preferences_disabled=[^;]+/)" } + ] +} \ No newline at end of file diff --git a/rules/autoconsent/cookie-notice.json b/rules/autoconsent/cookie-notice.json index 2985b43d..ce21fcd3 100644 --- a/rules/autoconsent/cookie-notice.json +++ b/rules/autoconsent/cookie-notice.json @@ -1,7 +1,9 @@ { "name": "cookie-notice", "prehideSelectors": ["#cookie-notice"], - "detectCmp": [{ "exists": "#cookie-notice" }], + "detectCmp": [ + { "visible": "#cookie-notice .cookie-notice-container" } + ], "detectPopup": [{ "visible": "#cookie-notice" }], "optIn": [{ "click": ["#cn-accept-cookie"] }], "optOut": [{ "hide": ["#cookie-notice"] }] diff --git a/rules/autoconsent/cookieconsent.json b/rules/autoconsent/cookieconsent.json deleted file mode 100644 index 466dc5dc..00000000 --- a/rules/autoconsent/cookieconsent.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "cookieconsent", - "prehideSelectors": ["[aria-label=\"cookieconsent\"][aria-describedby=\"cookieconsent:desc\"]"], - "detectCmp": [{ "exists": "[aria-label=\"cookieconsent\"][aria-describedby=\"cookieconsent:desc\"]" }], - "detectPopup": [{ "visible": "[aria-label=\"cookieconsent\"][aria-describedby=\"cookieconsent:desc\"]" }], - "optIn": [{ "click": ".cc-dismiss" }], - "optOut": [{ "hide": ["[aria-label=\"cookieconsent\"][aria-describedby=\"cookieconsent:desc\"]"] }] -} \ No newline at end of file diff --git a/rules/autoconsent/cookieinformation.json b/rules/autoconsent/cookieinformation.json new file mode 100644 index 00000000..9dad5767 --- /dev/null +++ b/rules/autoconsent/cookieinformation.json @@ -0,0 +1,14 @@ +{ + "name": "Cookie Information Banner", + "prehideSelectors": ["#cookie-information-template-wrapper"], + "detectCmp": [{ "exists": "#cookie-information-template-wrapper" }], + "detectPopup": [{ "visible": "#cookie-information-template-wrapper" }], + "optIn": [ { "eval": "CookieInformation.submitAllCategories() || true"} ], + "optOut": [ + { "hide": ["#cookie-information-template-wrapper"], "comment": "some templates don't hide the banner automatically" }, + { "eval": "CookieInformation.declineAllCategories() || true"} + ], + "test": [ + { "eval": "document.cookie.includes('CookieInformationConsent=')" } + ] +} \ No newline at end of file diff --git a/rules/autoconsent/destatis-de.json b/rules/autoconsent/destatis-de.json deleted file mode 100644 index 909010bb..00000000 --- a/rules/autoconsent/destatis-de.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "destatis.de", - "prehideSelectors": ["div[aria-labelledby=cookiebannerhead]"], - "detectCmp": [{ "exists": ".cookiebannerbox" }], - "detectPopup": [{ "visible": ".cookiebannerbox" }], - "optOut": [{ "hide": [".cookiebannerbox"] }], - "optIn": [{ "click": [".cookiebannerbox .close"] }] -} diff --git a/rules/autoconsent/dsgvo.json b/rules/autoconsent/dsgvo.json new file mode 100644 index 00000000..85e83288 --- /dev/null +++ b/rules/autoconsent/dsgvo.json @@ -0,0 +1,16 @@ +{ + "name": "WP DSGVO Tools", + "link": "https://wordpress.org/plugins/shapepress-dsgvo/", + "prehideSelectors": [".sp-dsgvo"], + "detectCmp": [{ "exists": ".sp-dsgvo.sp-dsgvo-popup-overlay" }], + "detectPopup": [{ "visible": ".sp-dsgvo.sp-dsgvo-popup-overlay", "check": "any" }], + "optIn": [ + { "click": ".sp-dsgvo-privacy-btn-accept-all", "all": true } + ], + "optOut": [ + { "hide": [".sp-dsgvo.sp-dsgvo-popup-overlay"] } + ], + "test": [ + { "eval": "!document.cookie.includes('sp_dsgvo_cookie_settings')" } + ] +} \ No newline at end of file diff --git a/rules/autoconsent/eu-cookie-law.json b/rules/autoconsent/eu-cookie-law.json new file mode 100644 index 00000000..ad7829bf --- /dev/null +++ b/rules/autoconsent/eu-cookie-law.json @@ -0,0 +1,20 @@ +{ + "name": "EU Cookie Law", + "prehideSelectors": [".pea_cook_wrapper,.pea_cook_more_info_popover"], + "detectCmp": [{ "exists": ".pea_cook_wrapper" }], + "detectPopup": [ + { "wait": 500 }, + { "visible": ".pea_cook_wrapper" } + ], + "optIn": [ + { + "click": "#pea_cook_btn" + } + ], + "optOut": [ + { "hide": [".pea_cook_wrapper"] } + ], + "test": [ + { "eval": "!document.cookie.includes('euCookie')" } + ] +} \ No newline at end of file diff --git a/rules/autoconsent/ezoic.json b/rules/autoconsent/ezoic.json new file mode 100644 index 00000000..8ec224c9 --- /dev/null +++ b/rules/autoconsent/ezoic.json @@ -0,0 +1,19 @@ +{ + "name": "EZoic", + "prehideSelectors": ["#ez-cookie-dialog-wrapper"], + "detectCmp": [{ "exists": "#ez-cookie-dialog-wrapper" }], + "detectPopup": [{ "visible": "#ez-cookie-dialog-wrapper" }], + "optIn": [ + { "click": "#ez-accept-all", "optional": true }, + { "eval": "ezCMP.handleAcceptAllClick()", "optional": true } + ], + "optOut": [ + { "click": "#ez-manage-settings" }, + { "waitFor": "#ez-cookie-dialog input[type=checkbox]" }, + { "click": "#ez-cookie-dialog input[type=checkbox][checked]", "all": true }, + { "click": "#ez-save-settings" } + ], + "test": [ + { "eval": "!!document.cookie.match(/ezCMPCookieConsent=[^;]+\\|2=0\\|3=0\\|4=0/)" } + ] +} \ No newline at end of file diff --git a/rules/autoconsent/iubenda.json b/rules/autoconsent/iubenda.json new file mode 100644 index 00000000..94987816 --- /dev/null +++ b/rules/autoconsent/iubenda.json @@ -0,0 +1,23 @@ +{ + "name": "iubenda", + "prehideSelectors": ["#iubenda-cs-banner"], + "detectCmp": [{ "exists": "#iubenda-cs-banner" }], + "detectPopup": [{ "visible": ".iubenda-cs-accept-btn" }], + "optIn": [ + { "click": ".iubenda-cs-accept-btn" } + ], + "optOut": [ + { + "click": ".iubenda-cs-customize-btn" + }, + { + "eval": "document.querySelectorAll('.purposes-item input[type=checkbox]:not([disabled])').forEach(x => {if(x.checked) x.click()}) || true" + }, + { + "click": "#iubFooterBtn" + } + ], + "test": [ + { "eval": "!!document.cookie.match(/_iub_cs-\\d+=/)" } + ] +} diff --git a/rules/autoconsent/jquery-cookiebar.json b/rules/autoconsent/jquery-cookiebar.json new file mode 100644 index 00000000..1cfe4aea --- /dev/null +++ b/rules/autoconsent/jquery-cookiebar.json @@ -0,0 +1,25 @@ +{ + "name": "jquery.cookieBar", + "comment": "https://github.com/kovarp/jquery.cookieBar", + "prehideSelectors": [".cookie-bar"], + "detectCmp": [{ "exists": ".cookie-bar .cookie-bar__message,.cookie-bar .cookie-bar__buttons" }], + "detectPopup": [{ + "visible": ".cookie-bar .cookie-bar__message,.cookie-bar .cookie-bar__buttons", + "check": "any" + }], + "optIn": [ + { "click": ".cookie-bar .cookie-bar__btn" } + ], + "optOut": [ + { "hide": [".cookie-bar"] } + ], + "test": [ + { + "visible": ".cookie-bar .cookie-bar__message,.cookie-bar .cookie-bar__buttons", + "check": "none" + }, + { + "eval": "!document.cookie.includes('cookies-state=accepted')" + } + ] +} \ No newline at end of file diff --git a/rules/autoconsent/klaro.json b/rules/autoconsent/klaro.json deleted file mode 100644 index ed9b25d2..00000000 --- a/rules/autoconsent/klaro.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "klaro", - "detectCmp": [{ "exists": ".klaro > .cookie-notice" }], - "detectPopup": [{ "visible": ".klaro > .cookie-notice" }], - "optIn": [{ "click": ".cm-btn-success" }], - "optOut": [{ "click": ".cn-decline" }], - "test": [ - { "eval": "Object.values(klaro.getManager().consents).every(c => !c)" } - ] -} diff --git a/rules/autoconsent/mediavine.json b/rules/autoconsent/mediavine.json new file mode 100644 index 00000000..05d41264 --- /dev/null +++ b/rules/autoconsent/mediavine.json @@ -0,0 +1,20 @@ +{ + "name": "Mediavine", + "prehideSelectors": ["[data-name=\"mediavine-gdpr-cmp\"]"], + "detectCmp": [{ "exists": "[data-name=\"mediavine-gdpr-cmp\"]" }], + "detectPopup": [ + { "wait": 500 }, + { "visible": "[data-name=\"mediavine-gdpr-cmp\"]" } + ], + "optIn": [ + { + "waitForThenClick": "[data-name=\"mediavine-gdpr-cmp\"] [format=\"primary\"]" + } + ], + "optOut": [ + { "waitForThenClick": "[data-name=\"mediavine-gdpr-cmp\"] [data-view=\"manageSettings\"]" }, + { "waitFor": "[data-name=\"mediavine-gdpr-cmp\"] input[type=checkbox]" }, + { "eval": "document.querySelectorAll(\"[data-name=\\\"mediavine-gdpr-cmp\\\"] input[type=checkbox]\").forEach(x => x.checked && x.click()) || true", "optional": true }, + { "click": "[data-name=\"mediavine-gdpr-cmp\"] [format=\"secondary\"]" } + ] +} \ No newline at end of file diff --git a/rules/autoconsent/moove.json b/rules/autoconsent/moove.json new file mode 100644 index 00000000..adfad4ec --- /dev/null +++ b/rules/autoconsent/moove.json @@ -0,0 +1,28 @@ +{ + "name": "Moove", + "prehideSelectors": ["#moove_gdpr_cookie_info_bar"], + "detectCmp": [{ "exists": "#moove_gdpr_cookie_info_bar" }], + "detectPopup": [{ "visible": "#moove_gdpr_cookie_info_bar" }], + "optIn": [ + { "waitForThenClick": ".moove-gdpr-infobar-allow-all" } + ], + "optOut": [ + { + "if": { + "exists": "#moove_gdpr_cookie_info_bar .change-settings-button" + }, + "then": [ + { "click": "#moove_gdpr_cookie_info_bar .change-settings-button" }, + { "waitForVisible": "#moove_gdpr_cookie_modal" }, + { "eval": "document.querySelectorAll('#moove_gdpr_cookie_modal input').forEach(i => { if (!i.disabled) i.checked = false }) || true" }, + { "click": ".moove-gdpr-modal-save-settings" } + ], + "else": [ + { "hide": ["#moove_gdpr_cookie_info_bar"] } + ] + } + ], + "test": [ + { "visible": "#moove_gdpr_cookie_info_bar", "check": "none" } + ] +} \ No newline at end of file diff --git a/rules/autoconsent/primebox.json b/rules/autoconsent/primebox.json new file mode 100644 index 00000000..fcf688e9 --- /dev/null +++ b/rules/autoconsent/primebox.json @@ -0,0 +1,19 @@ +{ + "name": "PrimeBox CookieBar", + "prehideSelectors": ["#cookie-bar"], + "detectCmp": [{ "exists": "#cookie-bar .cb-enable,#cookie-bar .cb-disable,#cookie-bar .cb-policy" }], + "detectPopup": [{ + "visible": "#cookie-bar .cb-enable,#cookie-bar .cb-disable,#cookie-bar .cb-policy", + "check": "any" + }], + "optIn": [ + { "waitForThenClick": "#cookie-bar .cb-enable" } + ], + "optOut": [ + { "click": "#cookie-bar .cb-disable", "optional": true }, + { "hide": ["#cookie-bar"] } + ], + "test": [ + { "eval": "!document.cookie.includes('cb-enabled=accepted')" } + ] +} \ No newline at end of file diff --git a/rules/autoconsent/tarteaucitron.json b/rules/autoconsent/tarteaucitron.json new file mode 100644 index 00000000..13f2f75e --- /dev/null +++ b/rules/autoconsent/tarteaucitron.json @@ -0,0 +1,18 @@ +{ + "name": "tarteaucitron.js", + "prehideSelectors": ["#tarteaucitronRoot"], + "detectCmp": [{ "exists": "#tarteaucitronRoot" }], + "detectPopup": [{ + "visible": "#tarteaucitronRoot #tarteaucitronAlertSmall,#tarteaucitronRoot #tarteaucitronAlertBig", + "check": "any" + }], + "optIn": [ + { "eval": "tarteaucitron.userInterface.respondAll(true) || true" } + ], + "optOut": [ + { "eval": "tarteaucitron.userInterface.respondAll(false) || true" } + ], + "test": [ + { "eval": "document.cookie.match(/tarteaucitron=[^;]*/)[0].includes('false')", "comment": "sometimes there are required categories, so we check that at least something is false" } + ] +} diff --git a/rules/autoconsent/termly.json b/rules/autoconsent/termly.json new file mode 100644 index 00000000..121f4f4d --- /dev/null +++ b/rules/autoconsent/termly.json @@ -0,0 +1,31 @@ +{ + "name": "Termly", + "prehideSelectors": ["#termly-code-snippet-support"], + "detectCmp": [{ "exists": "#termly-code-snippet-support" }], + "detectPopup": [{ "visible": "#termly-code-snippet-support div" }], + "optIn": [ + { "waitForThenClick": "[data-tid=\"banner-accept\"]" } + ], + "optOut": [ + { + "if": { "exists": "[data-tid=\"banner-decline\"]" }, + "then": [ + { "click": "[data-tid=\"banner-decline\"]" } + ], + "else": [ + { "click": ".t-preference-button" }, + { "wait": 500 }, + { + "if": { "exists": ".t-declineAllButton" }, + "then": [ + { "click": ".t-declineAllButton" } + ], + "else": [ + { "waitForThenClick": ".t-preference-modal input[type=checkbox][checked]:not([disabled])", "all": true }, + { "waitForThenClick": ".t-saveButton" } + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/rules/autoconsent/testcmp.json b/rules/autoconsent/testcmp.json index c1ffc74a..99e106c3 100644 --- a/rules/autoconsent/testcmp.json +++ b/rules/autoconsent/testcmp.json @@ -3,7 +3,10 @@ "prehideSelectors": ["#reject-all"], "detectCmp": [{ "exists": "#privacy-test-page-cmp-test" }], "detectPopup": [{ "visible": "#privacy-test-page-cmp-test" }], - "optIn": [{ "click": "#accept-all" }], + "optIn": [ + { "waitFor": "#accept-all" }, + { "click": "#accept-all" } + ], "optOut": [ { "waitFor": "#reject-all" }, { "click": "#reject-all" } diff --git a/rules/autoconsent/uk-cookie-consent.json b/rules/autoconsent/uk-cookie-consent.json new file mode 100644 index 00000000..75a309ae --- /dev/null +++ b/rules/autoconsent/uk-cookie-consent.json @@ -0,0 +1,15 @@ +{ + "name": "UK Cookie Consent", + "prehideSelectors": ["#catapult-cookie-bar"], + "detectCmp": [{ "exists": "#catapult-cookie-bar" }], + "detectPopup": [{ "exists": ".has-cookie-bar #catapult-cookie-bar" }], + "optIn": [ + { "click": "#catapultCookie" } + ], + "optOut": [ + { "hide": ["#catapult-cookie-bar"] } + ], + "test": [ + { "eval": "!document.cookie.includes('catAccCookies')" } + ] +} \ No newline at end of file diff --git a/rules/autoconsent/usercentrics-1.json b/rules/autoconsent/usercentrics-api.json similarity index 75% rename from rules/autoconsent/usercentrics-1.json rename to rules/autoconsent/usercentrics-api.json index d9de868b..93725137 100644 --- a/rules/autoconsent/usercentrics-1.json +++ b/rules/autoconsent/usercentrics-api.json @@ -1,9 +1,9 @@ { - "name": "usercentrics-1", + "name": "usercentrics-api", "detectCmp": [{ "exists": "#usercentrics-root" }], "detectPopup": [ { - "eval": "!!document.querySelector('#usercentrics-root').shadowRoot.querySelector('#uc-center-container')" + "eval": "typeof UC_UI === 'object'" } ], "optIn": [ diff --git a/rules/autoconsent/usercentrics-button.json b/rules/autoconsent/usercentrics-button.json new file mode 100644 index 00000000..579e9a55 --- /dev/null +++ b/rules/autoconsent/usercentrics-button.json @@ -0,0 +1,14 @@ +{ + "name": "usercentrics-button", + "detectCmp": [{ "exists": "#usercentrics-button" }], + "detectPopup": [ + { "visible": "#usercentrics-button #uc-btn-accept-banner" } + ], + "optIn": [ + { "click": "#usercentrics-button #uc-btn-accept-banner" } + ], + "optOut": [ + { "click": "#usercentrics-button #uc-btn-deny-banner" } + ], + "test": [{ "eval": "JSON.parse(localStorage.getItem('usercentrics')).consents.every(c => c.isEssential || !c.consentStatus)" }] +} diff --git a/rules/autoconsent/vodafone-de.json b/rules/autoconsent/vodafone-de.json index 81a53898..53efdb60 100644 --- a/rules/autoconsent/vodafone-de.json +++ b/rules/autoconsent/vodafone-de.json @@ -1,13 +1,13 @@ { "name": "vodafone.de", + "runContext": { + "url": "https://www.vodafone.de/" + }, "prehideSelectors": [".dip-consent,.dip-consent-container"], "detectCmp": [{ "exists": ".dip-consent-container" }], "detectPopup": [{ "visible": ".dip-consent-content" }], "optOut": [ - { "click": ".dip-consent-btn.white-btn" }, - { - "eval": "Array.from(document.querySelectorAll('.dip-consent-btn.red-btn')).filter(e => e.innerText === 'Auswahl bestätigen')[0].click() || true" - } + { "click": ".dip-consent-btn[tabindex=\"2\"]" } ], - "optIn": [{ "click": ".dip-consent-btn.red-btn" }] + "optIn": [{ "click": ".dip-consent-btn[tabindex=\"1\"]" }] } diff --git a/rules/autoconsent/wp-cookie-notice.json b/rules/autoconsent/wp-cookie-notice.json new file mode 100644 index 00000000..bcb86940 --- /dev/null +++ b/rules/autoconsent/wp-cookie-notice.json @@ -0,0 +1,12 @@ +{ + "name": "WP Cookie Notice for GDPR", + "comment": "https://wordpress.org/plugins/gdpr-cookie-consent/", + "prehideSelectors": ["#gdpr-cookie-consent-bar"], + "detectCmp": [{ "exists": "#gdpr-cookie-consent-bar" }], + "detectPopup": [{ "visible": "#gdpr-cookie-consent-bar" }], + "optIn": [ { "waitForThenClick": "#gdpr-cookie-consent-bar #cookie_action_accept" } ], + "optOut": [ { "waitForThenClick": "#gdpr-cookie-consent-bar #cookie_action_reject" } ], + "test": [ + { "eval": "document.cookie.includes('wpl_viewed_cookie=no')" } + ] +} \ No newline at end of file diff --git a/tests/complianz-banner.spec.ts b/tests/complianz-banner.spec.ts new file mode 100644 index 00000000..9807698c --- /dev/null +++ b/tests/complianz-banner.spec.ts @@ -0,0 +1,9 @@ +import generateCMPTests from "../playwright/runner"; + +generateCMPTests('Complianz banner', [ + 'http://v3.oann.com/', + 'https://bloodpressureok.com/', + 'https://www.fussball-wm.pro/', + 'https://biselliano.info/', +], {} +); diff --git a/tests/complianz-categories.spec.ts b/tests/complianz-categories.spec.ts new file mode 100644 index 00000000..809c443c --- /dev/null +++ b/tests/complianz-categories.spec.ts @@ -0,0 +1,14 @@ +import generateCMPTests from "../playwright/runner"; + +generateCMPTests('Complianz categories', [ + 'https://www.expatica.com/de', + 'https://carnavaldecadiztv.com/', +], { + skipRegions: ['GB'] +}); + +generateCMPTests('Complianz categories', [ + 'https://hypotheses.org/', +], { + skipRegions: ['US', 'GB'] +}); diff --git a/tests/cookieconsent.spec.ts b/tests/complianz-notice.spec.ts similarity index 67% rename from tests/cookieconsent.spec.ts rename to tests/complianz-notice.spec.ts index 260c9bfb..4ea0eb4c 100644 --- a/tests/cookieconsent.spec.ts +++ b/tests/complianz-notice.spec.ts @@ -1,9 +1,8 @@ import generateCMPTests from "../playwright/runner"; -generateCMPTests('cookieconsent', [ +generateCMPTests('Complianz notice', [ 'https://yrc.com/', 'https://www.worldometers.info/', - 'https://www.expatica.com/de', ], { skipRegions: ['GB'] }); diff --git a/tests/complianz-optin.spec.ts b/tests/complianz-optin.spec.ts new file mode 100644 index 00000000..42f337c3 --- /dev/null +++ b/tests/complianz-optin.spec.ts @@ -0,0 +1,6 @@ +import generateCMPTests from "../playwright/runner"; + +generateCMPTests('Complianz optin', [ + 'https://stetson.com/', +], { +}); diff --git a/tests/consentmanager.spec.ts b/tests/consentmanager.spec.ts index 96272cda..fc626d95 100644 --- a/tests/consentmanager.spec.ts +++ b/tests/consentmanager.spec.ts @@ -3,7 +3,7 @@ import generateCMPTests from "../playwright/runner"; generateCMPTests('consentmanager.net', [ // 'https://sourceforge.net/', // disabled because of a botwall - // 'https://www.dastelefonbuch.de/', // disabled due to Playwright bug in WebKit: https://github.com/microsoft/playwright/issues/14745 + 'https://www.dastelefonbuch.de/', 'https://www.history.de/', ] , { diff --git a/tests/cookienotice.spec.ts b/tests/cookie-notice.spec.ts similarity index 100% rename from tests/cookienotice.spec.ts rename to tests/cookie-notice.spec.ts diff --git a/tests/cookieinformation.spec.ts b/tests/cookieinformation.spec.ts new file mode 100644 index 00000000..ecb13ba6 --- /dev/null +++ b/tests/cookieinformation.spec.ts @@ -0,0 +1,10 @@ +import generateCMPTests from "../playwright/runner"; + +generateCMPTests('Cookie Information Banner', [ + 'https://water.org/', + // 'https://www.phaseone.com/', // appears only on user iteraction + 'https://www.georgjensen.com/', + 'https://www.power.no/', + 'https://www.yourhearing.com/', +], {} +); diff --git a/tests/destatis.spec.ts b/tests/destatis.spec.ts deleted file mode 100644 index bb2b7835..00000000 --- a/tests/destatis.spec.ts +++ /dev/null @@ -1,7 +0,0 @@ -import generateCMPTests from "../playwright/runner"; - -generateCMPTests('destatis.de', [ - 'https://destatis.de'], { - skipRegions: ["US", "FR", "GB"] - } -); diff --git a/tests/dsgvo.spec.ts b/tests/dsgvo.spec.ts new file mode 100644 index 00000000..28da5e56 --- /dev/null +++ b/tests/dsgvo.spec.ts @@ -0,0 +1,6 @@ +import generateCMPTests from "../playwright/runner"; + +generateCMPTests('WP DSGVO Tools', [ + 'https://ccmedia.ch/', + 'https://rlalpbsl.web.belwue.de/', +], {}); diff --git a/tests/eu-cookie-law.spec.ts b/tests/eu-cookie-law.spec.ts new file mode 100644 index 00000000..2c04aad1 --- /dev/null +++ b/tests/eu-cookie-law.spec.ts @@ -0,0 +1,6 @@ +import generateCMPTests from "../playwright/runner"; + +generateCMPTests('EU Cookie Law', [ + 'https://pv-magazine-usa.com/', + 'https://www.prolificliving.com/', +], {}); diff --git a/tests/ezoic.spec.ts b/tests/ezoic.spec.ts new file mode 100644 index 00000000..b1a34dc9 --- /dev/null +++ b/tests/ezoic.spec.ts @@ -0,0 +1,8 @@ +import generateCMPTests from "../playwright/runner"; + +generateCMPTests('EZoic', [ + 'https://singletrackworld.com/', + 'https://www.diyphotography.net/', +], { + skipRegions: ['US'], +}); diff --git a/tests/iubenda.spec.ts b/tests/iubenda.spec.ts new file mode 100644 index 00000000..df4cd6fc --- /dev/null +++ b/tests/iubenda.spec.ts @@ -0,0 +1,8 @@ +import generateCMPTests from "../playwright/runner"; + +generateCMPTests('iubenda', [ + 'https://www.rossignol.com/us/', + 'https://www.lofficielusa.com/', + 'https://www.3bmeteo.com/', +],{ +}); diff --git a/tests/jquery-cookiebar.spec.ts b/tests/jquery-cookiebar.spec.ts new file mode 100644 index 00000000..14ec4d20 --- /dev/null +++ b/tests/jquery-cookiebar.spec.ts @@ -0,0 +1,6 @@ +import generateCMPTests from "../playwright/runner"; + +generateCMPTests('jquery.cookieBar', [ + 'https://www.minotstateu.edu/', + 'https://www.myersbriggs.org/', +], {}); diff --git a/tests/klaro.spec.ts b/tests/klaro.spec.ts index bb805d47..b4df9c6f 100644 --- a/tests/klaro.spec.ts +++ b/tests/klaro.spec.ts @@ -1,5 +1,9 @@ import generateCMPTests from "../playwright/runner"; -generateCMPTests('klaro', [ - 'https://heyklaro.com/' +generateCMPTests('Klaro', [ + 'https://heyklaro.com/', + 'https://www.zeitraum-moebel.de/', + 'https://repisalud.isciii.es/', + 'https://www.innogames.com/', + // 'https://dspace.library.stonybrook.edu', // polyfills Promise so playwright doesn't work ]); diff --git a/tests/mediavine.spec.ts b/tests/mediavine.spec.ts new file mode 100644 index 00000000..558f38d2 --- /dev/null +++ b/tests/mediavine.spec.ts @@ -0,0 +1,8 @@ +import generateCMPTests from "../playwright/runner"; + +generateCMPTests('Mediavine', [ + 'https://www.passionforsavings.com/', + 'https://europeupclose.com/', +], { + skipRegions: ['US'] +}); diff --git a/tests/moove.spec.ts b/tests/moove.spec.ts new file mode 100644 index 00000000..1df7a6f0 --- /dev/null +++ b/tests/moove.spec.ts @@ -0,0 +1,13 @@ +import generateCMPTests from "../playwright/runner"; + +generateCMPTests('Moove', [ + 'https://impact.parkinson.org/', + 'https://wamu.org/', + 'https://www.phorest.com/', +], {}); + +generateCMPTests('Moove', [ + 'https://www.yourcloudlibrary.com/', +], { + skipRegions: ['US', 'GB'] +}); diff --git a/tests/onetrust.spec.ts b/tests/onetrust.spec.ts index ddd7f288..e65e913b 100644 --- a/tests/onetrust.spec.ts +++ b/tests/onetrust.spec.ts @@ -9,7 +9,7 @@ generateCMPTests('Onetrust', [ ]); generateCMPTests('Onetrust', [ - 'https://mailchimp.com/', + // 'https://mailchimp.com/', // polyfills Promise so playwright doesn't work "https://www.accenture.com/", 'https://www.zoom.us', ], { @@ -18,7 +18,7 @@ generateCMPTests('Onetrust', [ // opt-in is not necessary in the US on this sites generateCMPTests('Onetrust', [ - 'https://mailchimp.com/', + // 'https://mailchimp.com/', // polyfills Promise so playwright doesn't work "https://www.accenture.com/", 'https://www.zoom.us', ], { diff --git a/tests/primebox.spec.ts b/tests/primebox.spec.ts new file mode 100644 index 00000000..2210a297 --- /dev/null +++ b/tests/primebox.spec.ts @@ -0,0 +1,8 @@ +import generateCMPTests from "../playwright/runner"; + +generateCMPTests('PrimeBox CookieBar', [ + 'https://inpn.mnhn.fr/accueil/index', + 'https://firmenvorteile.rh.aok.de/', + 'http://manunicast.seaes.manchester.ac.uk/', +], {} +); diff --git a/tests/tarteaucitron.spec.ts b/tests/tarteaucitron.spec.ts new file mode 100644 index 00000000..88393554 --- /dev/null +++ b/tests/tarteaucitron.spec.ts @@ -0,0 +1,9 @@ +import generateCMPTests from "../playwright/runner"; + +generateCMPTests('tarteaucitron.js', [ + 'https://planetside2.com', + 'https://marseille.intercontinental.com/', + 'https://www.powellflutes.com/en/', + 'https://www.neweuropetours.eu/', +], {} +); diff --git a/tests/tealium.spec.ts b/tests/tealium.spec.ts index 983e0312..41c50790 100644 --- a/tests/tealium.spec.ts +++ b/tests/tealium.spec.ts @@ -1,6 +1,6 @@ import generateCMPTests from "../playwright/runner"; generateCMPTests('Tealium', [ - 'https://www.bahn.de/', + // 'https://www.bahn.de/', // uses shadow DOM, see https://app.asana.com/0/1201844467387842/1202635343225979/f 'https://www.lufthansa.com/de/en/homepage', ]); diff --git a/tests/termly.spec.ts b/tests/termly.spec.ts new file mode 100644 index 00000000..ae044d91 --- /dev/null +++ b/tests/termly.spec.ts @@ -0,0 +1,7 @@ +import generateCMPTests from "../playwright/runner"; + +generateCMPTests('Termly', [ + 'https://itsalovelylife.com/', + 'https://visualsbyimpulse.com/', + 'https://www.iccsafe.org/', +], {}); diff --git a/tests/trustarc.spec.ts b/tests/trustarc.spec.ts index 433c347b..d56c610b 100644 --- a/tests/trustarc.spec.ts +++ b/tests/trustarc.spec.ts @@ -13,15 +13,7 @@ generateCMPTests('TrustArc-top', [ ], { testOptOut: true, testSelfTest: false, - skipRegions: ["US", "FR"] -}); - -generateCMPTests('TrustArc-frame', [ - 'https://www.garmin.com/de-DE/', -], { - testOptOut: true, - testSelfTest: false, - onlyRegions: ["FR"] + skipRegions: ["US"] }); generateCMPTests('TrustArc-frame', [ diff --git a/tests/uk-cookie-consent.spec.ts b/tests/uk-cookie-consent.spec.ts new file mode 100644 index 00000000..0f8d894f --- /dev/null +++ b/tests/uk-cookie-consent.spec.ts @@ -0,0 +1,7 @@ +import generateCMPTests from "../playwright/runner"; + +generateCMPTests('UK Cookie Consent', [ + 'https://ondinebio.mystagingwebsite.com/', + 'https://www.equinoxpub.com/home/', + 'https://london.msg.com/', +], {}); diff --git a/tests/usercentrics-1.spec.ts b/tests/usercentrics-api.spec.ts similarity index 59% rename from tests/usercentrics-1.spec.ts rename to tests/usercentrics-api.spec.ts index 7683d204..1c566e4a 100644 --- a/tests/usercentrics-1.spec.ts +++ b/tests/usercentrics-api.spec.ts @@ -1,8 +1,9 @@ import generateCMPTests from "../playwright/runner"; -generateCMPTests('usercentrics-1', [ +generateCMPTests('usercentrics-api', [ 'https://hornbach.de', - 'https://dm.de' + 'https://dm.de', + 'https://usercentrics.com/', ], { skipRegions: ["US", "GB", "FR"] } diff --git a/tests/usercentrics-button.spec.ts b/tests/usercentrics-button.spec.ts new file mode 100644 index 00000000..b6639d1b --- /dev/null +++ b/tests/usercentrics-button.spec.ts @@ -0,0 +1,8 @@ +import generateCMPTests from "../playwright/runner"; + +generateCMPTests('usercentrics-button', [ + 'https://www.commerzbank.de/', + 'https://www.nkd.com/', + 'https://shopbetreiber-blog.de/', +], {} +); diff --git a/tests/wp-cookie-notice.spec.ts b/tests/wp-cookie-notice.spec.ts new file mode 100644 index 00000000..925548f7 --- /dev/null +++ b/tests/wp-cookie-notice.spec.ts @@ -0,0 +1,8 @@ +import generateCMPTests from "../playwright/runner"; + +generateCMPTests('WP Cookie Notice for GDPR', [ + 'https://veryceleb.com/', + 'https://nysba.org/', + // 'https://www.independentsentinel.com/', // appears only on user iteraction +], {} +);