@duckduckgo/autoconsent 14.82.0 → 14.84.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.md +3 -1
- package/CHANGELOG.md +27 -0
- package/dist/addon-firefox/background.bundle.js +7 -0
- package/dist/addon-firefox/compact-rules.json +1 -1
- package/dist/addon-firefox/content.bundle.js +16 -2
- package/dist/addon-firefox/manifest.json +1 -1
- package/dist/addon-firefox/popup.bundle.js +20 -0
- package/dist/addon-firefox/popup.html +14 -0
- package/dist/addon-firefox/rules.json +1 -1
- package/dist/addon-mv3/background.bundle.js +7 -0
- package/dist/addon-mv3/compact-rules.json +1 -1
- package/dist/addon-mv3/content.bundle.js +16 -2
- package/dist/addon-mv3/manifest.json +1 -1
- package/dist/addon-mv3/popup.bundle.js +20 -0
- package/dist/addon-mv3/popup.html +14 -0
- package/dist/addon-mv3/rules.json +1 -1
- package/dist/autoconsent.cjs.js +16 -2
- package/dist/autoconsent.esm.js +16 -2
- package/dist/autoconsent.extra.cjs.js +16 -2
- package/dist/autoconsent.extra.esm.js +16 -2
- package/dist/autoconsent.playwright.js +16 -2
- package/dist/types/types.d.ts +1 -0
- package/lib/types.ts +1 -0
- package/lib/utils.ts +1 -0
- package/lib/web.ts +17 -3
- package/package.json +1 -1
- package/rules/autoconsent/escaparium.ca.json +35 -0
- package/rules/compact-rules.json +1 -1
- package/rules/rules.json +1 -1
- package/tests/escaparium.ca.spec.ts +3 -0
- package/tests-wtr/lifecycle/wait-for-popup.html +14 -0
- package/tests-wtr/lifecycle/wait-for-popup.ts +214 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<html>
|
|
2
|
+
<body>
|
|
3
|
+
<script type="module">
|
|
4
|
+
import { runTests } from '@web/test-runner-mocha';
|
|
5
|
+
|
|
6
|
+
runTests(async () => {
|
|
7
|
+
await import('./wait-for-popup');
|
|
8
|
+
});
|
|
9
|
+
</script>
|
|
10
|
+
<div id="page-content">
|
|
11
|
+
<p>Test page for waitForPopup tests</p>
|
|
12
|
+
</div>
|
|
13
|
+
</body>
|
|
14
|
+
</html>
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { expect } from '@esm-bundle/chai';
|
|
2
|
+
import Autoconsent from '../../lib/web';
|
|
3
|
+
import { AutoCMP } from '../../lib/types';
|
|
4
|
+
|
|
5
|
+
function createAutoconsent(enablePopupMutationObserver: boolean): Autoconsent {
|
|
6
|
+
return new Autoconsent(() => Promise.resolve(), {
|
|
7
|
+
enabled: false,
|
|
8
|
+
autoAction: null,
|
|
9
|
+
enablePopupMutationObserver,
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function createMockCmp(detectPopupFn: () => Promise<boolean>): AutoCMP {
|
|
14
|
+
return {
|
|
15
|
+
name: 'mock-cmp',
|
|
16
|
+
hasSelfTest: false,
|
|
17
|
+
isIntermediate: false,
|
|
18
|
+
isCosmetic: false,
|
|
19
|
+
runContext: { main: true, frame: false },
|
|
20
|
+
checkRunContext: () => true,
|
|
21
|
+
checkFrameContext: () => true,
|
|
22
|
+
hasMatchingUrlPattern: () => true,
|
|
23
|
+
detectCmp: () => Promise.resolve(true),
|
|
24
|
+
detectPopup: detectPopupFn,
|
|
25
|
+
optOut: () => Promise.resolve(true),
|
|
26
|
+
optIn: () => Promise.resolve(true),
|
|
27
|
+
openCmp: () => Promise.resolve(true),
|
|
28
|
+
test: () => Promise.resolve(true),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
describe('Autoconsent.waitForPopup', () => {
|
|
33
|
+
describe('without mutation observer (legacy polling)', () => {
|
|
34
|
+
let autoconsent: Autoconsent;
|
|
35
|
+
|
|
36
|
+
beforeEach(() => {
|
|
37
|
+
autoconsent = createAutoconsent(false);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('should resolve true if popup is detected on first check', async () => {
|
|
41
|
+
const cmp = createMockCmp(() => Promise.resolve(true));
|
|
42
|
+
const result = await autoconsent.waitForPopup(cmp, 5, 50);
|
|
43
|
+
expect(result).to.be.true;
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('should resolve false if popup is never detected', async () => {
|
|
47
|
+
const cmp = createMockCmp(() => Promise.resolve(false));
|
|
48
|
+
const result = await autoconsent.waitForPopup(cmp, 2, 50);
|
|
49
|
+
expect(result).to.be.false;
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('should retry and detect popup that appears later', async () => {
|
|
53
|
+
let callCount = 0;
|
|
54
|
+
const cmp = createMockCmp(() => {
|
|
55
|
+
callCount++;
|
|
56
|
+
return Promise.resolve(callCount >= 3);
|
|
57
|
+
});
|
|
58
|
+
const result = await autoconsent.waitForPopup(cmp, 5, 50);
|
|
59
|
+
expect(result).to.be.true;
|
|
60
|
+
expect(callCount).to.equal(3);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('should handle errors in detectPopup gracefully', async () => {
|
|
64
|
+
const cmp = createMockCmp(() => Promise.reject(new Error('detection error')));
|
|
65
|
+
const result = await autoconsent.waitForPopup(cmp, 2, 50);
|
|
66
|
+
expect(result).to.be.false;
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('should not retry when retries is 0', async () => {
|
|
70
|
+
let callCount = 0;
|
|
71
|
+
const cmp = createMockCmp(() => {
|
|
72
|
+
callCount++;
|
|
73
|
+
return Promise.resolve(false);
|
|
74
|
+
});
|
|
75
|
+
const result = await autoconsent.waitForPopup(cmp, 0, 50);
|
|
76
|
+
expect(result).to.be.false;
|
|
77
|
+
expect(callCount).to.equal(1);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
describe('with mutation observer', () => {
|
|
82
|
+
let autoconsent: Autoconsent;
|
|
83
|
+
|
|
84
|
+
beforeEach(() => {
|
|
85
|
+
autoconsent = createAutoconsent(true);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('should resolve true if popup is detected on first check', async () => {
|
|
89
|
+
const cmp = createMockCmp(() => Promise.resolve(true));
|
|
90
|
+
const result = await autoconsent.waitForPopup(cmp, 5, 50);
|
|
91
|
+
expect(result).to.be.true;
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('should resolve false when retries are exhausted despite mutations', async () => {
|
|
95
|
+
const cmp = createMockCmp(() => Promise.resolve(false));
|
|
96
|
+
|
|
97
|
+
const mutationInterval = setInterval(() => {
|
|
98
|
+
const el = document.createElement('div');
|
|
99
|
+
el.className = 'test-exhaust-mutation';
|
|
100
|
+
document.body.appendChild(el);
|
|
101
|
+
}, 30);
|
|
102
|
+
|
|
103
|
+
const result = await autoconsent.waitForPopup(cmp, 2, 50);
|
|
104
|
+
|
|
105
|
+
clearInterval(mutationInterval);
|
|
106
|
+
document.querySelectorAll('.test-exhaust-mutation').forEach((el) => el.remove());
|
|
107
|
+
|
|
108
|
+
expect(result).to.be.false;
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('should retry when a DOM mutation occurs and detect popup', async () => {
|
|
112
|
+
let callCount = 0;
|
|
113
|
+
const cmp = createMockCmp(() => {
|
|
114
|
+
callCount++;
|
|
115
|
+
return Promise.resolve(callCount >= 2);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// schedule a DOM mutation so the observer resolves
|
|
119
|
+
setTimeout(() => {
|
|
120
|
+
const el = document.createElement('span');
|
|
121
|
+
el.id = 'test-mutation-element';
|
|
122
|
+
document.body.appendChild(el);
|
|
123
|
+
}, 30);
|
|
124
|
+
|
|
125
|
+
const result = await autoconsent.waitForPopup(cmp, 5, 50);
|
|
126
|
+
expect(result).to.be.true;
|
|
127
|
+
expect(callCount).to.equal(2);
|
|
128
|
+
|
|
129
|
+
document.getElementById('test-mutation-element')?.remove();
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it('should detect popup that appears after multiple mutations', async () => {
|
|
133
|
+
let callCount = 0;
|
|
134
|
+
const cmp = createMockCmp(() => {
|
|
135
|
+
callCount++;
|
|
136
|
+
return Promise.resolve(callCount >= 3);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
// schedule DOM mutations to keep the observer firing
|
|
140
|
+
const mutationInterval = setInterval(() => {
|
|
141
|
+
const el = document.createElement('div');
|
|
142
|
+
el.className = 'test-multi-mutation';
|
|
143
|
+
document.body.appendChild(el);
|
|
144
|
+
}, 40);
|
|
145
|
+
|
|
146
|
+
const result = await autoconsent.waitForPopup(cmp, 5, 50);
|
|
147
|
+
|
|
148
|
+
clearInterval(mutationInterval);
|
|
149
|
+
document.querySelectorAll('.test-multi-mutation').forEach((el) => el.remove());
|
|
150
|
+
|
|
151
|
+
expect(result).to.be.true;
|
|
152
|
+
expect(callCount).to.equal(3);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('should handle errors in detectPopup gracefully', async () => {
|
|
156
|
+
let callCount = 0;
|
|
157
|
+
const cmp = createMockCmp(() => {
|
|
158
|
+
callCount++;
|
|
159
|
+
if (callCount <= 2) {
|
|
160
|
+
return Promise.reject(new Error('transient error'));
|
|
161
|
+
}
|
|
162
|
+
return Promise.resolve(true);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
// schedule mutations so retries proceed
|
|
166
|
+
const mutationInterval = setInterval(() => {
|
|
167
|
+
const el = document.createElement('div');
|
|
168
|
+
el.className = 'test-error-mutation';
|
|
169
|
+
document.body.appendChild(el);
|
|
170
|
+
}, 30);
|
|
171
|
+
|
|
172
|
+
const result = await autoconsent.waitForPopup(cmp, 5, 50);
|
|
173
|
+
|
|
174
|
+
clearInterval(mutationInterval);
|
|
175
|
+
document.querySelectorAll('.test-error-mutation').forEach((el) => el.remove());
|
|
176
|
+
|
|
177
|
+
expect(result).to.be.true;
|
|
178
|
+
expect(callCount).to.equal(3);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it('should not retry when retries is 0', async () => {
|
|
182
|
+
let callCount = 0;
|
|
183
|
+
const cmp = createMockCmp(() => {
|
|
184
|
+
callCount++;
|
|
185
|
+
return Promise.resolve(false);
|
|
186
|
+
});
|
|
187
|
+
const result = await autoconsent.waitForPopup(cmp, 0, 50);
|
|
188
|
+
expect(result).to.be.false;
|
|
189
|
+
expect(callCount).to.equal(1);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it('should continue retrying after mutation observer timeout', async () => {
|
|
193
|
+
// Override waitForMutation to use a very short timeout so it rejects quickly
|
|
194
|
+
const originalWaitForMutation = autoconsent.domActions.waitForMutation.bind(autoconsent.domActions);
|
|
195
|
+
autoconsent.domActions.waitForMutation = (selector, _timeout?) => {
|
|
196
|
+
return originalWaitForMutation(selector, 10);
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
let callCount = 0;
|
|
200
|
+
const cmp = createMockCmp(() => {
|
|
201
|
+
callCount++;
|
|
202
|
+
// popup appears on the 3rd attempt (after 2 mutation timeouts)
|
|
203
|
+
return Promise.resolve(callCount >= 3);
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
const result = await autoconsent.waitForPopup(cmp, 5, 50);
|
|
207
|
+
|
|
208
|
+
autoconsent.domActions.waitForMutation = originalWaitForMutation;
|
|
209
|
+
|
|
210
|
+
expect(result).to.be.true;
|
|
211
|
+
expect(callCount).to.equal(3);
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
});
|