- Vitest multi-project setup (unit / integration / component) - Real-Postgres integration harness via in-process PGlite (TEST_DATABASE_URL override), migrations applied per worker; production code untouched - Unit: routing, locale, validation/Zod schemas, metadata, mail, site-theme, marquee, media, portfolio helpers, plus architecture-rule tests - Integration: Prisma data layer, API routes, and all server actions - Component: UI primitives and form components (jsdom + Testing Library) - 371 tests passing
143 lines
4.9 KiB
TypeScript
143 lines
4.9 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
|
|
import {
|
|
DEFAULT_SITE_NAME,
|
|
MAINTENANCE_MODE_KEY,
|
|
SITE_NAME_KEY,
|
|
SITE_SETTINGS_ENTITY_ID,
|
|
SITE_SETTINGS_ENTITY_TYPE,
|
|
SITE_SETTINGS_FAVICON_FIELD_KEY,
|
|
SITE_SETTINGS_LOGO_LIGHT_FIELD_KEY,
|
|
buildDefaultMailSettings,
|
|
buildDefaultMarqueeSettings,
|
|
getMailSettings,
|
|
getMaintenanceMode,
|
|
getMarqueeSettings,
|
|
getSiteSettings,
|
|
getSiteSettingsMediaBindings,
|
|
setMaintenanceMode,
|
|
updateMailSettings,
|
|
updateMarqueeSettings,
|
|
updateSiteSettings,
|
|
} from "@/lib/app-config";
|
|
import { prisma } from "@/lib/prisma";
|
|
import { createMediaAsset } from "@/tests/helpers/factories";
|
|
|
|
describe("maintenance mode", () => {
|
|
it("defaults to false when unset", async () => {
|
|
expect(await getMaintenanceMode()).toBe(false);
|
|
});
|
|
|
|
it("persists and reads back the enabled flag", async () => {
|
|
await setMaintenanceMode(true);
|
|
expect(await getMaintenanceMode()).toBe(true);
|
|
const row = await prisma.appConfig.findUnique({ where: { key: MAINTENANCE_MODE_KEY } });
|
|
expect(row?.value).toBe("true");
|
|
await setMaintenanceMode(false);
|
|
expect(await getMaintenanceMode()).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe("site settings", () => {
|
|
it("returns defaults (with fallback name) when nothing stored", async () => {
|
|
const settings = await getSiteSettings();
|
|
expect(settings.defaultLocale).toBe("de");
|
|
expect(settings.locales.en.siteName).toBe(DEFAULT_SITE_NAME);
|
|
});
|
|
|
|
it("uses the stored siteName key as the fallback name", async () => {
|
|
await prisma.appConfig.create({ data: { key: SITE_NAME_KEY, value: "My Studio" } });
|
|
const settings = await getSiteSettings();
|
|
expect(settings.locales.ar.siteName).toBe("My Studio");
|
|
});
|
|
|
|
it("round-trips an updated settings object", async () => {
|
|
const next = await getSiteSettings();
|
|
next.defaultLocale = "ar";
|
|
next.brand.primaryColor = "#123456";
|
|
next.locales.en.siteName = "Updated EN";
|
|
await updateSiteSettings(next);
|
|
|
|
const reloaded = await getSiteSettings();
|
|
expect(reloaded.defaultLocale).toBe("ar");
|
|
expect(reloaded.brand.primaryColor).toBe("#123456");
|
|
expect(reloaded.locales.en.siteName).toBe("Updated EN");
|
|
});
|
|
});
|
|
|
|
describe("mail settings", () => {
|
|
it("returns defaults when unset", async () => {
|
|
expect(await getMailSettings()).toEqual(buildDefaultMailSettings());
|
|
});
|
|
|
|
it("round-trips stored mail settings", async () => {
|
|
const next = buildDefaultMailSettings();
|
|
next.smtp.host = "smtp.test";
|
|
next.smtp.port = 465;
|
|
next.sender.email = "from@test";
|
|
next.recipients.contact = "c@test";
|
|
await updateMailSettings(next);
|
|
|
|
const reloaded = await getMailSettings();
|
|
expect(reloaded.smtp.host).toBe("smtp.test");
|
|
expect(reloaded.smtp.port).toBe(465);
|
|
expect(reloaded.recipients.contact).toBe("c@test");
|
|
});
|
|
});
|
|
|
|
describe("marquee settings", () => {
|
|
it("returns defaults when unset", async () => {
|
|
const settings = await getMarqueeSettings();
|
|
expect(settings.locales.de.row1).toBe(buildDefaultMarqueeSettings().locales.de.row1);
|
|
});
|
|
|
|
it("stores german-synced values", async () => {
|
|
const next = buildDefaultMarqueeSettings();
|
|
next.locales.de.row1 = "GERMAN ROW";
|
|
next.locales.en.row1 = "will be overwritten";
|
|
await updateMarqueeSettings(next);
|
|
|
|
const reloaded = await getMarqueeSettings();
|
|
expect(reloaded.locales.de.row1).toBe("GERMAN ROW");
|
|
expect(reloaded.locales.en.row1).toBe("GERMAN ROW");
|
|
expect(reloaded.locales.ar.row1).toBe("GERMAN ROW");
|
|
});
|
|
});
|
|
|
|
describe("getSiteSettingsMediaBindings", () => {
|
|
it("returns nulls when there are no usages", async () => {
|
|
const bindings = await getSiteSettingsMediaBindings();
|
|
expect(bindings).toEqual({ siteLogoLight: null, siteLogoDark: null, favicon: null, defaultOgImage: null });
|
|
});
|
|
|
|
it("maps media usages to their field bindings", async () => {
|
|
const logo = await createMediaAsset({ url: "https://cdn/logo.png" });
|
|
const favicon = await createMediaAsset({ url: "https://cdn/favicon.svg" });
|
|
await prisma.mediaUsage.create({
|
|
data: {
|
|
assetId: logo.id,
|
|
usageType: "GENERIC",
|
|
entityType: SITE_SETTINGS_ENTITY_TYPE,
|
|
entityId: SITE_SETTINGS_ENTITY_ID,
|
|
fieldKey: SITE_SETTINGS_LOGO_LIGHT_FIELD_KEY,
|
|
},
|
|
});
|
|
await prisma.mediaUsage.create({
|
|
data: {
|
|
assetId: favicon.id,
|
|
usageType: "GENERIC",
|
|
entityType: SITE_SETTINGS_ENTITY_TYPE,
|
|
entityId: SITE_SETTINGS_ENTITY_ID,
|
|
fieldKey: SITE_SETTINGS_FAVICON_FIELD_KEY,
|
|
},
|
|
});
|
|
|
|
const bindings = await getSiteSettingsMediaBindings();
|
|
expect(bindings.siteLogoLight?.assetId).toBe(logo.id);
|
|
expect(bindings.siteLogoLight?.url).toBe("https://cdn/logo.png");
|
|
expect(bindings.favicon?.assetId).toBe(favicon.id);
|
|
expect(bindings.favicon?.version).toMatch(/\d{4}-\d{2}-\d{2}T/); // updatedAt ISO string
|
|
expect(bindings.siteLogoDark).toBeNull();
|
|
});
|
|
});
|