@duckduckgo/autoconsent 2.0.0 → 2.1.2

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.
Files changed (65) hide show
  1. package/Jenkinsfile +1 -1
  2. package/dist/addon-firefox/background.bundle.js +1 -0
  3. package/dist/addon-firefox/content.bundle.js +1 -0
  4. package/dist/addon-firefox/icons/cog.png +0 -0
  5. package/dist/addon-firefox/icons/cookie-idle.png +0 -0
  6. package/dist/addon-firefox/icons/cookie.png +0 -0
  7. package/dist/addon-firefox/icons/party.png +0 -0
  8. package/dist/addon-firefox/icons/tick.png +0 -0
  9. package/dist/addon-firefox/icons/verified.png +0 -0
  10. package/dist/addon-firefox/manifest.json +32 -0
  11. package/dist/addon-firefox/rules.json +4245 -0
  12. package/dist/addon-mv3/background.bundle.js +1 -0
  13. package/dist/addon-mv3/content.bundle.js +1 -0
  14. package/dist/addon-mv3/icons/cog.png +0 -0
  15. package/dist/addon-mv3/icons/cookie-idle.png +0 -0
  16. package/dist/addon-mv3/icons/cookie.png +0 -0
  17. package/dist/addon-mv3/icons/party.png +0 -0
  18. package/dist/addon-mv3/icons/tick.png +0 -0
  19. package/dist/addon-mv3/icons/verified.png +0 -0
  20. package/dist/addon-mv3/manifest.json +34 -0
  21. package/dist/addon-mv3/rules.json +4245 -0
  22. package/dist/autoconsent.cjs.js +1 -1
  23. package/dist/autoconsent.esm.js +1 -1
  24. package/dist/autoconsent.playwright.js +1 -1
  25. package/dist/autoconsent.standalone.js +1 -1
  26. package/lib/cmps/base.ts +5 -0
  27. package/lib/cmps/onetrust.ts +1 -1
  28. package/lib/cmps/sourcepoint-frame.ts +9 -7
  29. package/lib/cmps/trustarc-top.ts +6 -0
  30. package/lib/web/consentomatic/index.js +188 -0
  31. package/lib/web/consentomatic/tools.js +177 -0
  32. package/lib/web.ts +7 -2
  33. package/package.json +5 -4
  34. package/playwright/content.ts +1 -7
  35. package/playwright/runner.ts +104 -73
  36. package/readme.md +5 -1
  37. package/rollup.config.js +27 -13
  38. package/rules/autoconsent/affinity-serif-com.json +40 -0
  39. package/rules/autoconsent/ausopen.json +2 -1
  40. package/rules/autoconsent/cookie-law-info.json +1 -1
  41. package/rules/autoconsent/cookie-notice.json +1 -1
  42. package/rules/autoconsent/destatis-de.json +2 -1
  43. package/rules/autoconsent/dunelm.json +1 -1
  44. package/rules/autoconsent/etsy.json +1 -1
  45. package/rules/autoconsent/marksandspencer.json +2 -1
  46. package/rules/autoconsent/mediamarkt-de.json +1 -1
  47. package/rules/autoconsent/microsoft.json +1 -1
  48. package/rules/autoconsent/monzo-com.json +22 -0
  49. package/rules/autoconsent/osano.json +4 -1
  50. package/rules/autoconsent/snigel.json +2 -1
  51. package/rules/autoconsent/thefreedictionary.json +1 -1
  52. package/rules/rules.json +113 -8
  53. package/tests/affinity-serif-com.spec.ts +5 -0
  54. package/tests/didomi.spec.ts +1 -1
  55. package/tests/evidon.spec.ts +6 -1
  56. package/tests/monzo-com.spec.ts +5 -0
  57. package/tests/oil.spec.ts +1 -1
  58. package/tests/onetrust.spec.ts +19 -3
  59. package/tests/quantcast.spec.ts +1 -1
  60. package/tests/springer.spec.ts +1 -1
  61. package/tests/trustarc.spec.ts +1 -0
  62. package/tests/wordpressgdpr.spec.ts +1 -1
  63. package/update_version.js +10 -6
  64. package/.vscode/settings.json +0 -7
  65. package/playwright/standalone.ts +0 -36
