Files
cookie-consent-jurisdiction…/tests/audit/audit-test.mjs
T

257 lines
7.8 KiB
JavaScript

import assert from "node:assert/strict";
import { createIntegratedConsentEngine } from "../../integration/index.js";
// This suite exercises real persistence (acceptAll/revoke/reset expected to
// take effect), unlike tests/integration/integration-test.mjs which
// deliberately asserts the no-op behavior of a bare Node environment.
// A document.cookie mock is required here for the same reason it is
// required in test-core.mjs.
let jar = new Map();
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) {
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);
}
});
let passed = 0;
function test(name, fn) {
// Each test starts from a clean cookie jar so persisted consent from
// one test cannot leak into the next (they share default jurisdiction
// and policyVersion, so a stale cookie would otherwise be reloaded).
jar.clear();
try {
fn();
console.log(`PASS ${name}`);
passed += 1;
} catch (error) {
console.error(`FAIL ${name}`);
throw error;
}
}
function createEngine(jurisdiction = "us-ma") {
return createIntegratedConsentEngine({
jurisdiction: {
mode: "fixed",
jurisdiction
}
});
}
test("dynamic jurisdiction is reflected in Core state", () => {
const consent = createEngine("global");
consent.initialize();
const state = consent.setJurisdiction("us-ma");
assert.equal(state.jurisdiction, "us-ma");
});
test("GPC state is represented without granting optional consent", () => {
const consent = createEngine();
consent.initialize();
const state = consent.setGpc(true);
assert.equal(state.gpc, true);
assert.equal(state.hasDecision, false);
assert.equal(state.categories.preferences, "unknown");
assert.equal(state.categories.analytics, "unknown");
assert.equal(state.categories.marketing, "unknown");
});
test("revoke produces the Core-defined denied state and is idempotent", () => {
const consent = createEngine();
consent.initialize();
consent.acceptAll();
const accepted = consent.getState();
assert.equal(accepted.hasDecision, true);
let revokedEvents = 0;
consent.on("consent:revoked", () => revokedEvents++);
const revoked = consent.revoke();
const secondRevoke = consent.revoke();
assert.equal(revoked.categories.necessary, "granted");
assert.equal(revoked.categories.preferences, "denied");
assert.equal(revoked.categories.analytics, "denied");
assert.equal(revoked.categories.marketing, "denied");
assert.equal(secondRevoke.categories.analytics, "denied");
assert.equal(revokedEvents, 1);
});
test("reset returns Core to an undecided state", () => {
const consent = createEngine();
consent.initialize();
consent.acceptAll();
const reset = consent.reset();
assert.equal(reset.hasDecision, false);
assert.equal(reset.categories.necessary, "granted");
assert.equal(reset.categories.preferences, "unknown");
assert.equal(reset.categories.analytics, "unknown");
assert.equal(reset.categories.marketing, "unknown");
});
test("policy version is part of the Core state", () => {
const consent = createEngine();
const config = consent.getConfig();
assert.equal(typeof config.policyVersion, "string");
assert.ok(config.policyVersion.length > 0);
});
test("persistence preserves the resolved jurisdiction after acceptance", () => {
const consent = createEngine("us-ma");
consent.initialize();
const saved = consent.acceptAll();
assert.equal(saved.hasDecision, true);
assert.equal(saved.jurisdiction, "us-ma");
});
test("event sequence reports the consent transition", () => {
const consent = createEngine();
const events = [];
consent.on("consent:changed", () => events.push("changed"));
consent.on("consent:accepted", () => events.push("accepted"));
consent.initialize();
consent.acceptAll();
assert.deepEqual(events, ["changed", "accepted"]);
});
test("Core state remains isolated from returned object mutation", () => {
const consent = createEngine();
consent.initialize();
const state = consent.getState();
state.categories.analytics = "granted";
state.jurisdiction = "changed";
const current = consent.getState();
assert.equal(current.categories.analytics, "unknown");
assert.equal(current.jurisdiction, "us-ma");
});
test("separate Core instances do not share in-memory state", () => {
const first = createEngine("us-ma");
const second = createEngine("eu");
first.initialize();
second.initialize();
first.setConsent({ analytics: "granted" });
assert.equal(first.getState().categories.analytics, "granted");
assert.equal(second.getState().categories.analytics, "unknown");
assert.equal(first.getState().jurisdiction, "us-ma");
assert.equal(second.getState().jurisdiction, "eu");
});
test("partial consent remains undecided until all optional categories are resolved", () => {
const consent = createEngine();
consent.initialize();
const state = consent.setConsent({ analytics: "granted" });
assert.equal(state.categories.analytics, "granted");
assert.equal(state.categories.preferences, "unknown");
assert.equal(state.categories.marketing, "unknown");
assert.equal(state.hasDecision, false);
assert.equal(consent.isComplete(), false);
});
test("necessary remains granted through valid consent changes", () => {
const consent = createEngine();
consent.initialize();
const state = consent.setConsent({
preferences: "denied",
analytics: "granted",
marketing: "denied"
});
assert.equal(state.categories.necessary, "granted");
assert.equal(state.categories.preferences, "denied");
assert.equal(state.categories.analytics, "granted");
assert.equal(state.categories.marketing, "denied");
});
test("acceptAll is idempotent through the integration boundary", () => {
const consent = createEngine();
consent.initialize();
let changed = 0;
let accepted = 0;
consent.on("consent:changed", () => changed++);
consent.on("consent:accepted", () => accepted++);
consent.acceptAll();
const first = consent.getState();
consent.acceptAll();
const second = consent.getState();
assert.equal(first.hasDecision, true);
assert.equal(second.hasDecision, true);
assert.equal(changed, 1);
assert.equal(accepted, 1);
assert.equal(second.timestamp, first.timestamp);
});
test("reset is idempotent through the integration boundary", () => {
const consent = createEngine();
consent.initialize();
consent.acceptAll();
let reset = 0;
consent.on("consent:reset", () => reset++);
consent.reset();
const first = consent.getState();
consent.reset();
const second = consent.getState();
assert.equal(first.hasDecision, false);
assert.equal(second.hasDecision, false);
assert.equal(second.categories.analytics, "unknown");
});
test("GPC never grants optional categories through the integration boundary", () => {
const consent = createEngine();
consent.initialize();
const state = consent.setGpc(true);
assert.equal(state.gpc, true);
assert.equal(state.categories.preferences, "unknown");
assert.equal(state.categories.analytics, "unknown");
assert.equal(state.categories.marketing, "unknown");
assert.equal(state.hasDecision, false);
});
console.log(`${passed} audit tests passed.`);