

























@@ -118,6 +118,44 @@ function resetTelegramWebhookMocks(): void {
118118}));
119119}
120120121+type MockCallReader = { mock: { calls: unknown[][] } };
122+123+function requireRecord(value: unknown, label: string): Record<string, unknown> {
124+if (!value || typeof value !== "object" || Array.isArray(value)) {
125+throw new Error(`expected ${label} to be an object`);
126+}
127+return value as Record<string, unknown>;
128+}
129+130+function requireMockCall(mock: unknown, index: number, label: string): unknown[] {
131+const call = (mock as MockCallReader).mock.calls.at(index);
132+if (!call) {
133+throw new Error(`expected ${label} call ${index}`);
134+}
135+return call;
136+}
137+138+function mockMessages(mock: unknown): string[] {
139+return (mock as MockCallReader).mock.calls.map((call) => String(call[0] ?? ""));
140+}
141+142+function expectMockMessageContains(mock: unknown, expected: string): void {
143+expect(mockMessages(mock).some((message) => message.includes(expected))).toBe(true);
144+}
145+146+function expectStatusCall(
147+mock: unknown,
148+expected: Record<string, unknown>,
149+): Record<string, unknown> {
150+const match = (mock as MockCallReader).mock.calls
151+.map((call) => requireRecord(call[0], "status call"))
152+.find((status) => Object.entries(expected).every(([key, value]) => status[key] === value));
153+if (!match) {
154+throw new Error(`expected status call containing ${JSON.stringify(expected)}`);
155+}
156+return match;
157+}
158+121159beforeAll(async () => {
122160({ startTelegramWebhook } = await import("./webhook.js"));
123161});
@@ -425,37 +463,35 @@ describe("startTelegramWebhook", () => {
425463 setStatus,
426464},
427465async ({ port }) => {
428-expect(createTelegramBotSpy).toHaveBeenCalledWith(
429-expect.objectContaining({
430-accountId: "opie",
431-config: expect.objectContaining({ bindings: [] }),
432-}),
466+const botParams = requireRecord(
467+requireMockCall(createTelegramBotSpy, 0, "createTelegramBot")[0],
468+"createTelegramBot params",
433469);
470+expect(botParams.accountId).toBe("opie");
471+expect(requireRecord(botParams.config, "telegram config").bindings).toEqual([]);
434472const health = await fetch(`http://127.0.0.1:${port}/healthz`);
435473expect(health.status).toBe(200);
436474expect(initSpy).toHaveBeenCalledTimes(1);
437475expect(setWebhookSpy).toHaveBeenCalled();
438-expect(runtimeLog).toHaveBeenCalledWith(
439-expect.stringContaining("webhook local listener on http://127.0.0.1:"),
440-);
441-expect(runtimeLog).toHaveBeenCalledWith(expect.stringContaining("/telegram-webhook"));
442-expect(runtimeLog).toHaveBeenCalledWith(
443-expect.stringContaining("webhook advertised to telegram on http://"),
444-);
476+expectMockMessageContains(runtimeLog, "webhook local listener on http://127.0.0.1:");
477+expectMockMessageContains(runtimeLog, "/telegram-webhook");
478+expectMockMessageContains(runtimeLog, "webhook advertised to telegram on http://");
445479expect(setStatus).toHaveBeenNthCalledWith(1, {
446480mode: "webhook",
447481connected: false,
448482lastConnectedAt: null,
449483lastEventAt: null,
450484lastTransportActivityAt: null,
451485});
452-expect(setStatus).toHaveBeenNthCalledWith(2, {
453-mode: "webhook",
454-connected: true,
455-lastConnectedAt: expect.any(Number),
456-lastEventAt: expect.any(Number),
457-lastError: null,
458-});
486+const connectedStatus = requireRecord(
487+requireMockCall(setStatus, 1, "setStatus")[0],
488+"connected status",
489+);
490+expect(connectedStatus.mode).toBe("webhook");
491+expect(connectedStatus.connected).toBe(true);
492+expect(typeof connectedStatus.lastConnectedAt).toBe("number");
493+expect(typeof connectedStatus.lastEventAt).toBe("number");
494+expect(connectedStatus.lastError).toBeNull();
459495},
460496);
461497});
@@ -483,26 +519,16 @@ describe("startTelegramWebhook", () => {
483519const health = await fetch(`http://127.0.0.1:${port}/healthz`);
484520expect(health.status).toBe(200);
485521expect(stopSpy).not.toHaveBeenCalled();
486-expect(runtimeError).toHaveBeenCalledWith(
487-expect.stringContaining("telegram setWebhook failed: fetch failed"),
488-);
522+expectMockMessageContains(runtimeError, "telegram setWebhook failed: fetch failed");
489523await vi.waitFor(() => expect(setWebhookSpy).toHaveBeenCalledTimes(2));
490524expect(runtimeLog).toHaveBeenCalledWith("telegram setWebhook retry 1 scheduled in 0ms");
491-expect(runtimeLog).toHaveBeenCalledWith(
492-expect.stringContaining("webhook advertised to telegram on http://"),
493-);
525+expectMockMessageContains(runtimeLog, "webhook advertised to telegram on http://");
494526expect(setStatus).toHaveBeenCalledWith({
495527mode: "webhook",
496528connected: false,
497529lastError: "fetch failed",
498530});
499-expect(setStatus).toHaveBeenCalledWith(
500-expect.objectContaining({
501-mode: "webhook",
502-connected: true,
503-lastError: null,
504-}),
505-);
531+expectStatusCall(setStatus, { mode: "webhook", connected: true, lastError: null });
506532},
507533);
508534});
@@ -523,9 +549,7 @@ describe("startTelegramWebhook", () => {
523549).rejects.toThrow("unauthorized");
524550525551expect(stopSpy).toHaveBeenCalledTimes(1);
526-expect(runtimeError).toHaveBeenCalledWith(
527-expect.stringContaining("telegram setWebhook failed: unauthorized"),
528-);
552+expectMockMessageContains(runtimeError, "telegram setWebhook failed: unauthorized");
529553});
530554531555it("registers webhook with certificate when webhookCertPath is provided", async () => {
@@ -537,13 +561,11 @@ describe("startTelegramWebhook", () => {
537561webhookCertPath: "/path/to/cert.pem",
538562},
539563async () => {
540-expect(setWebhookSpy).toHaveBeenCalledWith(
541-expect.any(String),
542-expect.objectContaining({
543-certificate: expect.anything(),
544-}),
545-);
546-const certificate = setWebhookSpy.mock.calls[0]?.[1]?.certificate as
564+const setWebhookCall = requireMockCall(setWebhookSpy, 0, "setWebhook");
565+expect(typeof setWebhookCall[0]).toBe("string");
566+const options = requireRecord(setWebhookCall[1], "setWebhook options");
567+expect(options.certificate).toBeTruthy();
568+const certificate = options.certificate as
547569| { path?: string; fileData?: string; filename?: string }
548570| undefined;
549571if (!certificate) {
@@ -552,12 +574,8 @@ describe("startTelegramWebhook", () => {
552574if (certificate && "path" in certificate && typeof certificate.path === "string") {
553575expect(certificate.path).toBe("/path/to/cert.pem");
554576} else {
555-expect(certificate).toEqual(
556-expect.objectContaining({
557-fileData: "/path/to/cert.pem",
558-filename: "cert.pem",
559-}),
560-);
577+expect(certificate.fileData).toBe("/path/to/cert.pem");
578+expect(certificate.filename).toBe("cert.pem");
561579}
562580},
563581);
@@ -577,12 +595,12 @@ describe("startTelegramWebhook", () => {
577595 setStatus,
578596},
579597async ({ port }) => {
580-expect(createTelegramBotSpy).toHaveBeenCalledWith(
581-expect.objectContaining({
582-accountId: "opie",
583-config: expect.objectContaining({ bindings: [] }),
584-}),
598+const botParams = requireRecord(
599+requireMockCall(createTelegramBotSpy, 0, "createTelegramBot")[0],
600+"createTelegramBot params",
585601);
602+expect(botParams.accountId).toBe("opie");
603+expect(requireRecord(botParams.config, "telegram config").bindings).toEqual([]);
586604const payload = JSON.stringify({ update_id: 1, message: { text: "hello" } });
587605const response = await postWebhookJson({
588606url: webhookUrl(port, TELEGRAM_WEBHOOK_PATH),
@@ -591,13 +609,7 @@ describe("startTelegramWebhook", () => {
591609});
592610expect(response.status).toBe(200);
593611await vi.waitFor(() => expect(handleUpdateSpy).toHaveBeenCalledWith(JSON.parse(payload)));
594-expect(setStatus).toHaveBeenCalledWith(
595-expect.objectContaining({
596-mode: "webhook",
597-connected: true,
598-lastError: null,
599-}),
600-);
612+expectStatusCall(setStatus, { mode: "webhook", connected: true, lastError: null });
601613},
602614);
603615});
@@ -659,10 +671,9 @@ describe("startTelegramWebhook", () => {
659671expect(response.status).toBe(200);
660672expect(await response.text()).toBe("");
661673await vi.waitFor(() =>
662-expect(runtimeLog).toHaveBeenCalledWith(
663-expect.stringContaining(
664-"webhook update processing failed after ack: agent turn failed",
665-),
674+expectMockMessageContains(
675+runtimeLog,
676+"webhook update processing failed after ack: agent turn failed",
666677),
667678);
668679},
@@ -853,11 +864,10 @@ describe("startTelegramWebhook", () => {
853864async ({ port }) => {
854865expect(port).toBeGreaterThan(0);
855866expect(setWebhookSpy).toHaveBeenCalledTimes(1);
856-expect(setWebhookSpy).toHaveBeenCalledWith(
857-webhookUrl(port, TELEGRAM_WEBHOOK_PATH),
858-expect.objectContaining({
859-secret_token: TELEGRAM_SECRET,
860-}),
867+const setWebhookCall = requireMockCall(setWebhookSpy, 0, "setWebhook");
868+expect(setWebhookCall[0]).toBe(webhookUrl(port, TELEGRAM_WEBHOOK_PATH));
869+expect(requireRecord(setWebhookCall[1], "setWebhook options").secret_token).toBe(
870+TELEGRAM_SECRET,
861871);
862872expect(runtimeLog).toHaveBeenCalledWith(
863873`webhook local listener on ${webhookUrl(port, TELEGRAM_WEBHOOK_PATH)}`,
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。