Files
sofa/packages/core/test/thumbhash.test.ts
T
jake 3c1b7cfe11 refactor: enforce layered architecture by extracting all DB queries into @sofa/db/queries/*
- Create 18 new query modules under `packages/db/src/queries/` covering every domain (availability, cache, colors, credits, cron, discovery, image-cache, imports, integrations, lists, metadata, person, settings, system-health, thumbhash, title, tracking, webhooks)
- Remove all direct `db` client imports and raw Drizzle expressions from `@sofa/core` services and `apps/server` procedures/cron; replace with named query functions
- Extract cron DB helpers (`startCronRun`, `completeCronRun`, `failCronRun`, `getLibraryTitleIds`, `getStaleLibraryTitles`, etc.) into `packages/core/src/cron.ts`
- Extract integration DB helpers into `packages/core/src/integrations.ts`
- Add `drizzle-orm` as a direct dependency of `@sofa/db` and remove it from `@sofa/core`
- Update `AGENTS.md` to document the strict layered architecture rule
2026-03-18 17:31:18 -04:00

69 lines
2.0 KiB
TypeScript

import { afterEach, beforeEach, describe, expect, mock, spyOn, test } from "bun:test";
import { episodes, seasons, titles } from "@sofa/db/schema";
import { clearAllTables, eq, testDb } from "@sofa/db/test-utils";
const TINY_PNG = Buffer.from(
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIHWP4//8/AwAI/AL+X2NDNwAAAABJRU5ErkJggg==",
"base64",
);
let nextBuffer: Buffer | null = TINY_PNG;
import { generateEpisodeThumbHash, generateThumbHash } from "../src/thumbhash";
beforeEach(() => {
clearAllTables();
process.env.IMAGE_CACHE_ENABLED = "false";
nextBuffer = TINY_PNG;
spyOn(globalThis, "fetch").mockImplementation((async (
_input: string | URL | Request,
_init?: RequestInit,
) => {
if (!nextBuffer) {
return new Response(null, { status: 404 });
}
return new Response(nextBuffer, {
status: 200,
headers: { "content-type": "image/png" },
});
}) as typeof fetch);
});
afterEach(() => {
delete process.env.IMAGE_CACHE_ENABLED;
mock.restore();
});
describe("thumbhash generation", () => {
test("generates a thumbhash from a loaded image buffer", async () => {
const hash = await generateThumbHash("/poster.png", "posters");
expect(hash).toBeString();
expect(hash).not.toBe("");
});
test("clears a stale episode thumbhash when regeneration fails", async () => {
testDb.insert(titles).values({ id: "tv-1", tmdbId: 100, type: "tv", title: "Show" }).run();
testDb.insert(seasons).values({ id: "season-1", titleId: "tv-1", seasonNumber: 1 }).run();
testDb
.insert(episodes)
.values({
id: "ep-1",
seasonId: "season-1",
episodeNumber: 1,
stillPath: "/old-still.png",
stillThumbHash: "stale-hash",
})
.run();
nextBuffer = null;
const hash = await generateEpisodeThumbHash("ep-1", "/new-still.png");
const episode = testDb.select().from(episodes).where(eq(episodes.id, "ep-1")).get();
expect(hash).toBeNull();
expect(episode?.stillThumbHash).toBeNull();
});
});