refactor(mattermost): deduplicate draft stream tests (#118215)

This commit is contained in:
Peter Steinberger
2026-08-02 15:01:34 -07:00
committed by GitHub
parent c54f7e9733
commit 761c3e33be
2 changed files with 107 additions and 368 deletions
@@ -12,11 +12,20 @@ type RequestRecord = {
init?: RequestInit;
};
function createMockClient(): {
type DraftStreamOptions = Omit<
Parameters<typeof createMattermostDraftStream>[0],
"client" | "channelId"
> & {
request?: MattermostClient["request"];
};
function createDraftStreamFixture(options: DraftStreamOptions = {}): {
client: MattermostClient;
calls: RequestRecord[];
requestMock: ReturnType<typeof vi.fn<MattermostClient["request"]>>;
stream: ReturnType<typeof createMattermostDraftStream>;
} {
const { request, ...streamOptions } = options;
const calls: RequestRecord[] = [];
let nextId = 1;
const requestImpl: MattermostClient["request"] = async <T>(
@@ -32,7 +41,7 @@ function createMockClient(): {
}
return {} as T;
};
const requestMock = vi.fn(requestImpl);
const requestMock = vi.fn(request ?? requestImpl);
const client: MattermostClient = {
baseUrl: "https://chat.example.com",
apiBaseUrl: "https://chat.example.com/api/v4",
@@ -40,7 +49,13 @@ function createMockClient(): {
request: requestMock as MattermostClient["request"],
fetchImpl: vi.fn() as MattermostClient["fetchImpl"],
};
return { client, calls, requestMock };
const stream = createMattermostDraftStream({
client,
channelId: "channel-1",
throttleMs: 0,
...streamOptions,
});
return { client, calls, requestMock, stream };
}
function parseRequestJson(init: RequestInit | undefined): Record<string, unknown> {
@@ -56,13 +71,7 @@ function parseRequestJson(init: RequestInit | undefined): Record<string, unknown
describe("createMattermostDraftStream", () => {
it("creates a preview post and updates it on later changes", async () => {
const { client, calls } = createMockClient();
const stream = createMattermostDraftStream({
client,
channelId: "channel-1",
rootId: "root-1",
throttleMs: 0,
});
const { calls, stream } = createDraftStreamFixture({ rootId: "root-1" });
stream.update("Running `read`…");
await stream.flush();
@@ -81,12 +90,7 @@ describe("createMattermostDraftStream", () => {
});
it("does not resend identical updates", async () => {
const { client, calls } = createMockClient();
const stream = createMattermostDraftStream({
client,
channelId: "channel-1",
throttleMs: 0,
});
const { calls, stream } = createDraftStreamFixture();
stream.update("Working...");
await stream.flush();
@@ -97,13 +101,7 @@ describe("createMattermostDraftStream", () => {
});
it("clears the preview post when no final reply is delivered", async () => {
const { client, calls } = createMockClient();
const stream = createMattermostDraftStream({
client,
channelId: "channel-1",
rootId: "root-1",
throttleMs: 0,
});
const { calls, stream } = createDraftStreamFixture({ rootId: "root-1" });
stream.update("Working...");
await stream.flush();
@@ -116,13 +114,7 @@ describe("createMattermostDraftStream", () => {
});
it("discardPending keeps the preview post but ignores later updates", async () => {
const { client, calls } = createMockClient();
const stream = createMattermostDraftStream({
client,
channelId: "channel-1",
rootId: "root-1",
throttleMs: 0,
});
const { calls, stream } = createDraftStreamFixture({ rootId: "root-1" });
stream.update("Working...");
await stream.flush();
@@ -136,13 +128,7 @@ describe("createMattermostDraftStream", () => {
});
it("seal keeps the preview post and cancels pending final overwrites", async () => {
const { client, calls } = createMockClient();
const stream = createMattermostDraftStream({
client,
channelId: "channel-1",
rootId: "root-1",
throttleMs: 0,
});
const { calls, stream } = createDraftStreamFixture({ rootId: "root-1" });
stream.update("Working...");
await stream.flush();
@@ -156,13 +142,7 @@ describe("createMattermostDraftStream", () => {
});
it("stop flushes the last pending update and ignores later ones", async () => {
const { client, calls } = createMockClient();
const stream = createMattermostDraftStream({
client,
channelId: "channel-1",
rootId: "root-1",
throttleMs: 1000,
});
const { calls, stream } = createDraftStreamFixture({ rootId: "root-1", throttleMs: 1000 });
stream.update("Working...");
await stream.flush();
@@ -185,20 +165,7 @@ describe("createMattermostDraftStream", () => {
const requestImpl: MattermostClient["request"] = async () => {
throw new Error("boom");
};
const requestMock = vi.fn(requestImpl);
const client: MattermostClient = {
baseUrl: "https://chat.example.com",
apiBaseUrl: "https://chat.example.com/api/v4",
token: "token",
request: requestMock as MattermostClient["request"],
fetchImpl: vi.fn() as MattermostClient["fetchImpl"],
};
const stream = createMattermostDraftStream({
client,
channelId: "channel-1",
throttleMs: 0,
warn,
});
const { requestMock, stream } = createDraftStreamFixture({ request: requestImpl, warn });
stream.update("Working...");
await stream.flush();
@@ -212,14 +179,8 @@ describe("createMattermostDraftStream", () => {
it("retains an accepted preview failure after its background flush has settled", async () => {
const warn = vi.fn();
const { client, requestMock } = createMockClient();
const { requestMock, stream } = createDraftStreamFixture({ warn });
requestMock.mockResolvedValueOnce({ message: "already visible" });
const stream = createMattermostDraftStream({
client,
channelId: "channel-1",
throttleMs: 0,
warn,
});
stream.update("Already delivered");
await vi.waitFor(() => expect(warn).toHaveBeenCalledOnce());
@@ -250,16 +211,10 @@ describe("createMattermostDraftStream", () => {
});
it("truncates on a code-point boundary so a straddling emoji is dropped whole", async () => {
const { client, calls } = createMockClient();
// maxChars=12 => cut point is maxChars-3=9. The emoji 😀 occupies UTF-16
// indices 8-9, so a raw slice(0,9) would keep the lone high surrogate at
// index 8 and drop its low surrogate at index 9, leaking a dangling half.
const stream = createMattermostDraftStream({
client,
channelId: "channel-1",
throttleMs: 0,
maxChars: 12,
});
const { calls, stream } = createDraftStreamFixture({ maxChars: 12 });
const input = `${"a".repeat(8)}\u{1F600}${"b".repeat(5)}`;
stream.update(input);
@@ -296,20 +251,7 @@ describe("createMattermostDraftStream", () => {
}
return {} as T;
};
const requestMock = vi.fn(requestImpl);
const client: MattermostClient = {
baseUrl: "https://chat.example.com",
apiBaseUrl: "https://chat.example.com/api/v4",
token: "token",
request: requestMock as MattermostClient["request"],
fetchImpl: vi.fn() as MattermostClient["fetchImpl"],
};
const stream = createMattermostDraftStream({
client,
channelId: "channel-1",
throttleMs: 1000,
warn,
});
const { stream } = createDraftStreamFixture({ request: requestImpl, throttleMs: 1000, warn });
stream.update("Working...");
await stream.flush();
@@ -326,11 +268,7 @@ describe("createMattermostDraftStream", () => {
describe("createMattermostDraftStream forceNewMessage", () => {
it("propagates a provider-accepted boundary post without an identity", async () => {
const { client, requestMock } = createMockClient();
const stream = createMattermostDraftStream({
client,
channelId: "channel-1",
throttleMs: 0,
const { requestMock, stream } = createDraftStreamFixture({
maxChars: 10,
chunkText: () => ["aaaaaaaaaa", "bbbbbbbbbb"],
});
@@ -347,17 +285,13 @@ describe("createMattermostDraftStream forceNewMessage", () => {
});
it("retains accepted boundary failures before synchronous warning callbacks re-enter", async () => {
const { client, requestMock } = createMockClient();
let reenteredBoundary: Promise<void> | undefined;
const warn = vi.fn(() => {
stream.update("must not publish twice");
reenteredBoundary = stream.forceNewMessage();
void reenteredBoundary.catch(() => {});
});
const stream = createMattermostDraftStream({
client,
channelId: "channel-1",
throttleMs: 0,
const { requestMock, stream } = createDraftStreamFixture({
maxChars: 10,
chunkText: () => ["aaaaaaaaaa", "bbbbbbbbbb"],
warn,
@@ -376,7 +310,7 @@ describe("createMattermostDraftStream forceNewMessage", () => {
});
it("propagates an accepted background failure that settles during boundary rotation", async () => {
const { client, requestMock } = createMockClient();
const { requestMock, stream } = createDraftStreamFixture();
let releaseCreate: (() => void) | undefined;
const createReady = new Promise<void>((resolve) => {
releaseCreate = resolve;
@@ -385,11 +319,6 @@ describe("createMattermostDraftStream forceNewMessage", () => {
await createReady;
return { message: "already visible" };
});
const stream = createMattermostDraftStream({
client,
channelId: "channel-1",
throttleMs: 0,
});
stream.update("Accepted background preview");
await vi.waitFor(() => expect(requestMock).toHaveBeenCalledOnce());
@@ -402,13 +331,7 @@ describe("createMattermostDraftStream forceNewMessage", () => {
});
it("creates a new post on the next update after forceNewMessage", async () => {
const { client, calls } = createMockClient();
const stream = createMattermostDraftStream({
client,
channelId: "channel-1",
rootId: "root-1",
throttleMs: 0,
});
const { calls, stream } = createDraftStreamFixture({ rootId: "root-1" });
stream.update("Running `read`…");
await stream.flush();
@@ -436,14 +359,10 @@ describe("createMattermostDraftStream forceNewMessage", () => {
});
it("restores and chunks an already-flushed over-limit block before rotating", async () => {
const { client, calls } = createMockClient();
const firstChunk = "a".repeat(10);
const secondChunk = "b".repeat(10);
const chunkText = vi.fn(() => [firstChunk, secondChunk]);
const configuredStream = createMattermostDraftStream({
client,
channelId: "channel-1",
throttleMs: 0,
const { calls, stream: configuredStream } = createDraftStreamFixture({
maxChars: 10,
chunkText,
});
@@ -507,19 +426,7 @@ describe("createMattermostDraftStream forceNewMessage", () => {
}
return {} as T;
};
const requestMock = vi.fn(requestImpl);
const client: MattermostClient = {
baseUrl: "https://chat.example.com",
apiBaseUrl: "https://chat.example.com/api/v4",
token: "token",
request: requestMock as MattermostClient["request"],
fetchImpl: vi.fn() as MattermostClient["fetchImpl"],
};
const stream = createMattermostDraftStream({
client,
channelId: "channel-1",
throttleMs: 0,
});
const { stream } = createDraftStreamFixture({ request: requestImpl });
stream.update("tool start");
stream.update("tool complete");
@@ -573,19 +480,7 @@ describe("createMattermostDraftStream forceNewMessage", () => {
}
return {} as T;
};
const requestMock = vi.fn(requestImpl);
const client: MattermostClient = {
baseUrl: "https://chat.example.com",
apiBaseUrl: "https://chat.example.com/api/v4",
token: "token",
request: requestMock as MattermostClient["request"],
fetchImpl: vi.fn() as MattermostClient["fetchImpl"],
};
const stream = createMattermostDraftStream({
client,
channelId: "channel-1",
throttleMs: 0,
});
const { stream } = createDraftStreamFixture({ request: requestImpl });
stream.update("Looking into the logs");
stream.update("Looking into the logs now");
@@ -600,12 +495,7 @@ describe("createMattermostDraftStream forceNewMessage", () => {
});
it("opens a fresh post for a partial that arrives before a fire-and-forget boundary settles", async () => {
const { client, calls } = createMockClient();
const stream = createMattermostDraftStream({
client,
channelId: "channel-1",
throttleMs: 0,
});
const { calls, stream } = createDraftStreamFixture();
stream.update("block A");
await stream.flush();
@@ -624,12 +514,7 @@ describe("createMattermostDraftStream forceNewMessage", () => {
});
it("resolves a cumulative terminal reply to the current confirmed generation", async () => {
const { client } = createMockClient();
const stream = createMattermostDraftStream({
client,
channelId: "channel-1",
throttleMs: 0,
});
const { stream } = createDraftStreamFixture();
stream.updateAssistantText("First block");
await stream.flush();
@@ -655,12 +540,7 @@ describe("createMattermostDraftStream forceNewMessage", () => {
});
it("strips confirmed assistant blocks but not transient progress generations", async () => {
const { client } = createMockClient();
const stream = createMattermostDraftStream({
client,
channelId: "channel-1",
throttleMs: 0,
});
const { stream } = createDraftStreamFixture();
stream.updateAssistantText("First block");
await stream.flush();
@@ -692,12 +572,7 @@ describe("createMattermostDraftStream forceNewMessage", () => {
});
it("uses provider-finalized content from a boundary edit", async () => {
const { client, requestMock } = createMockClient();
const stream = createMattermostDraftStream({
client,
channelId: "channel-1",
throttleMs: 0,
});
const { requestMock, stream } = createDraftStreamFixture();
stream.updateAssistantText("Draft block");
await stream.flush();
@@ -712,12 +587,7 @@ describe("createMattermostDraftStream forceNewMessage", () => {
});
it("keeps the canonical final when an assistant boundary fails to publish", async () => {
const { client, requestMock } = createMockClient();
const stream = createMattermostDraftStream({
client,
channelId: "channel-1",
throttleMs: 0,
});
const { requestMock, stream } = createDraftStreamFixture();
stream.updateAssistantText("First block");
await stream.flush();
@@ -734,11 +604,7 @@ describe("createMattermostDraftStream forceNewMessage", () => {
});
it("retains posts published before a later boundary chunk fails", async () => {
const { client, requestMock } = createMockClient();
const stream = createMattermostDraftStream({
client,
channelId: "channel-1",
throttleMs: 0,
const { requestMock, stream } = createDraftStreamFixture({
chunkText: () => ["First half", "Second half"],
});
@@ -758,11 +624,7 @@ describe("createMattermostDraftStream forceNewMessage", () => {
});
it("does not strip a requested prefix rewritten by the provider", async () => {
const { client, requestMock } = createMockClient();
const stream = createMattermostDraftStream({
client,
channelId: "channel-1",
throttleMs: 0,
const { requestMock, stream } = createDraftStreamFixture({
chunkText: () => ["First half", "Second half"],
});
@@ -23,6 +23,23 @@ function createMattermostClientMock(): MattermostClient {
};
}
function createMattermostReceipt(messageId: string, kind: "text" | "preview" | "media") {
return createMessageReceiptFromOutboundResults({
results: [{ channel: "mattermost", messageId }],
kind,
});
}
function createConfirmedPreviewDelivery(messageId: string, content: string) {
return {
outcome: "text" as const,
messageIds: [messageId],
receipt: createMattermostReceipt(messageId, "preview"),
visibleReplySent: true,
content,
};
}
function createDraftStreamMock(postId: string | null | undefined = "preview-post-1") {
return {
flush: vi.fn(async () => {}),
@@ -37,10 +54,7 @@ function createDeliverFinalMock() {
return vi.fn(async (payload: { text?: string }) => ({
outcome: "text" as const,
messageIds: ["delivered-post-1"],
receipt: createMessageReceiptFromOutboundResults({
results: [{ channel: "mattermost", messageId: "delivered-post-1" }],
kind: "text",
}),
receipt: createMattermostReceipt("delivered-post-1", "text"),
visibleReplySent: true,
content: payload.text ?? "",
}));
@@ -51,6 +65,23 @@ function resolvePreviewFinalText(text?: string) {
return editText ? { editText, alreadyDelivered: false } : undefined;
}
type DraftDeliveryParams = Parameters<typeof deliverMattermostReplyWithDraftPreview>[0];
function deliverDraftPreview(
params: Pick<DraftDeliveryParams, "payload" | "draftStream" | "deliverPayload"> &
Partial<Omit<DraftDeliveryParams, "payload" | "draftStream" | "deliverPayload">>,
) {
return deliverMattermostReplyWithDraftPreview({
info: { kind: "final" },
kind: "channel",
client: createMattermostClientMock(),
resolvePreviewFinalText,
previewState: { finalizedViaPreviewPost: false },
logVerboseMessage: vi.fn(),
...params,
});
}
function mockCall(mock: { mock: { calls: unknown[][] } }, index: number, label: string): unknown[] {
const resolvedIndex = index < 0 ? mock.mock.calls.length + index : index;
const call = mock.mock.calls[resolvedIndex];
@@ -71,16 +102,10 @@ describe("deliverMattermostReplyWithDraftPreview", () => {
const deliverFinal = createDeliverFinalMock();
const recordThreadParticipation = vi.fn();
await deliverMattermostReplyWithDraftPreview({
await deliverDraftPreview({
payload: { text: " \n > Reasoning:\n> _hidden_" } as never,
info: { kind: "final" },
kind: "channel",
client: createMattermostClientMock(),
draftStream,
effectiveReplyToId: "thread-root-1",
resolvePreviewFinalText,
previewState: { finalizedViaPreviewPost: false },
logVerboseMessage: vi.fn(),
recordThreadParticipation,
deliverPayload: deliverFinal,
});
@@ -99,16 +124,10 @@ describe("deliverMattermostReplyWithDraftPreview", () => {
const deliverFinal = createDeliverFinalMock();
const recordThreadParticipation = vi.fn();
const result = await deliverMattermostReplyWithDraftPreview({
const result = await deliverDraftPreview({
payload: { text: "All good" } as never,
info: { kind: "final" },
kind: "channel",
client: createMattermostClientMock(),
draftStream,
effectiveReplyToId: "thread-root-1",
resolvePreviewFinalText,
previewState: { finalizedViaPreviewPost: false },
logVerboseMessage: vi.fn(),
recordThreadParticipation,
deliverPayload: deliverFinal,
});
@@ -131,30 +150,16 @@ describe("deliverMattermostReplyWithDraftPreview", () => {
it("reports a final already published in a sealed preview generation", async () => {
const draftStream = createDraftStreamMock(null);
const deliverFinal = createDeliverFinalMock();
const confirmedReceipt = createMessageReceiptFromOutboundResults({
results: [{ channel: "mattermost", messageId: "sealed-post-1" }],
kind: "preview",
});
const confirmedDelivery = createConfirmedPreviewDelivery("sealed-post-1", "Already visible");
const result = await deliverMattermostReplyWithDraftPreview({
const result = await deliverDraftPreview({
payload: { text: "Already visible" } as never,
info: { kind: "final" },
kind: "channel",
client: createMattermostClientMock(),
draftStream,
effectiveReplyToId: "thread-root-1",
resolvePreviewFinalText: () => ({
alreadyDelivered: true,
confirmedDelivery: {
outcome: "text",
messageIds: ["sealed-post-1"],
receipt: confirmedReceipt,
visibleReplySent: true,
content: "Already visible",
},
confirmedDelivery,
}),
previewState: { finalizedViaPreviewPost: false },
logVerboseMessage: vi.fn(),
deliverPayload: deliverFinal,
});
@@ -171,14 +176,8 @@ describe("deliverMattermostReplyWithDraftPreview", () => {
it("still delivers media when the text is already published", async () => {
const draftStream = createDraftStreamMock(null);
const confirmedReceipt = createMessageReceiptFromOutboundResults({
results: [{ channel: "mattermost", messageId: "sealed-post-1" }],
kind: "preview",
});
const mediaReceipt = createMessageReceiptFromOutboundResults({
results: [{ channel: "mattermost", messageId: "media-post-1" }],
kind: "media",
});
const confirmedDelivery = createConfirmedPreviewDelivery("sealed-post-1", "Already visible");
const mediaReceipt = createMattermostReceipt("media-post-1", "media");
const deliverFinal = vi.fn(async () => ({
outcome: "media" as const,
messageIds: ["media-post-1"],
@@ -187,25 +186,14 @@ describe("deliverMattermostReplyWithDraftPreview", () => {
content: "",
}));
const result = await deliverMattermostReplyWithDraftPreview({
const result = await deliverDraftPreview({
payload: { text: "Already visible", mediaUrl: "https://example.com/image.png" } as never,
info: { kind: "final" },
kind: "channel",
client: createMattermostClientMock(),
draftStream,
effectiveReplyToId: "thread-root-1",
resolvePreviewFinalText: () => ({
alreadyDelivered: true,
confirmedDelivery: {
outcome: "text",
messageIds: ["sealed-post-1"],
receipt: confirmedReceipt,
visibleReplySent: true,
content: "Already visible",
},
confirmedDelivery,
}),
previewState: { finalizedViaPreviewPost: false },
logVerboseMessage: vi.fn(),
deliverPayload: deliverFinal,
});
@@ -224,31 +212,17 @@ describe("deliverMattermostReplyWithDraftPreview", () => {
it("aggregates sealed and current preview posts into one terminal result", async () => {
const draftStream = createDraftStreamMock("current-preview");
const deliverFinal = createDeliverFinalMock();
const confirmedReceipt = createMessageReceiptFromOutboundResults({
results: [{ channel: "mattermost", messageId: "sealed-post-1" }],
kind: "preview",
});
const confirmedDelivery = createConfirmedPreviewDelivery("sealed-post-1", "First block");
const result = await deliverMattermostReplyWithDraftPreview({
const result = await deliverDraftPreview({
payload: { text: "First block\n\nSecond block" } as never,
info: { kind: "final" },
kind: "channel",
client: createMattermostClientMock(),
draftStream,
effectiveReplyToId: "thread-root-1",
resolvePreviewFinalText: () => ({
editText: "Second block",
alreadyDelivered: false,
confirmedDelivery: {
outcome: "text",
messageIds: ["sealed-post-1"],
receipt: confirmedReceipt,
visibleReplySent: true,
content: "First block",
},
confirmedDelivery,
}),
previewState: { finalizedViaPreviewPost: false },
logVerboseMessage: vi.fn(),
deliverPayload: deliverFinal,
});
@@ -268,32 +242,18 @@ describe("deliverMattermostReplyWithDraftPreview", () => {
it("sends only the remaining suffix after a partial boundary publish", async () => {
const draftStream = createDraftStreamMock(null);
const deliverFinal = createDeliverFinalMock();
const confirmedReceipt = createMessageReceiptFromOutboundResults({
results: [{ channel: "mattermost", messageId: "partial-post-1" }],
kind: "preview",
});
const confirmedDelivery = createConfirmedPreviewDelivery("partial-post-1", "First half");
const result = await deliverMattermostReplyWithDraftPreview({
const result = await deliverDraftPreview({
payload: { text: "First half Second half" } as never,
info: { kind: "final" },
kind: "channel",
client: createMattermostClientMock(),
draftStream,
effectiveReplyToId: "thread-root-1",
resolvePreviewFinalText: () => ({
editText: "Second half",
deliveryText: "Second half",
alreadyDelivered: false,
confirmedDelivery: {
outcome: "text",
messageIds: ["partial-post-1"],
receipt: confirmedReceipt,
visibleReplySent: true,
content: "First half",
},
confirmedDelivery,
}),
previewState: { finalizedViaPreviewPost: false },
logVerboseMessage: vi.fn(),
deliverPayload: deliverFinal,
});
@@ -343,15 +303,9 @@ describe("deliverMattermostReplyWithDraftPreview", () => {
const draftStream = createDraftStreamMock();
const deliverFinal = createDeliverFinalMock();
await deliverMattermostReplyWithDraftPreview({
await deliverDraftPreview({
payload: { text: "All good", replyToId: "reply-1" } as never,
info: { kind: "final" },
kind: "channel",
client: createMattermostClientMock(),
draftStream,
resolvePreviewFinalText,
previewState: { finalizedViaPreviewPost: false },
logVerboseMessage: vi.fn(),
deliverPayload: deliverFinal,
});
@@ -369,15 +323,9 @@ describe("deliverMattermostReplyWithDraftPreview", () => {
let caught: unknown;
try {
await deliverMattermostReplyWithDraftPreview({
await deliverDraftPreview({
payload: { text: "Already visible", replyToId: "reply-1" } as never,
info: { kind: "final" },
kind: "channel",
client: createMattermostClientMock(),
draftStream,
resolvePreviewFinalText,
previewState: { finalizedViaPreviewPost: false },
logVerboseMessage: vi.fn(),
deliverPayload: deliverFinal,
});
} catch (error: unknown) {
@@ -401,20 +349,14 @@ describe("deliverMattermostReplyWithDraftPreview", () => {
const draftStream = createDraftStreamMock();
const deliverFinal = createDeliverFinalMock();
await deliverMattermostReplyWithDraftPreview({
await deliverDraftPreview({
payload: {
text: "Photo",
replyToId: "reply-1",
mediaUrl: "https://example.com/a.png",
} as never,
info: { kind: "final" },
kind: "channel",
client: createMattermostClientMock(),
draftStream,
effectiveReplyToId: "thread-root-1",
resolvePreviewFinalText,
previewState: { finalizedViaPreviewPost: false },
logVerboseMessage: vi.fn(),
deliverPayload: deliverFinal,
});
@@ -428,21 +370,15 @@ describe("deliverMattermostReplyWithDraftPreview", () => {
const draftStream = createDraftStreamMock();
const deliverFinal = createDeliverFinalMock();
await deliverMattermostReplyWithDraftPreview({
await deliverDraftPreview({
payload: {
mediaUrl: "https://example.com/tts.mp3",
audioAsVoice: true,
spokenText: "Spoken answer",
ttsSupplement: { spokenText: "Spoken answer" },
} as never,
info: { kind: "final" },
kind: "channel",
client: createMattermostClientMock(),
draftStream,
effectiveReplyToId: "thread-root-1",
resolvePreviewFinalText,
previewState: { finalizedViaPreviewPost: false },
logVerboseMessage: vi.fn(),
deliverPayload: deliverFinal,
});
@@ -474,30 +410,21 @@ describe("deliverMattermostReplyWithDraftPreview", () => {
return {
outcome: "text" as const,
messageIds: ["supplement-post-1"],
receipt: createMessageReceiptFromOutboundResults({
results: [{ channel: "mattermost", messageId: "supplement-post-1" }],
kind: "media",
}),
receipt: createMattermostReceipt("supplement-post-1", "media"),
visibleReplySent: true,
content: payload.text ?? "",
};
});
const result = await deliverMattermostReplyWithDraftPreview({
const result = await deliverDraftPreview({
payload: {
mediaUrl: "https://example.com/tts.mp3",
audioAsVoice: true,
spokenText: "Spoken answer",
ttsSupplement: { spokenText: "Spoken answer" },
} as never,
info: { kind: "final" },
kind: "channel",
client: createMattermostClientMock(),
draftStream,
effectiveReplyToId: "thread-root-1",
resolvePreviewFinalText,
previewState: { finalizedViaPreviewPost: false },
logVerboseMessage: vi.fn(),
deliverPayload: deliverFinal,
});
@@ -512,10 +439,7 @@ describe("deliverMattermostReplyWithDraftPreview", () => {
it("preserves the finalized preview receipt when its supplement fails after sending", async () => {
const draftStream = createDraftStreamMock();
const mediaReceipt = createMessageReceiptFromOutboundResults({
results: [{ channel: "mattermost", messageId: "media-post-1" }],
kind: "media",
});
const mediaReceipt = createMattermostReceipt("media-post-1", "media");
const deliverFinal = vi.fn(async () => {
throw createChannelPartialDeliveryError(new Error("supplement bookkeeping failed"), {
messageIds: ["media-post-1"],
@@ -527,21 +451,15 @@ describe("deliverMattermostReplyWithDraftPreview", () => {
let caught: unknown;
try {
await deliverMattermostReplyWithDraftPreview({
await deliverDraftPreview({
payload: {
mediaUrl: "https://example.com/tts.mp3",
audioAsVoice: true,
spokenText: "Spoken answer",
ttsSupplement: { spokenText: "Spoken answer" },
} as never,
info: { kind: "final" },
kind: "channel",
client: createMattermostClientMock(),
draftStream,
effectiveReplyToId: "thread-root-1",
resolvePreviewFinalText,
previewState: { finalizedViaPreviewPost: false },
logVerboseMessage: vi.fn(),
deliverPayload: deliverFinal,
});
} catch (error: unknown) {
@@ -564,16 +482,13 @@ describe("deliverMattermostReplyWithDraftPreview", () => {
const deliverFinal = createDeliverFinalMock();
updateMattermostPostSpy.mockRejectedValueOnce(new Error("edit failed"));
await deliverMattermostReplyWithDraftPreview({
await deliverDraftPreview({
payload: {
mediaUrl: "https://example.com/tts.mp3",
audioAsVoice: true,
spokenText: "Spoken answer",
ttsSupplement: { spokenText: "Spoken answer" },
} as never,
info: { kind: "final" },
kind: "channel",
client: createMattermostClientMock(),
draftStream,
effectiveReplyToId: "thread-root-1",
resolvePreviewFinalText: (text) => ({
@@ -581,8 +496,6 @@ describe("deliverMattermostReplyWithDraftPreview", () => {
deliveryText: "",
alreadyDelivered: false,
}),
previewState: { finalizedViaPreviewPost: false },
logVerboseMessage: vi.fn(),
deliverPayload: deliverFinal,
});
@@ -603,7 +516,7 @@ describe("deliverMattermostReplyWithDraftPreview", () => {
const deliverFinal = createDeliverFinalMock();
updateMattermostPostSpy.mockRejectedValueOnce(new Error("edit failed"));
await deliverMattermostReplyWithDraftPreview({
await deliverDraftPreview({
payload: {
mediaUrl: "https://example.com/tts.mp3",
audioAsVoice: true,
@@ -613,9 +526,6 @@ describe("deliverMattermostReplyWithDraftPreview", () => {
visibleTextAlreadyDelivered: true,
},
} as never,
info: { kind: "final" },
kind: "channel",
client: createMattermostClientMock(),
draftStream,
effectiveReplyToId: "thread-root-1",
resolvePreviewFinalText: (text) => ({
@@ -623,8 +533,6 @@ describe("deliverMattermostReplyWithDraftPreview", () => {
deliveryText: text?.trim(),
alreadyDelivered: false,
}),
previewState: { finalizedViaPreviewPost: false },
logVerboseMessage: vi.fn(),
deliverPayload: deliverFinal,
});
@@ -643,34 +551,20 @@ describe("deliverMattermostReplyWithDraftPreview", () => {
const draftStream = createDraftStreamMock();
const deliverFinal = createDeliverFinalMock();
await deliverMattermostReplyWithDraftPreview({
await deliverDraftPreview({
payload: {
mediaUrl: "https://example.com/tts.mp3",
audioAsVoice: true,
spokenText: "Spoken answer",
ttsSupplement: { spokenText: "Spoken answer" },
} as never,
info: { kind: "final" },
kind: "channel",
client: createMattermostClientMock(),
draftStream,
effectiveReplyToId: "thread-root-1",
resolvePreviewFinalText: () => ({
deliveryText: "",
confirmedDelivery: {
outcome: "text",
messageIds: ["preview-post-1"],
receipt: createMessageReceiptFromOutboundResults({
results: [{ channel: "mattermost", messageId: "preview-post-1" }],
kind: "preview",
}),
visibleReplySent: true,
content: "Spoken answer",
},
confirmedDelivery: createConfirmedPreviewDelivery("preview-post-1", "Spoken answer"),
alreadyDelivered: true,
}),
previewState: { finalizedViaPreviewPost: false },
logVerboseMessage: vi.fn(),
deliverPayload: deliverFinal,
});
@@ -686,16 +580,10 @@ describe("deliverMattermostReplyWithDraftPreview", () => {
const draftStream = createDraftStreamMock();
const deliverFinal = createDeliverFinalMock();
await deliverMattermostReplyWithDraftPreview({
await deliverDraftPreview({
payload: { text: "Error", isError: true } as never,
info: { kind: "final" },
kind: "channel",
client: createMattermostClientMock(),
draftStream,
effectiveReplyToId: "thread-root-1",
resolvePreviewFinalText,
previewState: { finalizedViaPreviewPost: false },
logVerboseMessage: vi.fn(),
deliverPayload: deliverFinal,
});
@@ -709,16 +597,11 @@ describe("deliverMattermostReplyWithDraftPreview", () => {
const deliverFinal = createDeliverFinalMock();
const client = createMattermostClientMock();
await deliverMattermostReplyWithDraftPreview({
await deliverDraftPreview({
payload: { text: "Final answer", replyToId: "child-post-789" } as never,
info: { kind: "final" },
kind: "channel",
client,
draftStream,
effectiveReplyToId: "thread-root-456",
resolvePreviewFinalText,
previewState: { finalizedViaPreviewPost: false },
logVerboseMessage: vi.fn(),
deliverPayload: deliverFinal,
});
@@ -747,15 +630,9 @@ describe("deliverMattermostReplyWithDraftPreview", () => {
});
await expect(
deliverMattermostReplyWithDraftPreview({
deliverDraftPreview({
payload: { text: "Broken", replyToId: "reply-1" } as never,
info: { kind: "final" },
kind: "channel",
client: createMattermostClientMock(),
draftStream,
resolvePreviewFinalText,
previewState: { finalizedViaPreviewPost: false },
logVerboseMessage: vi.fn(),
deliverPayload: deliverFinal,
}),
).rejects.toThrow("send failed");