import { DateTime } from "luxon"; import { beforeEach, describe, expect, it, mock } from "bun:test"; import type { DelayedTaskMetadata } from "./delayedTask"; import { deserializeDelayedTask, generateTaskKey, serializeDelayedTask, } from "./delayedTask"; describe("delayedTask", () => { describe("generateTaskKey", () => { it("generates key with correct format", () => { const scheduledTime = 1732896000; const taskId = "abc-123-def"; const key = generateTaskKey(scheduledTime, taskId); expect(key).toBe("delayed-task:1732896000:abc-123-def"); }); it("generates unique keys for different timestamps", () => { const taskId = "same-id"; const key1 = generateTaskKey(1000, taskId); const key2 = generateTaskKey(2000, taskId); expect(key1).not.toBe(key2); }); it("generates unique keys for different task IDs", () => { const timestamp = 1000; const key1 = generateTaskKey(timestamp, "id-1"); const key2 = generateTaskKey(timestamp, "id-2"); expect(key1).not.toBe(key2); }); }); describe("serializeDelayedTask & deserializeDelayedTask", () => { let testMetadata: DelayedTaskMetadata; beforeEach(() => { testMetadata = { queueName: "NEW_EPISODE", body: { aniListId: 12345, episodeNumber: 1 }, headers: { "Content-Type": "application/json", "X-Anilist-Token": "test-token", }, scheduledEpochTime: 1732896000, taskId: "test-task-id", createdAt: 1732800000, retryCount: 0, }; }); it("serializes metadata to JSON string", () => { const serialized = serializeDelayedTask(testMetadata); expect(serialized).toBeTypeOf("string"); expect(() => JSON.parse(serialized)).not.toThrow(); }); it("deserializes JSON string back to metadata", () => { const serialized = serializeDelayedTask(testMetadata); const deserialized = deserializeDelayedTask(serialized); expect(deserialized).toEqual(testMetadata); }); it("preserves all metadata fields", () => { const serialized = serializeDelayedTask(testMetadata); const deserialized = deserializeDelayedTask(serialized); expect(deserialized.queueName).toBe("NEW_EPISODE"); expect(deserialized.body).toEqual({ aniListId: 12345, episodeNumber: 1 }); expect(deserialized.headers).toEqual({ "Content-Type": "application/json", "X-Anilist-Token": "test-token", }); expect(deserialized.scheduledEpochTime).toBe(1732896000); expect(deserialized.taskId).toBe("test-task-id"); expect(deserialized.createdAt).toBe(1732800000); expect(deserialized.retryCount).toBe(0); }); it("handles metadata without retryCount", () => { delete testMetadata.retryCount; const serialized = serializeDelayedTask(testMetadata); const deserialized = deserializeDelayedTask(serialized); expect(deserialized.retryCount).toBeUndefined(); }); it("handles ANILIST_UPDATES queue body", () => { const anilistMetadata: DelayedTaskMetadata = { queueName: "ANILIST_UPDATES", body: { deviceId: "device-123", watchStatus: null, titleId: 456, updateType: 0, }, headers: { "Content-Type": "application/json" }, scheduledEpochTime: 1732896000, taskId: "test-id", createdAt: 1732800000, }; const serialized = serializeDelayedTask(anilistMetadata); const deserialized = deserializeDelayedTask(serialized); expect(deserialized.queueName).toBe("ANILIST_UPDATES"); expect(deserialized.body).toEqual({ deviceId: "device-123", watchStatus: null, titleId: 456, updateType: 0, }); }); }); });