Files
MOH 0a5f77d8de REFACTORED - migrate the data layer from Prisma to Drizzle (unify the stack)
- Add lib/db (Drizzle schema: 7 tables + 6 enums + relations, postgres.js client),
  drizzle.config.ts, lib/db/enums.ts (Prisma-compatible enum objects)
- Rewrite all 14 app consumers + 4 admin components to Drizzle
- Move the test DB layer to Drizzle + in-process PGlite; convert all 8 integration
  test files + factories (371 tests green)
- Remove Prisma: deps, prisma/ schema+migrations, lib/prisma.ts, Dockerfile prisma
  generate; wire db:generate/migrate/push/studio to drizzle-kit; update Makefile
- Preserve the old seed as scripts/legacy-prisma-seed.cjs (needs a Drizzle rewrite)
2026-08-07 14:18:41 +02:00

135 lines
4.7 KiB
TypeScript

import { describe, expect, it } from "vitest";
import {
countMediaUsageReferences,
createMediaAsset,
deleteEntityMediaUsages,
getAdminMediaAssets,
getMediaAssetById,
getMediaOptions,
getPortfolioMediaBindings,
replaceEntityMediaUsages,
} from "@/lib/media";
import { db } from "@/lib/db";
import { mediaUsage } from "@/lib/db/schema";
import { createMediaAsset as seedAsset } from "@/tests/helpers/factories";
describe("createMediaAsset / getMediaAssetById", () => {
it("creates and reads back an asset with usages", async () => {
const created = await createMediaAsset({
source: "EXTERNAL",
kind: "IMAGE",
url: "https://cdn/x.png",
fileName: "x.png",
label: "X",
});
const found = await getMediaAssetById(created.id);
expect(found?.url).toBe("https://cdn/x.png");
expect(found?.usages).toEqual([]);
});
it("returns null for a missing asset", async () => {
expect(await getMediaAssetById("nope")).toBeNull();
});
});
describe("getMediaOptions", () => {
it("filters by kind", async () => {
await seedAsset({ kind: "IMAGE" });
await seedAsset({ kind: "DOCUMENT" });
const images = await getMediaOptions({ kind: "IMAGE" });
expect(images.every((a) => a.kind === "IMAGE")).toBe(true);
const all = await getMediaOptions();
expect(all.length).toBe(2);
});
});
describe("getAdminMediaAssets", () => {
it("returns newest first with usage details", async () => {
const a = await seedAsset();
await createMediaUsageFor(a.id);
const list = await getAdminMediaAssets();
expect(list.length).toBe(1);
expect(list[0].usages.length).toBe(1);
});
});
describe("replaceEntityMediaUsages", () => {
it("replaces existing usages transactionally", async () => {
const a1 = await seedAsset();
const a2 = await seedAsset();
await replaceEntityMediaUsages({
entityType: "portfolio-project",
entityId: "p1",
usages: [{ assetId: a1.id, usageType: "PORTFOLIO_COVER", fieldKey: "cover" }],
});
expect(await countMediaUsageReferences(a1.id)).toBe(1);
await replaceEntityMediaUsages({
entityType: "portfolio-project",
entityId: "p1",
usages: [{ assetId: a2.id, usageType: "PORTFOLIO_COVER", fieldKey: "cover" }],
});
expect(await countMediaUsageReferences(a1.id)).toBe(0);
expect(await countMediaUsageReferences(a2.id)).toBe(1);
});
it("clears usages when given an empty list", async () => {
const a1 = await seedAsset();
await replaceEntityMediaUsages({
entityType: "portfolio-project",
entityId: "p2",
usages: [{ assetId: a1.id, usageType: "PORTFOLIO_ASSET", fieldKey: "a" }],
});
await replaceEntityMediaUsages({ entityType: "portfolio-project", entityId: "p2", usages: [] });
expect(await countMediaUsageReferences(a1.id)).toBe(0);
});
});
describe("deleteEntityMediaUsages", () => {
it("removes only the target entity's usages", async () => {
const a1 = await seedAsset();
await replaceEntityMediaUsages({
entityType: "portfolio-project",
entityId: "keep",
usages: [{ assetId: a1.id, usageType: "PORTFOLIO_ASSET", fieldKey: "a" }],
});
await replaceEntityMediaUsages({
entityType: "portfolio-project",
entityId: "drop",
usages: [{ assetId: a1.id, usageType: "PORTFOLIO_ASSET", fieldKey: "b" }],
});
await deleteEntityMediaUsages("portfolio-project", "drop");
expect(await countMediaUsageReferences(a1.id)).toBe(1);
});
});
describe("getPortfolioMediaBindings", () => {
it("routes usages into cover / section / asset buckets", async () => {
const cover = await seedAsset();
const section = await seedAsset();
const asset = await seedAsset();
await db.insert(mediaUsage).values([
{ assetId: cover.id, usageType: "PORTFOLIO_COVER", entityType: "portfolio-project", entityId: "proj", fieldKey: "cover" },
{ assetId: section.id, usageType: "PORTFOLIO_SECTION", entityType: "portfolio-project", entityId: "proj", fieldKey: "sec_1" },
{ assetId: asset.id, usageType: "PORTFOLIO_ASSET", entityType: "portfolio-project", entityId: "proj", fieldKey: "ast_1" },
]);
const bindings = await getPortfolioMediaBindings("proj");
expect(bindings.coverAssetId).toBe(cover.id);
expect(bindings.sectionAssetIds.sec_1).toBe(section.id);
expect(bindings.assetIds.ast_1).toBe(asset.id);
});
it("returns empty bindings for an unknown project", async () => {
const bindings = await getPortfolioMediaBindings("missing");
expect(bindings).toEqual({ coverAssetId: null, sectionAssetIds: {}, assetIds: {} });
});
});
async function createMediaUsageFor(assetId: string) {
await db.insert(mediaUsage).values({ assetId, usageType: "GENERIC", entityType: "e", entityId: "1", fieldKey: "f" });
}