1import { env } from "cloudflare:workers";2import { createScheduledController } from "cloudflare:test";3import { beforeEach, describe, expect, it } from "vitest";4import worker from "../src/index.ts";56describe("game retention", () => {7 beforeEach(async () => {8 await env.DB.prepare("DROP TABLE IF EXISTS moves").run();9 await env.DB.prepare("DROP TABLE IF EXISTS games").run();10 await env.DB.prepare("CREATE TABLE games (id TEXT PRIMARY KEY, updated_at TEXT NOT NULL)").run();11 await env.DB12 .prepare(13 `CREATE TABLE moves (14 game_id TEXT NOT NULL,15 revision INTEGER NOT NULL,16 PRIMARY KEY (game_id, revision),17 FOREIGN KEY (game_id) REFERENCES games(id) ON DELETE CASCADE18 )`,19 )20 .run();21 await env.DB.prepare("CREATE INDEX idx_games_updated_at ON games(updated_at)").run();22 await env.DB.batch([23 env.DB.prepare("INSERT INTO games (id, updated_at) VALUES (?1, ?2)").bind(24 "expired",25 "2026-07-29T11:59:59.999Z",26 ),27 env.DB.prepare("INSERT INTO games (id, updated_at) VALUES (?1, ?2)").bind(28 "boundary",29 "2026-07-29T12:00:00.000Z",30 ),31 env.DB.prepare("INSERT INTO games (id, updated_at) VALUES (?1, ?2)").bind(32 "recent",33 "2026-08-01T00:00:00.000Z",34 ),35 env.DB.prepare("INSERT INTO moves (game_id, revision) VALUES (?1, 1)").bind("expired"),36 env.DB.prepare("INSERT INTO moves (game_id, revision) VALUES (?1, 1)").bind("boundary"),37 env.DB.prepare("INSERT INTO moves (game_id, revision) VALUES (?1, 1)").bind("recent"),38 ]);39 });4041 it("deletes games inactive for more than 14 days and cascades their moves", async () => {42 const controller = createScheduledController({43 cron: "17 4 * * *",44 scheduledTime: Date.parse("2026-08-12T12:00:00.000Z"),45 });4647 await worker.scheduled(controller, env);4849 const games = await env.DB.prepare("SELECT id FROM games ORDER BY id").all<{ id: string }>();50 const moves = await env.DB.prepare("SELECT game_id FROM moves ORDER BY game_id").all<{ game_id: string }>();51 expect(games.results.map((row) => row.id)).toEqual(["boundary", "recent"]);52 expect(moves.results.map((row) => row.game_id)).toEqual(["boundary", "recent"]);53 });54});