import { afterEach, describe, expect, it, vi } from "vitest" ;
import { importFreshModule } from "../../../test/helpers/import-fresh.js" ;
import {
clearSlackThreadParticipationCache,
hasSlackThreadParticipation,
recordSlackThreadParticipation,
} from "./sent-thread-cache.js" ;
describe("slack sent-thread-cache" , () => {
afterEach(() => {
clearSlackThreadParticipationCache();
vi.restoreAllMocks();
});
it("records and checks thread participation" , () => {
recordSlackThreadParticipation("A1" , "C123" , "1700000000.000001" );
expect(hasSlackThreadParticipation("A1" , "C123" , "1700000000.000001" )).toBe(true );
});
it("returns false for unrecorded threads" , () => {
expect(hasSlackThreadParticipation("A1" , "C123" , "1700000000.000001" )).toBe(false );
});
it("distinguishes different channels and threads" , () => {
recordSlackThreadParticipation("A1" , "C123" , "1700000000.000001" );
expect(hasSlackThreadParticipation("A1" , "C123" , "1700000000.000002" )).toBe(false );
expect(hasSlackThreadParticipation("A1" , "C456" , "1700000000.000001" )).toBe(false );
});
it("scopes participation by accountId" , () => {
recordSlackThreadParticipation("A1" , "C123" , "1700000000.000001" );
expect(hasSlackThreadParticipation("A2" , "C123" , "1700000000.000001" )).toBe(false );
expect(hasSlackThreadParticipation("A1" , "C123" , "1700000000.000001" )).toBe(true );
});
it("ignores empty accountId, channelId, or threadTs" , () => {
recordSlackThreadParticipation("" , "C123" , "1700000000.000001" );
recordSlackThreadParticipation("A1" , "" , "1700000000.000001" );
recordSlackThreadParticipation("A1" , "C123" , "" );
expect(hasSlackThreadParticipation("" , "C123" , "1700000000.000001" )).toBe(false );
expect(hasSlackThreadParticipation("A1" , "" , "1700000000.000001" )).toBe(false );
expect(hasSlackThreadParticipation("A1" , "C123" , "" )).toBe(false );
});
it("clears all entries" , () => {
recordSlackThreadParticipation("A1" , "C123" , "1700000000.000001" );
recordSlackThreadParticipation("A1" , "C456" , "1700000000.000002" );
clearSlackThreadParticipationCache();
expect(hasSlackThreadParticipation("A1" , "C123" , "1700000000.000001" )).toBe(false );
expect(hasSlackThreadParticipation("A1" , "C456" , "1700000000.000002" )).toBe(false );
});
it("shares thread participation across distinct module instances" , async () => {
const cacheA = await importFreshModule<typeof import ("./sent-thread-cache.js" )>(
import .meta.url,
"./sent-thread-cache.js?scope=shared-a" ,
);
const cacheB = await importFreshModule<typeof import ("./sent-thread-cache.js" )>(
import .meta.url,
"./sent-thread-cache.js?scope=shared-b" ,
);
cacheA.clearSlackThreadParticipationCache();
try {
cacheA.recordSlackThreadParticipation("A1" , "C123" , "1700000000.000001" );
expect(cacheB.hasSlackThreadParticipation("A1" , "C123" , "1700000000.000001" )).toBe(true );
cacheB.clearSlackThreadParticipationCache();
expect(cacheA.hasSlackThreadParticipation("A1" , "C123" , "1700000000.000001" )).toBe(false );
} finally {
cacheA.clearSlackThreadParticipationCache();
}
});
it("expired entries return false and are cleaned up on read" , () => {
recordSlackThreadParticipation("A1" , "C123" , "1700000000.000001" );
// Advance time past the 24-hour TTL
vi.spyOn(Date, "now" ).mockReturnValue(Date.now() + 25 * 60 * 60 * 1000 );
expect(hasSlackThreadParticipation("A1" , "C123" , "1700000000.000001" )).toBe(false );
});
it("enforces maximum entries by evicting oldest fresh entries" , () => {
for (let i = 0 ; i < 5001 ; i += 1 ) {
recordSlackThreadParticipation("A1" , "C123" , `1700000000 .${String(i).padStart(6 , "0" )}`);
}
expect(hasSlackThreadParticipation("A1" , "C123" , "1700000000.000000" )).toBe(false );
expect(hasSlackThreadParticipation("A1" , "C123" , "1700000000.005000" )).toBe(true );
});
});
Messung V0.5 in Prozent C=97 H=91 G=93
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet am 2026-06-05)
¤
*© Formatika GbR, Deutschland