/** * Unit tests for `summariseActivePairings` — the pure helper that * groups shadow sample rows by `activeVariantId` to power the * "compared against active" badge in the admin Evolution UI. * * Pure-function only: lives in `shadow-core.ts` so the test stays * free of DB / Express / events imports. * * Run with: * node --test artifacts/api-server/src/lib/__tests__/shadow-active-pairings.unit.test.ts */ import { test } from "node:test"; import assert from "node:assert/strict"; import { summariseActivePairings } from "../evolution/shadow-core.ts"; test("summariseActivePairings: empty input → empty output", () => { assert.deepEqual(summariseActivePairings([]), []); }); test("summariseActivePairings: single pairing → one row with null timestamps when createdAt absent", () => { const out = summariseActivePairings([ { activeVariantId: "v_active_a" }, { activeVariantId: "v_active_a" }, { activeVariantId: "v_active_a" }, ]); assert.deepEqual(out, [ { activeVariantId: "v_active_a", sampleCount: 3, firstSampleAt: null, lastSampleAt: null, }, ]); }); test("summariseActivePairings: multiple pairings sorted by descending count", () => { const out = summariseActivePairings([ { activeVariantId: "v_active_b" }, { activeVariantId: "v_active_a" }, { activeVariantId: "v_active_a" }, { activeVariantId: "v_active_a" }, { activeVariantId: "v_active_b" }, ]); assert.deepEqual(out, [ { activeVariantId: "v_active_a", sampleCount: 3, firstSampleAt: null, lastSampleAt: null, }, { activeVariantId: "v_active_b", sampleCount: 2, firstSampleAt: null, lastSampleAt: null, }, ]); }); test("summariseActivePairings: ties broken by lexicographic variant id", () => { // Deterministic ordering matters because the admin UI keys list // entries by activeVariantId — flapping the order between renders // would defeat React's reconciliation and cause the warning badge to // jitter when two actives share an equal sample count. const out = summariseActivePairings([ { activeVariantId: "v_zzz" }, { activeVariantId: "v_aaa" }, { activeVariantId: "v_zzz" }, { activeVariantId: "v_aaa" }, ]); assert.equal(out.length, 2); assert.equal(out[0]!.activeVariantId, "v_aaa"); assert.equal(out[1]!.activeVariantId, "v_zzz"); }); test("summariseActivePairings: caller cannot mutate the input array", () => { // Defensive: the helper accepts a ReadonlyArray, so passing a frozen // array must not throw. const rows = Object.freeze([ { activeVariantId: "v_active_a" }, { activeVariantId: "v_active_b" }, ]); const out = summariseActivePairings(rows); assert.equal(out.length, 2); }); test("summariseActivePairings: tracks first/last sample timestamps per pairing", () => { // The admin overview tooltips the chip with this date range, so we // need the earliest sample for the pairing and the latest one — even // when rows arrive out of order (the route reads them desc by // createdAt, but the helper must not assume any input ordering). const out = summariseActivePairings([ { activeVariantId: "v_a", createdAt: new Date("2026-01-03T00:00:00Z") }, { activeVariantId: "v_a", createdAt: new Date("2026-01-01T00:00:00Z") }, { activeVariantId: "v_a", createdAt: new Date("2026-01-02T00:00:00Z") }, { activeVariantId: "v_b", createdAt: new Date("2026-01-04T00:00:00Z") }, ]); assert.equal(out[0]!.activeVariantId, "v_a"); assert.equal( out[0]!.firstSampleAt!.toISOString(), "2026-01-01T00:00:00.000Z", ); assert.equal( out[0]!.lastSampleAt!.toISOString(), "2026-01-03T00:00:00.000Z", ); assert.equal(out[1]!.activeVariantId, "v_b"); assert.equal( out[1]!.firstSampleAt!.toISOString(), "2026-01-04T00:00:00.000Z", ); assert.equal( out[1]!.lastSampleAt!.toISOString(), "2026-01-04T00:00:00.000Z", ); }); test("summariseActivePairings: rows missing createdAt do not corrupt the timestamps", () => { // Defensive: a half-populated row (missing createdAt) must not blow // away timestamps already collected from sibling rows. const out = summariseActivePairings([ { activeVariantId: "v_a", createdAt: new Date("2026-01-02T00:00:00Z") }, { activeVariantId: "v_a" }, { activeVariantId: "v_a", createdAt: null }, ]); assert.equal(out[0]!.sampleCount, 3); assert.equal( out[0]!.firstSampleAt!.toISOString(), "2026-01-02T00:00:00.000Z", ); assert.equal( out[0]!.lastSampleAt!.toISOString(), "2026-01-02T00:00:00.000Z", ); });