mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-25 03:45:46 -06:00
test(msteams): cover agent reaction removal parity (#128560)
Parity assessment for Microsoft's Lobster patch 0018 via giodl73-repo/lobster-plugins-and-patches.
This commit is contained in:
committed by
GitHub
parent
8f54c1ad04
commit
2de095746b
@@ -20,6 +20,7 @@ const {
|
||||
sendAdaptiveCardMSTeamsMock,
|
||||
sendMessageMSTeamsMock,
|
||||
unpinMessageMSTeamsMock,
|
||||
unreactMessageMSTeamsMock,
|
||||
} = vi.hoisted(() => ({
|
||||
addParticipantMSTeamsMock: vi.fn(),
|
||||
editMessageMSTeamsMock: vi.fn(),
|
||||
@@ -37,6 +38,7 @@ const {
|
||||
sendAdaptiveCardMSTeamsMock: vi.fn(),
|
||||
sendMessageMSTeamsMock: vi.fn(),
|
||||
unpinMessageMSTeamsMock: vi.fn(),
|
||||
unreactMessageMSTeamsMock: vi.fn(),
|
||||
}));
|
||||
vi.mock("./channel.runtime.js", () => ({
|
||||
msTeamsChannelRuntime: {
|
||||
@@ -56,6 +58,7 @@ vi.mock("./channel.runtime.js", () => ({
|
||||
sendAdaptiveCardMSTeams: sendAdaptiveCardMSTeamsMock,
|
||||
sendMessageMSTeams: sendMessageMSTeamsMock,
|
||||
unpinMessageMSTeams: unpinMessageMSTeamsMock,
|
||||
unreactMessageMSTeams: unreactMessageMSTeamsMock,
|
||||
},
|
||||
}));
|
||||
|
||||
@@ -76,6 +79,7 @@ const actionMocks = [
|
||||
sendAdaptiveCardMSTeamsMock,
|
||||
sendMessageMSTeamsMock,
|
||||
unpinMessageMSTeamsMock,
|
||||
unreactMessageMSTeamsMock,
|
||||
];
|
||||
const currentChannelId = "conversation:19:ctx@thread.tacv2";
|
||||
const graphTeamId = "11111111-1111-1111-1111-111111111111";
|
||||
@@ -1090,30 +1094,43 @@ describe("msteamsPlugin message actions", () => {
|
||||
expect(properties).toHaveProperty("pinnedMessageId");
|
||||
});
|
||||
|
||||
it.each([
|
||||
{
|
||||
chatType: "channel",
|
||||
conversationTarget: "conversation:19:c@thread.tacv2",
|
||||
currentMessagingTarget: "team-1/19:c@thread.tacv2",
|
||||
expectedTarget: "team-1/19:c@thread.tacv2",
|
||||
},
|
||||
{
|
||||
chatType: "group",
|
||||
conversationTarget: "conversation:19:g@thread.v2",
|
||||
currentMessagingTarget: undefined,
|
||||
expectedTarget: "conversation:19:g@thread.v2",
|
||||
},
|
||||
{
|
||||
chatType: "direct",
|
||||
conversationTarget: "conversation:a:dm",
|
||||
currentMessagingTarget: undefined,
|
||||
expectedTarget: "conversation:a:dm",
|
||||
},
|
||||
] as const)(
|
||||
"routes agent react actions and preserves their result shape for $chatType turns",
|
||||
async ({ chatType, conversationTarget, currentMessagingTarget, expectedTarget }) => {
|
||||
it.each(
|
||||
(
|
||||
[
|
||||
{
|
||||
chatType: "channel",
|
||||
conversationTarget: "conversation:19:c@thread.tacv2",
|
||||
currentMessagingTarget: "team-1/19:c@thread.tacv2",
|
||||
expectedTarget: "team-1/19:c@thread.tacv2",
|
||||
},
|
||||
{
|
||||
chatType: "group",
|
||||
conversationTarget: "conversation:19:g@thread.v2",
|
||||
currentMessagingTarget: undefined,
|
||||
expectedTarget: "conversation:19:g@thread.v2",
|
||||
},
|
||||
{
|
||||
chatType: "direct",
|
||||
conversationTarget: "conversation:a:dm",
|
||||
currentMessagingTarget: undefined,
|
||||
expectedTarget: "conversation:a:dm",
|
||||
},
|
||||
] as const
|
||||
).flatMap((conversation) =>
|
||||
[false, true].map((remove) => ({
|
||||
conversation,
|
||||
chatType: conversation.chatType,
|
||||
operation: remove ? "remove" : "add",
|
||||
remove,
|
||||
})),
|
||||
),
|
||||
)(
|
||||
"routes agent reaction $operation actions and preserves their result shape for $chatType turns",
|
||||
async ({ conversation, remove }) => {
|
||||
const { chatType, conversationTarget, currentMessagingTarget, expectedTarget } = conversation;
|
||||
const resultDetails = { ...(remove ? { removed: true } : {}), reactionType };
|
||||
await expectSuccessfulAction({
|
||||
mockFn: reactMessageMSTeamsMock,
|
||||
mockFn: remove ? unreactMessageMSTeamsMock : reactMessageMSTeamsMock,
|
||||
mockResult: { ok: true },
|
||||
action: "react",
|
||||
cfg: unrestrictedReadCfg,
|
||||
@@ -1123,6 +1140,7 @@ describe("msteamsPlugin message actions", () => {
|
||||
...(chatType === "channel" ? { target: conversationTarget } : {}),
|
||||
messageId: padded("msg-react"),
|
||||
emoji: padded(reactionType),
|
||||
...(remove ? { remove: true } : {}),
|
||||
},
|
||||
toolContext: {
|
||||
currentChannelProvider: "msteams",
|
||||
@@ -1135,11 +1153,11 @@ describe("msteamsPlugin message actions", () => {
|
||||
messageId: "msg-react",
|
||||
reactionType,
|
||||
},
|
||||
details: okMSTeamsActionDetails("react", { reactionType }),
|
||||
details: okMSTeamsActionDetails("react", resultDetails),
|
||||
contentDetails: {
|
||||
channel: "msteams",
|
||||
action: "react",
|
||||
reactionType,
|
||||
...resultDetails,
|
||||
ok: true,
|
||||
},
|
||||
});
|
||||
@@ -1258,20 +1276,24 @@ describe("msteamsPlugin message actions", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("reports the allowed reaction types when emoji is missing", async () => {
|
||||
await expectActionParamError(
|
||||
"react",
|
||||
{
|
||||
to: targetChannelId,
|
||||
messageId: "msg-4",
|
||||
},
|
||||
reactMissingEmojiError,
|
||||
{
|
||||
error: reactMissingEmojiDetail,
|
||||
validTypes: reactionTypes,
|
||||
},
|
||||
);
|
||||
});
|
||||
it.each([false, true])(
|
||||
"reports the allowed reaction types when emoji is missing (remove=%s)",
|
||||
async (remove) => {
|
||||
await expectActionParamError(
|
||||
"react",
|
||||
{
|
||||
to: targetChannelId,
|
||||
messageId: "msg-4",
|
||||
...(remove ? { remove: true } : {}),
|
||||
},
|
||||
reactMissingEmojiError,
|
||||
{
|
||||
error: reactMissingEmojiDetail,
|
||||
validTypes: reactionTypes,
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
it("requires a non-empty search query after trimming", async () => {
|
||||
await expectActionError(
|
||||
@@ -1342,6 +1364,11 @@ describe("msteamsPlugin message actions", () => {
|
||||
params: { to: graphChannelTarget, messageId: "msg-1", emoji: "like" },
|
||||
runtimeMock: reactMessageMSTeamsMock,
|
||||
},
|
||||
{
|
||||
action: "react",
|
||||
params: { to: graphChannelTarget, messageId: "msg-1", emoji: "like", remove: true },
|
||||
runtimeMock: unreactMessageMSTeamsMock,
|
||||
},
|
||||
])("rejects a blocked $action target before the provider operation", async (testCase) => {
|
||||
await expect(
|
||||
runAction({
|
||||
|
||||
@@ -131,6 +131,7 @@ describe("reactMessageMSTeams", () => {
|
||||
});
|
||||
|
||||
expect(result).toEqual({ ok: true });
|
||||
expect(mockState.resolveGraphToken).toHaveBeenCalledWith({}, { preferDelegated: true });
|
||||
expect(mockState.mutateGraphJson).toHaveBeenCalledWith({
|
||||
token: TOKEN,
|
||||
path: `/chats/${encodeURIComponent(CHAT_ID)}/messages/msg-1/setReaction`,
|
||||
@@ -236,6 +237,7 @@ describe("unreactMessageMSTeams", () => {
|
||||
});
|
||||
|
||||
expect(result).toEqual({ ok: true });
|
||||
expect(mockState.resolveGraphToken).toHaveBeenCalledWith({}, { preferDelegated: true });
|
||||
expect(mockState.mutateGraphJson).toHaveBeenCalledWith({
|
||||
token: TOKEN,
|
||||
path: `/chats/${encodeURIComponent(CHAT_ID)}/messages/msg-1/unsetReaction`,
|
||||
@@ -264,4 +266,29 @@ describe("unreactMessageMSTeams", () => {
|
||||
beta: true,
|
||||
});
|
||||
});
|
||||
|
||||
it.each([
|
||||
{ reactionType: " LAUGH ", expectedReaction: "😆" },
|
||||
{ reactionType: " 🎉 ", expectedReaction: "🎉" },
|
||||
])(
|
||||
"normalizes $reactionType when removing a reaction",
|
||||
async ({ reactionType, expectedReaction }) => {
|
||||
mockState.mutateGraphJson.mockResolvedValue(undefined);
|
||||
|
||||
await unreactMessageMSTeams({
|
||||
cfg: {} as OpenClawConfig,
|
||||
to: CHAT_ID,
|
||||
messageId: "msg-1",
|
||||
reactionType,
|
||||
});
|
||||
|
||||
expect(mockState.mutateGraphJson).toHaveBeenCalledWith({
|
||||
token: TOKEN,
|
||||
path: `/chats/${encodeURIComponent(CHAT_ID)}/messages/msg-1/unsetReaction`,
|
||||
method: "POST",
|
||||
body: { reactionType: expectedReaction },
|
||||
beta: true,
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user