




















@@ -199,6 +199,31 @@ function getFirstDeliveryText(deliver: ReturnType<typeof vi.fn>): string {
199199return firstCall?.payloads?.[0]?.text ?? "";
200200}
201201202+function requireRecord(value: unknown, label: string): Record<string, unknown> {
203+if (!value || typeof value !== "object") {
204+throw new Error(`expected ${label} to be an object`);
205+}
206+return value as Record<string, unknown>;
207+}
208+209+function requireFirstCallArg(
210+mock: ReturnType<typeof vi.fn>,
211+label: string,
212+): Record<string, unknown> {
213+return requireRecord(mock.mock.calls[0]?.[0], label);
214+}
215+216+function requireFirstPayload(deliver: ReturnType<typeof vi.fn>): ReplyPayload {
217+const delivery = requireFirstCallArg(deliver, "delivery params") as {
218+payloads?: ReplyPayload[];
219+};
220+const payload = delivery.payloads?.[0];
221+if (!payload) {
222+throw new Error("expected first delivery payload");
223+}
224+return payload;
225+}
226+202227function makeTargetsCfg(targets: Array<{ channel: string; to: string }>): OpenClawConfig {
203228return {
204229approvals: {
@@ -435,12 +460,11 @@ describe("exec approval forwarder", () => {
435460await expect(forwarder.handleRequested(baseRequest)).resolves.toBe(true);
436461await flushPendingDelivery();
437462expect(deliver).toHaveBeenCalled();
438-expect(beforeDeliverPayload).toHaveBeenCalledWith(
439-expect.objectContaining({
440-hint: { kind: "approval-pending", approvalKind: "exec" },
441-target: expect.objectContaining({ channel: "slack", to: "U123" }),
442-}),
443-);
463+const hookParams = requireFirstCallArg(beforeDeliverPayload, "beforeDeliverPayload params");
464+expect(hookParams.hint).toEqual({ kind: "approval-pending", approvalKind: "exec" });
465+const target = requireRecord(hookParams.target, "delivery target");
466+expect(target.channel).toBe("slack");
467+expect(target.to).toBe("U123");
444468});
445469446470it("skips telegram forwarding when telegram exec approvals handler is enabled", async () => {
@@ -502,45 +526,35 @@ describe("exec approval forwarder", () => {
502526).resolves.toBe(true);
503527504528expect(deliver).toHaveBeenCalledTimes(1);
505-expect(deliver).toHaveBeenCalledWith(
506-expect.objectContaining({
507-channel: "telegram",
508-to: "123",
509-payloads: [
510-expect.objectContaining({
511-channelData: expect.objectContaining({
512-execApproval: expect.objectContaining({
513-approvalId: "req-1",
514-}),
515-}),
516-interactive: expect.objectContaining({
517-blocks: [
518-{
519-type: "buttons",
520-buttons: [
521-{
522-label: "Allow Once",
523-value: "/approve req-1 allow-once",
524-style: "success",
525-},
526-{
527-label: "Allow Always",
528-value: "/approve req-1 allow-always",
529-style: "primary",
530-},
531-{
532-label: "Deny",
533-value: "/approve req-1 deny",
534-style: "danger",
535-},
536-],
537-},
538-],
539-}),
540-}),
541-],
542-}),
543-);
529+const delivery = requireFirstCallArg(deliver, "delivery params");
530+expect(delivery.channel).toBe("telegram");
531+expect(delivery.to).toBe("123");
532+const payload = requireFirstPayload(deliver);
533+expect(payload.channelData?.execApproval).toEqual({ approvalId: "req-1" });
534+expect(payload.interactive).toEqual({
535+blocks: [
536+{
537+type: "buttons",
538+buttons: [
539+{
540+label: "Allow Once",
541+value: "/approve req-1 allow-once",
542+style: "success",
543+},
544+{
545+label: "Allow Always",
546+value: "/approve req-1 allow-always",
547+style: "primary",
548+},
549+{
550+label: "Deny",
551+value: "/approve req-1 deny",
552+style: "danger",
553+},
554+],
555+},
556+],
557+});
544558});
545559546560it("stores exec metadata on generic forwarded fallback payloads", async () => {
@@ -550,22 +564,12 @@ describe("exec approval forwarder", () => {
550564await expect(forwarder.handleRequested(baseRequest)).resolves.toBe(true);
551565552566expect(deliver).toHaveBeenCalledTimes(1);
553-expect(deliver.mock.calls[0]?.[0]).toEqual(
554-expect.objectContaining({
555-payloads: [
556-expect.objectContaining({
557-channelData: expect.objectContaining({
558-execApproval: expect.objectContaining({
559-approvalId: "req-1",
560-approvalKind: "exec",
561-agentId: "main",
562-sessionKey: "agent:main:main",
563-}),
564-}),
565-}),
566-],
567-}),
568-);
567+const payload = requireFirstPayload(deliver);
568+const execApproval = requireRecord(payload.channelData?.execApproval, "exec approval metadata");
569+expect(execApproval.approvalId).toBe("req-1");
570+expect(execApproval.approvalKind).toBe("exec");
571+expect(execApproval.agentId).toBe("main");
572+expect(execApproval.sessionKey).toBe("agent:main:main");
569573});
570574571575it("formats single-line commands as inline code", async () => {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。