import assert from 'node:assert/strict'; import { createConsentEngine, ENGINE_VERSION } from './core/consent.js'; import { isStoragePayload } from './core/storage.js'; import { isValidCategoriesObject } from './core/categories.js'; let jar = new Map(); let blockWrites = false; globalThis.location = { protocol: 'http:' }; globalThis.document = {}; Object.defineProperty(globalThis.document, 'cookie', { configurable: true, get() { return [...jar.entries()].map(([k,v]) => `${k}=${v}`).join('; '); }, set(value) { if (blockWrites) return; const parts = value.split(';').map(x => x.trim()); const [name, raw = ''] = parts[0].split('='); const maxAge = parts.find(x => /^Max-Age=/i.test(x)); if (maxAge && maxAge.toLowerCase() === 'max-age=0') { jar.delete(name); return; } jar.set(name, raw); } }); function clearCookie() { jar.clear(); blockWrites = false; } function make() { return createConsentEngine({ policyVersion: '2026-01', jurisdiction: 'global', storage: { name: 'cc_consent', duration: 180, path: '/', sameSite: 'Lax' } }); } let passed = 0; function test(name, fn) { try { fn(); passed++; console.log(`PASS ${name}`); } catch (e) { console.error(`FAIL ${name}\n`, e); process.exitCode = 1; } } clearCookie(); test('default state is undecided', () => { const e = make(); e.initialize(); const s = e.getState(); assert.equal(s.categories.necessary, 'granted'); assert.equal(s.categories.analytics, 'unknown'); assert.equal(s.hasDecision, false); }); test('accept all', () => { clearCookie(); const e = make(); e.initialize(); let changed = 0, accepted = 0; e.on('consent:changed', () => changed++); e.on('consent:accepted', () => accepted++); e.acceptAll(); assert.equal(e.getState().hasDecision, true); assert.equal(e.getState().categories.analytics, 'granted'); assert.equal(changed, 1); assert.equal(accepted, 1); }); test('accept all is idempotent', () => { clearCookie(); const e = make(); e.initialize(); let events = 0; e.on('consent:changed', () => events++); e.acceptAll(); const before = e.getState().timestamp; e.acceptAll(); assert.equal(events, 1); assert.equal(e.getState().timestamp, before); }); test('persistence loads from storage', () => { clearCookie(); const e = make(); e.initialize(); e.rejectAll(); const fresh = make(); fresh.initialize(); const s = fresh.getState(); assert.equal(s.source, 'storage'); assert.equal(s.categories.analytics, 'denied'); }); test('reject all is idempotent', () => { clearCookie(); const e = make(); e.initialize(); let events = 0; e.on('consent:changed', () => events++); e.rejectAll(); e.rejectAll(); assert.equal(events, 1); }); test('selective consent', () => { clearCookie(); const e = make(); e.initialize(); e.setConsent({ analytics: 'granted', marketing: 'denied', preferences: 'denied' }); assert.equal(e.getState().categories.analytics, 'granted'); assert.equal(e.isComplete(), true); }); test('invalid consent value throws', () => { clearCookie(); const e = make(); e.initialize(); assert.throws(() => e.setConsent({ analytics: 'banana' }), TypeError); }); test('necessary cannot be denied', () => { clearCookie(); const e = make(); e.initialize(); assert.throws(() => e.setConsent({ necessary: 'denied', analytics: 'granted' }), TypeError); assert.equal(e.getState().categories.necessary, 'granted'); assert.equal(e.getState().categories.analytics, 'unknown'); }); test('revoke is idempotent', () => { clearCookie(); const e = make(); e.initialize(); e.acceptAll(); let revoked = 0; e.on('consent:revoked', () => revoked++); e.revoke(); e.revoke(); assert.equal(revoked, 1); assert.equal(e.getState().categories.analytics, 'denied'); }); test('reset removes persistence', () => { clearCookie(); const e = make(); e.initialize(); e.acceptAll(); e.reset(); assert.equal(e.isComplete(), false); assert.equal(document.cookie, ''); const fresh = make(); fresh.initialize(); assert.equal(fresh.isComplete(), false); assert.equal(fresh.getState().source, 'default'); }); test('reset does not lie when storage removal fails', () => { clearCookie(); const e = make(); e.initialize(); e.acceptAll(); blockWrites = true; let reset = 0, errors = 0; e.on('consent:reset', () => reset++); e.on('storage:error', () => errors++); const before = e.getState(); e.reset(); assert.equal(reset, 0); assert.equal(errors, 1); assert.equal(e.getState().categories.analytics, before.categories.analytics); }); test('strict stored envelope validation', () => { assert.equal(isStoragePayload({}), false); assert.equal(isStoragePayload({ engineVersion: ENGINE_VERSION, policyVersion: '2026-01', timestamp: Date.now(), categories: {}, jurisdiction: 'global', gpc: false }), true); }); test('strict category validation', () => { assert.equal(isValidCategoriesObject({ necessary:'granted', preferences:'unknown', analytics:'granted', marketing:'denied' }), true); assert.equal(isValidCategoriesObject({ necessary:'denied', preferences:'unknown', analytics:'granted', marketing:'denied' }), false); assert.equal(isValidCategoriesObject({ necessary:'granted', preferences:'banana', analytics:'granted', marketing:'denied' }), false); }); test('initialize is idempotent', () => { clearCookie(); const e = make(); let initialized = 0; e.on('initialized', () => initialized++); e.initialize(); e.initialize(); assert.equal(initialized, 1); }); test('policy mismatch removes valid cookie', () => { clearCookie(); const e = make(); e.initialize(); e.acceptAll(); const fresh = createConsentEngine({ policyVersion:'2027-01', jurisdiction:'global', storage:{ name:'cc_consent', duration:180, path:'/', sameSite:'Lax' } }); fresh.initialize(); assert.equal(fresh.isComplete(), false); assert.equal(document.cookie, ''); }); test('expired cookie is rejected', () => { clearCookie(); const e = make(); e.initialize(); e.acceptAll(); const raw = decodeURIComponent(document.cookie.split('=').slice(1).join('=')); const payload = JSON.parse(raw); payload.timestamp = Date.now() - 181*24*60*60*1000; document.cookie = `cc_consent=${encodeURIComponent(JSON.stringify(payload))}; Path=/; SameSite=Lax`; const fresh = make(); let expired = 0; fresh.on('consent:expired', () => expired++); fresh.initialize(); assert.equal(expired, 1); assert.equal(fresh.isComplete(), false); assert.equal(document.cookie, ''); }); test('necessary denial is explicitly rejected', () => { clearCookie(); const e = make(); e.initialize(); assert.throws(() => e.setConsent({ necessary: 'denied' }), TypeError); assert.equal(e.getState().categories.necessary, 'granted'); }); test('invalid persisted category payload is ignored and removed', () => { clearCookie(); const bad = { engineVersion: ENGINE_VERSION, policyVersion: '2026-01', timestamp: Date.now(), categories: { necessary: 'granted', preferences: 'banana', analytics: 'granted', marketing: 'denied' }, jurisdiction: 'global', gpc: false }; document.cookie = `cc_consent=${encodeURIComponent(JSON.stringify(bad))}; Path=/; SameSite=Lax`; const e = make(); e.initialize(); assert.equal(e.isComplete(), false); assert.equal(document.cookie, ''); }); test('future timestamp is rejected', () => { clearCookie(); const e = make(); e.initialize(); e.acceptAll(); const raw = decodeURIComponent(document.cookie.split('=').slice(1).join('=')); const payload = JSON.parse(raw); payload.timestamp = Date.now() + 60 * 60 * 1000; document.cookie = `cc_consent=${encodeURIComponent(JSON.stringify(payload))}; Path=/; SameSite=Lax`; const fresh = make(); fresh.initialize(); assert.equal(fresh.isComplete(), false); assert.equal(document.cookie, ''); }); console.log(`\n${passed} tests passed.`); if (process.exitCode) process.exit(1);