Analytics: Heatmap-Endpunkt nachgeschaerft

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
ClaudeandClaude Sonnet 5.5 committed 2026-10-01 09:59:48 +00:00
1 parent 28c7a90d8b
commit add7fa4add
4 files changed
+97 -13

No files matched your search

+28 -1
View File
@@ -1,7 +1,7 @@
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { openDb } from '../src/db.js';
import { runNightly, nextRunAt, dayOf } from '../src/jobs.js';
import { runNightly, nextRunAt, dayOf, scheduleNightly } from '../src/jobs.js';
import { createAdminServer } from '../src/server.js';
const KEY = 'abcdef0123456789abcd';
@@ -177,3 +177,30 @@ test('Stats: Top 20 absteigend, consentRate 0 ohne Entscheidungen, Fehlerfälle'
assert.equal((await a.get(`/a/admin/stats/${KEY}?range=7`, 'Bearer nope')).status, 401);
a.close();
});
test('scheduleNightly: früh feuernder Timer läuft nicht vorzeitig und nie doppelt für dasselbe 02:30', () => {
let t = Date.UTC(2026, 9, 10, 10, 0, 0);
const pending = [];
const timers = { setTimeout: (fn, ms) => { const h = { fn, at: t + ms }; pending.push(h); return h; }, clearTimeout: (h) => { const i = pending.indexOf(h); if (i >= 0) pending.splice(i, 1); } };
const runs = [];
const quiet = { log() {}, error() {} };
const s = scheduleNightly({}, { startDelayMs: 1000, log: quiet, now: () => t, timers, job: (db, o) => { runs.push(o.now); return { aggregated: 0, sitesDeleted: 0 }; } });
const fire = (clock) => { const h = pending.shift(); t = clock ?? h.at; h.fn(); };
fire(); // Startlauf
assert.equal(runs.length, 1);
const target = nextRunAt(t);
assert.equal(pending.length, 1);
assert.equal(pending[0].at, target);
fire(target - 500); // Timer feuert 500 ms zu früh
assert.equal(runs.length, 1, 'kein vorzeitiger Lauf');
assert.equal(pending.length, 1);
assert.equal(pending[0].at, target, 'neu auf das Ziel gesetzt');
fire(target); // pünktlich
assert.equal(runs.length, 2);
assert.equal(pending[0].at, nextRunAt(target + 1000));
assert.ok(pending[0].at > target + 20 * 3600000, 'nächster Lauf am Folgetag');
fire(pending[0].at - 1); // wieder zu früh
assert.equal(runs.length, 2);
s.stop();
assert.equal(pending.length, 0);
});