mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-18 17:34:45 +00:00
test: tighten msteams send assertions
This commit is contained in:
@@ -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();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user