import { describe, it, expect } from "vitest"; import { isWithinBannerWindow, shouldShowBanner, type RestorableMigrationJournal, } from "./categoryRestoreService"; const DAY = 24 * 60 * 60 * 1000; describe("isWithinBannerWindow", () => { it("returns true for a migration just done", () => { const now = Date.parse("2026-04-20T00:00:00Z"); const ts = "2026-04-19T00:00:00Z"; expect(isWithinBannerWindow(ts, now)).toBe(true); }); it("returns true on the 90-day boundary", () => { const now = Date.parse("2026-04-20T00:00:00Z"); const ts = new Date(now - 90 * DAY).toISOString(); expect(isWithinBannerWindow(ts, now)).toBe(true); }); it("returns false past 90 days", () => { const now = Date.parse("2026-04-20T00:00:00Z"); const ts = new Date(now - 91 * DAY).toISOString(); expect(isWithinBannerWindow(ts, now)).toBe(false); }); it("returns false for a timestamp in the future", () => { const now = Date.parse("2026-04-20T00:00:00Z"); const ts = new Date(now + DAY).toISOString(); expect(isWithinBannerWindow(ts, now)).toBe(false); }); it("returns false for an unparseable timestamp", () => { const now = Date.parse("2026-04-20T00:00:00Z"); expect(isWithinBannerWindow("not-a-date", now)).toBe(false); }); it("respects a custom window length", () => { const now = Date.parse("2026-04-20T00:00:00Z"); const ts = new Date(now - 31 * DAY).toISOString(); expect(isWithinBannerWindow(ts, now, 30)).toBe(false); expect(isWithinBannerWindow(ts, now, 60)).toBe(true); }); }); describe("shouldShowBanner", () => { const now = Date.parse("2026-04-20T00:00:00Z"); function journal( overrides: Partial = {}, ): RestorableMigrationJournal { return { timestamp: "2026-04-15T10:00:00Z", backupPath: "/tmp/profile_avant-migration.sref", outcome: { insertedV1Count: 1, updatedTransactionsCount: 2, updatedBudgetsCount: 0, updatedKeywordsCount: 0, deletedV2Count: 0, customPreservedCount: 0, }, ...overrides, }; } it("hides the banner when no migration has run", () => { expect(shouldShowBanner(null, null, now)).toBe(false); }); it("shows the banner for a recent un-dismissed un-reverted migration", () => { expect(shouldShowBanner(journal(), null, now)).toBe(true); }); it("hides the banner when the user already dismissed it", () => { expect(shouldShowBanner(journal(), "1", now)).toBe(false); }); it("hides the banner when the migration was already reverted", () => { expect( shouldShowBanner( journal({ reverted_at: "2026-04-19T12:00:00Z" }), null, now, ), ).toBe(false); }); it("hides the banner past the 90-day window", () => { expect( shouldShowBanner( journal({ timestamp: "2026-01-01T00:00:00Z" }), null, now, ), ).toBe(false); }); it("ignores arbitrary dismissal-pref values that are not '1'", () => { // Defensive: we treat anything other than the literal "1" as "not // dismissed" so an accidental write of "0" or "" still shows the banner. expect(shouldShowBanner(journal(), "0", now)).toBe(true); expect(shouldShowBanner(journal(), "", now)).toBe(true); }); });