@@ -0,0 +1,188 @@
1
+ import Tools from "./tools";
2
+ export function matches(config) {
3
+ const result = Tools.find(config);
4
+ if (config.type === "css") {
5
+ return !!result.target;
6
+ }
7
+ else if (config.type === "checkbox") {
8
+ return !!result.target && result.target.checked;
9
+ }
10
+ }
11
+ export async function executeAction(config, param) {
12
+ switch (config.type) {
13
+ case "click":
14
+ return clickAction(config);
15
+ case "list":
16
+ return listAction(config, param);
17
+ case "consent":
18
+ return consentAction(config, param);
19
+ case "ifcss":
20
+ return ifCssAction(config, param);
21
+ case "waitcss":
22
+ return waitCssAction(config);
23
+ case "foreach":
24
+ return forEachAction(config, param);
25
+ case "hide":
26
+ return hideAction(config);
27
+ case "slide":
28
+ return slideAction(config);
29
+ case "close":
30
+ return closeAction(config);
31
+ case "wait":
32
+ return waitAction(config);
33
+ case "eval":
34
+ return evalAction(config);
35
+ default:
36
+ throw "Unknown action type: " + config.type;
37
+ }
38
+ }
39
+ const STEP_TIMEOUT = 0;
40
+ function waitTimeout(timeout) {
41
+ return new Promise(resolve => {
42
+ setTimeout(() => {
43
+ resolve();
44
+ }, timeout);
45
+ });
46
+ }
47
+ async function clickAction(config) {
48
+ const result = Tools.find(config);
49
+ if (result.target != null) {
50
+ result.target.click();
51
+ }
52
+ return waitTimeout(STEP_TIMEOUT);
53
+ }
54
+ async function listAction(config, param) {
55
+ for (let action of config.actions) {
56
+ await executeAction(action, param);
57
+ }
58
+ }
59
+ async function consentAction(config, consentTypes) {
60
+ for (const consentConfig of config.consents) {
61
+ const shouldEnable = consentTypes.indexOf(consentConfig.type) !== -1;
62
+ if (consentConfig.matcher && consentConfig.toggleAction) {
63
+ const isEnabled = matches(consentConfig.matcher);
64
+ if (isEnabled !== shouldEnable) {
65
+ await executeAction(consentConfig.toggleAction);
66
+ }
67
+ }
68
+ else {
69
+ if (shouldEnable) {
70
+ await executeAction(consentConfig.trueAction);
71
+ }
72
+ else {
73
+ await executeAction(consentConfig.falseAction);
74
+ }
75
+ }
76
+ }
77
+ }
78
+ async function ifCssAction(config, param) {
79
+ const result = Tools.find(config);
80
+ if (!result.target) {
81
+ if (config.trueAction) {
82
+ await executeAction(config.trueAction, param);
83
+ }
84
+ }
85
+ else {
86
+ if (config.falseAction) {
87
+ await executeAction(config.falseAction, param);
88
+ }
89
+ }
90
+ }
91
+ async function waitCssAction(config) {
92
+ await new Promise(resolve => {
93
+ let numRetries = config.retries || 10;
94
+ const waitTime = config.waitTime || 250;
95
+ const checkCss = () => {
96
+ const result = Tools.find(config);
97
+ if ((config.negated && result.target) ||
98
+ (!config.negated && !result.target)) {
99
+ if (numRetries > 0) {
100
+ numRetries -= 1;
101
+ setTimeout(checkCss, waitTime);
102
+ }
103
+ else {
104
+ resolve();
105
+ }
106
+ }
107
+ else {
108
+ resolve();
109
+ }
110
+ };
111
+ checkCss();
112
+ });
113
+ }
114
+ async function forEachAction(config, param) {
115
+ const results = Tools.find(config, true);
116
+ const oldBase = Tools.base;
117
+ for (const result of results) {
118
+ if (result.target) {
119
+ Tools.setBase(result.target);
120
+ await executeAction(config.action, param);
121
+ }
122
+ }
123
+ Tools.setBase(oldBase);
124
+ }
125
+ async function hideAction(config) {
126
+ const result = Tools.find(config);
127
+ if (result.target) {
128
+ result.target.classList.add("Autoconsent-Hidden");
129
+ // result.target.setAttribute("style", "display: none;");
130
+ }
131
+ }
132
+ async function slideAction(config) {
133
+ const result = Tools.find(config);
134
+ const dragResult = Tools.find(config.dragTarget);
135
+ if (result.target) {
136
+ let targetBounds = result.target.getBoundingClientRect();
137
+ let dragTargetBounds = dragResult.target.getBoundingClientRect();
138
+ let yDiff = dragTargetBounds.top - targetBounds.top;
139
+ let xDiff = dragTargetBounds.left - targetBounds.left;
140
+ if (this.config.axis.toLowerCase() === "y") {
141
+ xDiff = 0;
142
+ }
143
+ if (this.config.axis.toLowerCase() === "x") {
144
+ yDiff = 0;
145
+ }
146
+ let screenX = window.screenX + targetBounds.left + targetBounds.width / 2.0;
147
+ let screenY = window.screenY + targetBounds.top + targetBounds.height / 2.0;
148
+ let clientX = targetBounds.left + targetBounds.width / 2.0;
149
+ let clientY = targetBounds.top + targetBounds.height / 2.0;
150
+ let mouseDown = document.createEvent("MouseEvents");
151
+ mouseDown.initMouseEvent("mousedown", true, true, window, 0, screenX, screenY, clientX, clientY, false, false, false, false, 0, result.target);
152
+ let mouseMove = document.createEvent("MouseEvents");
153
+ mouseMove.initMouseEvent("mousemove", true, true, window, 0, screenX + xDiff, screenY + yDiff, clientX + xDiff, clientY + yDiff, false, false, false, false, 0, result.target);
154
+ let mouseUp = document.createEvent("MouseEvents");
155
+ mouseUp.initMouseEvent("mouseup", true, true, window, 0, screenX + xDiff, screenY + yDiff, clientX + xDiff, clientY + yDiff, false, false, false, false, 0, result.target);
156
+ result.target.dispatchEvent(mouseDown);
157
+ await this.waitTimeout(10);
158
+ result.target.dispatchEvent(mouseMove);
159
+ await this.waitTimeout(10);
160
+ result.target.dispatchEvent(mouseUp);
161
+ }
162
+ }
163
+ async function waitAction(config) {
164
+ await waitTimeout(config.waitTime);
165
+ }
166
+ async function closeAction(config) {
167
+ window.close();
168
+ }
169
+ async function evalAction(config) {
170
+ console.log("eval!", config.code);
171
+ return new Promise(resolve => {
172
+ try {
173
+ if (config.async) {
174
+ window.eval(config.code);
175
+ setTimeout(() => {
176
+ resolve(window.eval("window.__consentCheckResult"));
177
+ }, config.timeout || 250);
178
+ }
179
+ else {
180
+ resolve(window.eval(config.code));
181
+ }
182
+ }
183
+ catch (e) {
184
+ console.warn("eval error", e, config.code);
185
+ resolve(false);
186
+ }
187
+ });
188
+ }
@@ -0,0 +1,177 @@
1
+ /**
2
+ * This code is in most parts copied from https://github.com/cavi-au/Consent-O-Matic/blob/master/Extension/Tools.js
3
+ * which is licened under the MIT.
4
+ */
5
+ export default class Tools {
6
+ static setBase(base) {
7
+ Tools.base = base;
8
+ }
9
+ static findElement(options, parent = null, multiple = false) {
10
+ let possibleTargets = null;
11
+ if (parent != null) {
12
+ possibleTargets = Array.from(parent.querySelectorAll(options.selector));
13
+ }
14
+ else {
15
+ if (Tools.base != null) {
16
+ possibleTargets = Array.from(Tools.base.querySelectorAll(options.selector));
17
+ }
18
+ else {
19
+ possibleTargets = Array.from(document.querySelectorAll(options.selector));
20
+ }
21
+ }
22
+ if (options.textFilter != null) {
23
+ possibleTargets = possibleTargets.filter(possibleTarget => {
24
+ let textContent = possibleTarget.textContent.toLowerCase();
25
+ if (Array.isArray(options.textFilter)) {
26
+ let foundText = false;
27
+ for (let text of options.textFilter) {
28
+ if (textContent.indexOf(text.toLowerCase()) !== -1) {
29
+ foundText = true;
30
+ break;
31
+ }
32
+ }
33
+ return foundText;
34
+ }
35
+ else if (options.textFilter != null) {
36
+ return textContent.indexOf(options.textFilter.toLowerCase()) !== -1;
37
+ }
38
+ });
39
+ }
40
+ if (options.styleFilters != null) {
41
+ possibleTargets = possibleTargets.filter(possibleTarget => {
42
+ let styles = window.getComputedStyle(possibleTarget);
43
+ let keep = true;
44
+ for (let styleFilter of options.styleFilters) {
45
+ let option = styles[styleFilter.option];
46
+ if (styleFilter.negated) {
47
+ keep = keep && option !== styleFilter.value;
48
+ }
49
+ else {
50
+ keep = keep && option === styleFilter.value;
51
+ }
52
+ }
53
+ return keep;
54
+ });
55
+ }
56
+ if (options.displayFilter != null) {
57
+ possibleTargets = possibleTargets.filter(possibleTarget => {
58
+ if (options.displayFilter) {
59
+ //We should be displayed
60
+ return possibleTarget.offsetHeight !== 0;
61
+ }
62
+ else {
63
+ //We should not be displayed
64
+ return possibleTarget.offsetHeight === 0;
65
+ }
66
+ });
67
+ }
68
+ if (options.iframeFilter != null) {
69
+ possibleTargets = possibleTargets.filter(possibleTarget => {
70
+ if (options.iframeFilter) {
71
+ //We should be inside an iframe
72
+ return window.location !== window.parent.location;
73
+ }
74
+ else {
75
+ //We should not be inside an iframe
76
+ return window.location === window.parent.location;
77
+ }
78
+ });
79
+ }
80
+ if (options.childFilter != null) {
81
+ possibleTargets = possibleTargets.filter(possibleTarget => {
82
+ let oldBase = Tools.base;
83
+ Tools.setBase(possibleTarget);
84
+ let childResults = Tools.find(options.childFilter);
85
+ Tools.setBase(oldBase);
86
+ return childResults.target != null;
87
+ });
88
+ }
89
+ if (multiple) {
90
+ return possibleTargets;
91
+ }
92
+ else {
93
+ if (possibleTargets.length > 1) {
94
+ console.warn("Multiple possible targets: ", possibleTargets, options, parent);
95
+ }
96
+ return possibleTargets[0];
97
+ }
98
+ }
99
+ static find(options, multiple = false) {
100
+ let results = [];
101
+ if (options.parent != null) {
102
+ let parent = Tools.findElement(options.parent, null, multiple);
103
+ if (parent != null) {
104
+ if (parent instanceof Array) {
105
+ parent.forEach(p => {
106
+ let targets = Tools.findElement(options.target, p, multiple);
107
+ if (targets instanceof Array) {
108
+ targets.forEach(target => {
109
+ results.push({
110
+ parent: p,
111
+ target: target
112
+ });
113
+ });
114
+ }
115
+ else {
116
+ results.push({
117
+ parent: p,
118
+ target: targets
119
+ });
120
+ }
121
+ });
122
+ return results;
123
+ }
124
+ else {
125
+ let targets = Tools.findElement(options.target, parent, multiple);
126
+ if (targets instanceof Array) {
127
+ targets.forEach(target => {
128
+ results.push({
129
+ parent: parent,
130
+ target: target
131
+ });
132
+ });
133
+ }
134
+ else {
135
+ results.push({
136
+ parent: parent,
137
+ target: targets
138
+ });
139
+ }
140
+ }
141
+ }
142
+ }
143
+ else {
144
+ let targets = Tools.findElement(options.target, null, multiple);
145
+ if (targets instanceof Array) {
146
+ targets.forEach(target => {
147
+ results.push({
148
+ parent: null,
149
+ target: target
150
+ });
151
+ });
152
+ }
153
+ else {
154
+ results.push({
155
+ parent: null,
156
+ target: targets
157
+ });
158
+ }
159
+ }
160
+ if (results.length === 0) {
161
+ results.push({
162
+ parent: null,
163
+ target: null
164
+ });
165
+ }
166
+ if (multiple) {
167
+ return results;
168
+ }
169
+ else {
170
+ if (results.length !== 1) {
171
+ console.warn("Multiple results found, even though multiple false", results);
172
+ }
173
+ return results[0];
174
+ }
175
+ }
176
+ }
177
+ Tools.base = null;
package/lib/web.ts CHANGED
@@ -24,6 +24,9 @@ export default class AutoConsent {
24
24
  if (config) {
25
25
  this.initialize(config, declarativeRules);
26
26
  } else {
27
+ if (declarativeRules) {
28
+ this.parseRules(declarativeRules);
29
+ }
27
30
  const initMsg: InitMessage = {
28
31
  type: "init",
29
32
  url: window.location.href,
@@ -39,7 +42,9 @@ export default class AutoConsent {
39
42
  return;
40
43
  }
41
44
 
42
- this.parseRules(declarativeRules);
45
+ if (declarativeRules) {
46
+ this.parseRules(declarativeRules);
47
+ }
43
48
  if (config.disabledCmps?.length > 0) {
44
49
  this.disableCMPs(config.disabledCmps);
45
50
  }
@@ -241,7 +246,7 @@ export default class AutoConsent {
241
246
  type: 'optInResult',
242
247
  cmp: this.foundCmp ? this.foundCmp.name : 'none',
243
248
  result: optInResult,
244
- scheduleSelfTest: this.foundCmp && this.foundCmp.hasSelfTest,
249
+ scheduleSelfTest: false, // self-tests are only for opt-out at the moment
245
250
  url: location.href,
246
251
  });
247
252
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@duckduckgo/autoconsent",
3
- "version": "2.0.0",
3
+ "version": "2.1.2",
4
4
  "description": "",
5
5
  "main": "dist/autoconsent.cjs.js",
6
6
  "module": "dist/autoconsent.esm.js",
@@ -8,7 +8,7 @@
8
8
  "lib": "lib"
9
9
  },
10
10
  "scripts": {
11
- "clean": "rm -r dist lib/**/*.js lib/*.js addon/*.js",
11
+ "clean": "rm -r dist",
12
12
  "bundle": "rollup -c",
13
13
  "watch": "rollup -c -w",
14
14
  "test": "playwright test",
@@ -17,8 +17,8 @@
17
17
  "test:chrome": "playwright test --project chrome",
18
18
  "fetch-fanboy-list": "wget https://www.fanboy.co.nz/fanboy-cookiemonster.txt",
19
19
  "fetch-site-list": "curl https://s3.amazonaws.com/cdn.cliqz.com/re-consent/supported_sites.txt > sites.txt",
20
- "build-rules": "node rules/build.js && cp rules/rules.json addon/",
21
- "version": "node update_version.js && git add addon/manifest.json",
20
+ "build-rules": "node rules/build.js",
21
+ "version": "node update_version.js && git add addon/manifest.*.json",
22
22
  "vendor-copy": "mkdir -p addon/vendor && cp node_modules/mocha/mocha.* addon/vendor/ && cp node_modules/chai/chai.js addon/vendor/",
23
23
  "prepublish": "npm run build-rules && npm run bundle"
24
24
  },
@@ -37,6 +37,7 @@
37
37
  "eslint-config-airbnb": "^19.0.4",
38
38
  "mocha": "^10.0.0",
39
39
  "rollup": "^2.73.0",
40
+ "rollup-plugin-copy": "^3.4.0",
40
41
  "rollup-plugin-terser": "^7.0.2",
41
42
  "tslib": "^2.4.0",
42
43
  "typescript": "^4.6.4"
@@ -11,13 +11,7 @@ declare global {
11
11
  }
12
12
 
13
13
  if (!window.autoconsentReceiveMessage) {
14
- const consent = new AutoConsent(window.autoconsentSendMessage, {
15
- enabled: true,
16
- autoAction: 'optOut',
17
- disabledCmps: [],
18
- enablePrehide: true,
19
- detectRetries: 20,
20
- }, <RuleBundle>rules);
14
+ const consent = new AutoConsent(window.autoconsentSendMessage, null, <RuleBundle>rules);
21
15
 
22
16
  window.autoconsentReceiveMessage = (message: BackgroundMessage) => {
23
17
  return Promise.resolve(consent.receiveMessageCallback(message));
@@ -4,17 +4,20 @@ import { test, expect, Page, Frame } from "@playwright/test";
4
4
  import { waitFor } from "../lib/utils";
5
5
  import { ContentScriptMessage } from "../lib/messages";
6
6
  import { enableLogs } from "../lib/config";
7
+ import { AutoAction } from "../lib/types";
7
8
 
8
9
  const testRegion = (process.env.REGION || "NA").trim();
9
10
 
10
11
  type TestOptions = {
11
12
  testOptOut: boolean;
12
13
  testSelfTest: boolean;
14
+ testOptIn: boolean;
13
15
  skipRegions?: string[];
14
16
  onlyRegions?: string[];
15
17
  };
16
18
  const defaultOptions: TestOptions = {
17
19
  testOptOut: true,
20
+ testOptIn: true,
18
21
  testSelfTest: true,
19
22
  skipRegions: [],
20
23
  onlyRegions: [],
@@ -37,85 +40,113 @@ export async function injectContentScript(page: Page | Frame) {
37
40
  export function generateTest(
38
41
  url: string,
39
42
  expectedCmp: string,
40
- options: TestOptions = { testOptOut: true, testSelfTest: true }
43
+ options: TestOptions = defaultOptions
41
44
  ) {
42
- test(`${url.split("://")[1]} .${testRegion}`, async ({ page }) => {
43
- if (options.onlyRegions && options.onlyRegions.length > 0 && !options.onlyRegions.includes(testRegion)) {
44
- test.skip();
45
- }
46
- if (options.skipRegions && options.skipRegions.includes(testRegion)) {
47
- test.skip();
48
- }
49
- enableLogs && page.on('console', async msg => {
50
- console.log(` page log:`, msg.text());
51
- });
52
- await page.exposeBinding("autoconsentSendMessage", messageCallback);
53
- await page.goto(url, { waitUntil: "commit" });
54
-
55
- // set up a messaging function
56
- const received: ContentScriptMessage[] = [];
57
-
58
- function isMessageReceived(msg: Partial<ContentScriptMessage>, partial = true) {
59
- return received.some((m) => {
60
- const keysMatch = partial || Object.keys(m).length === Object.keys(msg).length;
61
- return keysMatch && Object.keys(msg).every(
62
- (k) => (<any>m)[k] === (<any>msg)[k]
63
- );
45
+ function genTest(autoAction: AutoAction) {
46
+ test(`${url.split("://")[1]} .${testRegion} ${autoAction}`, async ({ page }) => {
47
+ if (options.onlyRegions && options.onlyRegions.length > 0 && !options.onlyRegions.includes(testRegion)) {
48
+ test.skip();
49
+ }
50
+ if (options.skipRegions && options.skipRegions.includes(testRegion)) {
51
+ test.skip();
52
+ }
53
+ enableLogs && page.on('console', async msg => {
54
+ console.log(` page log:`, msg.text());
64
55
  });
65
- }
66
-
67
- let selfTestFrame: Frame = null;
68
- async function messageCallback({ frame }: { frame: Frame }, msg: ContentScriptMessage) {
69
- enableLogs && msg.type !== 'eval' && console.log(msg);
70
- received.push(msg);
71
- switch (msg.type) {
72
- case 'optInResult':
73
- case 'optOutResult': {
74
- if (msg.scheduleSelfTest) {
75
- selfTestFrame = frame;
56
+ await page.exposeBinding("autoconsentSendMessage", messageCallback);
57
+ await page.goto(url, { waitUntil: "commit" });
58
+
59
+ // set up a messaging function
60
+ const received: ContentScriptMessage[] = [];
61
+
62
+ function isMessageReceived(msg: Partial<ContentScriptMessage>, partial = true) {
63
+ return received.some((m) => {
64
+ const keysMatch = partial || Object.keys(m).length === Object.keys(msg).length;
65
+ return keysMatch && Object.keys(msg).every(
66
+ (k) => (<any>m)[k] === (<any>msg)[k]
67
+ );
68
+ });
69
+ }
70
+
71
+ let selfTestFrame: Frame = null;
72
+ async function messageCallback({ frame }: { frame: Frame }, msg: ContentScriptMessage) {
73
+ enableLogs && msg.type !== 'eval' && console.log(msg);
74
+ received.push(msg);
75
+ switch (msg.type) {
76
+ case 'init': {
77
+ await frame.evaluate(`autoconsentReceiveMessage({ type: "initResp", config: ${JSON.stringify({
78
+ enabled: true,
79
+ autoAction: autoAction,
80
+ disabledCmps: [],
81
+ enablePrehide: true,
82
+ detectRetries: 20,
83
+ })} })`);
84
+ break;
76
85
  }
77
- break;
78
- }
79
- case 'autoconsentDone': {
80
- if (selfTestFrame && options.testSelfTest) {
81
- await selfTestFrame.evaluate(`autoconsentReceiveMessage({ type: "selfTest" })`);
86
+ case 'optInResult':
87
+ case 'optOutResult': {
88
+ if (msg.scheduleSelfTest) {
89
+ selfTestFrame = frame;
90
+ }
91
+ break;
92
+ }
93
+ case 'autoconsentDone': {
94
+ if (selfTestFrame && options.testSelfTest) {
95
+ await selfTestFrame.evaluate(`autoconsentReceiveMessage({ type: "selfTest" })`);
96
+ }
97
+ break;
98
+ }
99
+ case 'eval': {
100
+ const result = await frame.evaluate(msg.code);
101
+ await frame.evaluate(`autoconsentReceiveMessage({ id: "${msg.id}", type: "evalResp", result: ${JSON.stringify(result)} })`);
102
+ break;
103
+ }
104
+ case 'autoconsentError': {
105
+ console.error(url, msg.details);
106
+ break;
82
107
  }
83
- break;
84
- }
85
- case 'eval': {
86
- const result = await frame.evaluate(msg.code);
87
- await frame.evaluate(`autoconsentReceiveMessage({ id: "${msg.id}", type: "evalResp", result: ${JSON.stringify(result)} })`);
88
- break;
89
- }
90
- case 'autoconsentError': {
91
- console.error(url, msg.details);
92
- break;
93
108
  }
94
109
  }
95
- }
96
-
97
- // inject content scripts into every frame
98
- await injectContentScript(page);
99
- page.frames().forEach(injectContentScript);
100
- page.on("framenavigated", injectContentScript);
101
-
102
- // wait for all messages and assertions
103
- await waitFor(() => isMessageReceived({ type: "popupFound", cmp: expectedCmp }), 50, 500);
104
- expect(isMessageReceived({ type: "popupFound", cmp: expectedCmp })).toBe(true);
105
-
106
- if (options.testOptOut) {
107
- await waitFor(() => isMessageReceived({ type: "optOutResult", result: true }), 50, 300);
108
- expect(isMessageReceived({ type: "optOutResult", result: true })).toBe(true);
109
- }
110
- if (options.testSelfTest && selfTestFrame) {
111
- await waitFor(() => isMessageReceived({ type: "selfTestResult", result: true }), 50, 300);
112
- expect(isMessageReceived({ type: "selfTestResult", result: true })).toBe(true);
113
- }
114
- await waitFor(() => isMessageReceived({ type: "autoconsentDone" }), 10, 500);
115
- expect(isMessageReceived({ type: "autoconsentDone" })).toBe(true);
116
-
117
- expect(isMessageReceived({ type: "autoconsentError" })).toBe(false);
118
- });
110
+
111
+ // inject content scripts into every frame
112
+ await injectContentScript(page);
113
+ page.frames().forEach(injectContentScript);
114
+ page.on("framenavigated", injectContentScript);
115
+
116
+ // wait for all messages and assertions
117
+ await waitFor(() => isMessageReceived({ type: "popupFound", cmp: expectedCmp }), 50, 500);
118
+ expect(isMessageReceived({ type: "popupFound", cmp: expectedCmp })).toBe(true);
119
+
120
+ if (autoAction === 'optOut') {
121
+ await waitFor(() => isMessageReceived({ type: "optOutResult", result: true }), 50, 300);
122
+ expect(isMessageReceived({ type: "optOutResult", result: true })).toBe(true);
123
+ }
124
+ if (autoAction === 'optIn') {
125
+ await waitFor(() => isMessageReceived({ type: "optInResult", result: true }), 50, 300);
126
+ expect(isMessageReceived({ type: "optInResult", result: true })).toBe(true);
127
+ }
128
+ if (options.testSelfTest && selfTestFrame) {
129
+ await waitFor(() => isMessageReceived({ type: "selfTestResult", result: true }), 50, 300);
130
+ expect(isMessageReceived({ type: "selfTestResult", result: true })).toBe(true);
131
+ }
132
+ await waitFor(() => isMessageReceived({ type: "autoconsentDone" }), 10, 500);
133
+ expect(isMessageReceived({ type: "autoconsentDone" })).toBe(true);
134
+
135
+ expect(isMessageReceived({ type: "autoconsentError" })).toBe(false);
136
+ })
137
+ }
138
+
139
+ if (!options.testOptIn && !options.testOptOut) {
140
+ genTest(null);
141
+ }
142
+
143
+ if (options.testOptIn) {
144
+ genTest('optIn');
145
+ }
146
+
147
+ if (options.testOptOut) {
148
+ genTest('optOut');
149
+ }
119
150
  }
120
151
 
121
152
  export default function generateCMPTests(
package/readme.md CHANGED
@@ -18,7 +18,11 @@ npm run build-rules
18
18
  npm run bundle
19
19
  ```
20
20
 
21
- The extension-specific code can be found in the `addon` directory and can be [loaded directly from there](https://developer.chrome.com/docs/extensions/mv3/getstarted/#unpacked) in developer mode.
21
+ The extension-specific code can be found in the `addon` directory. There are two versions of the
22
+ addon (found under `dist/addon` after building), one for `mv3` version for Chromium-based browsers, and a `firefox` version for Firefox.
23
+ You can load these in [Chrome](https://developer.chrome.com/docs/extensions/mv3/getstarted/#unpacked)
24
+ in developer mode, and in [Firefox](https://extensionworkshop.com/documentation/develop/temporary-installation-in-firefox/)
25
+ as a tempoary addon.
22
26
 
23
27
  ## Rules
24
28