@duckduckgo/autoconsent 16.59.0 → 16.61.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/lib/regional-testing/harness.mjs +4 -172
- package/.agents/skills/oxylabs-testing/SKILL.md +4 -4
- package/.agents/skills/oxylabs-testing/scripts/oxylabs.mjs +17 -164
- package/.agents/skills/oxylabs-testing/scripts/oxylabs.test.mjs +6 -3
- package/.agents/skills/verify-pr/SKILL.md +1 -1
- package/AGENTS.md +1 -1
- package/CHANGELOG.md +107 -0
- package/Jenkinsfile +36 -1
- package/dist/addon-firefox/background.bundle.js +21 -0
- package/dist/addon-firefox/compact-rules.json +1 -1
- package/dist/addon-firefox/content.bundle.js +253 -93
- package/dist/addon-firefox/manifest.json +1 -1
- package/dist/addon-firefox/rule-index.json +1 -1
- package/dist/addon-firefox/rules.json +1 -1
- package/dist/addon-mv3/background.bundle.js +21 -0
- package/dist/addon-mv3/compact-rules.json +1 -1
- package/dist/addon-mv3/content.bundle.js +253 -93
- package/dist/addon-mv3/manifest.json +1 -1
- package/dist/addon-mv3/rule-index.json +1 -1
- package/dist/addon-mv3/rules.json +1 -1
- package/dist/autoconsent.cjs.js +253 -93
- package/dist/autoconsent.esm.js +253 -93
- package/dist/autoconsent.playwright.js +253 -93
- package/dist/autoconsent.standalone.js +254 -94
- package/dist/heuristics.cjs.js +29 -3
- package/dist/heuristics.mjs +28 -3
- package/dist/types/cmps/onetrust.d.ts +1 -0
- package/dist/types/eval-snippets.d.ts +3 -0
- package/dist/types/heuristic-classify.d.ts +1 -0
- package/dist/types/heuristics.d.ts +10 -1
- package/lib/cmps/onetrust.ts +15 -0
- package/lib/eval-snippets.ts +21 -0
- package/lib/heuristic-classify.ts +6 -0
- package/lib/heuristic-patterns.ts +26 -1
- package/lib/heuristics.ts +256 -104
- package/package.json +1 -1
- package/playwright/isolated-world.mjs +217 -0
- package/playwright/oxylabs.mjs +196 -0
- package/playwright/runner.ts +183 -39
- package/playwright.config.ts +4 -1
- package/rules/autoconsent/aeolservice.json +39 -0
- package/rules/autoconsent/airbnb.json +32 -0
- package/rules/autoconsent/amazon-music.json +13 -0
- package/rules/autoconsent/annunci69.json +19 -0
- package/rules/autoconsent/appconsent.json +6 -1
- package/rules/autoconsent/arbeidsplassen-nav-no.json +33 -0
- package/rules/autoconsent/att.json +36 -0
- package/rules/autoconsent/auctionet.json +39 -0
- package/rules/autoconsent/autodoc.json +18 -0
- package/rules/autoconsent/bbc.com-orb-cosmetic.json +34 -0
- package/rules/autoconsent/bbc.com.json +8 -5
- package/rules/autoconsent/bokadirekt.se.json +50 -0
- package/rules/autoconsent/bouvet-cookiepanel.json +29 -0
- package/rules/autoconsent/com-consent-layer.json +10 -0
- package/rules/autoconsent/consent-studio.json +25 -13
- package/rules/autoconsent/cookielegit.json +21 -0
- package/rules/autoconsent/cookieprompter.json +21 -0
- package/rules/autoconsent/cookiereports.json +10 -0
- package/rules/autoconsent/cookietractor.json +37 -0
- package/rules/autoconsent/de-volksbank.json +14 -0
- package/rules/autoconsent/dpgmedia-nl.json +20 -8
- package/rules/autoconsent/eon.pl.json +18 -0
- package/rules/autoconsent/eroticiracconti-it.json +13 -0
- package/rules/autoconsent/ersatzteile-24.json +49 -0
- package/rules/autoconsent/fastweb-cookie-center.json +13 -0
- package/rules/autoconsent/futurabolzano-it.json +35 -0
- package/rules/autoconsent/gobasic.json +10 -0
- package/rules/autoconsent/gravito.json +23 -16
- package/rules/autoconsent/hacon-next-gen.json +41 -0
- package/rules/autoconsent/ing-de.json +31 -0
- package/rules/autoconsent/interia.json +1 -4
- package/rules/autoconsent/intesasanpaolo.json +37 -0
- package/rules/autoconsent/jobindex.json +40 -0
- package/rules/autoconsent/kaspersky-cookies-notification.json +9 -0
- package/rules/autoconsent/lantmateriet.json +13 -0
- package/rules/autoconsent/livsmedelsverket.json +18 -0
- package/rules/autoconsent/mainichi.json +39 -0
- package/rules/autoconsent/mango.json +56 -0
- package/rules/autoconsent/nederlandseloterij.json +35 -0
- package/rules/autoconsent/newsbreak.json +16 -0
- package/rules/autoconsent/nhsapp.json +10 -0
- package/rules/autoconsent/nordea.json +21 -0
- package/rules/autoconsent/nordnet.json +33 -0
- package/rules/autoconsent/ok.json +4 -12
- package/rules/autoconsent/onlineradiobox.json +35 -0
- package/rules/autoconsent/pe-cookies.json +30 -0
- package/rules/autoconsent/pensionsmyndigheten.json +13 -0
- package/rules/autoconsent/pro-euclp-cookies-box.json +31 -0
- package/rules/autoconsent/pubfactory.json +45 -0
- package/rules/autoconsent/puesc-gov-pl.json +37 -0
- package/rules/autoconsent/rambler.json +30 -0
- package/rules/autoconsent/rejestr-io.json +36 -0
- package/rules/autoconsent/sas.json +6 -6
- package/rules/autoconsent/scb.se.json +13 -0
- package/rules/autoconsent/schumacher.com.json +53 -0
- package/rules/autoconsent/sitevision.json +18 -1
- package/rules/autoconsent/skatteverket-se.json +33 -0
- package/rules/autoconsent/smile-insurances.json +13 -0
- package/rules/autoconsent/studentapan.json +16 -0
- package/rules/autoconsent/svt.se.json +7 -7
- package/rules/autoconsent/temu.json +12 -16
- package/rules/autoconsent/thecode.json +21 -0
- package/rules/autoconsent/tv2reg-cookie-notice.json +39 -0
- package/rules/autoconsent/uk-parliament.json +19 -0
- package/rules/autoconsent/wirtualna-polska.json +13 -10
- package/rules/autoconsent/xenforo-cookie-consent.json +62 -0
- package/rules/autoconsent/zorginstituut-cookiewarning.json +33 -0
- package/rules/compact-rules.json +1 -1
- package/rules/rule-index.json +1 -1
- package/rules/rules.json +1 -1
- package/tests/aeolservice.spec.ts +5 -0
- package/tests/airbnb.spec.ts +3 -0
- package/tests/amazon-music.spec.ts +9 -0
- package/tests/annunci69.spec.ts +5 -0
- package/tests/appconsent.spec.ts +6 -0
- package/tests/arbeidsplassen-nav-no.spec.ts +3 -0
- package/tests/att.spec.ts +3 -0
- package/tests/auctionet.spec.ts +3 -0
- package/tests/autodoc.spec.ts +8 -0
- package/tests/bbc.com-orb-cosmetic.spec.ts +8 -0
- package/tests/bbc.com.spec.ts +11 -9
- package/tests/bokadirekt.se.spec.ts +3 -0
- package/tests/bouvet-cookiepanel.spec.ts +9 -0
- package/tests/com-consent-layer.spec.ts +6 -0
- package/tests/consent-studio.spec.ts +5 -0
- package/tests/cookiebot.spec.ts +1 -0
- package/tests/cookielegit.spec.ts +3 -0
- package/tests/cookieprompter.spec.ts +9 -0
- package/tests/cookiereports.spec.ts +13 -0
- package/tests/cookietractor.spec.ts +12 -0
- package/tests/de-volksbank.spec.ts +5 -0
- package/tests/dpgmedia-nl.spec.ts +15 -1
- package/tests/eon.pl.spec.ts +3 -0
- package/tests/eroticiracconti-it.spec.ts +3 -0
- package/tests/ersatzteile-24.spec.ts +6 -0
- package/tests/fastweb-cookie-center.spec.ts +3 -0
- package/tests/futurabolzano-it.spec.ts +3 -0
- package/tests/gobasic.spec.ts +3 -0
- package/tests/gravito.spec.ts +7 -1
- package/tests/hacon-next-gen.spec.ts +6 -0
- package/tests/ing-de.spec.ts +3 -0
- package/tests/interia.spec.ts +1 -1
- package/tests/intesasanpaolo.spec.ts +3 -0
- package/tests/jobindex.spec.ts +3 -0
- package/tests/kaspersky-cookies-notification.spec.ts +8 -0
- package/tests/lantmateriet.spec.ts +3 -0
- package/tests/livsmedelsverket.spec.ts +5 -0
- package/tests/mainichi.spec.ts +10 -0
- package/tests/mango.spec.ts +3 -0
- package/tests/nederlandseloterij.spec.ts +9 -0
- package/tests/newsbreak.spec.ts +3 -0
- package/tests/nhsapp.spec.ts +3 -0
- package/tests/nordea.spec.ts +6 -0
- package/tests/nordnet.spec.ts +8 -0
- package/tests/onlineradiobox.spec.ts +5 -0
- package/tests/pe-cookies.spec.ts +6 -0
- package/tests/pensionsmyndigheten.spec.ts +3 -0
- package/tests/pro-euclp-cookies-box.spec.ts +8 -0
- package/tests/pubfactory.spec.ts +10 -0
- package/tests/puesc-gov-pl.spec.ts +3 -0
- package/tests/rambler.spec.ts +3 -0
- package/tests/rejestr-io.spec.ts +3 -0
- package/tests/sas.spec.ts +1 -1
- package/tests/scb.se.spec.ts +4 -0
- package/tests/schumacher.com.spec.ts +6 -0
- package/tests/sitevision-cookie-consent.spec.ts +1 -0
- package/tests/sitevision.spec.ts +7 -0
- package/tests/skatteverket-se.spec.ts +3 -0
- package/tests/smile-insurances.spec.ts +6 -0
- package/tests/studentapan.spec.ts +3 -0
- package/tests/svt.se.spec.ts +1 -3
- package/tests/temu.spec.ts +3 -1
- package/tests/thecode.spec.ts +3 -0
- package/tests/tv2reg-cookie-notice.spec.ts +16 -0
- package/tests/uk-parliament.spec.ts +8 -0
- package/tests/wirtualna-polska.spec.ts +6 -1
- package/tests/xenforo-cookie-consent.spec.ts +6 -0
- package/tests/zorginstituut-cookiewarning.spec.ts +10 -0
- package/tests-wtr/heuristics/get-potential-popups.test.ts +330 -9
- package/tests-wtr/heuristics/heuristics-utils.test.ts +98 -0
- package/rules/autoconsent/twitter.json +0 -34
- package/rules/generated/auto_AU_flysas.com_r1s.json +0 -40
- package/rules/generated/auto_CH_airbnb.de_83z.json +0 -40
- package/rules/generated/auto_CH_autodoc.de_krd.json +0 -40
- package/rules/generated/auto_CH_svtplay.se_d39.json +0 -40
- package/rules/generated/auto_GB_parliamentlive.tv_r3v.json +0 -28
- package/rules/generated/auto_NL_asnbank.nl_e28.json +0 -40
- package/rules/generated/auto_NL_eurojackpot.nederlandseloterij.nl_7hr.json +0 -40
- package/rules/generated/auto_NL_lotto.nederlandseloterij.nl_7c8.json +0 -40
- package/rules/generated/auto_NL_nederlandseloterij.nl_b60.json +0 -40
- package/rules/generated/auto_NL_staatsloterij.nederlandseloterij.nl_197.json +0 -40
- package/rules/generated/auto_NO_arronet.se_vo5.json +0 -40
- package/rules/generated/auto_NO_liseberg.se_qy4.json +0 -40
- package/rules/generated/auto_NO_nordnet.se_2en.json +0 -40
- package/rules/generated/auto_NO_regeringen.se_uhv.json +0 -40
- package/rules/generated/auto_NO_svtplay.se_ujn.json +0 -40
- package/rules/generated/auto_NO_uu.se_eea.json +0 -40
- package/rules/generated/auto_US_newsbreak.com_0.json +0 -28
- package/tests/generated/auto_AU_flysas.com_r1s.spec.ts +0 -2
- package/tests/generated/auto_CH_airbnb.de_83z.spec.ts +0 -2
- package/tests/generated/auto_CH_autodoc.de_krd.spec.ts +0 -2
- package/tests/generated/auto_CH_svtplay.se_d39.spec.ts +0 -2
- package/tests/generated/auto_GB_parliamentlive.tv_r3v.spec.ts +0 -6
- package/tests/generated/auto_NL_asnbank.nl_e28.spec.ts +0 -6
- package/tests/generated/auto_NL_eurojackpot.nederlandseloterij.nl_7hr.spec.ts +0 -6
- package/tests/generated/auto_NL_lotto.nederlandseloterij.nl_7c8.spec.ts +0 -6
- package/tests/generated/auto_NL_nederlandseloterij.nl_b60.spec.ts +0 -6
- package/tests/generated/auto_NL_staatsloterij.nederlandseloterij.nl_197.spec.ts +0 -6
- package/tests/generated/auto_NO_arronet.se_vo5.spec.ts +0 -2
- package/tests/generated/auto_NO_liseberg.se_qy4.spec.ts +0 -2
- package/tests/generated/auto_NO_nordnet.se_2en.spec.ts +0 -2
- package/tests/generated/auto_NO_regeringen.se_uhv.spec.ts +0 -6
- package/tests/generated/auto_NO_svtplay.se_ujn.spec.ts +0 -2
- package/tests/generated/auto_NO_uu.se_eea.spec.ts +0 -2
- package/tests/generated/auto_US_newsbreak.com_0.spec.ts +0 -2
- package/tests/twitter.spec.ts +0 -10
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
import { expect } from '@esm-bundle/chai';
|
|
2
|
-
import { getPotentialPopups } from '../../lib/heuristics';
|
|
2
|
+
import { getActionablePopups, getButtonData, getFramePopupElement, getPotentialPopups } from '../../lib/heuristics';
|
|
3
|
+
import { getHidingStyle } from '../../lib/utils';
|
|
4
|
+
|
|
5
|
+
const BANNER = `
|
|
6
|
+
<p>We use cookies.</p>
|
|
7
|
+
<button>Reject all</button>
|
|
8
|
+
<button>Accept all</button>
|
|
9
|
+
`;
|
|
10
|
+
|
|
11
|
+
function fixedBanner(id: string): string {
|
|
12
|
+
return `<div id="${id}" style="position: fixed; bottom: 0;">${BANNER}</div>`;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// hides the selector the way prehide does
|
|
16
|
+
function addPrehideStyle(selector: string): HTMLStyleElement {
|
|
17
|
+
const style = document.createElement('style');
|
|
18
|
+
style.textContent = `${selector} { ${getHidingStyle('opacity')} }`;
|
|
19
|
+
document.head.appendChild(style);
|
|
20
|
+
return style;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function attachShadow(host: HTMLElement, html: string): ShadowRoot {
|
|
24
|
+
const root = host.attachShadow({ mode: 'open' });
|
|
25
|
+
root.innerHTML = html;
|
|
26
|
+
return root;
|
|
27
|
+
}
|
|
3
28
|
|
|
4
29
|
describe('getPotentialPopups', () => {
|
|
5
30
|
let container: HTMLDivElement;
|
|
@@ -13,16 +38,312 @@ describe('getPotentialPopups', () => {
|
|
|
13
38
|
container.remove();
|
|
14
39
|
});
|
|
15
40
|
|
|
41
|
+
// adds an element with an open shadow root to the container
|
|
42
|
+
function shadowHost(hostStyle: string, html: string): ShadowRoot {
|
|
43
|
+
container.innerHTML = `<div id="host" style="${hostStyle}"></div>`;
|
|
44
|
+
return attachShadow(container.querySelector('#host')!, html);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function popupIds(): string[] {
|
|
48
|
+
return getPotentialPopups(1000).map((p) => p.element.id);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function findPopup(id: string) {
|
|
52
|
+
return getPotentialPopups(1000).find((p) => p.element.id === id);
|
|
53
|
+
}
|
|
54
|
+
|
|
16
55
|
it('returns positioned popups with their buttons', () => {
|
|
17
|
-
container.innerHTML =
|
|
18
|
-
|
|
19
|
-
<p>We use cookies.</p>
|
|
20
|
-
<button>Reject all</button>
|
|
21
|
-
<button>Accept all</button>
|
|
22
|
-
</div>
|
|
23
|
-
`;
|
|
24
|
-
const popup = getPotentialPopups(1000).find((p) => p.element.id === 'popup');
|
|
56
|
+
container.innerHTML = fixedBanner('popup');
|
|
57
|
+
const popup = findPopup('popup');
|
|
25
58
|
expect(popup).to.exist;
|
|
26
59
|
expect(popup!.buttons.map((b) => b.text).sort()).to.deep.equal(['Accept all', 'Reject all']);
|
|
27
60
|
});
|
|
61
|
+
|
|
62
|
+
describe('shadow DOM', () => {
|
|
63
|
+
it('finds a positioned popup inside an open shadow root', () => {
|
|
64
|
+
shadowHost('', fixedBanner('banner'));
|
|
65
|
+
|
|
66
|
+
const popup = findPopup('banner');
|
|
67
|
+
expect(popup).to.exist;
|
|
68
|
+
expect(popup!.text).to.contain('We use cookies.');
|
|
69
|
+
expect(popup!.buttons.map((b) => b.text).sort()).to.deep.equal(['Accept all', 'Reject all']);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('reads text and buttons from the shadow root of a positioned host', () => {
|
|
73
|
+
shadowHost('position: fixed; bottom: 0;', `<style>.banner { color: red; }</style><div class="banner">${BANNER}</div>`);
|
|
74
|
+
|
|
75
|
+
const popup = findPopup('host');
|
|
76
|
+
expect(popup).to.exist;
|
|
77
|
+
expect(popup!.text.match(/We use cookies/g)).to.have.length(1);
|
|
78
|
+
expect(popup!.text).not.to.contain('color: red');
|
|
79
|
+
expect(popup!.buttons.map((b) => b.text).sort()).to.deep.equal(['Accept all', 'Reject all']);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('does not read hidden shadow content of a positioned host', () => {
|
|
83
|
+
shadowHost('position: fixed; bottom: 0;', `<div>${BANNER}</div><div style="display: none">Hidden settings panel</div>`);
|
|
84
|
+
|
|
85
|
+
const popup = findPopup('host');
|
|
86
|
+
expect(popup).to.exist;
|
|
87
|
+
expect(popup!.text).not.to.contain('Hidden settings panel');
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('finds a popup in nested shadow roots', () => {
|
|
91
|
+
const outer = shadowHost('', '<div><div id="inner-host"></div></div>');
|
|
92
|
+
attachShadow(outer.querySelector('#inner-host')!, fixedBanner('banner'));
|
|
93
|
+
|
|
94
|
+
const popup = findPopup('banner');
|
|
95
|
+
expect(popup).to.exist;
|
|
96
|
+
expect(popup!.buttons).to.have.length(2);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('prefers a positioned element inside the shadow root over its positioned host', () => {
|
|
100
|
+
shadowHost('position: fixed; bottom: 0;', fixedBanner('banner'));
|
|
101
|
+
|
|
102
|
+
const ids = popupIds();
|
|
103
|
+
expect(ids).to.include('banner');
|
|
104
|
+
expect(ids).not.to.include('host');
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('finds buttons in a shadow root nested inside the popup', () => {
|
|
108
|
+
container.innerHTML =
|
|
109
|
+
'<div id="popup" style="position: fixed; bottom: 0;"><p>We use cookies.</p><div id="buttons-host"></div></div>';
|
|
110
|
+
attachShadow(container.querySelector('#buttons-host')!, '<button>Reject all</button><button>Accept all</button>');
|
|
111
|
+
|
|
112
|
+
const popup = findPopup('popup');
|
|
113
|
+
expect(popup).to.exist;
|
|
114
|
+
expect(popup!.buttons.map((b) => b.text).sort()).to.deep.equal(['Accept all', 'Reject all']);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('finds buttons in shadow roots when called without known shadow hosts', () => {
|
|
118
|
+
const root = shadowHost('', '<div id="inner-host"></div>');
|
|
119
|
+
attachShadow(root.querySelector('#inner-host')!, '<button>Reject all</button>');
|
|
120
|
+
expect(getButtonData(container).map((b) => b.text)).to.deep.equal(['Reject all']);
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it('makes a shadow DOM popup actionable', () => {
|
|
124
|
+
shadowHost('', fixedBanner('banner'));
|
|
125
|
+
|
|
126
|
+
const popups = getActionablePopups('reject', 1000);
|
|
127
|
+
const popup = popups.find((p) => p.element.id === 'banner');
|
|
128
|
+
expect(popup).to.exist;
|
|
129
|
+
expect(popup!.regexClassification).to.equal('reject');
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
describe('visibility', () => {
|
|
134
|
+
const hiddenCases: Record<string, string> = {
|
|
135
|
+
'an ancestor with display none': `<div style="display: none">${fixedBanner('panel')}</div>`,
|
|
136
|
+
'an ancestor with visibility hidden': `<div style="visibility: hidden">${fixedBanner('panel')}</div>`,
|
|
137
|
+
'an ancestor with visibility hidden (dialog-like)': `<div style="visibility: hidden"><div id="panel" role="dialog">${BANNER}</div></div>`,
|
|
138
|
+
'a position outside the viewport': `<div id="panel" style="position: fixed; top: -2000px;">${BANNER}</div>`,
|
|
139
|
+
'zero size': `<div id="panel" style="position: fixed; bottom: 0; width: 0; height: 0; overflow: hidden;">${BANNER}</div>`,
|
|
140
|
+
'a zero-size wrapper whose content is outside the viewport': `<div id="panel" style="position: fixed; top: 0; height: 0;"><div style="position: relative; top: -2000px;">${BANNER}</div></div>`,
|
|
141
|
+
};
|
|
142
|
+
for (const [name, html] of Object.entries(hiddenCases)) {
|
|
143
|
+
it(`ignores a positioned panel hidden by ${name}`, () => {
|
|
144
|
+
container.innerHTML = html;
|
|
145
|
+
expect(popupIds()).not.to.include('panel');
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
it('ignores a hidden panel inside a shadow root', () => {
|
|
150
|
+
shadowHost('visibility: hidden', fixedBanner('panel'));
|
|
151
|
+
expect(popupIds()).not.to.include('panel');
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('finds a popup hidden with opacity 0, as prehide does', () => {
|
|
155
|
+
const style = addPrehideStyle('#panel');
|
|
156
|
+
try {
|
|
157
|
+
container.innerHTML = fixedBanner('panel');
|
|
158
|
+
expect(popupIds()).to.include('panel');
|
|
159
|
+
} finally {
|
|
160
|
+
style.remove();
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it('finds a popup in a zero-size positioned wrapper whose content is on screen', () => {
|
|
165
|
+
container.innerHTML = `<div id="panel" style="position: fixed; bottom: 0; left: 0; right: 0; height: 0;"><div style="position: absolute; bottom: 0;">${BANNER}</div></div>`;
|
|
166
|
+
expect(popupIds()).to.include('panel');
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
describe('popup fragments', () => {
|
|
171
|
+
it('expands a sticky button bar to the banner that contains it', () => {
|
|
172
|
+
container.innerHTML = `
|
|
173
|
+
<div id="banner" style="position: fixed; bottom: 0;">
|
|
174
|
+
<p>We use cookies.</p>
|
|
175
|
+
<div id="button-bar" style="position: sticky; bottom: 0;">
|
|
176
|
+
<button>Reject all</button>
|
|
177
|
+
<button>Accept all</button>
|
|
178
|
+
</div>
|
|
179
|
+
</div>
|
|
180
|
+
`;
|
|
181
|
+
const popups = getPotentialPopups(1000);
|
|
182
|
+
const ids = popups.map((p) => p.element.id);
|
|
183
|
+
expect(ids).to.include('banner');
|
|
184
|
+
expect(ids).not.to.include('button-bar');
|
|
185
|
+
const banner = popups.find((p) => p.element.id === 'banner')!;
|
|
186
|
+
expect(banner.text).to.contain('We use cookies.');
|
|
187
|
+
expect(banner.buttons).to.have.length(2);
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
it('expands a fixed button bar to an ancestor that is not positioned', () => {
|
|
191
|
+
container.innerHTML = `
|
|
192
|
+
<div id="banner">
|
|
193
|
+
<p>We use cookies.</p>
|
|
194
|
+
<div id="button-bar" style="position: fixed; bottom: 0;">
|
|
195
|
+
<button>Reject all</button>
|
|
196
|
+
<button>Accept all</button>
|
|
197
|
+
</div>
|
|
198
|
+
</div>
|
|
199
|
+
`;
|
|
200
|
+
const ids = popupIds();
|
|
201
|
+
expect(ids).to.include('banner');
|
|
202
|
+
expect(ids).not.to.include('button-bar');
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it('expands past text whose only buttons are policy links', () => {
|
|
206
|
+
container.innerHTML = `
|
|
207
|
+
<div id="banner">
|
|
208
|
+
<div id="banner-text">
|
|
209
|
+
<h2 style="position: sticky; top: 0;">Cookie settings</h2>
|
|
210
|
+
<p>We use cookies. Read our <a href="#">Privacy Policy</a>.</p>
|
|
211
|
+
</div>
|
|
212
|
+
<button>Reject all</button>
|
|
213
|
+
<button>Accept all</button>
|
|
214
|
+
</div>
|
|
215
|
+
`;
|
|
216
|
+
const ids = popupIds();
|
|
217
|
+
expect(ids).to.include('banner');
|
|
218
|
+
expect(ids).not.to.include('banner-text');
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
it('expands a sticky heading with no buttons to its dialog', () => {
|
|
222
|
+
container.innerHTML = `
|
|
223
|
+
<div id="dialog" role="dialog" style="position: absolute; top: 0; height: 300px; overflow: auto;">
|
|
224
|
+
<header id="heading" style="position: sticky; top: 0;">Cookie settings</header>
|
|
225
|
+
<p>We use cookies.</p>
|
|
226
|
+
<button>Reject all</button>
|
|
227
|
+
<button>Accept all</button>
|
|
228
|
+
</div>
|
|
229
|
+
`;
|
|
230
|
+
const ids = popupIds();
|
|
231
|
+
expect(ids).to.include('dialog');
|
|
232
|
+
expect(ids).not.to.include('heading');
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
it('returns one popup when several fragments expand to the same banner', () => {
|
|
236
|
+
container.innerHTML = `
|
|
237
|
+
<div id="banner">
|
|
238
|
+
<p>We use cookies.</p>
|
|
239
|
+
<div style="position: fixed; top: 0;"><button>Close</button></div>
|
|
240
|
+
<div style="position: fixed; bottom: 0;"><button>Reject all</button><button>Accept all</button></div>
|
|
241
|
+
</div>
|
|
242
|
+
`;
|
|
243
|
+
const popups = getPotentialPopups(1000).filter((p) => container.contains(p.element));
|
|
244
|
+
expect(popups.map((p) => p.element.id)).to.deep.equal(['banner']);
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
it('keeps a fragment when no ancestor looks like a consent popup', () => {
|
|
248
|
+
container.innerHTML = `
|
|
249
|
+
<div id="wrapper">
|
|
250
|
+
<p>Sign up for our newsletter.</p>
|
|
251
|
+
<div id="bar" style="position: fixed; bottom: 0;"><button>Subscribe</button></div>
|
|
252
|
+
</div>
|
|
253
|
+
`;
|
|
254
|
+
const ids = popupIds();
|
|
255
|
+
expect(ids).to.include('bar');
|
|
256
|
+
expect(ids).not.to.include('wrapper');
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
it('does not expand into a container taller than the viewport', () => {
|
|
260
|
+
container.innerHTML = `
|
|
261
|
+
<div id="page" style="height: 3000px;">
|
|
262
|
+
<nav id="nav" style="position: fixed; top: 0;"><a href="#">Home</a><a href="#">About</a></nav>
|
|
263
|
+
<footer>We use cookies to improve this site.</footer>
|
|
264
|
+
</div>
|
|
265
|
+
`;
|
|
266
|
+
const ids = popupIds();
|
|
267
|
+
expect(ids).to.include('nav');
|
|
268
|
+
expect(ids).not.to.include('page');
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
it('expands a fragment inside a shadow root', () => {
|
|
272
|
+
shadowHost(
|
|
273
|
+
'',
|
|
274
|
+
`<div id="banner"><p>We use cookies.</p><div id="button-bar" style="position: fixed; bottom: 0;"><button>Reject all</button><button>Accept all</button></div></div>`,
|
|
275
|
+
);
|
|
276
|
+
const ids = popupIds();
|
|
277
|
+
expect(ids).to.include('banner');
|
|
278
|
+
expect(ids).not.to.include('button-bar');
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
it('makes an expanded popup actionable', () => {
|
|
282
|
+
container.innerHTML = `
|
|
283
|
+
<div id="banner" style="position: fixed; bottom: 0;">
|
|
284
|
+
<p>We use cookies.</p>
|
|
285
|
+
<div style="position: sticky; bottom: 0;"><button>Reject all</button><button>Accept all</button></div>
|
|
286
|
+
</div>
|
|
287
|
+
`;
|
|
288
|
+
const popup = getActionablePopups('reject', 1000).find((p) => p.element.id === 'banner');
|
|
289
|
+
expect(popup).to.exist;
|
|
290
|
+
expect(popup!.regexClassification).to.equal('reject');
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
it('expands a button bar into an age gate so that the gate is excluded', () => {
|
|
294
|
+
container.innerHTML = `
|
|
295
|
+
<div role="dialog" style="position: absolute; top: 0;">
|
|
296
|
+
<h2>Age verification</h2>
|
|
297
|
+
<p>This website contains adult material and is only accessible to persons over 18 years of age. This site uses cookies.</p>
|
|
298
|
+
<div style="position: sticky; bottom: 0;"><button>Accept all</button></div>
|
|
299
|
+
</div>
|
|
300
|
+
`;
|
|
301
|
+
const popups = getActionablePopups('tier2', 1000).filter((p) => container.contains(p.element));
|
|
302
|
+
expect(popups).to.have.length(0);
|
|
303
|
+
});
|
|
304
|
+
});
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
describe('getFramePopupElement', () => {
|
|
308
|
+
let iframe: HTMLIFrameElement;
|
|
309
|
+
|
|
310
|
+
async function loadFrame(html: string, style = 'width: 400px; height: 300px;') {
|
|
311
|
+
iframe = document.createElement('iframe');
|
|
312
|
+
iframe.setAttribute('style', style);
|
|
313
|
+
const loaded = new Promise((resolve) => iframe.addEventListener('load', resolve, { once: true }));
|
|
314
|
+
iframe.srcdoc = html;
|
|
315
|
+
document.body.appendChild(iframe);
|
|
316
|
+
await loaded;
|
|
317
|
+
return iframe.contentDocument!;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
afterEach(() => {
|
|
321
|
+
iframe?.remove();
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
it('returns the body of a frame with text', async () => {
|
|
325
|
+
const doc = await loadFrame(`<body>${BANNER}</body>`);
|
|
326
|
+
expect(getFramePopupElement(doc)).to.equal(doc.body);
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
it('returns the body when all frame content is positioned', async () => {
|
|
330
|
+
const doc = await loadFrame(`<body><div style="position: fixed; bottom: 0;">${BANNER}</div></body>`);
|
|
331
|
+
expect(doc.body.getBoundingClientRect().height).to.equal(0);
|
|
332
|
+
expect(getFramePopupElement(doc)).to.equal(doc.body);
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
it('ignores a frame without text', async () => {
|
|
336
|
+
const doc = await loadFrame('<body><div></div></body>');
|
|
337
|
+
expect(getFramePopupElement(doc)).to.be.null;
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
it('ignores a frame with a hidden body', async () => {
|
|
341
|
+
const doc = await loadFrame(`<body style="visibility: hidden">${BANNER}</body>`);
|
|
342
|
+
expect(getFramePopupElement(doc)).to.be.null;
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
it('ignores a frame that is not rendered', async () => {
|
|
346
|
+
const doc = await loadFrame(`<body>${BANNER}</body>`, 'display: none;');
|
|
347
|
+
expect(getFramePopupElement(doc)).to.be.null;
|
|
348
|
+
});
|
|
28
349
|
});
|
|
@@ -120,6 +120,47 @@ describe('checkHeuristicPatterns with Russian popups', () => {
|
|
|
120
120
|
});
|
|
121
121
|
});
|
|
122
122
|
|
|
123
|
+
describe('checkHeuristicPatterns with Italian popups', () => {
|
|
124
|
+
it('detects Italian cookie notices', () => {
|
|
125
|
+
const texts = [
|
|
126
|
+
'Qualcuno ha detto… cookie? Noi e i nostri partner utilizziamo i cookie per fornirti un servizio migliore',
|
|
127
|
+
'Utilizziamo cookie tecnici e di profilazione',
|
|
128
|
+
'Questo sito utilizza i cookie per migliorare la tua esperienza',
|
|
129
|
+
'Noi e i nostri 150 partner archiviamo informazioni come i cookie',
|
|
130
|
+
'Archiviare e/o accedere a informazioni su un dispositivo',
|
|
131
|
+
];
|
|
132
|
+
for (const text of texts) {
|
|
133
|
+
expect(checkHeuristicPatterns(text).patterns.length, text).to.be.greaterThan(0);
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it('does not detect unrelated Italian text', () => {
|
|
138
|
+
expect(
|
|
139
|
+
checkHeuristicPatterns(
|
|
140
|
+
'Noi e i nostri partner commerciali utilizziamo materiali riciclati. Il sito usa la tecnologia più moderna.',
|
|
141
|
+
).patterns,
|
|
142
|
+
).to.have.length(0);
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
describe('checkHeuristicPatterns with Swedish popups', () => {
|
|
147
|
+
it('detects Swedish cookie notices', () => {
|
|
148
|
+
const texts = [
|
|
149
|
+
// svtplay.se
|
|
150
|
+
'Viss datahantering är nödvändig för att säkerställa att vår tjänst fungerar, vilket innebär att vi använder spårningstekniker såsom cookies.',
|
|
151
|
+
'Vi använder cookies för att förbättra din upplevelse',
|
|
152
|
+
'Webbplatsen använder kakor',
|
|
153
|
+
];
|
|
154
|
+
for (const text of texts) {
|
|
155
|
+
expect(checkHeuristicPatterns(text).patterns.length, text).to.be.greaterThan(0);
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('does not detect unrelated Swedish text', () => {
|
|
160
|
+
expect(checkHeuristicPatterns('Vi använder svenska råvaror i våra bullar').patterns).to.have.length(0);
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
|
|
123
164
|
describe('checkHeuristicPatterns with Japanese popups', () => {
|
|
124
165
|
it('detects Japanese cookie notices', () => {
|
|
125
166
|
const texts = [
|
|
@@ -137,6 +178,22 @@ describe('checkHeuristicPatterns with Japanese popups', () => {
|
|
|
137
178
|
});
|
|
138
179
|
});
|
|
139
180
|
|
|
181
|
+
describe('checkHeuristicPatterns with Danish popups', () => {
|
|
182
|
+
it('detects Danish cookie notices', () => {
|
|
183
|
+
const texts = [
|
|
184
|
+
'Sundhed.dk og tredjepartstjenester bruger cookies til at forbedre brugeroplevelsen.',
|
|
185
|
+
'Vi bruger cookies for at give dig den bedste oplevelse.',
|
|
186
|
+
];
|
|
187
|
+
for (const text of texts) {
|
|
188
|
+
expect(checkHeuristicPatterns(text).patterns.length, text).to.be.greaterThan(0);
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it('does not detect unrelated Danish text', () => {
|
|
193
|
+
expect(checkHeuristicPatterns('Find information om sundhed og sygdom').patterns).to.have.length(0);
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
|
|
140
197
|
describe('isExcludedPopup', () => {
|
|
141
198
|
it('flags doublelist-style age verification popups', () => {
|
|
142
199
|
// Real-world text from the doublelist.com age gate (listings page)
|
|
@@ -280,6 +337,17 @@ describe('classifyButtonTextRegex', () => {
|
|
|
280
337
|
expect(classifyButtonTextRegex('同意して続ける')).not.to.equal('reject');
|
|
281
338
|
});
|
|
282
339
|
|
|
340
|
+
it('matches Danish reject buttons', () => {
|
|
341
|
+
expect(classifyButtonTextRegex('Nej tak')).to.equal('reject');
|
|
342
|
+
expect(classifyButtonTextRegex('Nej, tak')).to.equal('reject');
|
|
343
|
+
expect(classifyButtonTextRegex('Afvis alle')).to.equal('reject');
|
|
344
|
+
expect(classifyButtonTextRegex('Afvis cookies')).to.equal('reject');
|
|
345
|
+
expect(classifyButtonTextRegex('Kun nødvendige')).to.equal('reject');
|
|
346
|
+
expect(classifyButtonTextRegex('Tillad kun nødvendige cookies')).to.equal('reject');
|
|
347
|
+
expect(classifyButtonTextRegex('Ja tak')).not.to.equal('reject');
|
|
348
|
+
expect(classifyButtonTextRegex('Læs mere om brugen af cookies på sundhed.dk')).not.to.equal('reject');
|
|
349
|
+
});
|
|
350
|
+
|
|
283
351
|
it('matches Russian settings buttons', () => {
|
|
284
352
|
expect(classifyButtonTextRegex('Настроить')).to.equal('settings');
|
|
285
353
|
expect(classifyButtonTextRegex('Настройки')).to.equal('settings');
|
|
@@ -546,6 +614,36 @@ describe('excludeContainers', () => {
|
|
|
546
614
|
expect(result).to.have.length(1);
|
|
547
615
|
expect(result[0]).to.equal(inner);
|
|
548
616
|
});
|
|
617
|
+
it('excludes a shadow host that contains another element in its shadow root', () => {
|
|
618
|
+
const host = document.createElement('div');
|
|
619
|
+
const inner = document.createElement('button');
|
|
620
|
+
host.attachShadow({ mode: 'open' }).appendChild(inner);
|
|
621
|
+
|
|
622
|
+
const result = excludeContainers([host, inner]);
|
|
623
|
+
|
|
624
|
+
expect(result).to.deep.equal([inner]);
|
|
625
|
+
});
|
|
626
|
+
|
|
627
|
+
it('keeps the reversed input order', () => {
|
|
628
|
+
const parent = document.createElement('div');
|
|
629
|
+
const a = document.createElement('button');
|
|
630
|
+
const b = document.createElement('button');
|
|
631
|
+
const c = document.createElement('button');
|
|
632
|
+
parent.append(a, b, c);
|
|
633
|
+
|
|
634
|
+
expect(excludeContainers([parent, a, b, c])).to.deep.equal([c, b, a]);
|
|
635
|
+
});
|
|
636
|
+
|
|
637
|
+
it('handles thousands of elements quickly', () => {
|
|
638
|
+
const parent = document.createElement('nav');
|
|
639
|
+
const links = Array.from({ length: 5000 }, () => parent.appendChild(document.createElement('a')));
|
|
640
|
+
|
|
641
|
+
const start = performance.now();
|
|
642
|
+
const result = excludeContainers([parent, ...links]);
|
|
643
|
+
|
|
644
|
+
expect(result).to.have.length(5000);
|
|
645
|
+
expect(performance.now() - start).to.be.below(200);
|
|
646
|
+
});
|
|
549
647
|
});
|
|
550
648
|
|
|
551
649
|
describe('getActionablePopups', () => {
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "twitter",
|
|
3
|
-
"runContext": {
|
|
4
|
-
"urlPattern": "^https://([a-z0-9-]+\\.)?(twitter|x)\\.com/"
|
|
5
|
-
},
|
|
6
|
-
"prehideSelectors": ["[data-testid=\"BottomBar\"]"],
|
|
7
|
-
"detectCmp": [
|
|
8
|
-
{
|
|
9
|
-
"exists": "body > div#react-root > div:not([id]) > div:not([id]) > div:nth-child(1)#layers > div:not([id]) > div:nth-child(2):not([id]) > div:not([id]) > div:not([id])[data-testid=BottomBar] > div:not([id]) > div:nth-child(2):not([id]) > button:nth-child(2):not([id])"
|
|
10
|
-
}
|
|
11
|
-
],
|
|
12
|
-
"detectPopup": [
|
|
13
|
-
{
|
|
14
|
-
"visible": "body > div#react-root > div:not([id]) > div:not([id]) > div:nth-child(1)#layers > div:not([id]) > div:nth-child(2):not([id]) > div:not([id]) > div:not([id])[data-testid=BottomBar] > div:not([id]) > div:nth-child(2):not([id]) > button:nth-child(2):not([id])"
|
|
15
|
-
}
|
|
16
|
-
],
|
|
17
|
-
"optIn": [
|
|
18
|
-
{
|
|
19
|
-
"waitForThenClick": "[data-testid=\"BottomBar\"] > div:has(>div:first-child>div:last-child>button[role=button]>span) > div:last-child > button[role=button]:first-child"
|
|
20
|
-
}
|
|
21
|
-
],
|
|
22
|
-
"optOut": [
|
|
23
|
-
{
|
|
24
|
-
"waitForThenClick": "body > div#react-root > div:not([id]) > div:not([id]) > div:nth-child(1)#layers > div:not([id]) > div:nth-child(2):not([id]) > div:not([id]) > div:not([id])[data-testid=BottomBar] > div:not([id]) > div:nth-child(2):not([id]) > button:nth-child(2):not([id])"
|
|
25
|
-
}
|
|
26
|
-
],
|
|
27
|
-
"test": [
|
|
28
|
-
{
|
|
29
|
-
"waitForVisible": "body > div#react-root > div:not([id]) > div:not([id]) > div:nth-child(1)#layers > div:not([id]) > div:nth-child(2):not([id]) > div:not([id]) > div:not([id])[data-testid=BottomBar] > div:not([id]) > div:nth-child(2):not([id]) > button:nth-child(2):not([id])",
|
|
30
|
-
"timeout": 1000,
|
|
31
|
-
"check": "none"
|
|
32
|
-
}
|
|
33
|
-
]
|
|
34
|
-
}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "auto_AU_flysas.com_r1s",
|
|
3
|
-
"cosmetic": false,
|
|
4
|
-
"_metadata": {
|
|
5
|
-
"vendorUrl": "http://www.flysas.com/"
|
|
6
|
-
},
|
|
7
|
-
"runContext": {
|
|
8
|
-
"main": true,
|
|
9
|
-
"frame": false,
|
|
10
|
-
"urlPattern": "^https?://(www\\.)?flysas\\.com/"
|
|
11
|
-
},
|
|
12
|
-
"prehideSelectors": [],
|
|
13
|
-
"detectCmp": [
|
|
14
|
-
{
|
|
15
|
-
"exists": "body > dialog:not([id]) > div:not([id]) > div:nth-child(3):not([id]) > div:not([id]) > div:not([id]) > div:not([id]) > button:nth-child(2)#deny-consent-button"
|
|
16
|
-
}
|
|
17
|
-
],
|
|
18
|
-
"detectPopup": [
|
|
19
|
-
{
|
|
20
|
-
"visible": "body > dialog:not([id]) > div:not([id]) > div:nth-child(3):not([id]) > div:not([id]) > div:not([id]) > div:not([id]) > button:nth-child(2)#deny-consent-button"
|
|
21
|
-
}
|
|
22
|
-
],
|
|
23
|
-
"optIn": [],
|
|
24
|
-
"optOut": [
|
|
25
|
-
{
|
|
26
|
-
"wait": 500
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
"waitForThenClick": "body > dialog:not([id]) > div:not([id]) > div:nth-child(3):not([id]) > div:not([id]) > div:not([id]) > div:not([id]) > button:nth-child(2)#deny-consent-button",
|
|
30
|
-
"comment": "Deny"
|
|
31
|
-
}
|
|
32
|
-
],
|
|
33
|
-
"test": [
|
|
34
|
-
{
|
|
35
|
-
"waitForVisible": "body > dialog:not([id]) > div:not([id]) > div:nth-child(3):not([id]) > div:not([id]) > div:not([id]) > div:not([id]) > button:nth-child(2)#deny-consent-button",
|
|
36
|
-
"timeout": 1000,
|
|
37
|
-
"check": "none"
|
|
38
|
-
}
|
|
39
|
-
]
|
|
40
|
-
}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "auto_CH_airbnb.de_83z",
|
|
3
|
-
"cosmetic": false,
|
|
4
|
-
"_metadata": {
|
|
5
|
-
"vendorUrl": "http://www.airbnb.de/"
|
|
6
|
-
},
|
|
7
|
-
"runContext": {
|
|
8
|
-
"main": true,
|
|
9
|
-
"frame": false,
|
|
10
|
-
"urlPattern": "^https?://(www\\.)?airbnb\\.de/"
|
|
11
|
-
},
|
|
12
|
-
"prehideSelectors": [],
|
|
13
|
-
"detectCmp": [
|
|
14
|
-
{
|
|
15
|
-
"exists": "body > div#react-application > div:not([id]) > div:not([id])[data-testid=\"linaria-injector\"] > div:nth-child(1):not([id]) > div:not([id]) > div:nth-child(2):not([id])[data-testid=\"main-cookies-banner-container\"] > section:not([id]) > div:not([id]) > div:nth-child(2):not([id]) > div:nth-child(2):not([id]) > button:not([id])"
|
|
16
|
-
}
|
|
17
|
-
],
|
|
18
|
-
"detectPopup": [
|
|
19
|
-
{
|
|
20
|
-
"visible": "body > div#react-application > div:not([id]) > div:not([id])[data-testid=\"linaria-injector\"] > div:nth-child(1):not([id]) > div:not([id]) > div:nth-child(2):not([id])[data-testid=\"main-cookies-banner-container\"] > section:not([id]) > div:not([id]) > div:nth-child(2):not([id]) > div:nth-child(2):not([id]) > button:not([id])"
|
|
21
|
-
}
|
|
22
|
-
],
|
|
23
|
-
"optIn": [],
|
|
24
|
-
"optOut": [
|
|
25
|
-
{
|
|
26
|
-
"wait": 500
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
"waitForThenClick": "body > div#react-application > div:not([id]) > div:not([id])[data-testid=\"linaria-injector\"] > div:nth-child(1):not([id]) > div:not([id]) > div:nth-child(2):not([id])[data-testid=\"main-cookies-banner-container\"] > section:not([id]) > div:not([id]) > div:nth-child(2):not([id]) > div:nth-child(2):not([id]) > button:not([id])",
|
|
30
|
-
"comment": "Nur notwendige"
|
|
31
|
-
}
|
|
32
|
-
],
|
|
33
|
-
"test": [
|
|
34
|
-
{
|
|
35
|
-
"waitForVisible": "body > div#react-application > div:not([id]) > div:not([id])[data-testid=\"linaria-injector\"] > div:nth-child(1):not([id]) > div:not([id]) > div:nth-child(2):not([id])[data-testid=\"main-cookies-banner-container\"] > section:not([id]) > div:not([id]) > div:nth-child(2):not([id]) > div:nth-child(2):not([id]) > button:not([id])",
|
|
36
|
-
"timeout": 1000,
|
|
37
|
-
"check": "none"
|
|
38
|
-
}
|
|
39
|
-
]
|
|
40
|
-
}
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "auto_CH_autodoc.de_krd",
|
|
3
|
-
"cosmetic": false,
|
|
4
|
-
"_metadata": {
|
|
5
|
-
"vendorUrl": "http://www.autodoc.de/"
|
|
6
|
-
},
|
|
7
|
-
"runContext": {
|
|
8
|
-
"main": true,
|
|
9
|
-
"frame": false,
|
|
10
|
-
"urlPattern": "^https?://(www\\.)?autodoc\\.de/"
|
|
11
|
-
},
|
|
12
|
-
"prehideSelectors": [],
|
|
13
|
-
"detectCmp": [
|
|
14
|
-
{
|
|
15
|
-
"exists": "body > div:not([id])[data-popup=\"\"][data-popup-cookies=\"\"][data-terms-cookies-popup-common=\"\"][data-popup-need-overlay=\"true\"] > div:not([id])[data-terms-cookies-popup=\"\"][data-terms-cookies-popup-common=\"\"] > div:not([id]) > div:nth-child(2):not([id]) > button:nth-child(2):not([id])[data-cookies=\"disallow_all_cookies\"]"
|
|
16
|
-
}
|
|
17
|
-
],
|
|
18
|
-
"detectPopup": [
|
|
19
|
-
{
|
|
20
|
-
"visible": "body > div:not([id])[data-popup=\"\"][data-popup-cookies=\"\"][data-terms-cookies-popup-common=\"\"][data-popup-need-overlay=\"true\"] > div:not([id])[data-terms-cookies-popup=\"\"][data-terms-cookies-popup-common=\"\"] > div:not([id]) > div:nth-child(2):not([id]) > button:nth-child(2):not([id])[data-cookies=\"disallow_all_cookies\"]"
|
|
21
|
-
}
|
|
22
|
-
],
|
|
23
|
-
"optIn": [],
|
|
24
|
-
"optOut": [
|
|
25
|
-
{
|
|
26
|
-
"wait": 500
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
"waitForThenClick": "body > div:not([id])[data-popup=\"\"][data-popup-cookies=\"\"][data-terms-cookies-popup-common=\"\"][data-popup-need-overlay=\"true\"] > div:not([id])[data-terms-cookies-popup=\"\"][data-terms-cookies-popup-common=\"\"] > div:not([id]) > div:nth-child(2):not([id]) > button:nth-child(2):not([id])[data-cookies=\"disallow_all_cookies\"]",
|
|
30
|
-
"comment": "Ablehnen"
|
|
31
|
-
}
|
|
32
|
-
],
|
|
33
|
-
"test": [
|
|
34
|
-
{
|
|
35
|
-
"waitForVisible": "body > div:not([id])[data-popup=\"\"][data-popup-cookies=\"\"][data-terms-cookies-popup-common=\"\"][data-popup-need-overlay=\"true\"] > div:not([id])[data-terms-cookies-popup=\"\"][data-terms-cookies-popup-common=\"\"] > div:not([id]) > div:nth-child(2):not([id]) > button:nth-child(2):not([id])[data-cookies=\"disallow_all_cookies\"]",
|
|
36
|
-
"timeout": 1000,
|
|
37
|
-
"check": "none"
|
|
38
|
-
}
|
|
39
|
-
]
|
|
40
|
-
}
|