@gemx-dev/clarity-js 0.8.59 → 0.8.61
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/build/clarity.extended.js +1 -1
- package/build/clarity.insight.js +1 -1
- package/build/clarity.js +77 -47
- package/build/clarity.min.js +1 -1
- package/build/clarity.module.js +77 -47
- package/build/clarity.performance.js +1 -1
- package/package.json +1 -1
- package/src/core/config.ts +1 -0
- package/src/core/dynamic.ts +7 -2
- package/src/core/version.ts +1 -1
- package/src/data/metadata.ts +3 -3
- package/src/interaction/encode.ts +1 -0
- package/src/interaction/index.ts +3 -0
- package/src/interaction/pageshow.ts +35 -0
- package/src/interaction/scroll.ts +3 -2
- package/test/consentv2.test.ts +1164 -0
- package/types/core.d.ts +1 -0
- package/types/data.d.ts +15 -1
- package/types/interaction.d.ts +1 -0
|
@@ -0,0 +1,1164 @@
|
|
|
1
|
+
import { expect, test } from "@playwright/test";
|
|
2
|
+
import { readFileSync } from "fs";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Consent API tests - Tests the production consent functionality by loading
|
|
7
|
+
* the built clarity.min.js in a browser context. This approach tests the actual
|
|
8
|
+
* artifact that ships to users rather than individual source modules.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// Type definitions for test results
|
|
12
|
+
interface ConsentState {
|
|
13
|
+
source: number;
|
|
14
|
+
ad_Storage: string;
|
|
15
|
+
analytics_Storage: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Standard result type for all consent tests.
|
|
20
|
+
* Every test should capture and verify this complete state for consistent analysis.
|
|
21
|
+
*/
|
|
22
|
+
interface ConsentTestResult {
|
|
23
|
+
consent: ConsentState;
|
|
24
|
+
hasClskCookie: boolean;
|
|
25
|
+
hasClckCookie: boolean;
|
|
26
|
+
clskCookieValue: string;
|
|
27
|
+
clckCookieValue: string;
|
|
28
|
+
cookies: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const Constant = {
|
|
32
|
+
Granted: "granted",
|
|
33
|
+
Denied: "denied",
|
|
34
|
+
CookieKey: "_clck",
|
|
35
|
+
SessionKey: "_clsk",
|
|
36
|
+
} as const;
|
|
37
|
+
|
|
38
|
+
const ConsentSource = {
|
|
39
|
+
Implicit: 0,
|
|
40
|
+
API: 1,
|
|
41
|
+
GCM: 2,
|
|
42
|
+
TCF: 3,
|
|
43
|
+
APIv1: 4,
|
|
44
|
+
APIv2: 5,
|
|
45
|
+
Cookie: 6,
|
|
46
|
+
Default: 7,
|
|
47
|
+
} as const;
|
|
48
|
+
|
|
49
|
+
// Maximum time to wait from when consent() is called to when its callback resolves
|
|
50
|
+
const CONSENT_CALLBACK_TIMEOUT = 2000;
|
|
51
|
+
// Delay from when cookie mock is set up to when Clarity can reliably read it
|
|
52
|
+
const COOKIE_SETUP_DELAY = 500;
|
|
53
|
+
|
|
54
|
+
// Use the minified browser build which properly exposes window.clarity
|
|
55
|
+
const clarityJsPath = join(__dirname, "../build/clarity.min.js");
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Sets up a cookie mock for data: URLs which don't support cookies natively.
|
|
59
|
+
* Handles both cookie setting and deletion (via max-age or empty values).
|
|
60
|
+
*/
|
|
61
|
+
function setupCookieMock() {
|
|
62
|
+
let cookieStore = "";
|
|
63
|
+
Object.defineProperty(document, "cookie", {
|
|
64
|
+
get: () => cookieStore,
|
|
65
|
+
set: (value: string) => {
|
|
66
|
+
if (value.includes("max-age=-") || value.includes("=;") || value.includes("=^;")) {
|
|
67
|
+
const cookieName = value.split("=")[0];
|
|
68
|
+
const cookies = cookieStore.split("; ").filter(c => !c.startsWith(cookieName + "="));
|
|
69
|
+
cookieStore = cookies.join("; ");
|
|
70
|
+
} else {
|
|
71
|
+
const cookieName = value.split("=")[0];
|
|
72
|
+
const cookies = cookieStore.split("; ").filter(c => !c.startsWith(cookieName + "="));
|
|
73
|
+
cookies.push(value.split(";")[0]);
|
|
74
|
+
cookieStore = cookies.filter(c => c).join("; ");
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
configurable: true
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
test.describe("consentv2 - Production API", () => {
|
|
84
|
+
test.beforeEach(async ({ page }) => {
|
|
85
|
+
await page.goto("data:text/html,<!DOCTYPE html><html><head></head><body></body></html>");
|
|
86
|
+
|
|
87
|
+
// Expose timeout constants to the page context
|
|
88
|
+
await page.evaluate(({ timeout, delay }) => {
|
|
89
|
+
(window as any).CONSENT_CALLBACK_TIMEOUT = timeout;
|
|
90
|
+
(window as any).COOKIE_SETUP_DELAY = delay;
|
|
91
|
+
}, { timeout: CONSENT_CALLBACK_TIMEOUT, delay: COOKIE_SETUP_DELAY });
|
|
92
|
+
|
|
93
|
+
const clarityJs = readFileSync(clarityJsPath, "utf-8");
|
|
94
|
+
await page.evaluate((code) => {
|
|
95
|
+
eval(code);
|
|
96
|
+
}, clarityJs);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// ========================
|
|
100
|
+
// track=false tests
|
|
101
|
+
// ========================
|
|
102
|
+
|
|
103
|
+
test("implicit denied: track=false results in denied consent", async ({ page }) => {
|
|
104
|
+
await page.evaluate(setupCookieMock);
|
|
105
|
+
|
|
106
|
+
// Verify initial state (before Clarity starts) - no cookies should exist
|
|
107
|
+
const initialState = await page.evaluate(({ sessionKey, cookieKey }) => {
|
|
108
|
+
const cookies = document.cookie;
|
|
109
|
+
return {
|
|
110
|
+
cookies,
|
|
111
|
+
hasClskCookie: cookies.includes(`${sessionKey}=`),
|
|
112
|
+
hasClckCookie: cookies.includes(`${cookieKey}=`),
|
|
113
|
+
clskCookieValue: "",
|
|
114
|
+
clckCookieValue: ""
|
|
115
|
+
};
|
|
116
|
+
}, { sessionKey: Constant.SessionKey, cookieKey: Constant.CookieKey });
|
|
117
|
+
|
|
118
|
+
expect(initialState.cookies).toBe("");
|
|
119
|
+
expect(initialState.hasClskCookie).toBe(false);
|
|
120
|
+
expect(initialState.hasClckCookie).toBe(false);
|
|
121
|
+
|
|
122
|
+
// Start clarity with track=false (cookies disabled, no network calls)
|
|
123
|
+
const result = await page.evaluate(({ sessionKey, cookieKey }) => {
|
|
124
|
+
return new Promise((resolve) => {
|
|
125
|
+
(window as any).clarity("start", {
|
|
126
|
+
projectId: "test",
|
|
127
|
+
track: false,
|
|
128
|
+
upload: false
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// Register metadata callback AFTER starting clarity
|
|
132
|
+
// Signature: clarity('metadata', callback, wait, recall, consentInfo)
|
|
133
|
+
// The callback receives (data, upgrade, consent)
|
|
134
|
+
// wait=false (don't wait for data), recall=true (resend on changes), consentInfo=true (include consent)
|
|
135
|
+
(window as any).clarity("metadata", (_data: any, _upgrade: any, consent: any) => {
|
|
136
|
+
if (consent) {
|
|
137
|
+
const cookies = document.cookie;
|
|
138
|
+
const clskMatch = cookies.match(new RegExp(`${sessionKey}=([^;]+)`));
|
|
139
|
+
const clckMatch = cookies.match(new RegExp(`${cookieKey}=([^;]+)`));
|
|
140
|
+
resolve({
|
|
141
|
+
consent,
|
|
142
|
+
hasClskCookie: cookies.includes(`${sessionKey}=`),
|
|
143
|
+
hasClckCookie: cookies.includes(`${cookieKey}=`),
|
|
144
|
+
clskCookieValue: clskMatch ? clskMatch[1] : "",
|
|
145
|
+
clckCookieValue: clckMatch ? clckMatch[1] : "",
|
|
146
|
+
clckConsentCrumb: clckMatch ? (clckMatch[1].split("^")[3] || "") : "",
|
|
147
|
+
cookies
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
}, false, true, true);
|
|
151
|
+
|
|
152
|
+
// Timeout fallback
|
|
153
|
+
setTimeout(() => {
|
|
154
|
+
const cookies = document.cookie;
|
|
155
|
+
resolve({
|
|
156
|
+
consent: null,
|
|
157
|
+
hasClskCookie: cookies.includes(`${sessionKey}=`),
|
|
158
|
+
hasClckCookie: cookies.includes(`${cookieKey}=`),
|
|
159
|
+
clskCookieValue: "",
|
|
160
|
+
clckCookieValue: "",
|
|
161
|
+
cookies
|
|
162
|
+
});
|
|
163
|
+
}, (window as any).CONSENT_CALLBACK_TIMEOUT);
|
|
164
|
+
});
|
|
165
|
+
}, { sessionKey: Constant.SessionKey, cookieKey: Constant.CookieKey });
|
|
166
|
+
|
|
167
|
+
expect(result).not.toBeNull();
|
|
168
|
+
const consentResult = result as ConsentTestResult;
|
|
169
|
+
expect(consentResult.consent).not.toBeNull();
|
|
170
|
+
expect(consentResult.consent.source).toBe(ConsentSource.Implicit);
|
|
171
|
+
expect(consentResult.consent.ad_Storage).toBe(Constant.Denied);
|
|
172
|
+
expect(consentResult.consent.analytics_Storage).toBe(Constant.Denied);
|
|
173
|
+
// Verify cookies are not set when track=false
|
|
174
|
+
expect(consentResult.hasClskCookie).toBe(false);
|
|
175
|
+
expect(consentResult.hasClckCookie).toBe(false);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
test("cookie consent: track=false with consent cookie results in granted", async ({ page }) => {
|
|
179
|
+
// This test uses a pre-set cookie (simulating a returning user with consent)
|
|
180
|
+
// so we manually mock the cookie rather than using setupCookieMock
|
|
181
|
+
const result = await page.evaluate(({ sessionKey, cookieKey }) => {
|
|
182
|
+
// Mock document.cookie to simulate a consent cookie
|
|
183
|
+
// Format: _clck cookie with consent flag set to 1 (granted)
|
|
184
|
+
// Cookie format: userId^version^expiry^consent^dob
|
|
185
|
+
const userId = "testuser123";
|
|
186
|
+
const version = "2";
|
|
187
|
+
const expiry = Math.ceil((Date.now() + 31536e6) / 864e5).toString(36);
|
|
188
|
+
const consentFlag = "1"; // 1 = granted
|
|
189
|
+
const dob = "0";
|
|
190
|
+
const presetCookieValue = `${userId}^${version}^${expiry}^${consentFlag}^${dob}`;
|
|
191
|
+
|
|
192
|
+
Object.defineProperty(document, "cookie", {
|
|
193
|
+
writable: true,
|
|
194
|
+
value: `${cookieKey}=${presetCookieValue}`
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
// Capture initial state with the pre-set cookie
|
|
198
|
+
const initialCookies = document.cookie;
|
|
199
|
+
const initialState = {
|
|
200
|
+
cookies: initialCookies,
|
|
201
|
+
hasClskCookie: initialCookies.includes(`${sessionKey}=`),
|
|
202
|
+
hasClckCookie: initialCookies.includes(`${cookieKey}=`),
|
|
203
|
+
clckCookieValue: presetCookieValue
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
return new Promise((resolve) => {
|
|
207
|
+
// Start clarity with track=false but with consent cookie present
|
|
208
|
+
(window as any).clarity("start", {
|
|
209
|
+
projectId: "test",
|
|
210
|
+
track: false,
|
|
211
|
+
upload: false
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
// Register metadata callback
|
|
215
|
+
(window as any).clarity("metadata", (_data: any, _upgrade: any, consent: any) => {
|
|
216
|
+
if (consent) {
|
|
217
|
+
const cookies = document.cookie;
|
|
218
|
+
const clskMatch = cookies.match(new RegExp(`${sessionKey}=([^;]+)`));
|
|
219
|
+
const clckMatch = cookies.match(new RegExp(`${cookieKey}=([^;]+)`));
|
|
220
|
+
resolve({
|
|
221
|
+
initialState,
|
|
222
|
+
consent,
|
|
223
|
+
hasClskCookie: cookies.includes(`${sessionKey}=`),
|
|
224
|
+
hasClckCookie: cookies.includes(`${cookieKey}=`),
|
|
225
|
+
clskCookieValue: clskMatch ? clskMatch[1] : "",
|
|
226
|
+
clckCookieValue: clckMatch ? clckMatch[1] : "",
|
|
227
|
+
clckConsentCrumb: clckMatch ? (clckMatch[1].split("^")[3] || "") : "",
|
|
228
|
+
cookies
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
}, false, true, true);
|
|
232
|
+
|
|
233
|
+
// Timeout fallback
|
|
234
|
+
setTimeout(() => {
|
|
235
|
+
const cookies = document.cookie;
|
|
236
|
+
resolve({
|
|
237
|
+
initialState,
|
|
238
|
+
consent: null,
|
|
239
|
+
hasClskCookie: cookies.includes(`${sessionKey}=`),
|
|
240
|
+
hasClckCookie: cookies.includes(`${cookieKey}=`),
|
|
241
|
+
clskCookieValue: "",
|
|
242
|
+
clckCookieValue: "",
|
|
243
|
+
cookies
|
|
244
|
+
});
|
|
245
|
+
}, (window as any).CONSENT_CALLBACK_TIMEOUT);
|
|
246
|
+
});
|
|
247
|
+
}, { sessionKey: Constant.SessionKey, cookieKey: Constant.CookieKey });
|
|
248
|
+
|
|
249
|
+
expect(result).not.toBeNull();
|
|
250
|
+
const consentResult = result as ConsentTestResult & { initialState: { cookies: string; hasClskCookie: boolean; hasClckCookie: boolean; clckCookieValue: string } };
|
|
251
|
+
|
|
252
|
+
// Verify initial state had the pre-set consent cookie
|
|
253
|
+
expect(consentResult.initialState.hasClckCookie).toBe(true);
|
|
254
|
+
expect(consentResult.initialState.clckCookieValue).toContain("testuser123");
|
|
255
|
+
|
|
256
|
+
// Verify consent was read from cookie
|
|
257
|
+
expect(consentResult.consent).not.toBeNull();
|
|
258
|
+
expect(consentResult.consent.source).toBe(ConsentSource.Cookie);
|
|
259
|
+
expect(consentResult.consent.ad_Storage).toBe(Constant.Granted);
|
|
260
|
+
expect(consentResult.consent.analytics_Storage).toBe(Constant.Granted);
|
|
261
|
+
// Cookie should still exist
|
|
262
|
+
expect(consentResult.hasClckCookie).toBe(true);
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
test("consentv2 explicit denial: track=false → denied/denied remains without cookies", async ({ page }) => {
|
|
266
|
+
await page.evaluate(setupCookieMock);
|
|
267
|
+
|
|
268
|
+
// Verify initial state - no cookies before Clarity starts
|
|
269
|
+
const initialState = await page.evaluate(({ sessionKey, cookieKey }) => {
|
|
270
|
+
const cookies = document.cookie;
|
|
271
|
+
const clskMatch = cookies.match(new RegExp(`${sessionKey}=([^;]+)`));
|
|
272
|
+
const clckMatch = cookies.match(new RegExp(`${cookieKey}=([^;]+)`));
|
|
273
|
+
return {
|
|
274
|
+
cookies,
|
|
275
|
+
hasClskCookie: cookies.includes(`${sessionKey}=`),
|
|
276
|
+
hasClckCookie: cookies.includes(`${cookieKey}=`),
|
|
277
|
+
clskCookieValue: clskMatch ? clskMatch[1] : "",
|
|
278
|
+
clckCookieValue: clckMatch ? clckMatch[1] : ""
|
|
279
|
+
};
|
|
280
|
+
}, { sessionKey: Constant.SessionKey, cookieKey: Constant.CookieKey });
|
|
281
|
+
|
|
282
|
+
expect(initialState.cookies).toBe("");
|
|
283
|
+
expect(initialState.hasClskCookie).toBe(false);
|
|
284
|
+
expect(initialState.hasClckCookie).toBe(false);
|
|
285
|
+
|
|
286
|
+
// Start with track=false (implicit denied), then explicitly deny via consentv2
|
|
287
|
+
const result = await page.evaluate(({ sessionKey, cookieKey }) => {
|
|
288
|
+
return new Promise((resolve) => {
|
|
289
|
+
(window as any).clarity("start", {
|
|
290
|
+
projectId: "test",
|
|
291
|
+
track: false,
|
|
292
|
+
upload: false
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
setTimeout(() => {
|
|
296
|
+
(window as any).clarity("consentv2", {
|
|
297
|
+
ad_Storage: "denied",
|
|
298
|
+
analytics_Storage: "denied"
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
(window as any).clarity("metadata", (_data: any, _upgrade: any, consent: any) => {
|
|
302
|
+
if (consent) {
|
|
303
|
+
const cookies = document.cookie;
|
|
304
|
+
const clskMatch = cookies.match(new RegExp(`${sessionKey}=([^;]+)`));
|
|
305
|
+
const clckMatch = cookies.match(new RegExp(`${cookieKey}=([^;]+)`));
|
|
306
|
+
resolve({
|
|
307
|
+
consent,
|
|
308
|
+
hasClskCookie: cookies.includes(`${sessionKey}=`),
|
|
309
|
+
hasClckCookie: cookies.includes(`${cookieKey}=`),
|
|
310
|
+
clskCookieValue: clskMatch ? clskMatch[1] : "",
|
|
311
|
+
clckCookieValue: clckMatch ? clckMatch[1] : "",
|
|
312
|
+
clckConsentCrumb: clckMatch ? (clckMatch[1].split("^")[3] || "") : "",
|
|
313
|
+
cookies
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
}, false, false, true);
|
|
317
|
+
}, (window as any).COOKIE_SETUP_DELAY);
|
|
318
|
+
|
|
319
|
+
setTimeout(() => resolve(null), (window as any).CONSENT_CALLBACK_TIMEOUT);
|
|
320
|
+
});
|
|
321
|
+
}, { sessionKey: Constant.SessionKey, cookieKey: Constant.CookieKey });
|
|
322
|
+
|
|
323
|
+
expect(result).not.toBeNull();
|
|
324
|
+
const consentResult = result as ConsentTestResult;
|
|
325
|
+
expect(consentResult.consent.source).toBe(ConsentSource.APIv2);
|
|
326
|
+
expect(consentResult.consent.ad_Storage).toBe(Constant.Denied);
|
|
327
|
+
expect(consentResult.consent.analytics_Storage).toBe(Constant.Denied);
|
|
328
|
+
// Verify cookies are not set when analytics denied
|
|
329
|
+
expect(consentResult.hasClskCookie).toBe(false);
|
|
330
|
+
expect(consentResult.hasClckCookie).toBe(false);
|
|
331
|
+
expect(consentResult.clskCookieValue).toBe("");
|
|
332
|
+
expect(consentResult.clckCookieValue).toBe("");
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
test("consentv2 mixed consent: track=false → denied analytics, granted ads no cookies", async ({ page }) => {
|
|
336
|
+
await page.evaluate(setupCookieMock);
|
|
337
|
+
|
|
338
|
+
// Verify initial state - no cookies before Clarity starts
|
|
339
|
+
const initialState = await page.evaluate(({ sessionKey, cookieKey }) => {
|
|
340
|
+
const cookies = document.cookie;
|
|
341
|
+
const clskMatch = cookies.match(new RegExp(`${sessionKey}=([^;]+)`));
|
|
342
|
+
const clckMatch = cookies.match(new RegExp(`${cookieKey}=([^;]+)`));
|
|
343
|
+
return {
|
|
344
|
+
cookies,
|
|
345
|
+
hasClskCookie: cookies.includes(`${sessionKey}=`),
|
|
346
|
+
hasClckCookie: cookies.includes(`${cookieKey}=`),
|
|
347
|
+
clskCookieValue: clskMatch ? clskMatch[1] : "",
|
|
348
|
+
clckCookieValue: clckMatch ? clckMatch[1] : ""
|
|
349
|
+
};
|
|
350
|
+
}, { sessionKey: Constant.SessionKey, cookieKey: Constant.CookieKey });
|
|
351
|
+
|
|
352
|
+
expect(initialState.cookies).toBe("");
|
|
353
|
+
expect(initialState.hasClskCookie).toBe(false);
|
|
354
|
+
expect(initialState.hasClckCookie).toBe(false);
|
|
355
|
+
|
|
356
|
+
const result = await page.evaluate(({ sessionKey, cookieKey }) => {
|
|
357
|
+
return new Promise((resolve) => {
|
|
358
|
+
(window as any).clarity("start", {
|
|
359
|
+
projectId: "test",
|
|
360
|
+
track: false,
|
|
361
|
+
upload: false
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
(window as any).clarity("consentv2", {
|
|
365
|
+
ad_Storage: "granted",
|
|
366
|
+
analytics_Storage: "denied"
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
(window as any).clarity("metadata", (_data: any, _upgrade: any, consent: any) => {
|
|
370
|
+
if (consent) {
|
|
371
|
+
const cookies = document.cookie;
|
|
372
|
+
const clskMatch = cookies.match(new RegExp(`${sessionKey}=([^;]+)`));
|
|
373
|
+
const clckMatch = cookies.match(new RegExp(`${cookieKey}=([^;]+)`));
|
|
374
|
+
resolve({
|
|
375
|
+
consent,
|
|
376
|
+
hasClskCookie: cookies.includes(`${sessionKey}=`),
|
|
377
|
+
hasClckCookie: cookies.includes(`${cookieKey}=`),
|
|
378
|
+
clskCookieValue: clskMatch ? clskMatch[1] : "",
|
|
379
|
+
clckCookieValue: clckMatch ? clckMatch[1] : "",
|
|
380
|
+
clckConsentCrumb: clckMatch ? (clckMatch[1].split("^")[3] || "") : "",
|
|
381
|
+
cookies
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
}, false, false, true);
|
|
385
|
+
|
|
386
|
+
setTimeout(() => resolve(null), (window as any).CONSENT_CALLBACK_TIMEOUT);
|
|
387
|
+
});
|
|
388
|
+
}, { sessionKey: Constant.SessionKey, cookieKey: Constant.CookieKey });
|
|
389
|
+
|
|
390
|
+
expect(result).not.toBeNull();
|
|
391
|
+
const consentResult = result as ConsentTestResult;
|
|
392
|
+
expect(consentResult.consent.source).toBe(ConsentSource.APIv2);
|
|
393
|
+
expect(consentResult.consent.ad_Storage).toBe(Constant.Granted);
|
|
394
|
+
expect(consentResult.consent.analytics_Storage).toBe(Constant.Denied);
|
|
395
|
+
// Verify cookies are deleted when analytics is denied (regardless of ads)
|
|
396
|
+
expect(consentResult.hasClskCookie).toBe(false);
|
|
397
|
+
expect(consentResult.hasClckCookie).toBe(false);
|
|
398
|
+
expect(consentResult.clskCookieValue).toBe("");
|
|
399
|
+
expect(consentResult.clckCookieValue).toBe("");
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
test("consentv2 mixed consent: track=false → granted analytics, denied ads sets cookies", async ({ page }) => {
|
|
403
|
+
await page.evaluate(setupCookieMock);
|
|
404
|
+
|
|
405
|
+
// Verify initial state - no cookies before Clarity starts
|
|
406
|
+
const initialState = await page.evaluate(({ sessionKey, cookieKey }) => {
|
|
407
|
+
const cookies = document.cookie;
|
|
408
|
+
const clskMatch = cookies.match(new RegExp(`${sessionKey}=([^;]+)`));
|
|
409
|
+
const clckMatch = cookies.match(new RegExp(`${cookieKey}=([^;]+)`));
|
|
410
|
+
return {
|
|
411
|
+
cookies,
|
|
412
|
+
hasClskCookie: cookies.includes(`${sessionKey}=`),
|
|
413
|
+
hasClckCookie: cookies.includes(`${cookieKey}=`),
|
|
414
|
+
clskCookieValue: clskMatch ? clskMatch[1] : "",
|
|
415
|
+
clckCookieValue: clckMatch ? clckMatch[1] : ""
|
|
416
|
+
};
|
|
417
|
+
}, { sessionKey: Constant.SessionKey, cookieKey: Constant.CookieKey });
|
|
418
|
+
|
|
419
|
+
expect(initialState.cookies).toBe("");
|
|
420
|
+
expect(initialState.hasClskCookie).toBe(false);
|
|
421
|
+
expect(initialState.hasClckCookie).toBe(false);
|
|
422
|
+
|
|
423
|
+
// Start with track=false, then grant analytics but deny ads
|
|
424
|
+
const result = await page.evaluate(({ sessionKey, cookieKey }) => {
|
|
425
|
+
return new Promise((resolve) => {
|
|
426
|
+
(window as any).clarity("start", {
|
|
427
|
+
projectId: "test",
|
|
428
|
+
track: false,
|
|
429
|
+
upload: false
|
|
430
|
+
});
|
|
431
|
+
|
|
432
|
+
setTimeout(() => {
|
|
433
|
+
(window as any).clarity("consentv2", {
|
|
434
|
+
ad_Storage: "denied",
|
|
435
|
+
analytics_Storage: "granted"
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
(window as any).clarity("metadata", (_data: any, _upgrade: any, consent: any) => {
|
|
439
|
+
if (consent) {
|
|
440
|
+
const cookies = document.cookie;
|
|
441
|
+
const clskMatch = cookies.match(new RegExp(`${sessionKey}=([^;]+)`));
|
|
442
|
+
const clckMatch = cookies.match(new RegExp(`${cookieKey}=([^;]+)`));
|
|
443
|
+
resolve({
|
|
444
|
+
consent,
|
|
445
|
+
hasClskCookie: cookies.includes(`${sessionKey}=`),
|
|
446
|
+
hasClckCookie: cookies.includes(`${cookieKey}=`),
|
|
447
|
+
clskCookieValue: clskMatch ? clskMatch[1] : "",
|
|
448
|
+
clckCookieValue: clckMatch ? clckMatch[1] : "",
|
|
449
|
+
clckConsentCrumb: clckMatch ? (clckMatch[1].split("^")[3] || "") : "",
|
|
450
|
+
cookies
|
|
451
|
+
});
|
|
452
|
+
}
|
|
453
|
+
}, false, false, true);
|
|
454
|
+
}, (window as any).COOKIE_SETUP_DELAY);
|
|
455
|
+
|
|
456
|
+
setTimeout(() => resolve(null), (window as any).CONSENT_CALLBACK_TIMEOUT);
|
|
457
|
+
});
|
|
458
|
+
}, { sessionKey: Constant.SessionKey, cookieKey: Constant.CookieKey });
|
|
459
|
+
|
|
460
|
+
expect(result).not.toBeNull();
|
|
461
|
+
const consentResult = result as ConsentTestResult;
|
|
462
|
+
expect(consentResult.consent.source).toBe(ConsentSource.APIv2);
|
|
463
|
+
expect(consentResult.consent.ad_Storage).toBe(Constant.Denied);
|
|
464
|
+
expect(consentResult.consent.analytics_Storage).toBe(Constant.Granted);
|
|
465
|
+
// Verify _clck cookie is set when analytics granted (even if ads denied)
|
|
466
|
+
expect(consentResult.hasClckCookie).toBe(true);
|
|
467
|
+
expect(consentResult.clckCookieValue).not.toBe("");
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
test("consentv2 grants consent: track=false → granted/granted sets cookies", async ({ page }) => {
|
|
471
|
+
await page.evaluate(setupCookieMock);
|
|
472
|
+
|
|
473
|
+
// Verify initial state - no cookies before Clarity starts
|
|
474
|
+
const initialState = await page.evaluate(({ sessionKey, cookieKey }) => {
|
|
475
|
+
const cookies = document.cookie;
|
|
476
|
+
const clskMatch = cookies.match(new RegExp(`${sessionKey}=([^;]+)`));
|
|
477
|
+
const clckMatch = cookies.match(new RegExp(`${cookieKey}=([^;]+)`));
|
|
478
|
+
return {
|
|
479
|
+
cookies,
|
|
480
|
+
hasClskCookie: cookies.includes(`${sessionKey}=`),
|
|
481
|
+
hasClckCookie: cookies.includes(`${cookieKey}=`),
|
|
482
|
+
clskCookieValue: clskMatch ? clskMatch[1] : "",
|
|
483
|
+
clckCookieValue: clckMatch ? clckMatch[1] : ""
|
|
484
|
+
};
|
|
485
|
+
}, { sessionKey: Constant.SessionKey, cookieKey: Constant.CookieKey });
|
|
486
|
+
|
|
487
|
+
expect(initialState.cookies).toBe("");
|
|
488
|
+
expect(initialState.hasClskCookie).toBe(false);
|
|
489
|
+
expect(initialState.hasClckCookie).toBe(false);
|
|
490
|
+
|
|
491
|
+
// Start with track=false (implicit denied) and verify initial consent state
|
|
492
|
+
const initialConsent = await page.evaluate(({ sessionKey, cookieKey }) => {
|
|
493
|
+
return new Promise((resolve) => {
|
|
494
|
+
(window as any).clarity("start", {
|
|
495
|
+
projectId: "test",
|
|
496
|
+
track: false,
|
|
497
|
+
upload: false
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
(window as any).clarity("metadata", (_data: any, _upgrade: any, consent: any) => {
|
|
501
|
+
if (consent) {
|
|
502
|
+
const cookies = document.cookie;
|
|
503
|
+
const clskMatch = cookies.match(new RegExp(`${sessionKey}=([^;]+)`));
|
|
504
|
+
const clckMatch = cookies.match(new RegExp(`${cookieKey}=([^;]+)`));
|
|
505
|
+
resolve({
|
|
506
|
+
consent,
|
|
507
|
+
hasClskCookie: cookies.includes(`${sessionKey}=`),
|
|
508
|
+
hasClckCookie: cookies.includes(`${cookieKey}=`),
|
|
509
|
+
clskCookieValue: clskMatch ? clskMatch[1] : "",
|
|
510
|
+
clckCookieValue: clckMatch ? clckMatch[1] : "",
|
|
511
|
+
clckConsentCrumb: clckMatch ? (clckMatch[1].split("^")[3] || "") : "",
|
|
512
|
+
cookies
|
|
513
|
+
});
|
|
514
|
+
}
|
|
515
|
+
}, false, false, true);
|
|
516
|
+
|
|
517
|
+
setTimeout(() => resolve(null), (window as any).CONSENT_CALLBACK_TIMEOUT);
|
|
518
|
+
});
|
|
519
|
+
}, { sessionKey: Constant.SessionKey, cookieKey: Constant.CookieKey });
|
|
520
|
+
|
|
521
|
+
expect(initialConsent).not.toBeNull();
|
|
522
|
+
const initialResult = initialConsent as ConsentTestResult;
|
|
523
|
+
expect(initialResult.consent.source).toBe(ConsentSource.Implicit);
|
|
524
|
+
expect(initialResult.consent.ad_Storage).toBe(Constant.Denied);
|
|
525
|
+
expect(initialResult.consent.analytics_Storage).toBe(Constant.Denied);
|
|
526
|
+
// Cookies should not be set with track=false
|
|
527
|
+
expect(initialResult.hasClskCookie).toBe(false);
|
|
528
|
+
expect(initialResult.hasClckCookie).toBe(false);
|
|
529
|
+
|
|
530
|
+
// Grant consent via consentv2 API
|
|
531
|
+
const updatedConsent = await page.evaluate(({ sessionKey, cookieKey }) => {
|
|
532
|
+
return new Promise((resolve) => {
|
|
533
|
+
(window as any).clarity("consentv2", {
|
|
534
|
+
ad_Storage: "granted",
|
|
535
|
+
analytics_Storage: "granted"
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
(window as any).clarity("metadata", (_data: any, _upgrade: any, consent: any) => {
|
|
539
|
+
if (consent) {
|
|
540
|
+
const cookies = document.cookie;
|
|
541
|
+
const clskMatch = cookies.match(new RegExp(`${sessionKey}=([^;]+)`));
|
|
542
|
+
const clckMatch = cookies.match(new RegExp(`${cookieKey}=([^;]+)`));
|
|
543
|
+
resolve({
|
|
544
|
+
consent,
|
|
545
|
+
hasClskCookie: cookies.includes(`${sessionKey}=`),
|
|
546
|
+
hasClckCookie: cookies.includes(`${cookieKey}=`),
|
|
547
|
+
clskCookieValue: clskMatch ? clskMatch[1] : "",
|
|
548
|
+
clckCookieValue: clckMatch ? clckMatch[1] : "",
|
|
549
|
+
clckConsentCrumb: clckMatch ? (clckMatch[1].split("^")[3] || "") : "",
|
|
550
|
+
cookies
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
}, false, false, true);
|
|
554
|
+
|
|
555
|
+
setTimeout(() => resolve(null), (window as any).CONSENT_CALLBACK_TIMEOUT);
|
|
556
|
+
});
|
|
557
|
+
}, { sessionKey: Constant.SessionKey, cookieKey: Constant.CookieKey });
|
|
558
|
+
|
|
559
|
+
expect(updatedConsent).not.toBeNull();
|
|
560
|
+
const updatedResult = updatedConsent as ConsentTestResult;
|
|
561
|
+
expect(updatedResult.consent.source).toBe(ConsentSource.APIv2);
|
|
562
|
+
expect(updatedResult.consent.ad_Storage).toBe(Constant.Granted);
|
|
563
|
+
expect(updatedResult.consent.analytics_Storage).toBe(Constant.Granted);
|
|
564
|
+
// Verify cookies are set when consent is granted
|
|
565
|
+
expect(updatedResult.hasClskCookie).toBe(true);
|
|
566
|
+
expect(updatedResult.hasClckCookie).toBe(true);
|
|
567
|
+
expect(updatedResult.clskCookieValue).not.toBe("");
|
|
568
|
+
expect(updatedResult.clckCookieValue).not.toBe("");
|
|
569
|
+
});
|
|
570
|
+
|
|
571
|
+
// ========================
|
|
572
|
+
// track=true tests
|
|
573
|
+
// ========================
|
|
574
|
+
|
|
575
|
+
test("implicit granted: track=true results in granted consent", async ({ page }) => {
|
|
576
|
+
await page.evaluate(setupCookieMock);
|
|
577
|
+
|
|
578
|
+
// Verify initial state - no cookies before Clarity starts
|
|
579
|
+
const initialState = await page.evaluate(({ sessionKey, cookieKey }) => {
|
|
580
|
+
const cookies = document.cookie;
|
|
581
|
+
const clskMatch = cookies.match(new RegExp(`${sessionKey}=([^;]+)`));
|
|
582
|
+
const clckMatch = cookies.match(new RegExp(`${cookieKey}=([^;]+)`));
|
|
583
|
+
return {
|
|
584
|
+
cookies,
|
|
585
|
+
hasClskCookie: cookies.includes(`${sessionKey}=`),
|
|
586
|
+
hasClckCookie: cookies.includes(`${cookieKey}=`),
|
|
587
|
+
clskCookieValue: clskMatch ? clskMatch[1] : "",
|
|
588
|
+
clckCookieValue: clckMatch ? clckMatch[1] : ""
|
|
589
|
+
};
|
|
590
|
+
}, { sessionKey: Constant.SessionKey, cookieKey: Constant.CookieKey });
|
|
591
|
+
|
|
592
|
+
expect(initialState.cookies).toBe("");
|
|
593
|
+
expect(initialState.hasClskCookie).toBe(false);
|
|
594
|
+
expect(initialState.hasClckCookie).toBe(false);
|
|
595
|
+
|
|
596
|
+
// Start clarity with track=true (implicit granted consent)
|
|
597
|
+
const result = await page.evaluate(({ sessionKey, cookieKey }) => {
|
|
598
|
+
return new Promise((resolve) => {
|
|
599
|
+
(window as any).clarity("start", {
|
|
600
|
+
projectId: "test",
|
|
601
|
+
track: true,
|
|
602
|
+
upload: false
|
|
603
|
+
});
|
|
604
|
+
|
|
605
|
+
// Register metadata callback
|
|
606
|
+
// wait=false (don't wait for data), recall=true (resend on changes), consentInfo=true (include consent)
|
|
607
|
+
(window as any).clarity("metadata", (_data: any, _upgrade: any, consent: any) => {
|
|
608
|
+
if (consent) {
|
|
609
|
+
const cookies = document.cookie;
|
|
610
|
+
const clskMatch = cookies.match(new RegExp(`${sessionKey}=([^;]+)`));
|
|
611
|
+
const clckMatch = cookies.match(new RegExp(`${cookieKey}=([^;]+)`));
|
|
612
|
+
resolve({
|
|
613
|
+
consent,
|
|
614
|
+
hasClskCookie: cookies.includes(`${sessionKey}=`),
|
|
615
|
+
hasClckCookie: cookies.includes(`${cookieKey}=`),
|
|
616
|
+
clskCookieValue: clskMatch ? clskMatch[1] : "",
|
|
617
|
+
clckCookieValue: clckMatch ? clckMatch[1] : "",
|
|
618
|
+
clckConsentCrumb: clckMatch ? (clckMatch[1].split("^")[3] || "") : "",
|
|
619
|
+
cookies
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
}, false, true, true);
|
|
623
|
+
|
|
624
|
+
// Timeout fallback
|
|
625
|
+
setTimeout(() => {
|
|
626
|
+
const cookies = document.cookie;
|
|
627
|
+
resolve({
|
|
628
|
+
consent: null,
|
|
629
|
+
hasClskCookie: cookies.includes(`${sessionKey}=`),
|
|
630
|
+
hasClckCookie: cookies.includes(`${cookieKey}=`),
|
|
631
|
+
clskCookieValue: "",
|
|
632
|
+
clckCookieValue: "",
|
|
633
|
+
cookies
|
|
634
|
+
});
|
|
635
|
+
}, (window as any).CONSENT_CALLBACK_TIMEOUT);
|
|
636
|
+
});
|
|
637
|
+
}, { sessionKey: Constant.SessionKey, cookieKey: Constant.CookieKey });
|
|
638
|
+
|
|
639
|
+
expect(result).not.toBeNull();
|
|
640
|
+
const consentResult = result as ConsentTestResult;
|
|
641
|
+
expect(consentResult.consent).not.toBeNull();
|
|
642
|
+
expect(consentResult.consent.source).toBe(ConsentSource.Implicit);
|
|
643
|
+
expect(consentResult.consent.ad_Storage).toBe(Constant.Granted);
|
|
644
|
+
expect(consentResult.consent.analytics_Storage).toBe(Constant.Granted);
|
|
645
|
+
// With track=true, _clck cookie should be set
|
|
646
|
+
expect(consentResult.hasClckCookie).toBe(true);
|
|
647
|
+
expect(consentResult.clckCookieValue).not.toBe("");
|
|
648
|
+
});
|
|
649
|
+
|
|
650
|
+
test("consentv2 revokes consent: track=true → denied/denied deletes cookies", async ({ page }) => {
|
|
651
|
+
await page.evaluate(setupCookieMock);
|
|
652
|
+
|
|
653
|
+
// Verify initial state - no cookies before Clarity starts
|
|
654
|
+
const initialState = await page.evaluate(({ sessionKey, cookieKey }) => {
|
|
655
|
+
const cookies = document.cookie;
|
|
656
|
+
const clskMatch = cookies.match(new RegExp(`${sessionKey}=([^;]+)`));
|
|
657
|
+
const clckMatch = cookies.match(new RegExp(`${cookieKey}=([^;]+)`));
|
|
658
|
+
return {
|
|
659
|
+
cookies,
|
|
660
|
+
hasClskCookie: cookies.includes(`${sessionKey}=`),
|
|
661
|
+
hasClckCookie: cookies.includes(`${cookieKey}=`),
|
|
662
|
+
clskCookieValue: clskMatch ? clskMatch[1] : "",
|
|
663
|
+
clckCookieValue: clckMatch ? clckMatch[1] : ""
|
|
664
|
+
};
|
|
665
|
+
}, { sessionKey: Constant.SessionKey, cookieKey: Constant.CookieKey });
|
|
666
|
+
|
|
667
|
+
expect(initialState.cookies).toBe("");
|
|
668
|
+
expect(initialState.hasClskCookie).toBe(false);
|
|
669
|
+
expect(initialState.hasClckCookie).toBe(false);
|
|
670
|
+
|
|
671
|
+
// Step 1: Start with track=true and verify initial granted state with cookies
|
|
672
|
+
const initialConsent = await page.evaluate(({ sessionKey, cookieKey }) => {
|
|
673
|
+
return new Promise((resolve) => {
|
|
674
|
+
(window as any).clarity("start", {
|
|
675
|
+
projectId: "test",
|
|
676
|
+
track: true,
|
|
677
|
+
upload: false
|
|
678
|
+
});
|
|
679
|
+
|
|
680
|
+
// Get initial consent state
|
|
681
|
+
(window as any).clarity("metadata", (_data: any, _upgrade: any, consent: any) => {
|
|
682
|
+
if (consent) {
|
|
683
|
+
const cookies = document.cookie;
|
|
684
|
+
const clskMatch = cookies.match(new RegExp(`${sessionKey}=([^;]+)`));
|
|
685
|
+
const clckMatch = cookies.match(new RegExp(`${cookieKey}=([^;]+)`));
|
|
686
|
+
resolve({
|
|
687
|
+
consent,
|
|
688
|
+
hasClskCookie: cookies.includes(`${sessionKey}=`),
|
|
689
|
+
hasClckCookie: cookies.includes(`${cookieKey}=`),
|
|
690
|
+
clskCookieValue: clskMatch ? clskMatch[1] : "",
|
|
691
|
+
clckCookieValue: clckMatch ? clckMatch[1] : "",
|
|
692
|
+
clckConsentCrumb: clckMatch ? (clckMatch[1].split("^")[3] || "") : "",
|
|
693
|
+
cookies
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
}, false, false, true);
|
|
697
|
+
|
|
698
|
+
setTimeout(() => resolve(null), (window as any).CONSENT_CALLBACK_TIMEOUT);
|
|
699
|
+
});
|
|
700
|
+
}, { sessionKey: Constant.SessionKey, cookieKey: Constant.CookieKey });
|
|
701
|
+
|
|
702
|
+
// Verify initial state: implicit granted with cookies
|
|
703
|
+
expect(initialConsent).not.toBeNull();
|
|
704
|
+
const initialResult = initialConsent as ConsentTestResult;
|
|
705
|
+
expect(initialResult.consent.source).toBe(ConsentSource.Implicit);
|
|
706
|
+
expect(initialResult.consent.ad_Storage).toBe(Constant.Granted);
|
|
707
|
+
expect(initialResult.consent.analytics_Storage).toBe(Constant.Granted);
|
|
708
|
+
expect(initialResult.hasClckCookie).toBe(true);
|
|
709
|
+
|
|
710
|
+
// Step 2: Call consentv2 API to deny consent and verify cookies are deleted
|
|
711
|
+
const updatedConsent = await page.evaluate(({ sessionKey, cookieKey }) => {
|
|
712
|
+
return new Promise((resolve) => {
|
|
713
|
+
(window as any).clarity("consentv2", {
|
|
714
|
+
ad_Storage: "denied",
|
|
715
|
+
analytics_Storage: "denied"
|
|
716
|
+
});
|
|
717
|
+
|
|
718
|
+
// Get updated consent state and cookie status
|
|
719
|
+
(window as any).clarity("metadata", (_data: any, _upgrade: any, consent: any) => {
|
|
720
|
+
if (consent) {
|
|
721
|
+
const cookies = document.cookie;
|
|
722
|
+
const clskMatch = cookies.match(new RegExp(`${sessionKey}=([^;]+)`));
|
|
723
|
+
const clckMatch = cookies.match(new RegExp(`${cookieKey}=([^;]+)`));
|
|
724
|
+
resolve({
|
|
725
|
+
consent,
|
|
726
|
+
hasClskCookie: cookies.includes(`${sessionKey}=`),
|
|
727
|
+
hasClckCookie: cookies.includes(`${cookieKey}=`),
|
|
728
|
+
clskCookieValue: clskMatch ? clskMatch[1] : "",
|
|
729
|
+
clckCookieValue: clckMatch ? clckMatch[1] : "",
|
|
730
|
+
clckConsentCrumb: clckMatch ? (clckMatch[1].split("^")[3] || "") : "",
|
|
731
|
+
cookies
|
|
732
|
+
});
|
|
733
|
+
}
|
|
734
|
+
}, false, false, true);
|
|
735
|
+
|
|
736
|
+
setTimeout(() => resolve(null), (window as any).CONSENT_CALLBACK_TIMEOUT);
|
|
737
|
+
});
|
|
738
|
+
}, { sessionKey: Constant.SessionKey, cookieKey: Constant.CookieKey });
|
|
739
|
+
|
|
740
|
+
// Verify updated state: explicit denied with cookies deleted
|
|
741
|
+
expect(updatedConsent).not.toBeNull();
|
|
742
|
+
const updatedResult = updatedConsent as ConsentTestResult;
|
|
743
|
+
expect(updatedResult.consent.source).toBe(ConsentSource.APIv2);
|
|
744
|
+
expect(updatedResult.consent.ad_Storage).toBe(Constant.Denied);
|
|
745
|
+
expect(updatedResult.consent.analytics_Storage).toBe(Constant.Denied);
|
|
746
|
+
|
|
747
|
+
// Verify both cookies are deleted after consent is denied
|
|
748
|
+
expect(updatedResult.hasClskCookie).toBe(false);
|
|
749
|
+
expect(updatedResult.hasClckCookie).toBe(false);
|
|
750
|
+
});
|
|
751
|
+
|
|
752
|
+
test("consentv2 mixed consent: track=true → granted analytics, denied ads keeps cookies", async ({ page }) => {
|
|
753
|
+
await page.evaluate(setupCookieMock);
|
|
754
|
+
|
|
755
|
+
// Verify initial state - no cookies before Clarity starts
|
|
756
|
+
const initialState = await page.evaluate(({ sessionKey, cookieKey }) => {
|
|
757
|
+
const cookies = document.cookie;
|
|
758
|
+
const clskMatch = cookies.match(new RegExp(`${sessionKey}=([^;]+)`));
|
|
759
|
+
const clckMatch = cookies.match(new RegExp(`${cookieKey}=([^;]+)`));
|
|
760
|
+
return {
|
|
761
|
+
cookies,
|
|
762
|
+
hasClskCookie: cookies.includes(`${sessionKey}=`),
|
|
763
|
+
hasClckCookie: cookies.includes(`${cookieKey}=`),
|
|
764
|
+
clskCookieValue: clskMatch ? clskMatch[1] : "",
|
|
765
|
+
clckCookieValue: clckMatch ? clckMatch[1] : ""
|
|
766
|
+
};
|
|
767
|
+
}, { sessionKey: Constant.SessionKey, cookieKey: Constant.CookieKey });
|
|
768
|
+
|
|
769
|
+
expect(initialState.cookies).toBe("");
|
|
770
|
+
expect(initialState.hasClskCookie).toBe(false);
|
|
771
|
+
expect(initialState.hasClckCookie).toBe(false);
|
|
772
|
+
|
|
773
|
+
const result = await page.evaluate(({ sessionKey, cookieKey }) => {
|
|
774
|
+
return new Promise((resolve) => {
|
|
775
|
+
(window as any).clarity("start", {
|
|
776
|
+
projectId: "test",
|
|
777
|
+
track: true,
|
|
778
|
+
upload: false
|
|
779
|
+
});
|
|
780
|
+
|
|
781
|
+
(window as any).clarity("consentv2", {
|
|
782
|
+
ad_Storage: "denied",
|
|
783
|
+
analytics_Storage: "granted"
|
|
784
|
+
});
|
|
785
|
+
|
|
786
|
+
(window as any).clarity("metadata", (_data: any, _upgrade: any, consent: any) => {
|
|
787
|
+
if (consent) {
|
|
788
|
+
const cookies = document.cookie;
|
|
789
|
+
const clskMatch = cookies.match(new RegExp(`${sessionKey}=([^;]+)`));
|
|
790
|
+
const clckMatch = cookies.match(new RegExp(`${cookieKey}=([^;]+)`));
|
|
791
|
+
resolve({
|
|
792
|
+
consent,
|
|
793
|
+
hasClskCookie: cookies.includes(`${sessionKey}=`),
|
|
794
|
+
hasClckCookie: cookies.includes(`${cookieKey}=`),
|
|
795
|
+
clskCookieValue: clskMatch ? clskMatch[1] : "",
|
|
796
|
+
clckCookieValue: clckMatch ? clckMatch[1] : "",
|
|
797
|
+
clckConsentCrumb: clckMatch ? (clckMatch[1].split("^")[3] || "") : "",
|
|
798
|
+
cookies
|
|
799
|
+
});
|
|
800
|
+
}
|
|
801
|
+
}, false, false, true);
|
|
802
|
+
|
|
803
|
+
setTimeout(() => resolve(null), (window as any).CONSENT_CALLBACK_TIMEOUT);
|
|
804
|
+
});
|
|
805
|
+
}, { sessionKey: Constant.SessionKey, cookieKey: Constant.CookieKey });
|
|
806
|
+
|
|
807
|
+
expect(result).not.toBeNull();
|
|
808
|
+
const consentResult = result as ConsentTestResult;
|
|
809
|
+
expect(consentResult.consent.source).toBe(ConsentSource.APIv2);
|
|
810
|
+
expect(consentResult.consent.ad_Storage).toBe(Constant.Denied);
|
|
811
|
+
expect(consentResult.consent.analytics_Storage).toBe(Constant.Granted);
|
|
812
|
+
// Verify cookies remain when analytics is granted (even if ads is denied)
|
|
813
|
+
expect(consentResult.hasClskCookie).toBe(true);
|
|
814
|
+
expect(consentResult.hasClckCookie).toBe(true);
|
|
815
|
+
expect(consentResult.clskCookieValue).not.toBe("");
|
|
816
|
+
expect(consentResult.clckCookieValue).not.toBe("");
|
|
817
|
+
});
|
|
818
|
+
|
|
819
|
+
test("consentv2 mixed consent: track=true → denied analytics, granted ads deletes cookies", async ({ page }) => {
|
|
820
|
+
await page.evaluate(setupCookieMock);
|
|
821
|
+
|
|
822
|
+
// Verify initial state - no cookies before Clarity starts
|
|
823
|
+
const initialState = await page.evaluate(({ sessionKey, cookieKey }) => {
|
|
824
|
+
const cookies = document.cookie;
|
|
825
|
+
const clskMatch = cookies.match(new RegExp(`${sessionKey}=([^;]+)`));
|
|
826
|
+
const clckMatch = cookies.match(new RegExp(`${cookieKey}=([^;]+)`));
|
|
827
|
+
return {
|
|
828
|
+
cookies,
|
|
829
|
+
hasClskCookie: cookies.includes(`${sessionKey}=`),
|
|
830
|
+
hasClckCookie: cookies.includes(`${cookieKey}=`),
|
|
831
|
+
clskCookieValue: clskMatch ? clskMatch[1] : "",
|
|
832
|
+
clckCookieValue: clckMatch ? clckMatch[1] : ""
|
|
833
|
+
};
|
|
834
|
+
}, { sessionKey: Constant.SessionKey, cookieKey: Constant.CookieKey });
|
|
835
|
+
|
|
836
|
+
expect(initialState.cookies).toBe("");
|
|
837
|
+
expect(initialState.hasClskCookie).toBe(false);
|
|
838
|
+
expect(initialState.hasClckCookie).toBe(false);
|
|
839
|
+
|
|
840
|
+
// Start with track=true, then deny analytics but grant ads
|
|
841
|
+
const result = await page.evaluate(({ sessionKey, cookieKey }) => {
|
|
842
|
+
return new Promise((resolve) => {
|
|
843
|
+
(window as any).clarity("start", {
|
|
844
|
+
projectId: "test",
|
|
845
|
+
track: true,
|
|
846
|
+
upload: false
|
|
847
|
+
});
|
|
848
|
+
|
|
849
|
+
setTimeout(() => {
|
|
850
|
+
(window as any).clarity("consentv2", {
|
|
851
|
+
ad_Storage: "granted",
|
|
852
|
+
analytics_Storage: "denied"
|
|
853
|
+
});
|
|
854
|
+
|
|
855
|
+
(window as any).clarity("metadata", (_data: any, _upgrade: any, consent: any) => {
|
|
856
|
+
if (consent) {
|
|
857
|
+
const cookies = document.cookie;
|
|
858
|
+
const clskMatch = cookies.match(new RegExp(`${sessionKey}=([^;]+)`));
|
|
859
|
+
const clckMatch = cookies.match(new RegExp(`${cookieKey}=([^;]+)`));
|
|
860
|
+
resolve({
|
|
861
|
+
consent,
|
|
862
|
+
hasClskCookie: cookies.includes(`${sessionKey}=`),
|
|
863
|
+
hasClckCookie: cookies.includes(`${cookieKey}=`),
|
|
864
|
+
clskCookieValue: clskMatch ? clskMatch[1] : "",
|
|
865
|
+
clckCookieValue: clckMatch ? clckMatch[1] : "",
|
|
866
|
+
clckConsentCrumb: clckMatch ? (clckMatch[1].split("^")[3] || "") : "",
|
|
867
|
+
cookies
|
|
868
|
+
});
|
|
869
|
+
}
|
|
870
|
+
}, false, false, true);
|
|
871
|
+
}, (window as any).COOKIE_SETUP_DELAY);
|
|
872
|
+
|
|
873
|
+
setTimeout(() => resolve(null), (window as any).CONSENT_CALLBACK_TIMEOUT);
|
|
874
|
+
});
|
|
875
|
+
}, { sessionKey: Constant.SessionKey, cookieKey: Constant.CookieKey });
|
|
876
|
+
|
|
877
|
+
expect(result).not.toBeNull();
|
|
878
|
+
const consentResult = result as ConsentTestResult;
|
|
879
|
+
expect(consentResult.consent.source).toBe(ConsentSource.APIv2);
|
|
880
|
+
expect(consentResult.consent.ad_Storage).toBe(Constant.Granted);
|
|
881
|
+
expect(consentResult.consent.analytics_Storage).toBe(Constant.Denied);
|
|
882
|
+
// Verify cookies are deleted when analytics denied (even if ads granted)
|
|
883
|
+
expect(consentResult.hasClskCookie).toBe(false);
|
|
884
|
+
expect(consentResult.hasClckCookie).toBe(false);
|
|
885
|
+
expect(consentResult.clskCookieValue).toBe("");
|
|
886
|
+
expect(consentResult.clckCookieValue).toBe("");
|
|
887
|
+
});
|
|
888
|
+
|
|
889
|
+
test("consentv2 maintains consent: track=true → granted/granted keeps cookies", async ({ page }) => {
|
|
890
|
+
await page.evaluate(setupCookieMock);
|
|
891
|
+
|
|
892
|
+
// Verify initial state - no cookies before Clarity starts
|
|
893
|
+
const initialState = await page.evaluate(({ sessionKey, cookieKey }) => {
|
|
894
|
+
const cookies = document.cookie;
|
|
895
|
+
const clskMatch = cookies.match(new RegExp(`${sessionKey}=([^;]+)`));
|
|
896
|
+
const clckMatch = cookies.match(new RegExp(`${cookieKey}=([^;]+)`));
|
|
897
|
+
return {
|
|
898
|
+
cookies,
|
|
899
|
+
hasClskCookie: cookies.includes(`${sessionKey}=`),
|
|
900
|
+
hasClckCookie: cookies.includes(`${cookieKey}=`),
|
|
901
|
+
clskCookieValue: clskMatch ? clskMatch[1] : "",
|
|
902
|
+
clckCookieValue: clckMatch ? clckMatch[1] : ""
|
|
903
|
+
};
|
|
904
|
+
}, { sessionKey: Constant.SessionKey, cookieKey: Constant.CookieKey });
|
|
905
|
+
|
|
906
|
+
expect(initialState.cookies).toBe("");
|
|
907
|
+
expect(initialState.hasClskCookie).toBe(false);
|
|
908
|
+
expect(initialState.hasClckCookie).toBe(false);
|
|
909
|
+
|
|
910
|
+
// Start with track=true (implicit granted)
|
|
911
|
+
const initialConsent = await page.evaluate(({ sessionKey, cookieKey }) => {
|
|
912
|
+
return new Promise((resolve) => {
|
|
913
|
+
(window as any).clarity("start", {
|
|
914
|
+
projectId: "test",
|
|
915
|
+
track: true,
|
|
916
|
+
upload: false
|
|
917
|
+
});
|
|
918
|
+
|
|
919
|
+
// Wait a bit for cookies to be set, then check
|
|
920
|
+
setTimeout(() => {
|
|
921
|
+
(window as any).clarity("metadata", (_data: any, _upgrade: any, consent: any) => {
|
|
922
|
+
if (consent) {
|
|
923
|
+
const cookies = document.cookie;
|
|
924
|
+
const clskMatch = cookies.match(new RegExp(`${sessionKey}=([^;]+)`));
|
|
925
|
+
const clckMatch = cookies.match(new RegExp(`${cookieKey}=([^;]+)`));
|
|
926
|
+
resolve({
|
|
927
|
+
consent,
|
|
928
|
+
hasClskCookie: cookies.includes(`${sessionKey}=`),
|
|
929
|
+
hasClckCookie: cookies.includes(`${cookieKey}=`),
|
|
930
|
+
clskCookieValue: clskMatch ? clskMatch[1] : "",
|
|
931
|
+
clckCookieValue: clckMatch ? clckMatch[1] : "",
|
|
932
|
+
clckConsentCrumb: clckMatch ? (clckMatch[1].split("^")[3] || "") : "",
|
|
933
|
+
cookies
|
|
934
|
+
});
|
|
935
|
+
}
|
|
936
|
+
}, false, false, true);
|
|
937
|
+
}, (window as any).COOKIE_SETUP_DELAY);
|
|
938
|
+
|
|
939
|
+
setTimeout(() => resolve(null), (window as any).CONSENT_CALLBACK_TIMEOUT);
|
|
940
|
+
});
|
|
941
|
+
}, { sessionKey: Constant.SessionKey, cookieKey: Constant.CookieKey });
|
|
942
|
+
|
|
943
|
+
// Verify initial state: implicit granted with cookies
|
|
944
|
+
expect(initialConsent).not.toBeNull();
|
|
945
|
+
const initialResult = initialConsent as ConsentTestResult;
|
|
946
|
+
expect(initialResult.consent.source).toBe(ConsentSource.Implicit);
|
|
947
|
+
expect(initialResult.consent.ad_Storage).toBe(Constant.Granted);
|
|
948
|
+
expect(initialResult.consent.analytics_Storage).toBe(Constant.Granted);
|
|
949
|
+
// Note: _clsk cookie is only written during upload operations (metadata.save()), not during initial setup
|
|
950
|
+
// With upload: false in test config, only _clck is written by track() function during initialization
|
|
951
|
+
expect(initialResult.hasClckCookie).toBe(true);
|
|
952
|
+
expect(initialResult.clckCookieValue).not.toBe("");
|
|
953
|
+
|
|
954
|
+
// Explicitly grant via consentv2 API (should maintain granted state)
|
|
955
|
+
const result = await page.evaluate(({ sessionKey, cookieKey }) => {
|
|
956
|
+
return new Promise((resolve) => {
|
|
957
|
+
(window as any).clarity("consentv2", {
|
|
958
|
+
ad_Storage: "granted",
|
|
959
|
+
analytics_Storage: "granted"
|
|
960
|
+
});
|
|
961
|
+
|
|
962
|
+
(window as any).clarity("metadata", (_data: any, _upgrade: any, consent: any) => {
|
|
963
|
+
if (consent) {
|
|
964
|
+
const cookies = document.cookie;
|
|
965
|
+
const clskMatch = cookies.match(new RegExp(`${sessionKey}=([^;]+)`));
|
|
966
|
+
const clckMatch = cookies.match(new RegExp(`${cookieKey}=([^;]+)`));
|
|
967
|
+
resolve({
|
|
968
|
+
consent,
|
|
969
|
+
hasClskCookie: cookies.includes(`${sessionKey}=`),
|
|
970
|
+
hasClckCookie: cookies.includes(`${cookieKey}=`),
|
|
971
|
+
clskCookieValue: clskMatch ? clskMatch[1] : "",
|
|
972
|
+
clckCookieValue: clckMatch ? clckMatch[1] : "",
|
|
973
|
+
clckConsentCrumb: clckMatch ? (clckMatch[1].split("^")[3] || "") : "",
|
|
974
|
+
cookies
|
|
975
|
+
});
|
|
976
|
+
}
|
|
977
|
+
}, false, false, true);
|
|
978
|
+
|
|
979
|
+
setTimeout(() => resolve(null), (window as any).CONSENT_CALLBACK_TIMEOUT);
|
|
980
|
+
});
|
|
981
|
+
}, { sessionKey: Constant.SessionKey, cookieKey: Constant.CookieKey });
|
|
982
|
+
|
|
983
|
+
expect(result).not.toBeNull();
|
|
984
|
+
const consentResult = result as ConsentTestResult;
|
|
985
|
+
expect(consentResult.consent.source).toBe(ConsentSource.APIv2);
|
|
986
|
+
expect(consentResult.consent.ad_Storage).toBe(Constant.Granted);
|
|
987
|
+
expect(consentResult.consent.analytics_Storage).toBe(Constant.Granted);
|
|
988
|
+
// Verify _clck cookie remains set (user ID/consent preference cookie)
|
|
989
|
+
// Note: _clsk is only written during upload operations, so we only check _clck in tests with upload: false
|
|
990
|
+
expect(consentResult.hasClckCookie).toBe(true);
|
|
991
|
+
expect(consentResult.clckCookieValue).not.toBe("");
|
|
992
|
+
});
|
|
993
|
+
|
|
994
|
+
// ========================
|
|
995
|
+
// V1 Consent API tests
|
|
996
|
+
// The V1 API uses clarity("consent", boolean) where true=granted, false=denied
|
|
997
|
+
// It sets both ad_Storage and analytics_Storage to the same value
|
|
998
|
+
// ========================
|
|
999
|
+
|
|
1000
|
+
test("consent v1: track=false → consent(true) grants consent and sets cookies", async ({ page }) => {
|
|
1001
|
+
await page.evaluate(setupCookieMock);
|
|
1002
|
+
|
|
1003
|
+
// Verify initial state - no cookies before Clarity starts
|
|
1004
|
+
const initialState = await page.evaluate(({ sessionKey, cookieKey }) => {
|
|
1005
|
+
const cookies = document.cookie;
|
|
1006
|
+
const clskMatch = cookies.match(new RegExp(`${sessionKey}=([^;]+)`));
|
|
1007
|
+
const clckMatch = cookies.match(new RegExp(`${cookieKey}=([^;]+)`));
|
|
1008
|
+
return {
|
|
1009
|
+
cookies,
|
|
1010
|
+
hasClskCookie: cookies.includes(`${sessionKey}=`),
|
|
1011
|
+
hasClckCookie: cookies.includes(`${cookieKey}=`),
|
|
1012
|
+
clskCookieValue: clskMatch ? clskMatch[1] : "",
|
|
1013
|
+
clckCookieValue: clckMatch ? clckMatch[1] : ""
|
|
1014
|
+
};
|
|
1015
|
+
}, { sessionKey: Constant.SessionKey, cookieKey: Constant.CookieKey });
|
|
1016
|
+
|
|
1017
|
+
expect(initialState.cookies).toBe("");
|
|
1018
|
+
expect(initialState.hasClskCookie).toBe(false);
|
|
1019
|
+
expect(initialState.hasClckCookie).toBe(false);
|
|
1020
|
+
|
|
1021
|
+
// Start with track=false (implicit denied), then grant consent via V1 API
|
|
1022
|
+
const result = await page.evaluate(({ sessionKey, cookieKey }) => {
|
|
1023
|
+
return new Promise((resolve) => {
|
|
1024
|
+
(window as any).clarity("start", {
|
|
1025
|
+
projectId: "test",
|
|
1026
|
+
track: false,
|
|
1027
|
+
upload: false
|
|
1028
|
+
});
|
|
1029
|
+
|
|
1030
|
+
setTimeout(() => {
|
|
1031
|
+
// V1 API: consent(true) grants both ad_Storage and analytics_Storage
|
|
1032
|
+
(window as any).clarity("consent", true);
|
|
1033
|
+
|
|
1034
|
+
(window as any).clarity("metadata", (_data: any, _upgrade: any, consent: any) => {
|
|
1035
|
+
if (consent) {
|
|
1036
|
+
const cookies = document.cookie;
|
|
1037
|
+
const clskMatch = cookies.match(new RegExp(`${sessionKey}=([^;]+)`));
|
|
1038
|
+
const clckMatch = cookies.match(new RegExp(`${cookieKey}=([^;]+)`));
|
|
1039
|
+
resolve({
|
|
1040
|
+
consent,
|
|
1041
|
+
hasClskCookie: cookies.includes(`${sessionKey}=`),
|
|
1042
|
+
hasClckCookie: cookies.includes(`${cookieKey}=`),
|
|
1043
|
+
clskCookieValue: clskMatch ? clskMatch[1] : "",
|
|
1044
|
+
clckCookieValue: clckMatch ? clckMatch[1] : "",
|
|
1045
|
+
clckConsentCrumb: clckMatch ? (clckMatch[1].split("^")[3] || "") : "",
|
|
1046
|
+
cookies
|
|
1047
|
+
});
|
|
1048
|
+
}
|
|
1049
|
+
}, false, false, true);
|
|
1050
|
+
}, (window as any).COOKIE_SETUP_DELAY);
|
|
1051
|
+
|
|
1052
|
+
setTimeout(() => resolve(null), (window as any).CONSENT_CALLBACK_TIMEOUT);
|
|
1053
|
+
});
|
|
1054
|
+
}, { sessionKey: Constant.SessionKey, cookieKey: Constant.CookieKey });
|
|
1055
|
+
|
|
1056
|
+
expect(result).not.toBeNull();
|
|
1057
|
+
const consentResult = result as ConsentTestResult;
|
|
1058
|
+
expect(consentResult.consent.source).toBe(ConsentSource.APIv1);
|
|
1059
|
+
expect(consentResult.consent.ad_Storage).toBe(Constant.Granted);
|
|
1060
|
+
expect(consentResult.consent.analytics_Storage).toBe(Constant.Granted);
|
|
1061
|
+
// Verify cookies are set when consent is granted via V1 API
|
|
1062
|
+
expect(consentResult.hasClckCookie).toBe(true);
|
|
1063
|
+
expect(consentResult.clckCookieValue).not.toBe("");
|
|
1064
|
+
});
|
|
1065
|
+
|
|
1066
|
+
test("consent v1: track=true → consent(false) revokes consent and deletes cookies", async ({ page }) => {
|
|
1067
|
+
await page.evaluate(setupCookieMock);
|
|
1068
|
+
|
|
1069
|
+
// Verify initial state - no cookies before Clarity starts
|
|
1070
|
+
const initialState = await page.evaluate(({ sessionKey, cookieKey }) => {
|
|
1071
|
+
const cookies = document.cookie;
|
|
1072
|
+
const clskMatch = cookies.match(new RegExp(`${sessionKey}=([^;]+)`));
|
|
1073
|
+
const clckMatch = cookies.match(new RegExp(`${cookieKey}=([^;]+)`));
|
|
1074
|
+
return {
|
|
1075
|
+
cookies,
|
|
1076
|
+
hasClskCookie: cookies.includes(`${sessionKey}=`),
|
|
1077
|
+
hasClckCookie: cookies.includes(`${cookieKey}=`),
|
|
1078
|
+
clskCookieValue: clskMatch ? clskMatch[1] : "",
|
|
1079
|
+
clckCookieValue: clckMatch ? clckMatch[1] : ""
|
|
1080
|
+
};
|
|
1081
|
+
}, { sessionKey: Constant.SessionKey, cookieKey: Constant.CookieKey });
|
|
1082
|
+
|
|
1083
|
+
expect(initialState.cookies).toBe("");
|
|
1084
|
+
expect(initialState.hasClskCookie).toBe(false);
|
|
1085
|
+
expect(initialState.hasClckCookie).toBe(false);
|
|
1086
|
+
|
|
1087
|
+
// Start with track=true (implicit granted) and verify initial state
|
|
1088
|
+
const initialConsent = await page.evaluate(({ sessionKey, cookieKey }) => {
|
|
1089
|
+
return new Promise((resolve) => {
|
|
1090
|
+
(window as any).clarity("start", {
|
|
1091
|
+
projectId: "test",
|
|
1092
|
+
track: true,
|
|
1093
|
+
upload: false
|
|
1094
|
+
});
|
|
1095
|
+
|
|
1096
|
+
(window as any).clarity("metadata", (_data: any, _upgrade: any, consent: any) => {
|
|
1097
|
+
if (consent) {
|
|
1098
|
+
const cookies = document.cookie;
|
|
1099
|
+
const clskMatch = cookies.match(new RegExp(`${sessionKey}=([^;]+)`));
|
|
1100
|
+
const clckMatch = cookies.match(new RegExp(`${cookieKey}=([^;]+)`));
|
|
1101
|
+
resolve({
|
|
1102
|
+
consent,
|
|
1103
|
+
hasClskCookie: cookies.includes(`${sessionKey}=`),
|
|
1104
|
+
hasClckCookie: cookies.includes(`${cookieKey}=`),
|
|
1105
|
+
clskCookieValue: clskMatch ? clskMatch[1] : "",
|
|
1106
|
+
clckCookieValue: clckMatch ? clckMatch[1] : "",
|
|
1107
|
+
clckConsentCrumb: clckMatch ? (clckMatch[1].split("^")[3] || "") : "",
|
|
1108
|
+
cookies
|
|
1109
|
+
});
|
|
1110
|
+
}
|
|
1111
|
+
}, false, false, true);
|
|
1112
|
+
|
|
1113
|
+
setTimeout(() => resolve(null), (window as any).CONSENT_CALLBACK_TIMEOUT);
|
|
1114
|
+
});
|
|
1115
|
+
}, { sessionKey: Constant.SessionKey, cookieKey: Constant.CookieKey });
|
|
1116
|
+
|
|
1117
|
+
// Verify initial state: implicit granted with cookies
|
|
1118
|
+
expect(initialConsent).not.toBeNull();
|
|
1119
|
+
const initialResult = initialConsent as ConsentTestResult;
|
|
1120
|
+
expect(initialResult.consent.source).toBe(ConsentSource.Implicit);
|
|
1121
|
+
expect(initialResult.consent.ad_Storage).toBe(Constant.Granted);
|
|
1122
|
+
expect(initialResult.consent.analytics_Storage).toBe(Constant.Granted);
|
|
1123
|
+
expect(initialResult.hasClckCookie).toBe(true);
|
|
1124
|
+
|
|
1125
|
+
// Revoke consent via V1 API
|
|
1126
|
+
const result = await page.evaluate(({ sessionKey, cookieKey }) => {
|
|
1127
|
+
return new Promise((resolve) => {
|
|
1128
|
+
// V1 API: consent(false) denies both ad_Storage and analytics_Storage
|
|
1129
|
+
(window as any).clarity("consent", false);
|
|
1130
|
+
|
|
1131
|
+
(window as any).clarity("metadata", (_data: any, _upgrade: any, consent: any) => {
|
|
1132
|
+
if (consent) {
|
|
1133
|
+
const cookies = document.cookie;
|
|
1134
|
+
const clskMatch = cookies.match(new RegExp(`${sessionKey}=([^;]+)`));
|
|
1135
|
+
const clckMatch = cookies.match(new RegExp(`${cookieKey}=([^;]+)`));
|
|
1136
|
+
resolve({
|
|
1137
|
+
consent,
|
|
1138
|
+
hasClskCookie: cookies.includes(`${sessionKey}=`),
|
|
1139
|
+
hasClckCookie: cookies.includes(`${cookieKey}=`),
|
|
1140
|
+
clskCookieValue: clskMatch ? clskMatch[1] : "",
|
|
1141
|
+
clckCookieValue: clckMatch ? clckMatch[1] : "",
|
|
1142
|
+
clckConsentCrumb: clckMatch ? (clckMatch[1].split("^")[3] || "") : "",
|
|
1143
|
+
cookies
|
|
1144
|
+
});
|
|
1145
|
+
}
|
|
1146
|
+
}, false, false, true);
|
|
1147
|
+
|
|
1148
|
+
setTimeout(() => resolve(null), (window as any).CONSENT_CALLBACK_TIMEOUT);
|
|
1149
|
+
});
|
|
1150
|
+
}, { sessionKey: Constant.SessionKey, cookieKey: Constant.CookieKey });
|
|
1151
|
+
|
|
1152
|
+
expect(result).not.toBeNull();
|
|
1153
|
+
const consentResult = result as ConsentTestResult;
|
|
1154
|
+
expect(consentResult.consent.source).toBe(ConsentSource.APIv1);
|
|
1155
|
+
expect(consentResult.consent.ad_Storage).toBe(Constant.Denied);
|
|
1156
|
+
expect(consentResult.consent.analytics_Storage).toBe(Constant.Denied);
|
|
1157
|
+
// Verify cookies are deleted when consent is revoked via V1 API
|
|
1158
|
+
expect(consentResult.hasClskCookie).toBe(false);
|
|
1159
|
+
expect(consentResult.hasClckCookie).toBe(false);
|
|
1160
|
+
expect(consentResult.clskCookieValue).toBe("");
|
|
1161
|
+
expect(consentResult.clckCookieValue).toBe("");
|
|
1162
|
+
});
|
|
1163
|
+
});
|
|
1164
|
+
|