mirror of
https://github.com/openclaw/openclaw.git
synced 2026-02-19 18:39:20 -05:00
114 lines
3.6 KiB
TypeScript
114 lines
3.6 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import type { CronJob } from "../../cron/types.js";
|
|
import type { RuntimeEnv } from "../../runtime.js";
|
|
import { printCronList } from "./shared.js";
|
|
|
|
describe("printCronList", () => {
|
|
it("handles job with undefined sessionTarget (#9649)", () => {
|
|
const logs: string[] = [];
|
|
const mockRuntime = {
|
|
log: (msg: string) => logs.push(msg),
|
|
error: () => {},
|
|
exit: () => {},
|
|
} as RuntimeEnv;
|
|
|
|
// Simulate a job without sessionTarget (as reported in #9649)
|
|
const jobWithUndefinedTarget = {
|
|
id: "test-job-id",
|
|
agentId: "main",
|
|
name: "Test Job",
|
|
enabled: true,
|
|
createdAtMs: Date.now(),
|
|
updatedAtMs: Date.now(),
|
|
schedule: { kind: "at", at: new Date(Date.now() + 3600000).toISOString() },
|
|
// sessionTarget is intentionally omitted to simulate the bug
|
|
wakeMode: "next-heartbeat",
|
|
payload: { kind: "systemEvent", text: "test" },
|
|
state: { nextRunAtMs: Date.now() + 3600000 },
|
|
} as CronJob;
|
|
|
|
// This should not throw "Cannot read properties of undefined (reading 'trim')"
|
|
expect(() => printCronList([jobWithUndefinedTarget], mockRuntime)).not.toThrow();
|
|
|
|
// Verify output contains the job
|
|
expect(logs.length).toBeGreaterThan(1);
|
|
expect(logs.some((line) => line.includes("test-job-id"))).toBe(true);
|
|
});
|
|
|
|
it("handles job with defined sessionTarget", () => {
|
|
const logs: string[] = [];
|
|
const mockRuntime = {
|
|
log: (msg: string) => logs.push(msg),
|
|
error: () => {},
|
|
exit: () => {},
|
|
} as RuntimeEnv;
|
|
|
|
const jobWithTarget: CronJob = {
|
|
id: "test-job-id-2",
|
|
agentId: "main",
|
|
name: "Test Job 2",
|
|
enabled: true,
|
|
createdAtMs: Date.now(),
|
|
updatedAtMs: Date.now(),
|
|
schedule: { kind: "at", at: new Date(Date.now() + 3600000).toISOString() },
|
|
sessionTarget: "isolated",
|
|
wakeMode: "next-heartbeat",
|
|
payload: { kind: "systemEvent", text: "test" },
|
|
state: { nextRunAtMs: Date.now() + 3600000 },
|
|
};
|
|
|
|
expect(() => printCronList([jobWithTarget], mockRuntime)).not.toThrow();
|
|
expect(logs.some((line) => line.includes("isolated"))).toBe(true);
|
|
});
|
|
|
|
it("shows stagger label for cron schedules", () => {
|
|
const logs: string[] = [];
|
|
const mockRuntime = {
|
|
log: (msg: string) => logs.push(msg),
|
|
error: () => {},
|
|
exit: () => {},
|
|
} as RuntimeEnv;
|
|
|
|
const job: CronJob = {
|
|
id: "staggered-job",
|
|
name: "Staggered",
|
|
enabled: true,
|
|
createdAtMs: Date.now(),
|
|
updatedAtMs: Date.now(),
|
|
schedule: { kind: "cron", expr: "0 * * * *", staggerMs: 5 * 60_000 },
|
|
sessionTarget: "main",
|
|
wakeMode: "next-heartbeat",
|
|
payload: { kind: "systemEvent", text: "tick" },
|
|
state: {},
|
|
};
|
|
|
|
printCronList([job], mockRuntime);
|
|
expect(logs.some((line) => line.includes("(stagger 5m)"))).toBe(true);
|
|
});
|
|
|
|
it("shows exact label for cron schedules with stagger disabled", () => {
|
|
const logs: string[] = [];
|
|
const mockRuntime = {
|
|
log: (msg: string) => logs.push(msg),
|
|
error: () => {},
|
|
exit: () => {},
|
|
} as RuntimeEnv;
|
|
|
|
const job: CronJob = {
|
|
id: "exact-job",
|
|
name: "Exact",
|
|
enabled: true,
|
|
createdAtMs: Date.now(),
|
|
updatedAtMs: Date.now(),
|
|
schedule: { kind: "cron", expr: "0 7 * * *", staggerMs: 0 },
|
|
sessionTarget: "main",
|
|
wakeMode: "next-heartbeat",
|
|
payload: { kind: "systemEvent", text: "tick" },
|
|
state: {},
|
|
};
|
|
|
|
printCronList([job], mockRuntime);
|
|
expect(logs.some((line) => line.includes("(exact)"))).toBe(true);
|
|
});
|
|
});
|