Incognito-Wiki/tests/matomo-consent.test.mjs

132 lines
5.3 KiB
JavaScript

import assert from 'node:assert/strict';
import { readFile } from 'node:fs/promises';
import test from 'node:test';
import vm from 'node:vm';
import { parseHTML } from 'linkedom';
const controllerSource = await readFile('public/matomo-consent.js', 'utf8').catch(() => '');
const storageKey = 'incognito.analytics-consent.v1';
function queuedCommands(window) {
return JSON.parse(JSON.stringify(window._paq));
}
function runController({ decision, storageError = false } = {}) {
const { document } = parseHTML('<!doctype html><html><head></head><body></body></html>');
const values = new Map(decision ? [[storageKey, decision]] : []);
const localStorage = {
getItem(key) {
if (storageError) throw new Error('storage unavailable');
return values.get(key) ?? null;
},
setItem(key, value) {
if (storageError) throw new Error('storage unavailable');
values.set(key, value);
},
};
const window = { localStorage };
vm.runInNewContext(controllerSource, { window, document });
return { window, document, values };
}
test('first visit offers equal choices without initializing Matomo', () => {
const { window, document } = runController();
const banner = document.getElementById('incognito-analytics-consent');
const accept = document.getElementById('incognito-analytics-accept');
const decline = document.getElementById('incognito-analytics-decline');
assert.ok(banner, 'consent banner should exist');
assert.ok(accept, 'accept button should exist');
assert.ok(decline, 'decline button should exist');
assert.equal(window._paq, undefined);
assert.equal(document.querySelector('script[src*="analytics.msvincognito.nl"]'), null);
assert.equal(banner.hidden, false);
assert.equal(accept.className, decline.className);
assert.equal(
document.querySelector('#incognito-analytics-consent a').href,
'https://msvincognito.nl/privacy-policy',
);
});
test('accepting persists consent and initializes cookieless Matomo once', () => {
const { window, document, values } = runController();
const accept = document.getElementById('incognito-analytics-accept');
assert.ok(accept, 'accept button should exist');
accept.click();
accept.click();
assert.equal(values.get(storageKey), 'accepted');
assert.deepEqual(queuedCommands(window), [
['requireConsent'],
['disableCookies'],
['setConsentGiven'],
['setTrackerUrl', 'https://analytics.msvincognito.nl/matomo.php'],
['setSiteId', '1'],
['trackPageView'],
['enableLinkTracking'],
]);
const scripts = document.querySelectorAll('#incognito-matomo-script');
assert.equal(scripts.length, 1);
assert.equal(scripts[0].src, 'https://analytics.msvincognito.nl/matomo.js');
assert.equal(scripts[0].async, true);
});
test('declining persists the choice without creating Matomo state', () => {
const { window, document, values } = runController();
document.getElementById('incognito-analytics-decline').click();
assert.equal(values.get(storageKey), 'declined');
assert.equal(window._paq, undefined);
assert.equal(document.getElementById('incognito-matomo-script'), null);
assert.equal(document.getElementById('incognito-privacy-settings').hidden, false);
});
test('remembered acceptance tracks on a later page load', () => {
const { window, document } = runController({ decision: 'accepted' });
assert.ok(window._paq.some(([method]) => method === 'trackPageView'));
assert.equal(document.querySelectorAll('#incognito-matomo-script').length, 1);
assert.equal(document.getElementById('incognito-analytics-consent').hidden, true);
});
test('remembered decline never initializes Matomo', () => {
const { window, document } = runController({ decision: 'declined' });
assert.equal(window._paq, undefined);
assert.equal(document.getElementById('incognito-matomo-script'), null);
assert.equal(document.getElementById('incognito-privacy-settings').hidden, false);
});
test('storage failure defaults to no tracking and keeps consent available', () => {
const { window, document } = runController({ storageError: true });
assert.equal(window._paq, undefined);
assert.equal(document.getElementById('incognito-analytics-consent').hidden, false);
});
test('privacy settings allow an accepted visitor to withdraw consent', () => {
const { window, document, values } = runController({ decision: 'accepted' });
document.getElementById('incognito-privacy-settings').click();
document.getElementById('incognito-analytics-decline').click();
assert.equal(values.get(storageKey), 'declined');
assert.deepEqual(queuedCommands(window).slice(-2), [
['forgetConsentGiven'],
['deleteCookies'],
]);
const later = runController({ decision: values.get(storageKey) });
assert.equal(later.window._paq, undefined);
assert.equal(later.document.getElementById('incognito-matomo-script'), null);
});
test('running the local controller twice does not duplicate UI or tracking', () => {
const state = runController({ decision: 'accepted' });
vm.runInNewContext(controllerSource, { window: state.window, document: state.document });
assert.equal(state.document.querySelectorAll('#incognito-analytics-consent').length, 1);
assert.equal(state.document.querySelectorAll('#incognito-matomo-script').length, 1);
assert.equal(state.window._paq.filter(([method]) => method === 'trackPageView').length, 1);
});