mirror of
https://github.com/moltbot/moltbot.git
synced 2026-05-02 02:57:51 +00:00
test: dedupe fixtures and test harness setup
This commit is contained in:
@@ -1,9 +1,5 @@
|
||||
import type { PluginRuntime } from "openclaw/plugin-sdk";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { downloadMSTeamsAttachments } from "./attachments/download.js";
|
||||
import { buildMSTeamsGraphMessageUrls, downloadMSTeamsGraphMedia } from "./attachments/graph.js";
|
||||
import { buildMSTeamsAttachmentPlaceholder } from "./attachments/html.js";
|
||||
import { buildMSTeamsMediaPayload } from "./attachments/payload.js";
|
||||
import { setMSTeamsRuntime } from "./runtime.js";
|
||||
|
||||
/** Mock DNS resolver that always returns a public IP (for anti-SSRF validation in tests). */
|
||||
@@ -52,7 +48,58 @@ const runtimeStub = {
|
||||
},
|
||||
} as unknown as PluginRuntime;
|
||||
|
||||
type AttachmentsModule = typeof import("./attachments.js");
|
||||
type DownloadAttachmentsParams = Parameters<AttachmentsModule["downloadMSTeamsAttachments"]>[0];
|
||||
type DownloadGraphMediaParams = Parameters<AttachmentsModule["downloadMSTeamsGraphMedia"]>[0];
|
||||
|
||||
const DEFAULT_MESSAGE_URL = "https://graph.microsoft.com/v1.0/chats/19%3Achat/messages/123";
|
||||
const DEFAULT_MAX_BYTES = 1024 * 1024;
|
||||
const DEFAULT_ALLOW_HOSTS = ["x"];
|
||||
|
||||
const createOkFetchMock = (contentType: string, payload = "png") =>
|
||||
vi.fn(async () => {
|
||||
return new Response(Buffer.from(payload), {
|
||||
status: 200,
|
||||
headers: { "content-type": contentType },
|
||||
});
|
||||
});
|
||||
|
||||
const buildDownloadParams = (
|
||||
attachments: DownloadAttachmentsParams["attachments"],
|
||||
overrides: Partial<
|
||||
Omit<DownloadAttachmentsParams, "attachments" | "maxBytes" | "allowHosts" | "resolveFn">
|
||||
> &
|
||||
Pick<DownloadAttachmentsParams, "allowHosts" | "resolveFn"> = {},
|
||||
): DownloadAttachmentsParams => {
|
||||
return {
|
||||
attachments,
|
||||
maxBytes: DEFAULT_MAX_BYTES,
|
||||
allowHosts: DEFAULT_ALLOW_HOSTS,
|
||||
resolveFn: publicResolveFn,
|
||||
...overrides,
|
||||
};
|
||||
};
|
||||
|
||||
const buildDownloadGraphParams = (
|
||||
fetchFn: typeof fetch,
|
||||
overrides: Partial<
|
||||
Omit<DownloadGraphMediaParams, "messageUrl" | "tokenProvider" | "maxBytes">
|
||||
> = {},
|
||||
): DownloadGraphMediaParams => {
|
||||
return {
|
||||
messageUrl: DEFAULT_MESSAGE_URL,
|
||||
tokenProvider: { getAccessToken: vi.fn(async () => "token") },
|
||||
maxBytes: DEFAULT_MAX_BYTES,
|
||||
fetchFn,
|
||||
...overrides,
|
||||
};
|
||||
};
|
||||
|
||||
describe("msteams attachments", () => {
|
||||
const load = async () => {
|
||||
return await import("./attachments.js");
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
detectMimeMock.mockClear();
|
||||
saveMediaBufferMock.mockClear();
|
||||
@@ -62,11 +109,13 @@ describe("msteams attachments", () => {
|
||||
|
||||
describe("buildMSTeamsAttachmentPlaceholder", () => {
|
||||
it("returns empty string when no attachments", async () => {
|
||||
const { buildMSTeamsAttachmentPlaceholder } = await load();
|
||||
expect(buildMSTeamsAttachmentPlaceholder(undefined)).toBe("");
|
||||
expect(buildMSTeamsAttachmentPlaceholder([])).toBe("");
|
||||
});
|
||||
|
||||
it("returns image placeholder for image attachments", async () => {
|
||||
const { buildMSTeamsAttachmentPlaceholder } = await load();
|
||||
expect(
|
||||
buildMSTeamsAttachmentPlaceholder([
|
||||
{ contentType: "image/png", contentUrl: "https://x/img.png" },
|
||||
@@ -81,6 +130,7 @@ describe("msteams attachments", () => {
|
||||
});
|
||||
|
||||
it("treats Teams file.download.info image attachments as images", async () => {
|
||||
const { buildMSTeamsAttachmentPlaceholder } = await load();
|
||||
expect(
|
||||
buildMSTeamsAttachmentPlaceholder([
|
||||
{
|
||||
@@ -92,6 +142,7 @@ describe("msteams attachments", () => {
|
||||
});
|
||||
|
||||
it("returns document placeholder for non-image attachments", async () => {
|
||||
const { buildMSTeamsAttachmentPlaceholder } = await load();
|
||||
expect(
|
||||
buildMSTeamsAttachmentPlaceholder([
|
||||
{ contentType: "application/pdf", contentUrl: "https://x/x.pdf" },
|
||||
@@ -106,6 +157,7 @@ describe("msteams attachments", () => {
|
||||
});
|
||||
|
||||
it("counts inline images in text/html attachments", async () => {
|
||||
const { buildMSTeamsAttachmentPlaceholder } = await load();
|
||||
expect(
|
||||
buildMSTeamsAttachmentPlaceholder([
|
||||
{
|
||||
@@ -127,20 +179,13 @@ describe("msteams attachments", () => {
|
||||
|
||||
describe("downloadMSTeamsAttachments", () => {
|
||||
it("downloads and stores image contentUrl attachments", async () => {
|
||||
const fetchMock = vi.fn(async () => {
|
||||
return new Response(Buffer.from("png"), {
|
||||
status: 200,
|
||||
headers: { "content-type": "image/png" },
|
||||
});
|
||||
});
|
||||
|
||||
const media = await downloadMSTeamsAttachments({
|
||||
attachments: [{ contentType: "image/png", contentUrl: "https://x/img" }],
|
||||
maxBytes: 1024 * 1024,
|
||||
allowHosts: ["x"],
|
||||
fetchFn: fetchMock as unknown as typeof fetch,
|
||||
resolveFn: publicResolveFn,
|
||||
});
|
||||
const { downloadMSTeamsAttachments } = await load();
|
||||
const fetchMock = createOkFetchMock("image/png");
|
||||
const media = await downloadMSTeamsAttachments(
|
||||
buildDownloadParams([{ contentType: "image/png", contentUrl: "https://x/img" }], {
|
||||
fetchFn: fetchMock as unknown as typeof fetch,
|
||||
}),
|
||||
);
|
||||
|
||||
expect(fetchMock).toHaveBeenCalled();
|
||||
expect(saveMediaBufferMock).toHaveBeenCalled();
|
||||
@@ -149,50 +194,38 @@ describe("msteams attachments", () => {
|
||||
});
|
||||
|
||||
it("supports Teams file.download.info downloadUrl attachments", async () => {
|
||||
const fetchMock = vi.fn(async () => {
|
||||
return new Response(Buffer.from("png"), {
|
||||
status: 200,
|
||||
headers: { "content-type": "image/png" },
|
||||
});
|
||||
});
|
||||
|
||||
const media = await downloadMSTeamsAttachments({
|
||||
attachments: [
|
||||
{
|
||||
contentType: "application/vnd.microsoft.teams.file.download.info",
|
||||
content: { downloadUrl: "https://x/dl", fileType: "png" },
|
||||
},
|
||||
],
|
||||
maxBytes: 1024 * 1024,
|
||||
allowHosts: ["x"],
|
||||
fetchFn: fetchMock as unknown as typeof fetch,
|
||||
resolveFn: publicResolveFn,
|
||||
});
|
||||
const { downloadMSTeamsAttachments } = await load();
|
||||
const fetchMock = createOkFetchMock("image/png");
|
||||
const media = await downloadMSTeamsAttachments(
|
||||
buildDownloadParams(
|
||||
[
|
||||
{
|
||||
contentType: "application/vnd.microsoft.teams.file.download.info",
|
||||
content: { downloadUrl: "https://x/dl", fileType: "png" },
|
||||
},
|
||||
],
|
||||
{ fetchFn: fetchMock as unknown as typeof fetch },
|
||||
),
|
||||
);
|
||||
|
||||
expect(fetchMock).toHaveBeenCalled();
|
||||
expect(media).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("downloads non-image file attachments (PDF)", async () => {
|
||||
const fetchMock = vi.fn(async () => {
|
||||
return new Response(Buffer.from("pdf"), {
|
||||
status: 200,
|
||||
headers: { "content-type": "application/pdf" },
|
||||
});
|
||||
});
|
||||
const { downloadMSTeamsAttachments } = await load();
|
||||
const fetchMock = createOkFetchMock("application/pdf", "pdf");
|
||||
detectMimeMock.mockResolvedValueOnce("application/pdf");
|
||||
saveMediaBufferMock.mockResolvedValueOnce({
|
||||
path: "/tmp/saved.pdf",
|
||||
contentType: "application/pdf",
|
||||
});
|
||||
|
||||
const media = await downloadMSTeamsAttachments({
|
||||
attachments: [{ contentType: "application/pdf", contentUrl: "https://x/doc.pdf" }],
|
||||
maxBytes: 1024 * 1024,
|
||||
allowHosts: ["x"],
|
||||
fetchFn: fetchMock as unknown as typeof fetch,
|
||||
resolveFn: publicResolveFn,
|
||||
});
|
||||
const media = await downloadMSTeamsAttachments(
|
||||
buildDownloadParams([{ contentType: "application/pdf", contentUrl: "https://x/doc.pdf" }], {
|
||||
fetchFn: fetchMock as unknown as typeof fetch,
|
||||
}),
|
||||
);
|
||||
|
||||
expect(fetchMock).toHaveBeenCalled();
|
||||
expect(media).toHaveLength(1);
|
||||
@@ -201,48 +234,42 @@ describe("msteams attachments", () => {
|
||||
});
|
||||
|
||||
it("downloads inline image URLs from html attachments", async () => {
|
||||
const fetchMock = vi.fn(async () => {
|
||||
return new Response(Buffer.from("png"), {
|
||||
status: 200,
|
||||
headers: { "content-type": "image/png" },
|
||||
});
|
||||
});
|
||||
|
||||
const media = await downloadMSTeamsAttachments({
|
||||
attachments: [
|
||||
{
|
||||
contentType: "text/html",
|
||||
content: '<img src="https://x/inline.png" />',
|
||||
},
|
||||
],
|
||||
maxBytes: 1024 * 1024,
|
||||
allowHosts: ["x"],
|
||||
fetchFn: fetchMock as unknown as typeof fetch,
|
||||
resolveFn: publicResolveFn,
|
||||
});
|
||||
const { downloadMSTeamsAttachments } = await load();
|
||||
const fetchMock = createOkFetchMock("image/png");
|
||||
const media = await downloadMSTeamsAttachments(
|
||||
buildDownloadParams(
|
||||
[
|
||||
{
|
||||
contentType: "text/html",
|
||||
content: '<img src="https://x/inline.png" />',
|
||||
},
|
||||
],
|
||||
{ fetchFn: fetchMock as unknown as typeof fetch },
|
||||
),
|
||||
);
|
||||
|
||||
expect(media).toHaveLength(1);
|
||||
expect(fetchMock).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("stores inline data:image base64 payloads", async () => {
|
||||
const { downloadMSTeamsAttachments } = await load();
|
||||
const base64 = Buffer.from("png").toString("base64");
|
||||
const media = await downloadMSTeamsAttachments({
|
||||
attachments: [
|
||||
const media = await downloadMSTeamsAttachments(
|
||||
buildDownloadParams([
|
||||
{
|
||||
contentType: "text/html",
|
||||
content: `<img src="data:image/png;base64,${base64}" />`,
|
||||
},
|
||||
],
|
||||
maxBytes: 1024 * 1024,
|
||||
allowHosts: ["x"],
|
||||
});
|
||||
]),
|
||||
);
|
||||
|
||||
expect(media).toHaveLength(1);
|
||||
expect(saveMediaBufferMock).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("retries with auth when the first request is unauthorized", async () => {
|
||||
const { downloadMSTeamsAttachments } = await load();
|
||||
const fetchMock = vi.fn(async (_url: string, opts?: RequestInit) => {
|
||||
const headers = new Headers(opts?.headers);
|
||||
const hasAuth = Boolean(headers.get("Authorization"));
|
||||
@@ -255,21 +282,20 @@ describe("msteams attachments", () => {
|
||||
});
|
||||
});
|
||||
|
||||
const media = await downloadMSTeamsAttachments({
|
||||
attachments: [{ contentType: "image/png", contentUrl: "https://x/img" }],
|
||||
maxBytes: 1024 * 1024,
|
||||
tokenProvider: { getAccessToken: vi.fn(async () => "token") },
|
||||
allowHosts: ["x"],
|
||||
authAllowHosts: ["x"],
|
||||
fetchFn: fetchMock as unknown as typeof fetch,
|
||||
resolveFn: publicResolveFn,
|
||||
});
|
||||
const media = await downloadMSTeamsAttachments(
|
||||
buildDownloadParams([{ contentType: "image/png", contentUrl: "https://x/img" }], {
|
||||
tokenProvider: { getAccessToken: vi.fn(async () => "token") },
|
||||
authAllowHosts: ["x"],
|
||||
fetchFn: fetchMock as unknown as typeof fetch,
|
||||
}),
|
||||
);
|
||||
|
||||
expect(fetchMock).toHaveBeenCalled();
|
||||
expect(media).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("skips auth retries when the host is not in auth allowlist", async () => {
|
||||
const { downloadMSTeamsAttachments } = await load();
|
||||
const tokenProvider = { getAccessToken: vi.fn(async () => "token") };
|
||||
const fetchMock = vi.fn(async (_url: string, opts?: RequestInit) => {
|
||||
const headers = new Headers(opts?.headers);
|
||||
@@ -283,17 +309,17 @@ describe("msteams attachments", () => {
|
||||
});
|
||||
});
|
||||
|
||||
const media = await downloadMSTeamsAttachments({
|
||||
attachments: [
|
||||
{ contentType: "image/png", contentUrl: "https://attacker.azureedge.net/img" },
|
||||
],
|
||||
maxBytes: 1024 * 1024,
|
||||
tokenProvider,
|
||||
allowHosts: ["azureedge.net"],
|
||||
authAllowHosts: ["graph.microsoft.com"],
|
||||
fetchFn: fetchMock as unknown as typeof fetch,
|
||||
resolveFn: publicResolveFn,
|
||||
});
|
||||
const media = await downloadMSTeamsAttachments(
|
||||
buildDownloadParams(
|
||||
[{ contentType: "image/png", contentUrl: "https://attacker.azureedge.net/img" }],
|
||||
{
|
||||
tokenProvider,
|
||||
allowHosts: ["azureedge.net"],
|
||||
authAllowHosts: ["graph.microsoft.com"],
|
||||
fetchFn: fetchMock as unknown as typeof fetch,
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
expect(media).toHaveLength(0);
|
||||
expect(fetchMock).toHaveBeenCalled();
|
||||
@@ -301,13 +327,15 @@ describe("msteams attachments", () => {
|
||||
});
|
||||
|
||||
it("skips urls outside the allowlist", async () => {
|
||||
const { downloadMSTeamsAttachments } = await load();
|
||||
const fetchMock = vi.fn();
|
||||
const media = await downloadMSTeamsAttachments({
|
||||
attachments: [{ contentType: "image/png", contentUrl: "https://evil.test/img" }],
|
||||
maxBytes: 1024 * 1024,
|
||||
allowHosts: ["graph.microsoft.com"],
|
||||
fetchFn: fetchMock as unknown as typeof fetch,
|
||||
});
|
||||
const media = await downloadMSTeamsAttachments(
|
||||
buildDownloadParams([{ contentType: "image/png", contentUrl: "https://evil.test/img" }], {
|
||||
allowHosts: ["graph.microsoft.com"],
|
||||
resolveFn: undefined,
|
||||
fetchFn: fetchMock as unknown as typeof fetch,
|
||||
}),
|
||||
);
|
||||
|
||||
expect(media).toHaveLength(0);
|
||||
expect(fetchMock).not.toHaveBeenCalled();
|
||||
@@ -316,6 +344,7 @@ describe("msteams attachments", () => {
|
||||
|
||||
describe("buildMSTeamsGraphMessageUrls", () => {
|
||||
it("builds channel message urls", async () => {
|
||||
const { buildMSTeamsGraphMessageUrls } = await load();
|
||||
const urls = buildMSTeamsGraphMessageUrls({
|
||||
conversationType: "channel",
|
||||
conversationId: "19:thread@thread.tacv2",
|
||||
@@ -326,6 +355,7 @@ describe("msteams attachments", () => {
|
||||
});
|
||||
|
||||
it("builds channel reply urls when replyToId is present", async () => {
|
||||
const { buildMSTeamsGraphMessageUrls } = await load();
|
||||
const urls = buildMSTeamsGraphMessageUrls({
|
||||
conversationType: "channel",
|
||||
messageId: "reply-id",
|
||||
@@ -338,6 +368,7 @@ describe("msteams attachments", () => {
|
||||
});
|
||||
|
||||
it("builds chat message urls", async () => {
|
||||
const { buildMSTeamsGraphMessageUrls } = await load();
|
||||
const urls = buildMSTeamsGraphMessageUrls({
|
||||
conversationType: "groupChat",
|
||||
conversationId: "19:chat@thread.v2",
|
||||
@@ -349,6 +380,7 @@ describe("msteams attachments", () => {
|
||||
|
||||
describe("downloadMSTeamsGraphMedia", () => {
|
||||
it("downloads hostedContents images", async () => {
|
||||
const { downloadMSTeamsGraphMedia } = await load();
|
||||
const base64 = Buffer.from("png").toString("base64");
|
||||
const fetchMock = vi.fn(async (url: string) => {
|
||||
if (url.endsWith("/hostedContents")) {
|
||||
@@ -371,12 +403,9 @@ describe("msteams attachments", () => {
|
||||
return new Response("not found", { status: 404 });
|
||||
});
|
||||
|
||||
const media = await downloadMSTeamsGraphMedia({
|
||||
messageUrl: "https://graph.microsoft.com/v1.0/chats/19%3Achat/messages/123",
|
||||
tokenProvider: { getAccessToken: vi.fn(async () => "token") },
|
||||
maxBytes: 1024 * 1024,
|
||||
fetchFn: fetchMock as unknown as typeof fetch,
|
||||
});
|
||||
const media = await downloadMSTeamsGraphMedia(
|
||||
buildDownloadGraphParams(fetchMock as unknown as typeof fetch),
|
||||
);
|
||||
|
||||
expect(media.media).toHaveLength(1);
|
||||
expect(fetchMock).toHaveBeenCalled();
|
||||
@@ -384,6 +413,7 @@ describe("msteams attachments", () => {
|
||||
});
|
||||
|
||||
it("merges SharePoint reference attachments with hosted content", async () => {
|
||||
const { downloadMSTeamsGraphMedia } = await load();
|
||||
const hostedBase64 = Buffer.from("png").toString("base64");
|
||||
const shareUrl = "https://contoso.sharepoint.com/site/file";
|
||||
const fetchMock = vi.fn(async (url: string) => {
|
||||
@@ -440,17 +470,15 @@ describe("msteams attachments", () => {
|
||||
return new Response("not found", { status: 404 });
|
||||
});
|
||||
|
||||
const media = await downloadMSTeamsGraphMedia({
|
||||
messageUrl: "https://graph.microsoft.com/v1.0/chats/19%3Achat/messages/123",
|
||||
tokenProvider: { getAccessToken: vi.fn(async () => "token") },
|
||||
maxBytes: 1024 * 1024,
|
||||
fetchFn: fetchMock as unknown as typeof fetch,
|
||||
});
|
||||
const media = await downloadMSTeamsGraphMedia(
|
||||
buildDownloadGraphParams(fetchMock as unknown as typeof fetch),
|
||||
);
|
||||
|
||||
expect(media.media).toHaveLength(2);
|
||||
});
|
||||
|
||||
it("blocks SharePoint redirects to hosts outside allowHosts", async () => {
|
||||
const { downloadMSTeamsGraphMedia } = await load();
|
||||
const shareUrl = "https://contoso.sharepoint.com/site/file";
|
||||
const escapedUrl = "https://evil.example/internal.pdf";
|
||||
fetchRemoteMediaMock.mockImplementationOnce(async (params) => {
|
||||
@@ -515,13 +543,11 @@ describe("msteams attachments", () => {
|
||||
return new Response("not found", { status: 404 });
|
||||
});
|
||||
|
||||
const media = await downloadMSTeamsGraphMedia({
|
||||
messageUrl: "https://graph.microsoft.com/v1.0/chats/19%3Achat/messages/123",
|
||||
tokenProvider: { getAccessToken: vi.fn(async () => "token") },
|
||||
maxBytes: 1024 * 1024,
|
||||
allowHosts: ["graph.microsoft.com", "contoso.sharepoint.com"],
|
||||
fetchFn: fetchMock as unknown as typeof fetch,
|
||||
});
|
||||
const media = await downloadMSTeamsGraphMedia(
|
||||
buildDownloadGraphParams(fetchMock as unknown as typeof fetch, {
|
||||
allowHosts: ["graph.microsoft.com", "contoso.sharepoint.com"],
|
||||
}),
|
||||
);
|
||||
|
||||
expect(media.media).toHaveLength(0);
|
||||
const calledUrls = fetchMock.mock.calls.map((call) => String(call[0]));
|
||||
@@ -534,6 +560,7 @@ describe("msteams attachments", () => {
|
||||
|
||||
describe("buildMSTeamsMediaPayload", () => {
|
||||
it("returns single and multi-file fields", async () => {
|
||||
const { buildMSTeamsMediaPayload } = await load();
|
||||
const payload = buildMSTeamsMediaPayload([
|
||||
{ path: "/tmp/a.png", contentType: "image/png" },
|
||||
{ path: "/tmp/b.png", contentType: "image/png" },
|
||||
|
||||
@@ -49,6 +49,28 @@ const runtimeStub = {
|
||||
},
|
||||
} as unknown as PluginRuntime;
|
||||
|
||||
const createNoopAdapter = (): MSTeamsAdapter => ({
|
||||
continueConversation: async () => {},
|
||||
process: async () => {},
|
||||
});
|
||||
|
||||
const createRecordedSendActivity = (
|
||||
sink: string[],
|
||||
failFirstWithStatusCode?: number,
|
||||
): ((activity: unknown) => Promise<{ id: string }>) => {
|
||||
let attempts = 0;
|
||||
return async (activity: unknown) => {
|
||||
const { text } = activity as { text?: string };
|
||||
const content = text ?? "";
|
||||
sink.push(content);
|
||||
attempts += 1;
|
||||
if (failFirstWithStatusCode !== undefined && attempts === 1) {
|
||||
throw Object.assign(new Error("send failed"), { statusCode: failFirstWithStatusCode });
|
||||
}
|
||||
return { id: `id:${content}` };
|
||||
};
|
||||
};
|
||||
|
||||
describe("msteams messenger", () => {
|
||||
beforeEach(() => {
|
||||
setMSTeamsRuntime(runtimeStub);
|
||||
@@ -117,17 +139,9 @@ describe("msteams messenger", () => {
|
||||
it("sends thread messages via the provided context", async () => {
|
||||
const sent: string[] = [];
|
||||
const ctx = {
|
||||
sendActivity: async (activity: unknown) => {
|
||||
const { text } = activity as { text?: string };
|
||||
sent.push(text ?? "");
|
||||
return { id: `id:${text ?? ""}` };
|
||||
},
|
||||
};
|
||||
|
||||
const adapter: MSTeamsAdapter = {
|
||||
continueConversation: async () => {},
|
||||
process: async () => {},
|
||||
sendActivity: createRecordedSendActivity(sent),
|
||||
};
|
||||
const adapter = createNoopAdapter();
|
||||
|
||||
const ids = await sendMSTeamsMessages({
|
||||
replyStyle: "thread",
|
||||
@@ -149,11 +163,7 @@ describe("msteams messenger", () => {
|
||||
continueConversation: async (_appId, reference, logic) => {
|
||||
seen.reference = reference;
|
||||
await logic({
|
||||
sendActivity: async (activity: unknown) => {
|
||||
const { text } = activity as { text?: string };
|
||||
seen.texts.push(text ?? "");
|
||||
return { id: `id:${text ?? ""}` };
|
||||
},
|
||||
sendActivity: createRecordedSendActivity(seen.texts),
|
||||
});
|
||||
},
|
||||
process: async () => {},
|
||||
@@ -192,10 +202,7 @@ describe("msteams messenger", () => {
|
||||
},
|
||||
};
|
||||
|
||||
const adapter: MSTeamsAdapter = {
|
||||
continueConversation: async () => {},
|
||||
process: async () => {},
|
||||
};
|
||||
const adapter = createNoopAdapter();
|
||||
|
||||
const ids = await sendMSTeamsMessages({
|
||||
replyStyle: "thread",
|
||||
@@ -242,20 +249,9 @@ describe("msteams messenger", () => {
|
||||
const retryEvents: Array<{ nextAttempt: number; delayMs: number }> = [];
|
||||
|
||||
const ctx = {
|
||||
sendActivity: async (activity: unknown) => {
|
||||
const { text } = activity as { text?: string };
|
||||
attempts.push(text ?? "");
|
||||
if (attempts.length === 1) {
|
||||
throw Object.assign(new Error("throttled"), { statusCode: 429 });
|
||||
}
|
||||
return { id: `id:${text ?? ""}` };
|
||||
},
|
||||
};
|
||||
|
||||
const adapter: MSTeamsAdapter = {
|
||||
continueConversation: async () => {},
|
||||
process: async () => {},
|
||||
sendActivity: createRecordedSendActivity(attempts, 429),
|
||||
};
|
||||
const adapter = createNoopAdapter();
|
||||
|
||||
const ids = await sendMSTeamsMessages({
|
||||
replyStyle: "thread",
|
||||
@@ -280,10 +276,7 @@ describe("msteams messenger", () => {
|
||||
},
|
||||
};
|
||||
|
||||
const adapter: MSTeamsAdapter = {
|
||||
continueConversation: async () => {},
|
||||
process: async () => {},
|
||||
};
|
||||
const adapter = createNoopAdapter();
|
||||
|
||||
await expect(
|
||||
sendMSTeamsMessages({
|
||||
@@ -303,18 +296,7 @@ describe("msteams messenger", () => {
|
||||
|
||||
const adapter: MSTeamsAdapter = {
|
||||
continueConversation: async (_appId, _reference, logic) => {
|
||||
await logic({
|
||||
sendActivity: async (activity: unknown) => {
|
||||
const { text } = activity as { text?: string };
|
||||
attempts.push(text ?? "");
|
||||
if (attempts.length === 1) {
|
||||
throw Object.assign(new Error("server error"), {
|
||||
statusCode: 503,
|
||||
});
|
||||
}
|
||||
return { id: `id:${text ?? ""}` };
|
||||
},
|
||||
});
|
||||
await logic({ sendActivity: createRecordedSendActivity(attempts, 503) });
|
||||
},
|
||||
process: async () => {},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user