test: tighten msteams send assertions

This commit is contained in:
Peter Steinberger
2026-05-10 21:28:08 +01:00
parent 3066602f47
commit 7ee92be145

View File

@@ -181,6 +181,26 @@ function mockSharePointPdfUpload(params: {
});
}
type MockWithCalls = {
mock: { calls: unknown[][] };
};
function firstObjectArg(mock: MockWithCalls): Record<string, unknown> {
const value = mock.mock.calls[0]?.[0];
if (value === undefined || value === null || typeof value !== "object" || Array.isArray(value)) {
throw new Error("expected first mock call to receive an object argument");
}
return value as Record<string, unknown>;
}
function continueConversationRef(mock: MockWithCalls): Record<string, unknown> {
const ref = mock.mock.calls[0]?.[1];
if (ref === undefined || ref === null || typeof ref !== "object" || Array.isArray(ref)) {
throw new Error("expected continueConversation ref object");
}
return ref as Record<string, unknown>;
}
describe("sendMessageMSTeams", () => {
beforeEach(() => {
mockState.loadOutboundMediaFromUrl.mockReset();
@@ -244,21 +264,16 @@ describe("sendMessageMSTeams", () => {
},
);
expect(mockState.sendMSTeamsMessages).toHaveBeenCalledWith(
expect.objectContaining({
messages: [
expect.objectContaining({
text: "hello",
mediaUrl: `data:image/png;base64,${mediaBuffer.toString("base64")}`,
}),
],
}),
);
expect(result.receipt).toMatchObject({
primaryPlatformMessageId: "message-1",
platformMessageIds: ["message-1"],
parts: [expect.objectContaining({ platformMessageId: "message-1", kind: "media" })],
});
const sendPayload = firstObjectArg(mockState.sendMSTeamsMessages);
const messages = sendPayload.messages as Array<Record<string, unknown>>;
expect(messages).toHaveLength(1);
expect(messages[0]?.text).toBe("hello");
expect(messages[0]?.mediaUrl).toBe(`data:image/png;base64,${mediaBuffer.toString("base64")}`);
expect(result.receipt?.primaryPlatformMessageId).toBe("message-1");
expect(result.receipt?.platformMessageIds).toEqual(["message-1"]);
expect(result.receipt?.parts).toHaveLength(1);
expect(result.receipt?.parts[0]?.platformMessageId).toBe("message-1");
expect(result.receipt?.parts[0]?.kind).toBe("media");
});
it("sends with provided cfg even when Teams runtime text helpers are unavailable", async () => {
@@ -277,15 +292,13 @@ describe("sendMessageMSTeams", () => {
text: "hello",
});
expect(result).toMatchObject({
messageId: "message-1",
conversationId: "19:conversation@thread.tacv2",
receipt: {
primaryPlatformMessageId: "message-1",
platformMessageIds: ["message-1"],
parts: [expect.objectContaining({ platformMessageId: "message-1", kind: "text" })],
},
});
expect(result.messageId).toBe("message-1");
expect(result.conversationId).toBe("19:conversation@thread.tacv2");
expect(result.receipt?.primaryPlatformMessageId).toBe("message-1");
expect(result.receipt?.platformMessageIds).toEqual(["message-1"]);
expect(result.receipt?.parts).toHaveLength(1);
expect(result.receipt?.parts[0]?.platformMessageId).toBe("message-1");
expect(result.receipt?.parts[0]?.kind).toBe("text");
expect(mockState.resolveMarkdownTableMode).toHaveBeenCalledWith({
cfg: {},
@@ -317,9 +330,7 @@ describe("sendMessageMSTeams", () => {
text: "threaded reply",
});
expect(mockState.sendMSTeamsMessages).toHaveBeenCalledWith(
expect.objectContaining({ replyStyle: "thread" }),
);
expect(firstObjectArg(mockState.sendMSTeamsMessages).replyStyle).toBe("thread");
});
it("keeps top-level proactive replyStyle when resolved for a channel", async () => {
@@ -345,9 +356,7 @@ describe("sendMessageMSTeams", () => {
text: "top-level reply",
});
expect(mockState.sendMSTeamsMessages).toHaveBeenCalledWith(
expect.objectContaining({ replyStyle: "top-level" }),
);
expect(firstObjectArg(mockState.sendMSTeamsMessages).replyStyle).toBe("top-level");
});
it("uses graphChatId instead of conversationId when uploading to SharePoint", async () => {
@@ -378,12 +387,9 @@ describe("sendMessageMSTeams", () => {
});
// The Graph-native chatId must be passed to SharePoint upload, not the Bot Framework ID
expect(mockState.uploadAndShareSharePoint).toHaveBeenCalledWith(
expect.objectContaining({
chatId: graphChatId,
siteId: "site-123",
}),
);
const uploadPayload = firstObjectArg(mockState.uploadAndShareSharePoint);
expect(uploadPayload.chatId).toBe(graphChatId);
expect(uploadPayload.siteId).toBe("site-123");
});
it("falls back to conversationId when graphChatId is not available", async () => {
@@ -411,12 +417,9 @@ describe("sendMessageMSTeams", () => {
});
// Falls back to conversationId when graphChatId is null
expect(mockState.uploadAndShareSharePoint).toHaveBeenCalledWith(
expect.objectContaining({
chatId: botFrameworkConversationId,
siteId: "site-456",
}),
);
const uploadPayload = firstObjectArg(mockState.uploadAndShareSharePoint);
expect(uploadPayload.chatId).toBe(botFrameworkConversationId);
expect(uploadPayload.siteId).toBe("site-456");
});
});
@@ -477,9 +480,7 @@ describe("editMessageMSTeams", () => {
expect(mockContinueConversation).toHaveBeenCalledTimes(1);
const continueConversationCall = mockContinueConversation.mock.calls[0];
expect(continueConversationCall?.[0]).toBe("app-id");
expect(continueConversationCall?.[1]).toEqual(
expect.objectContaining({ activityId: undefined }),
);
expect(continueConversationRef(mockContinueConversation).activityId).toBeUndefined();
expect(typeof continueConversationCall?.[2]).toBe("function");
expect(mockUpdateActivity).toHaveBeenCalledWith({
type: "message",
@@ -530,9 +531,7 @@ describe("deleteMessageMSTeams", () => {
expect(mockContinueConversation).toHaveBeenCalledTimes(1);
const continueConversationCall = mockContinueConversation.mock.calls[0];
expect(continueConversationCall?.[0]).toBe("app-id");
expect(continueConversationCall?.[1]).toEqual(
expect.objectContaining({ activityId: undefined }),
);
expect(continueConversationRef(mockContinueConversation).activityId).toBeUndefined();
expect(typeof continueConversationCall?.[2]).toBe("function");
expect(mockDeleteActivity).toHaveBeenCalledWith("activity-456");
});
@@ -572,8 +571,6 @@ describe("deleteMessageMSTeams", () => {
// appId should be forwarded correctly
expect(mockContinueConversation.mock.calls[0]?.[0]).toBe("my-app-id");
// activityId on the proactive ref should be cleared (undefined) — proactive pattern
expect(mockContinueConversation.mock.calls[0]?.[1]).toMatchObject({
activityId: undefined,
});
expect(continueConversationRef(mockContinueConversation).activityId).toBeUndefined();
});
});