diff --git a/src/cron/store/failure-alert-codec.test.ts b/src/cron/store/failure-alert-codec.test.ts new file mode 100644 index 000000000000..2252592ed761 --- /dev/null +++ b/src/cron/store/failure-alert-codec.test.ts @@ -0,0 +1,54 @@ +// Unit tests for failure-alert SQLite column codec roundtrip. +import { describe, expect, it } from "vitest"; +import { bindFailureAlertColumns, failureAlertFromRow } from "./failure-alert-codec.js"; +import type { CronJobRow } from "./schema.js"; + +function roundtrip( + input: Parameters[0], +): ReturnType { + const columns = bindFailureAlertColumns(input); + return failureAlertFromRow(columns as CronJobRow); +} + +describe("failureAlertFromRow", () => { + it("round-trips disabled config (false)", () => { + expect(roundtrip(false)).toBe(false); + }); + + it("round-trips undefined (no alert config) as undefined", () => { + expect(roundtrip(undefined)).toBeUndefined(); + }); + + it("round-trips enabled-with-defaults ({}) as {}", () => { + const result = roundtrip({}); + expect(result).toEqual({}); + }); + + it("round-trips populated config with all fields", () => { + const config = { + after: 3, + cooldownMs: 120_000, + channel: "telegram" as const, + to: "@user", + mode: "announce" as const, + accountId: "acc-1", + includeSkipped: true, + }; + expect(roundtrip(config)).toEqual(config); + }); + + it("round-trips partial config (only after)", () => { + expect(roundtrip({ after: 5 })).toEqual({ after: 5 }); + }); + + it("enabled-with-defaults does not collapse to undefined on read", () => { + const columns = bindFailureAlertColumns({}); + const row = columns as CronJobRow; + expect(row.failure_alert_disabled).toBe(0); + expect(row.failure_alert_after).toBeNull(); + const decoded = failureAlertFromRow(row); + expect(decoded).toEqual({}); + expect(decoded).not.toBeUndefined(); + expect(decoded).toBeTruthy(); + }); +}); diff --git a/src/cron/store/failure-alert-codec.ts b/src/cron/store/failure-alert-codec.ts index 37eaffba98c8..b84c16f2cac6 100644 --- a/src/cron/store/failure-alert-codec.ts +++ b/src/cron/store/failure-alert-codec.ts @@ -46,6 +46,7 @@ export function failureAlertFromRow(row: CronJobRow): CronFailureAlert | false | if (row.failure_alert_disabled === 1) { return false; } + const failureAlertExplicitlyEnabled = row.failure_alert_disabled === 0; if ( row.failure_alert_after == null && !row.failure_alert_channel && @@ -53,7 +54,8 @@ export function failureAlertFromRow(row: CronJobRow): CronFailureAlert | false | row.failure_alert_cooldown_ms == null && row.failure_alert_include_skipped == null && !row.failure_alert_mode && - !row.failure_alert_account_id + !row.failure_alert_account_id && + !failureAlertExplicitlyEnabled ) { return undefined; }