
























@@ -70,6 +70,35 @@ function findRequestCall(
7070return call;
7171}
727273+function requireRecord(value: unknown, label: string): Record<string, unknown> {
74+if (!value || typeof value !== "object" || Array.isArray(value)) {
75+throw new Error(`expected ${label} to be a record`);
76+}
77+return value as Record<string, unknown>;
78+}
79+80+function expectRecordFields(record: Record<string, unknown>, fields: Record<string, unknown>) {
81+for (const [key, value] of Object.entries(fields)) {
82+expect(record[key]).toEqual(value);
83+}
84+}
85+86+function expectNestedRecordFields(
87+record: Record<string, unknown>,
88+key: string,
89+fields: Record<string, unknown>,
90+) {
91+expectRecordFields(requireRecord(record[key], key), fields);
92+}
93+94+function requestPayload(call: readonly [method: string, payload?: unknown]) {
95+return requireRecord(call[1], `${call[0]} payload`);
96+}
97+98+function requestPatch(call: readonly [method: string, payload?: unknown]) {
99+return requireRecord(requestPayload(call).patch, `${call[0]} patch`);
100+}
101+73102describe("cron controller", () => {
74103it("loads model suggestions from the configured model view", async () => {
75104const request = vi.fn(async () => ({
@@ -150,9 +179,13 @@ describe("cron controller", () => {
150179await addCronJob(state);
151180152181const addCall = findRequestCall(request.mock.calls, "cron.add");
153-expect(addCall[1]).toMatchObject({
182+const payload = requestPayload(addCall);
183+expectRecordFields(payload, {
154184name: "webhook job",
155-delivery: { mode: "webhook", to: "https://example.invalid/cron" },
185+});
186+expectNestedRecordFields(payload, "delivery", {
187+mode: "webhook",
188+to: "https://example.invalid/cron",
156189});
157190});
158191@@ -189,9 +222,13 @@ describe("cron controller", () => {
189222await addCronJob(state);
190223191224const addCall = findRequestCall(request.mock.calls, "cron.add");
192-expect(addCall[1]).toMatchObject({
225+const payload = requestPayload(addCall);
226+expectRecordFields(payload, {
193227sessionKey: "agent:ops:main",
194-delivery: { mode: "announce", accountId: "ops-bot" },
228+});
229+expectNestedRecordFields(payload, "delivery", {
230+mode: "announce",
231+accountId: "ops-bot",
195232});
196233});
197234@@ -228,8 +265,8 @@ describe("cron controller", () => {
228265await addCronJob(state);
229266230267const addCall = findRequestCall(request.mock.calls, "cron.add");
231-expect(addCall[1]).toMatchObject({
232-delivery: { mode: "announce" },
268+expectRecordFields(requireRecord(requestPayload(addCall).delivery, "delivery"), {
269+mode: "announce",
233270});
234271expect(
235272(addCall[1] as { delivery?: { channel?: string } } | undefined)?.delivery?.channel,
@@ -267,8 +304,9 @@ describe("cron controller", () => {
267304await addCronJob(state);
268305269306const addCall = findRequestCall(request.mock.calls, "cron.add");
270-expect(addCall[1]).toMatchObject({
271-payload: { kind: "agentTurn", lightContext: true },
307+expectNestedRecordFields(requestPayload(addCall), "payload", {
308+kind: "agentTurn",
309+lightContext: true,
272310});
273311});
274312@@ -391,7 +429,7 @@ describe("cron controller", () => {
391429await addCronJob(state);
392430393431const addCall = findRequestCall(request.mock.calls, "cron.add");
394-expect(addCall[1]).toMatchObject({
432+expectRecordFields(requestPayload(addCall), {
395433name: "main job",
396434});
397435// Delivery is explicitly sent as { mode: "none" } to clear the announce delivery on the backend.
@@ -440,17 +478,17 @@ describe("cron controller", () => {
440478await addCronJob(state);
441479442480const updateCall = findRequestCall(request.mock.calls, "cron.update");
443-expect(updateCall[1]).toMatchObject({
481+expectRecordFields(requestPayload(updateCall), {
444482id: "job-1",
445- patch: {
446- name: "edited job",
447- description: "",
448- agentId: null,
449- deleteAfterRun: false,
450- schedule: { kind: "cron", expr: "0 8 * * *", staggerMs: 0 },
451- payload: { kind: "systemEvent", text: "updated" },
452- delivery: { mode: "none" },
453-},
483+});
484+expectRecordFields(requestPatch(updateCall), {
485+name: "edited job",
486+description: "",
487+agentId: null,
488+deleteAfterRun: false,
489+schedule: { kind: "cron", expr: "0 8 * * *", staggerMs: 0 },
490+payload: { kind: "systemEvent", text: "updated" },
491+delivery: { mode: "none" },
454492});
455493expect(state.cronEditingJobId).toBeNull();
456494});
@@ -504,14 +542,12 @@ describe("cron controller", () => {
504542await addCronJob(state);
505543506544const updateCall = findRequestCall(request.mock.calls, "cron.update");
507-expect(updateCall[1]).toMatchObject({
545+expectRecordFields(requestPayload(updateCall), {
508546id: "job-clear-account-id",
509-patch: {
510-delivery: {
511-mode: "announce",
512-accountId: "",
513-},
514-},
547+});
548+expectRecordFields(requireRecord(requestPatch(updateCall).delivery, "delivery"), {
549+mode: "announce",
550+accountId: "",
515551});
516552});
517553@@ -587,11 +623,12 @@ describe("cron controller", () => {
587623await addCronJob(state);
588624589625const updateCall = findRequestCall(request.mock.calls, "cron.update");
590-expect(updateCall[1]).toMatchObject({
626+expectRecordFields(requestPayload(updateCall), {
591627id: "job-implicit-delivery",
592-patch: {
593-delivery: { mode: "announce", to: "123" },
594-},
628+});
629+expectRecordFields(requireRecord(requestPatch(updateCall).delivery, "delivery"), {
630+mode: "announce",
631+to: "123",
595632});
596633expect(
597634(updateCall[1] as { patch?: { delivery?: { channel?: string } } } | undefined)?.patch
@@ -676,19 +713,23 @@ describe("cron controller", () => {
676713await addCronJob(state);
677714678715const updateCall = findRequestCall(request.mock.calls, "cron.update");
679-expect(updateCall[1]).toMatchObject({
716+expectRecordFields(requestPayload(updateCall), {
680717id: "job-2",
681- patch: {
682- schedule: { kind: "cron", expr: "0 9 * * *", staggerMs: 30_000 },
683- payload: {
684- kind: "agentTurn",
685- message: "run it",
686- model: "opus",
687- thinking: "low",
688-},
689-delivery: { mode: "announce", bestEffort: true },
718+});
719+const patch = requestPatch(updateCall);
720+expectRecordFields(patch, {
721+schedule: { kind: "cron", expr: "0 9 * * *", staggerMs: 30_000 },
722+payload: {
723+kind: "agentTurn",
724+message: "run it",
725+model: "opus",
726+thinking: "low",
690727},
691728});
729+expectNestedRecordFields(patch, "delivery", {
730+mode: "announce",
731+bestEffort: true,
732+});
692733});
693734694735it("sends lightContext=false in cron.update when clearing prior light-context setting", async () => {
@@ -735,14 +776,12 @@ describe("cron controller", () => {
735776await addCronJob(state);
736777737778const updateCall = findRequestCall(request.mock.calls, "cron.update");
738-expect(updateCall[1]).toMatchObject({
779+expectRecordFields(requestPayload(updateCall), {
739780id: "job-clear-light",
740-patch: {
741-payload: {
742-kind: "agentTurn",
743-lightContext: false,
744-},
745-},
781+});
782+expectRecordFields(requireRecord(requestPatch(updateCall).payload, "payload"), {
783+kind: "agentTurn",
784+lightContext: false,
746785});
747786});
748787@@ -778,18 +817,16 @@ describe("cron controller", () => {
778817await addCronJob(state);
779818780819const updateCall = findRequestCall(request.mock.calls, "cron.update");
781-expect(updateCall[1]).toMatchObject({
820+expectRecordFields(requestPayload(updateCall), {
782821id: "job-alert",
783-patch: {
784-failureAlert: {
785-after: 3,
786-cooldownMs: 120_000,
787-channel: "telegram",
788-to: "123456",
789-mode: "announce",
790-accountId: undefined,
791-},
792-},
822+});
823+expectRecordFields(requireRecord(requestPatch(updateCall).failureAlert, "failureAlert"), {
824+after: 3,
825+cooldownMs: 120_000,
826+channel: "telegram",
827+to: "123456",
828+mode: "announce",
829+accountId: undefined,
793830});
794831});
795832@@ -824,15 +861,13 @@ describe("cron controller", () => {
824861await addCronJob(state);
825862826863const updateCall = findRequestCall(request.mock.calls, "cron.update");
827-expect(updateCall[1]).toMatchObject({
864+expectRecordFields(requestPayload(updateCall), {
828865id: "job-alert-mode",
829-patch: {
830-failureAlert: {
831-after: 1,
832-mode: "webhook",
833-accountId: "bot-a",
834-},
835-},
866+});
867+expectRecordFields(requireRecord(requestPatch(updateCall).failureAlert, "failureAlert"), {
868+after: 1,
869+mode: "webhook",
870+accountId: "bot-a",
836871});
837872});
838873@@ -872,15 +907,13 @@ describe("cron controller", () => {
872907await addCronJob(state);
873908874909const updateCall = findRequestCall(request.mock.calls, "cron.update");
875-expect(updateCall[1]).toMatchObject({
910+expectRecordFields(requestPayload(updateCall), {
876911id: "job-alert-implicit-channel",
877-patch: {
878-failureAlert: {
879-after: 2,
880-to: "123",
881-mode: "announce",
882-},
883-},
912+});
913+expectRecordFields(requireRecord(requestPatch(updateCall).failureAlert, "failureAlert"), {
914+after: 2,
915+to: "123",
916+mode: "announce",
884917});
885918expect(
886919(updateCall[1] as { patch?: { failureAlert?: { channel?: string } } } | undefined)?.patch
@@ -963,15 +996,13 @@ describe("cron controller", () => {
963996await addCronJob(state);
964997965998const updateCall = findRequestCall(request.mock.calls, "cron.update");
966-expect(updateCall[1]).toMatchObject({
999+expectRecordFields(requestPayload(updateCall), {
9671000id: "job-alert-no-cooldown",
968-patch: {
969-failureAlert: {
970-after: 3,
971-channel: "telegram",
972-to: "123456",
973-},
974-},
1001+});
1002+expectRecordFields(requireRecord(requestPatch(updateCall).failureAlert, "failureAlert"), {
1003+after: 3,
1004+channel: "telegram",
1005+to: "123456",
9751006});
9761007expect(
9771008(updateCall[1] as { patch?: { failureAlert?: { cooldownMs?: number } } })?.patch
@@ -1007,10 +1038,10 @@ describe("cron controller", () => {
10071038await addCronJob(state);
1008103910091040const updateCall = findRequestCall(request.mock.calls, "cron.update");
1010-expect(updateCall[1]).toMatchObject({
1041+expectRecordFields(requestPayload(updateCall), {
10111042id: "job-no-alert",
1012-patch: { failureAlert: false },
10131043});
1044+expect(requestPatch(updateCall).failureAlert).toBe(false);
10141045});
1015104610161047it("maps cron stagger, model, thinking, and best effort into form", () => {
@@ -1109,7 +1140,7 @@ describe("cron controller", () => {
11091140});
11101141await addCronJob(state);
11111142expect(request).not.toHaveBeenCalled();
1112-expect(state.cronFieldErrors).toMatchObject({
1143+expectRecordFields(state.cronFieldErrors, {
11131144name: "cron.errors.nameRequired",
11141145payloadText: "cron.errors.agentMessageRequired",
11151146});
@@ -1215,7 +1246,7 @@ describe("cron controller", () => {
12151246it("loads paged jobs with query/filter/sort params", async () => {
12161247const request = vi.fn(async (method: string, payload?: unknown) => {
12171248if (method === "cron.list") {
1218-expect(payload).toMatchObject({
1249+expectRecordFields(requireRecord(payload, "cron.list payload"), {
12191250limit: 50,
12201251offset: 0,
12211252query: "daily",
@@ -1346,7 +1377,10 @@ describe("cron controller", () => {
13461377it("runs cron job in due mode when requested", async () => {
13471378const request = vi.fn(async (method: string, payload?: unknown) => {
13481379if (method === "cron.run") {
1349-expect(payload).toMatchObject({ id: "job-due", mode: "due" });
1380+expectRecordFields(requireRecord(payload, "cron.run payload"), {
1381+id: "job-due",
1382+mode: "due",
1383+});
13501384return { ok: true };
13511385}
13521386if (method === "cron.runs") {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。