| import { describe, expect, it } from "vitest"; |
| import { |
| applyQueueRuntimeSettings, |
| buildQueueSummaryPrompt, |
| clearQueueSummaryState, |
| drainCollectItemIfNeeded, |
| previewQueueSummaryPrompt, |
| } from "./queue-helpers.js"; |
|
|
| describe("applyQueueRuntimeSettings", () => { |
| it("updates runtime queue settings with normalization", () => { |
| const target = { |
| mode: "followup" as const, |
| debounceMs: 1000, |
| cap: 20, |
| dropPolicy: "summarize" as const, |
| }; |
|
|
| applyQueueRuntimeSettings({ |
| target, |
| settings: { |
| mode: "collect", |
| debounceMs: -12, |
| cap: 9.8, |
| dropPolicy: "new", |
| }, |
| }); |
|
|
| expect(target).toEqual({ |
| mode: "collect", |
| debounceMs: 0, |
| cap: 9, |
| dropPolicy: "new", |
| }); |
| }); |
|
|
| it("keeps existing values when optional settings are missing/invalid", () => { |
| const target = { |
| mode: "followup" as const, |
| debounceMs: 1000, |
| cap: 20, |
| dropPolicy: "summarize" as const, |
| }; |
|
|
| applyQueueRuntimeSettings({ |
| target, |
| settings: { |
| mode: "queue", |
| cap: 0, |
| }, |
| }); |
|
|
| expect(target).toEqual({ |
| mode: "queue", |
| debounceMs: 1000, |
| cap: 20, |
| dropPolicy: "summarize", |
| }); |
| }); |
| }); |
|
|
| describe("queue summary helpers", () => { |
| it("previewQueueSummaryPrompt does not mutate state", () => { |
| const state = { |
| dropPolicy: "summarize" as const, |
| droppedCount: 2, |
| summaryLines: ["first", "second"], |
| }; |
|
|
| const prompt = previewQueueSummaryPrompt({ |
| state, |
| noun: "message", |
| }); |
|
|
| expect(prompt).toContain("[Queue overflow] Dropped 2 messages due to cap."); |
| expect(prompt).toContain("first"); |
| expect(state).toEqual({ |
| dropPolicy: "summarize", |
| droppedCount: 2, |
| summaryLines: ["first", "second"], |
| }); |
| }); |
|
|
| it("buildQueueSummaryPrompt clears state after rendering", () => { |
| const state = { |
| dropPolicy: "summarize" as const, |
| droppedCount: 1, |
| summaryLines: ["line"], |
| }; |
|
|
| const prompt = buildQueueSummaryPrompt({ |
| state, |
| noun: "announce", |
| }); |
|
|
| expect(prompt).toContain("[Queue overflow] Dropped 1 announce due to cap."); |
| expect(state).toEqual({ |
| dropPolicy: "summarize", |
| droppedCount: 0, |
| summaryLines: [], |
| }); |
| }); |
|
|
| it("clearQueueSummaryState resets summary counters", () => { |
| const state = { |
| dropPolicy: "summarize" as const, |
| droppedCount: 5, |
| summaryLines: ["a", "b"], |
| }; |
| clearQueueSummaryState(state); |
| expect(state.droppedCount).toBe(0); |
| expect(state.summaryLines).toEqual([]); |
| }); |
| }); |
|
|
| describe("drainCollectItemIfNeeded", () => { |
| it("skips when neither force mode nor cross-channel routing is active", async () => { |
| const seen: number[] = []; |
| const items = [1]; |
|
|
| const result = await drainCollectItemIfNeeded({ |
| forceIndividualCollect: false, |
| isCrossChannel: false, |
| items, |
| run: async (item) => { |
| seen.push(item); |
| }, |
| }); |
|
|
| expect(result).toBe("skipped"); |
| expect(seen).toEqual([]); |
| expect(items).toEqual([1]); |
| }); |
|
|
| it("drains one item in force mode", async () => { |
| const seen: number[] = []; |
| const items = [1, 2]; |
|
|
| const result = await drainCollectItemIfNeeded({ |
| forceIndividualCollect: true, |
| isCrossChannel: false, |
| items, |
| run: async (item) => { |
| seen.push(item); |
| }, |
| }); |
|
|
| expect(result).toBe("drained"); |
| expect(seen).toEqual([1]); |
| expect(items).toEqual([2]); |
| }); |
|
|
| it("switches to force mode and returns empty when cross-channel with no queued item", async () => { |
| let forced = false; |
|
|
| const result = await drainCollectItemIfNeeded({ |
| forceIndividualCollect: false, |
| isCrossChannel: true, |
| setForceIndividualCollect: (next) => { |
| forced = next; |
| }, |
| items: [], |
| run: async () => {}, |
| }); |
|
|
| expect(result).toBe("empty"); |
| expect(forced).toBe(true); |
| }); |
| }); |
|
|