test: use synthetic outbound utility fixtures

This commit is contained in:
Peter Steinberger
2026-04-20 23:26:51 +01:00
parent b07c40a5a8
commit 7e8b58cb25
6 changed files with 89 additions and 70 deletions

View File

@@ -1,21 +1,28 @@
import { describe, expect, it } from "vitest";
import { describe, expect, it, vi } from "vitest";
import {
resolveExternalBestEffortDeliveryTarget,
shouldDowngradeDeliveryToSessionOnly,
} from "./best-effort-delivery.js";
vi.mock("../../utils/message-channel.js", () => ({
INTERNAL_MESSAGE_CHANNEL: "webchat",
isDeliverableMessageChannel: (value: string) => ["alpha", "richchat"].includes(value),
normalizeMessageChannel: (value?: string | null) =>
typeof value === "string" ? value.trim().toLowerCase() : undefined,
}));
describe("best-effort delivery helpers", () => {
it("resolves external delivery targets only for deliverable channels with to", () => {
expect(
resolveExternalBestEffortDeliveryTarget({
channel: "discord",
channel: "richchat",
to: "channel:123",
accountId: "default",
threadId: "thread-1",
}),
).toEqual({
deliver: true,
channel: "discord",
channel: "richchat",
to: "channel:123",
accountId: "default",
threadId: "thread-1",
@@ -40,7 +47,7 @@ describe("best-effort delivery helpers", () => {
it("returns session-only when to is missing", () => {
expect(
resolveExternalBestEffortDeliveryTarget({
channel: "telegram",
channel: "alpha",
}),
).toEqual({
deliver: false,
@@ -72,7 +79,7 @@ describe("best-effort delivery helpers", () => {
shouldDowngradeDeliveryToSessionOnly({
wantsDelivery: true,
bestEffortDeliver: true,
resolvedChannel: "discord",
resolvedChannel: "richchat",
}),
).toBe(false);
});

View File

@@ -8,7 +8,7 @@ import {
const TARGET_SESSION_KEY = "agent:main:subagent:child";
function createDiscordBinding(
function createRuntimeBinding(
targetSessionKey: string,
conversationId: string,
boundAt: number,
@@ -19,7 +19,7 @@ function createDiscordBinding(
targetSessionKey,
targetKind: "subagent",
conversation: {
channel: "discord",
channel: "richchat",
accountId: "runtime",
conversationId,
parentConversationId,
@@ -29,12 +29,12 @@ function createDiscordBinding(
};
}
function registerDiscordSessionBindings(
function registerRuntimeSessionBindings(
targetSessionKey: string,
bindings: SessionBindingRecord[],
): void {
registerSessionBindingAdapter({
channel: "discord",
channel: "richchat",
accountId: "runtime",
listBySession: (requestedSessionKey) =>
requestedSessionKey === targetSessionKey ? bindings : [],
@@ -54,7 +54,7 @@ describe("bound delivery router", () => {
failClosed?: boolean;
}) => {
if (params.bindings) {
registerDiscordSessionBindings(
registerRuntimeSessionBindings(
params.targetSessionKey ?? TARGET_SESSION_KEY,
params.bindings,
);
@@ -65,7 +65,7 @@ describe("bound delivery router", () => {
...(params.requesterConversationId !== undefined
? {
requester: {
channel: "discord",
channel: "richchat",
accountId: "runtime",
conversationId: params.requesterConversationId,
},
@@ -78,7 +78,7 @@ describe("bound delivery router", () => {
it.each([
{
name: "resolves to a bound destination when a single active binding exists",
bindings: [createDiscordBinding(TARGET_SESSION_KEY, "thread-1", 1, "parent-1")],
bindings: [createRuntimeBinding(TARGET_SESSION_KEY, "thread-1", 1, "parent-1")],
requesterConversationId: "parent-1",
expected: {
mode: "bound",
@@ -98,8 +98,8 @@ describe("bound delivery router", () => {
{
name: "fails closed when multiple bindings exist without requester signal",
bindings: [
createDiscordBinding(TARGET_SESSION_KEY, "thread-1", 1),
createDiscordBinding(TARGET_SESSION_KEY, "thread-2", 2),
createRuntimeBinding(TARGET_SESSION_KEY, "thread-1", 1),
createRuntimeBinding(TARGET_SESSION_KEY, "thread-2", 2),
],
failClosed: true,
expected: {
@@ -111,8 +111,8 @@ describe("bound delivery router", () => {
{
name: "selects requester-matching conversation when multiple bindings exist",
bindings: [
createDiscordBinding(TARGET_SESSION_KEY, "thread-1", 1),
createDiscordBinding(TARGET_SESSION_KEY, "thread-2", 2),
createRuntimeBinding(TARGET_SESSION_KEY, "thread-1", 1),
createRuntimeBinding(TARGET_SESSION_KEY, "thread-2", 2),
],
requesterConversationId: "thread-2",
failClosed: true,
@@ -126,17 +126,17 @@ describe("bound delivery router", () => {
name: "normalizes adapter binding conversations before requester matching",
bindings: [
{
...createDiscordBinding(TARGET_SESSION_KEY, "thread-1", 1),
...createRuntimeBinding(TARGET_SESSION_KEY, "thread-1", 1),
conversation: {
channel: " discord ",
channel: " richchat ",
accountId: " runtime ",
conversationId: " thread-1 ",
},
},
{
...createDiscordBinding(TARGET_SESSION_KEY, "thread-2", 2),
...createRuntimeBinding(TARGET_SESSION_KEY, "thread-2", 2),
conversation: {
channel: " DISCORD ",
channel: " RICHCHAT ",
accountId: " Runtime ",
conversationId: " thread-2 ",
},
@@ -152,7 +152,7 @@ describe("bound delivery router", () => {
},
{
name: "falls back for invalid requester conversation values",
bindings: [createDiscordBinding(TARGET_SESSION_KEY, "thread-1", 1)],
bindings: [createRuntimeBinding(TARGET_SESSION_KEY, "thread-1", 1)],
requesterConversationId: " ",
failClosed: true,
expected: {

View File

@@ -7,21 +7,21 @@ describe("buildDirectoryCacheKey", () => {
it.each([
{
input: {
channel: "slack",
channel: "workspace",
kind: "channel",
source: "cache",
},
expected: "slack:default:channel:cache:default",
expected: "workspace:default:channel:cache:default",
},
{
input: {
channel: "discord",
channel: "richchat",
accountId: "work",
kind: "user",
source: "live",
signature: "v2",
},
expected: "discord:work:user:live:v2",
expected: "richchat:work:user:live:v2",
},
] satisfies Array<{ input: DirectoryCacheKey; expected: string }>)(
"includes account and signature fallbacks for %j",

View File

@@ -5,7 +5,7 @@ import type { OutboundDeliveryJson } from "./format.js";
describe("buildOutboundResultEnvelope", () => {
const delivery: OutboundDeliveryJson = {
channel: "telegram",
channel: "alpha",
via: "direct",
to: "123",
messageId: "m1",

View File

@@ -5,7 +5,19 @@ import {
formatOutboundDeliverySummary,
} from "./format.js";
const getChannelPluginMock = vi.hoisted(() => vi.fn((_channel: unknown) => undefined));
const getChannelPluginMock = vi.hoisted(() =>
vi.fn((channel: string) => {
const labels: Record<string, string> = {
alpha: "Alpha",
localchat: "Local Chat",
richchat: "Rich Chat",
workspace: "Workspace",
teamchat: "Team Chat",
};
const label = labels[channel];
return label ? { meta: { label } } : undefined;
}),
);
vi.mock("../../channels/plugins/index.js", () => ({
getLoadedChannelPlugin: getChannelPluginMock,
@@ -14,50 +26,50 @@ vi.mock("../../channels/plugins/index.js", () => ({
describe("formatOutboundDeliverySummary", () => {
it.each([
{
channel: "telegram" as const,
channel: "alpha" as const,
result: undefined,
expected: "✅ Sent via Telegram. Message ID: unknown",
expected: "✅ Sent via Alpha. Message ID: unknown",
},
{
channel: "imessage" as const,
channel: "localchat" as const,
result: undefined,
expected: "✅ Sent via iMessage. Message ID: unknown",
expected: "✅ Sent via Local Chat. Message ID: unknown",
},
{
channel: "telegram" as const,
channel: "alpha" as const,
result: {
channel: "telegram" as const,
channel: "alpha" as const,
messageId: "m1",
chatId: "c1",
},
expected: "✅ Sent via Telegram. Message ID: m1 (chat c1)",
expected: "✅ Sent via Alpha. Message ID: m1 (chat c1)",
},
{
channel: "discord" as const,
channel: "richchat" as const,
result: {
channel: "discord" as const,
channel: "richchat" as const,
messageId: "d1",
channelId: "chan",
},
expected: "✅ Sent via Discord. Message ID: d1 (channel chan)",
expected: "✅ Sent via Rich Chat. Message ID: d1 (channel chan)",
},
{
channel: "slack" as const,
channel: "workspace" as const,
result: {
channel: "slack" as const,
channel: "workspace" as const,
messageId: "s1",
roomId: "room-1",
},
expected: "✅ Sent via Slack. Message ID: s1 (room room-1)",
expected: "✅ Sent via Workspace. Message ID: s1 (room room-1)",
},
{
channel: "msteams" as const,
channel: "teamchat" as const,
result: {
channel: "msteams" as const,
channel: "teamchat" as const,
messageId: "t1",
conversationId: "conv-1",
},
expected: "✅ Sent via Microsoft Teams. Message ID: t1 (conversation conv-1)",
expected: "✅ Sent via Team Chat. Message ID: t1 (conversation conv-1)",
},
])("formats delivery summary for %j", ({ channel, result, expected }) => {
expect(formatOutboundDeliverySummary(channel, result)).toBe(expected);
@@ -68,13 +80,13 @@ describe("buildOutboundDeliveryJson", () => {
it.each([
{
input: {
channel: "telegram" as const,
channel: "alpha" as const,
to: "123",
result: { channel: "telegram" as const, messageId: "m1", chatId: "c1" },
result: { channel: "alpha" as const, messageId: "m1", chatId: "c1" },
mediaUrl: "https://example.com/a.png",
},
expected: {
channel: "telegram",
channel: "alpha",
via: "direct",
to: "123",
messageId: "m1",
@@ -84,12 +96,12 @@ describe("buildOutboundDeliveryJson", () => {
},
{
input: {
channel: "whatsapp" as const,
channel: "directchat" as const,
to: "+1",
result: { channel: "whatsapp" as const, messageId: "w1", toJid: "jid" },
result: { channel: "directchat" as const, messageId: "w1", toJid: "jid" },
},
expected: {
channel: "whatsapp",
channel: "directchat",
via: "direct",
to: "+1",
messageId: "w1",
@@ -99,12 +111,12 @@ describe("buildOutboundDeliveryJson", () => {
},
{
input: {
channel: "signal" as const,
channel: "pager" as const,
to: "+1",
result: { channel: "signal" as const, messageId: "s1", timestamp: 123 },
result: { channel: "pager" as const, messageId: "s1", timestamp: 123 },
},
expected: {
channel: "signal",
channel: "pager",
via: "direct",
to: "+1",
messageId: "s1",
@@ -114,7 +126,7 @@ describe("buildOutboundDeliveryJson", () => {
},
{
input: {
channel: "discord" as const,
channel: "richchat" as const,
to: "channel:1",
via: "gateway" as const,
result: {
@@ -124,7 +136,7 @@ describe("buildOutboundDeliveryJson", () => {
},
},
expected: {
channel: "discord",
channel: "richchat",
via: "gateway",
to: "channel:1",
messageId: "g1",
@@ -141,12 +153,12 @@ describe("buildOutboundDeliveryJson", () => {
describe("formatGatewaySummary", () => {
it.each([
{
input: { channel: "whatsapp", messageId: "m1" },
expected: "✅ Sent via gateway (whatsapp). Message ID: m1",
input: { channel: "directchat", messageId: "m1" },
expected: "✅ Sent via gateway (directchat). Message ID: m1",
},
{
input: { action: "Poll sent", channel: "discord", messageId: "p1" },
expected: "✅ Poll sent via gateway (discord). Message ID: p1",
input: { action: "Poll sent", channel: "richchat", messageId: "p1" },
expected: "✅ Poll sent via gateway (richchat). Message ID: p1",
},
{
input: {},

View File

@@ -60,23 +60,23 @@ describe("DirectoryCache", () => {
});
describe("buildOutboundResultEnvelope", () => {
const whatsappDelivery: OutboundDeliveryJson = {
channel: "whatsapp",
const directChatDelivery: OutboundDeliveryJson = {
channel: "directchat",
via: "gateway",
to: "+1",
messageId: "m1",
mediaUrl: null,
};
const telegramDelivery: OutboundDeliveryJson = {
channel: "telegram",
const alphaDelivery: OutboundDeliveryJson = {
channel: "alpha",
via: "direct",
to: "123",
messageId: "m2",
mediaUrl: null,
chatId: "c1",
};
const discordDelivery: OutboundDeliveryJson = {
channel: "discord",
const richChatDelivery: OutboundDeliveryJson = {
channel: "richchat",
via: "gateway",
to: "channel:C1",
messageId: "m3",
@@ -92,8 +92,8 @@ describe("buildOutboundResultEnvelope", () => {
}>([
{
name: "flatten delivery by default",
input: { delivery: whatsappDelivery },
expected: whatsappDelivery,
input: { delivery: directChatDelivery },
expected: directChatDelivery,
},
{
name: "keep payloads + meta",
@@ -108,17 +108,17 @@ describe("buildOutboundResultEnvelope", () => {
},
{
name: "include delivery when payloads exist",
input: { payloads: [], delivery: telegramDelivery, meta: { ok: true } },
input: { payloads: [], delivery: alphaDelivery, meta: { ok: true } },
expected: {
payloads: [],
meta: { ok: true },
delivery: telegramDelivery,
delivery: alphaDelivery,
},
},
{
name: "keep wrapped delivery when flatten disabled",
input: { delivery: discordDelivery, flattenDelivery: false },
expected: { delivery: discordDelivery },
input: { delivery: richChatDelivery, flattenDelivery: false },
expected: { delivery: richChatDelivery },
},
]),
)("$name", ({ input, expected }) => {