44 lines
1.7 KiB
TypeScript
44 lines
1.7 KiB
TypeScript
import type { SQL } from "drizzle-orm";
|
|
import { PgDialect } from "drizzle-orm/pg-core";
|
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
|
const candidates = vi.fn();
|
|
const returning = vi.fn();
|
|
const deleteWhere = vi.fn((condition: SQL) => { void condition; return { returning }; });
|
|
const deleteRows = vi.fn(() => ({ where: deleteWhere }));
|
|
const select = vi.fn(() => ({
|
|
from: () => ({
|
|
leftJoin: () => ({ where: () => ({ orderBy: () => ({ limit: candidates }) }) }),
|
|
where: () => ({}),
|
|
}),
|
|
}));
|
|
const set = vi.fn();
|
|
const evalRedis = vi.fn().mockResolvedValue(1);
|
|
|
|
vi.mock("server-only", () => ({}));
|
|
vi.mock("@/db/client", () => ({ getDb: () => ({ select, delete: deleteRows }) }));
|
|
vi.mock("@/lib/redis/client", () => ({ getRedisClient: async () => ({ set, eval: evalRedis }) }));
|
|
|
|
const { removeExpiredUnpaidCheckouts } = await import("./cleanup");
|
|
|
|
describe("expired checkout cleanup", () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
candidates.mockResolvedValue([{ id: "checkout-1" }, { id: "checkout-2" }]);
|
|
set.mockResolvedValueOnce("OK").mockResolvedValueOnce(null);
|
|
returning.mockResolvedValue([{ id: "checkout-1" }]);
|
|
});
|
|
|
|
it("deletes only an unlocked expired checkout with no ticket", async () => {
|
|
expect(await removeExpiredUnpaidCheckouts()).toBe(1);
|
|
expect(deleteRows).toHaveBeenCalledOnce();
|
|
expect(set).toHaveBeenCalledWith(expect.stringContaining("checkout-1"), expect.any(String), "EX", 60, "NX");
|
|
expect(evalRedis).toHaveBeenCalledOnce();
|
|
|
|
const query = new PgDialect().sqlToQuery(deleteWhere.mock.calls[0][0]);
|
|
expect(query.sql).toContain("not exists");
|
|
expect(query.sql).toContain('"created_at"');
|
|
expect(query.params).toContain("checkout-1");
|
|
});
|
|
});
|