Add adversarial test suite
This commit is contained in:
Executable
+50
@@ -0,0 +1,50 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -u
|
||||||
|
|
||||||
|
echo "========================================"
|
||||||
|
echo "Universal Cookie Consent — Test Suite"
|
||||||
|
echo "========================================"
|
||||||
|
echo
|
||||||
|
|
||||||
|
run_test() {
|
||||||
|
local name="$1"
|
||||||
|
local command="$2"
|
||||||
|
|
||||||
|
echo "----------------------------------------"
|
||||||
|
echo "$name"
|
||||||
|
echo "----------------------------------------"
|
||||||
|
|
||||||
|
if eval "$command"; then
|
||||||
|
echo
|
||||||
|
echo "PASS: $name"
|
||||||
|
echo
|
||||||
|
else
|
||||||
|
echo
|
||||||
|
echo "FAIL: $name"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
run_test "Core" \
|
||||||
|
"node test-core.mjs"
|
||||||
|
|
||||||
|
run_test "Jurisdiction" \
|
||||||
|
"node tests/jurisdiction-test.mjs"
|
||||||
|
|
||||||
|
run_test "Integration" \
|
||||||
|
"node tests/integration/integration-test.mjs"
|
||||||
|
|
||||||
|
run_test "Audit" \
|
||||||
|
"node tests/audit/audit-test.mjs"
|
||||||
|
|
||||||
|
run_test "Reliability" \
|
||||||
|
"node tests/reliability/reliability-test.mjs"
|
||||||
|
|
||||||
|
run_test "Adversarial" \
|
||||||
|
"node tests/adversarial/adversarial-test.mjs"
|
||||||
|
|
||||||
|
echo "========================================"
|
||||||
|
echo "ALL TEST GROUPS PASSED"
|
||||||
|
echo "========================================"
|
||||||
@@ -0,0 +1,640 @@
|
|||||||
|
import assert from "node:assert/strict";
|
||||||
|
|
||||||
|
import { createConsentEngine } from "../../core/consent.js";
|
||||||
|
import { isStoragePayload } from "../../core/storage.js";
|
||||||
|
import {
|
||||||
|
isValidCategoriesObject
|
||||||
|
} from "../../core/categories.js";
|
||||||
|
import {
|
||||||
|
resolveJurisdiction,
|
||||||
|
isValidResolution
|
||||||
|
} from "../../jurisdiction/resolver.js";
|
||||||
|
import {
|
||||||
|
createIntegratedConsentEngine
|
||||||
|
} from "../../integration/index.js";
|
||||||
|
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* Browser-like storage environment */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
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(([key, value]) => `${key}=${value}`)
|
||||||
|
.join("; ");
|
||||||
|
},
|
||||||
|
|
||||||
|
set(value) {
|
||||||
|
if (blockWrites) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const parts = value.split(";").map((item) => item.trim());
|
||||||
|
const [name, raw = ""] = parts[0].split("=");
|
||||||
|
|
||||||
|
const maxAge = parts.find(
|
||||||
|
(item) => /^Max-Age=/i.test(item)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (maxAge && maxAge.toLowerCase() === "max-age=0") {
|
||||||
|
jar.delete(name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
jar.set(name, raw);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function clearEnvironment() {
|
||||||
|
jar.clear();
|
||||||
|
blockWrites = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function make(options = {}) {
|
||||||
|
return createConsentEngine({
|
||||||
|
policyVersion: "2026-01",
|
||||||
|
jurisdiction: "global",
|
||||||
|
storage: {
|
||||||
|
name: "cc_adversarial",
|
||||||
|
duration: 180,
|
||||||
|
path: "/",
|
||||||
|
sameSite: "Lax"
|
||||||
|
},
|
||||||
|
...options
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let passed = 0;
|
||||||
|
|
||||||
|
function test(name, fn) {
|
||||||
|
clearEnvironment();
|
||||||
|
|
||||||
|
try {
|
||||||
|
fn();
|
||||||
|
passed += 1;
|
||||||
|
console.log(`PASS ${name}`);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`FAIL ${name}`);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* Input boundary */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
test("null configuration falls back safely", () => {
|
||||||
|
const consent = createConsentEngine(null);
|
||||||
|
|
||||||
|
consent.initialize();
|
||||||
|
|
||||||
|
assert.equal(consent.getState().jurisdiction, "global");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("array configuration falls back safely", () => {
|
||||||
|
const consent = createConsentEngine([]);
|
||||||
|
|
||||||
|
consent.initialize();
|
||||||
|
|
||||||
|
assert.equal(consent.getState().jurisdiction, "global");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("invalid storage object does not corrupt defaults", () => {
|
||||||
|
const consent = createConsentEngine({
|
||||||
|
storage: "invalid"
|
||||||
|
});
|
||||||
|
|
||||||
|
consent.initialize();
|
||||||
|
|
||||||
|
assert.equal(consent.getState().jurisdiction, "global");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("invalid storage duration does not corrupt initialization", () => {
|
||||||
|
const consent = make({
|
||||||
|
storage: {
|
||||||
|
duration: "invalid"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
consent.initialize();
|
||||||
|
|
||||||
|
assert.equal(consent.getState().hasDecision, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* Consent operation boundaries */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
test("empty consent payload does not create a decision", () => {
|
||||||
|
const consent = make();
|
||||||
|
|
||||||
|
consent.initialize();
|
||||||
|
|
||||||
|
const state = consent.setConsent({});
|
||||||
|
|
||||||
|
assert.equal(state.hasDecision, false);
|
||||||
|
assert.equal(state.categories.analytics, "unknown");
|
||||||
|
assert.equal(state.categories.marketing, "unknown");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("null consent payload is rejected", () => {
|
||||||
|
const consent = make();
|
||||||
|
|
||||||
|
consent.initialize();
|
||||||
|
|
||||||
|
assert.throws(
|
||||||
|
() => consent.setConsent(null),
|
||||||
|
TypeError
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("array consent payload is rejected", () => {
|
||||||
|
const consent = make();
|
||||||
|
|
||||||
|
consent.initialize();
|
||||||
|
|
||||||
|
assert.throws(
|
||||||
|
() => consent.setConsent([]),
|
||||||
|
TypeError
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("unknown consent property is ignored without changing state", () => {
|
||||||
|
const consent = make();
|
||||||
|
|
||||||
|
consent.initialize();
|
||||||
|
|
||||||
|
const before = consent.getState();
|
||||||
|
|
||||||
|
const after = consent.setConsent({
|
||||||
|
unknownCategory: "granted"
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.deepEqual(after.categories, before.categories);
|
||||||
|
assert.equal(after.hasDecision, before.hasDecision);
|
||||||
|
assert.equal(after.jurisdiction, before.jurisdiction);
|
||||||
|
assert.equal(after.timestamp, before.timestamp);
|
||||||
|
});
|
||||||
|
test("necessary cannot be changed to unknown", () => {
|
||||||
|
const consent = make();
|
||||||
|
|
||||||
|
consent.initialize();
|
||||||
|
|
||||||
|
assert.throws(
|
||||||
|
() => consent.setConsent({
|
||||||
|
necessary: "unknown"
|
||||||
|
}),
|
||||||
|
TypeError
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("revoke before acceptance remains deterministic", () => {
|
||||||
|
const consent = make();
|
||||||
|
|
||||||
|
consent.initialize();
|
||||||
|
|
||||||
|
const first = consent.revoke();
|
||||||
|
const second = consent.revoke();
|
||||||
|
|
||||||
|
assert.deepEqual(second.categories, first.categories);
|
||||||
|
assert.equal(second.hasDecision, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("reset before any decision remains deterministic", () => {
|
||||||
|
const consent = make();
|
||||||
|
|
||||||
|
consent.initialize();
|
||||||
|
|
||||||
|
const first = consent.reset();
|
||||||
|
const second = consent.reset();
|
||||||
|
|
||||||
|
assert.equal(first.hasDecision, false);
|
||||||
|
assert.equal(second.hasDecision, false);
|
||||||
|
assert.deepEqual(second.categories, first.categories);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* Operation sequences */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
test("accept then reject produces the expected final state", () => {
|
||||||
|
const consent = make();
|
||||||
|
|
||||||
|
consent.initialize();
|
||||||
|
consent.acceptAll();
|
||||||
|
|
||||||
|
const state = consent.rejectAll();
|
||||||
|
|
||||||
|
assert.equal(state.hasDecision, true);
|
||||||
|
assert.equal(state.categories.necessary, "granted");
|
||||||
|
assert.equal(state.categories.preferences, "denied");
|
||||||
|
assert.equal(state.categories.analytics, "denied");
|
||||||
|
assert.equal(state.categories.marketing, "denied");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("reject then accept produces the expected final state", () => {
|
||||||
|
const consent = make();
|
||||||
|
|
||||||
|
consent.initialize();
|
||||||
|
consent.rejectAll();
|
||||||
|
|
||||||
|
const state = consent.acceptAll();
|
||||||
|
|
||||||
|
assert.equal(state.hasDecision, true);
|
||||||
|
assert.equal(state.categories.necessary, "granted");
|
||||||
|
assert.equal(state.categories.preferences, "granted");
|
||||||
|
assert.equal(state.categories.analytics, "granted");
|
||||||
|
assert.equal(state.categories.marketing, "granted");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("reset after acceptance removes the decision", () => {
|
||||||
|
const consent = make();
|
||||||
|
|
||||||
|
consent.initialize();
|
||||||
|
consent.acceptAll();
|
||||||
|
|
||||||
|
const state = consent.reset();
|
||||||
|
|
||||||
|
assert.equal(state.hasDecision, false);
|
||||||
|
assert.equal(state.categories.necessary, "granted");
|
||||||
|
assert.equal(state.categories.preferences, "unknown");
|
||||||
|
assert.equal(state.categories.analytics, "unknown");
|
||||||
|
assert.equal(state.categories.marketing, "unknown");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("revoke followed by reset returns to undecided state", () => {
|
||||||
|
const consent = make();
|
||||||
|
|
||||||
|
consent.initialize();
|
||||||
|
consent.acceptAll();
|
||||||
|
consent.revoke();
|
||||||
|
|
||||||
|
const state = consent.reset();
|
||||||
|
|
||||||
|
assert.equal(state.hasDecision, false);
|
||||||
|
assert.equal(state.categories.preferences, "unknown");
|
||||||
|
assert.equal(state.categories.analytics, "unknown");
|
||||||
|
assert.equal(state.categories.marketing, "unknown");
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* Deep isolation */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
test("returned state nested mutation cannot alter internal state", () => {
|
||||||
|
const consent = make();
|
||||||
|
|
||||||
|
consent.initialize();
|
||||||
|
consent.acceptAll();
|
||||||
|
|
||||||
|
const state = consent.getState();
|
||||||
|
|
||||||
|
state.categories.preferences = "denied";
|
||||||
|
state.categories.analytics = "unknown";
|
||||||
|
|
||||||
|
const current = consent.getState();
|
||||||
|
|
||||||
|
assert.equal(current.categories.preferences, "granted");
|
||||||
|
assert.equal(current.categories.analytics, "granted");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("two engines remain isolated after independent transitions", () => {
|
||||||
|
const first = make({
|
||||||
|
jurisdiction: "us-ma"
|
||||||
|
});
|
||||||
|
|
||||||
|
const second = make({
|
||||||
|
jurisdiction: "eu"
|
||||||
|
});
|
||||||
|
|
||||||
|
first.initialize();
|
||||||
|
second.initialize();
|
||||||
|
|
||||||
|
first.acceptAll();
|
||||||
|
|
||||||
|
assert.equal(first.getState().jurisdiction, "us-ma");
|
||||||
|
assert.equal(second.getState().jurisdiction, "eu");
|
||||||
|
assert.equal(first.getState().hasDecision, true);
|
||||||
|
assert.equal(second.getState().hasDecision, false);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* Storage envelope adversarial cases */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
test("storage payload rejects NaN timestamp", () => {
|
||||||
|
assert.equal(
|
||||||
|
isStoragePayload({
|
||||||
|
engineVersion: "1.0.1",
|
||||||
|
policyVersion: "2026-01",
|
||||||
|
timestamp: NaN,
|
||||||
|
categories: {
|
||||||
|
necessary: "granted",
|
||||||
|
preferences: "unknown",
|
||||||
|
analytics: "unknown",
|
||||||
|
marketing: "unknown"
|
||||||
|
},
|
||||||
|
jurisdiction: "global",
|
||||||
|
gpc: false
|
||||||
|
}),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("storage payload rejects infinite timestamp", () => {
|
||||||
|
assert.equal(
|
||||||
|
isStoragePayload({
|
||||||
|
engineVersion: "1.0.1",
|
||||||
|
policyVersion: "2026-01",
|
||||||
|
timestamp: Infinity,
|
||||||
|
categories: {
|
||||||
|
necessary: "granted",
|
||||||
|
preferences: "unknown",
|
||||||
|
analytics: "unknown",
|
||||||
|
marketing: "unknown"
|
||||||
|
},
|
||||||
|
jurisdiction: "global",
|
||||||
|
gpc: false
|
||||||
|
}),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("storage payload rejects empty engine version", () => {
|
||||||
|
assert.equal(
|
||||||
|
isStoragePayload({
|
||||||
|
engineVersion: "",
|
||||||
|
policyVersion: "2026-01",
|
||||||
|
timestamp: Date.now(),
|
||||||
|
categories: {
|
||||||
|
necessary: "granted",
|
||||||
|
preferences: "unknown",
|
||||||
|
analytics: "unknown",
|
||||||
|
marketing: "unknown"
|
||||||
|
},
|
||||||
|
jurisdiction: "global",
|
||||||
|
gpc: false
|
||||||
|
}),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("storage payload rejects non-boolean GPC", () => {
|
||||||
|
assert.equal(
|
||||||
|
isStoragePayload({
|
||||||
|
engineVersion: "1.0.1",
|
||||||
|
policyVersion: "2026-01",
|
||||||
|
timestamp: Date.now(),
|
||||||
|
categories: {
|
||||||
|
necessary: "granted",
|
||||||
|
preferences: "unknown",
|
||||||
|
analytics: "unknown",
|
||||||
|
marketing: "unknown"
|
||||||
|
},
|
||||||
|
jurisdiction: "global",
|
||||||
|
gpc: "true"
|
||||||
|
}),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("storage payload rejects array categories", () => {
|
||||||
|
assert.equal(
|
||||||
|
isStoragePayload({
|
||||||
|
engineVersion: "1.0.1",
|
||||||
|
policyVersion: "2026-01",
|
||||||
|
timestamp: Date.now(),
|
||||||
|
categories: [],
|
||||||
|
jurisdiction: "global",
|
||||||
|
gpc: false
|
||||||
|
}),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("storage payload rejects missing jurisdiction", () => {
|
||||||
|
assert.equal(
|
||||||
|
isStoragePayload({
|
||||||
|
engineVersion: "1.0.1",
|
||||||
|
policyVersion: "2026-01",
|
||||||
|
timestamp: Date.now(),
|
||||||
|
categories: {
|
||||||
|
necessary: "granted",
|
||||||
|
preferences: "unknown",
|
||||||
|
analytics: "unknown",
|
||||||
|
marketing: "unknown"
|
||||||
|
},
|
||||||
|
gpc: false
|
||||||
|
}),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* Category contract */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
test("category contract rejects null", () => {
|
||||||
|
assert.equal(
|
||||||
|
isValidCategoriesObject(null),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("category contract rejects arrays", () => {
|
||||||
|
assert.equal(
|
||||||
|
isValidCategoriesObject([]),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("category contract rejects unknown consent value", () => {
|
||||||
|
assert.equal(
|
||||||
|
isValidCategoriesObject({
|
||||||
|
necessary: "granted",
|
||||||
|
preferences: "unknown",
|
||||||
|
analytics: "invalid",
|
||||||
|
marketing: "unknown"
|
||||||
|
}),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* Jurisdiction adversarial cases */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
test("jurisdiction resolver rejects null input", () => {
|
||||||
|
assert.throws(
|
||||||
|
() => resolveJurisdiction(null),
|
||||||
|
TypeError
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("jurisdiction resolver rejects array input", () => {
|
||||||
|
assert.throws(
|
||||||
|
() => resolveJurisdiction([]),
|
||||||
|
TypeError
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("fixed jurisdiction trims surrounding whitespace", () => {
|
||||||
|
const result = resolveJurisdiction({
|
||||||
|
mode: "fixed",
|
||||||
|
jurisdiction: " us-ma "
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(result.jurisdiction.id, "us-ma");
|
||||||
|
assert.equal(isValidResolution(result), true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("fixed jurisdiction rejects whitespace-only value", () => {
|
||||||
|
assert.throws(
|
||||||
|
() => resolveJurisdiction({
|
||||||
|
mode: "fixed",
|
||||||
|
jurisdiction: " "
|
||||||
|
}),
|
||||||
|
TypeError
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("invalid signal source is ignored during auto resolution", () => {
|
||||||
|
const result = resolveJurisdiction({
|
||||||
|
mode: "auto",
|
||||||
|
request: {
|
||||||
|
jurisdiction: "us-ma",
|
||||||
|
source: "invalid-source"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(result.source, "fallback");
|
||||||
|
assert.equal(result.jurisdiction.id, "global");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("valid server signal defeats lower-trust browser signal", () => {
|
||||||
|
const result = resolveJurisdiction({
|
||||||
|
mode: "auto",
|
||||||
|
request: {
|
||||||
|
jurisdiction: "us-ma",
|
||||||
|
source: "server"
|
||||||
|
},
|
||||||
|
visitor: {
|
||||||
|
jurisdiction: "eu",
|
||||||
|
source: "browser"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(result.jurisdiction.id, "us-ma");
|
||||||
|
assert.equal(result.source, "server");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("explicit fixed mode defeats conflicting request signals", () => {
|
||||||
|
const result = resolveJurisdiction({
|
||||||
|
mode: "fixed",
|
||||||
|
jurisdiction: "eu",
|
||||||
|
request: {
|
||||||
|
jurisdiction: "us-ma",
|
||||||
|
source: "server"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(result.jurisdiction.id, "eu");
|
||||||
|
assert.equal(result.source, "site-config");
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* Integration boundary */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
test("resolved jurisdiction cannot be overridden by Core jurisdiction option", () => {
|
||||||
|
const engine = createIntegratedConsentEngine({
|
||||||
|
jurisdiction: {
|
||||||
|
mode: "fixed",
|
||||||
|
jurisdiction: "eu"
|
||||||
|
},
|
||||||
|
core: {
|
||||||
|
jurisdiction: "us-ma"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
engine.initialize();
|
||||||
|
|
||||||
|
assert.equal(
|
||||||
|
engine.getState().jurisdiction,
|
||||||
|
"eu"
|
||||||
|
);
|
||||||
|
|
||||||
|
assert.equal(
|
||||||
|
engine.getJurisdictionContext().resolution.jurisdiction.id,
|
||||||
|
"eu"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("integration rejects invalid jurisdiction before Core creation", () => {
|
||||||
|
assert.throws(
|
||||||
|
() => createIntegratedConsentEngine({
|
||||||
|
jurisdiction: {
|
||||||
|
mode: "fixed",
|
||||||
|
jurisdiction: "unknown"
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
RangeError
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
/* GPC boundary */
|
||||||
|
/* -------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
test("GPC remains state information under adversarial consent sequence", () => {
|
||||||
|
const consent = make();
|
||||||
|
|
||||||
|
consent.initialize();
|
||||||
|
consent.setGpc(true);
|
||||||
|
|
||||||
|
const state = consent.getState();
|
||||||
|
|
||||||
|
assert.equal(state.gpc, true);
|
||||||
|
assert.equal(state.categories.necessary, "granted");
|
||||||
|
assert.equal(state.categories.preferences, "unknown");
|
||||||
|
assert.equal(state.categories.analytics, "unknown");
|
||||||
|
assert.equal(state.categories.marketing, "unknown");
|
||||||
|
});
|
||||||
|
|
||||||
|
test("explicit acceptance remains explicit after GPC activation", () => {
|
||||||
|
const consent = make();
|
||||||
|
|
||||||
|
consent.initialize();
|
||||||
|
consent.setGpc(true);
|
||||||
|
consent.acceptAll();
|
||||||
|
|
||||||
|
const state = consent.getState();
|
||||||
|
|
||||||
|
assert.equal(state.gpc, true);
|
||||||
|
assert.equal(state.hasDecision, true);
|
||||||
|
assert.equal(state.categories.preferences, "granted");
|
||||||
|
assert.equal(state.categories.analytics, "granted");
|
||||||
|
assert.equal(state.categories.marketing, "granted");
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
console.log();
|
||||||
|
console.log(`${passed} adversarial tests passed.`);
|
||||||
Reference in New Issue
Block a user