- 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
148 lines
5.1 KiB
TypeScript
148 lines
5.1 KiB
TypeScript
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
|
|
import {
|
|
buildAdminUrl,
|
|
buildSiteUrl,
|
|
fromDevelopmentAdminPath,
|
|
getAdminAppPath,
|
|
getAdminBaseUrl,
|
|
getAdminHost,
|
|
getRequestHostname,
|
|
getSiteBaseUrl,
|
|
getSiteHost,
|
|
hasDedicatedAdminHost,
|
|
INTERNAL_ADMIN_PREFIX,
|
|
isAdminHost,
|
|
isDevelopmentAdminPath,
|
|
isInternalAdminPath,
|
|
isLegacyAdminPath,
|
|
toInternalAdminPath,
|
|
} from "@/lib/admin-routing";
|
|
|
|
afterEach(() => {
|
|
vi.unstubAllEnvs();
|
|
});
|
|
|
|
describe("getRequestHostname", () => {
|
|
it("prefers the first non-empty candidate", () => {
|
|
expect(getRequestHostname("root.mohfarawati.de", "internal")).toBe("root.mohfarawati.de");
|
|
});
|
|
|
|
it("strips ports and takes the first comma-separated proxy value", () => {
|
|
expect(getRequestHostname(undefined, "root.mohfarawati.de:443, proxy")).toBe("root.mohfarawati.de");
|
|
});
|
|
|
|
it("lowercases the hostname", () => {
|
|
expect(getRequestHostname("ROOT.MohFarawati.de")).toBe("root.mohfarawati.de");
|
|
});
|
|
|
|
it("falls back to empty string when nothing matches", () => {
|
|
expect(getRequestHostname(undefined, null, "")).toBe("");
|
|
});
|
|
});
|
|
|
|
describe("host configuration", () => {
|
|
it("defaults admin and site hosts", () => {
|
|
expect(getAdminHost()).toBe("root.mohfarawati.de");
|
|
expect(getSiteHost()).toBe("mohfarawati.de");
|
|
expect(hasDedicatedAdminHost()).toBe(true);
|
|
});
|
|
|
|
it("reads ADMIN_HOST override and normalizes case/whitespace", () => {
|
|
vi.stubEnv("ADMIN_HOST", " Admin.Example.COM ");
|
|
expect(getAdminHost()).toBe("admin.example.com");
|
|
});
|
|
|
|
it("derives the site host from NEXT_PUBLIC_SITE_URL", () => {
|
|
vi.stubEnv("NEXT_PUBLIC_SITE_URL", "https://example.org/some/path");
|
|
expect(getSiteHost()).toBe("example.org");
|
|
});
|
|
|
|
it("hasDedicatedAdminHost is false when admin and site hosts match", () => {
|
|
vi.stubEnv("ADMIN_HOST", "example.com");
|
|
vi.stubEnv("NEXT_PUBLIC_SITE_URL", "https://example.com");
|
|
expect(hasDedicatedAdminHost()).toBe(false);
|
|
});
|
|
|
|
it("isAdminHost compares against the configured admin host", () => {
|
|
expect(isAdminHost("root.mohfarawati.de")).toBe(true);
|
|
expect(isAdminHost("mohfarawati.de")).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe("path predicates", () => {
|
|
it("recognizes legacy /root paths", () => {
|
|
expect(isLegacyAdminPath("/root")).toBe(true);
|
|
expect(isLegacyAdminPath("/root/portfolio")).toBe(true);
|
|
expect(isLegacyAdminPath("/rooting")).toBe(false);
|
|
expect(isLegacyAdminPath("/")).toBe(false);
|
|
});
|
|
|
|
it("recognizes development /root paths", () => {
|
|
expect(isDevelopmentAdminPath("/root")).toBe(true);
|
|
expect(isDevelopmentAdminPath("/root/media")).toBe(true);
|
|
expect(isDevelopmentAdminPath("/rootx")).toBe(false);
|
|
});
|
|
|
|
it("recognizes internal admin paths", () => {
|
|
expect(isInternalAdminPath(INTERNAL_ADMIN_PREFIX)).toBe(true);
|
|
expect(isInternalAdminPath(`${INTERNAL_ADMIN_PREFIX}/smtp`)).toBe(true);
|
|
expect(isInternalAdminPath("/admin")).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe("path translation", () => {
|
|
it("maps public paths to internal admin paths", () => {
|
|
expect(toInternalAdminPath("/")).toBe(INTERNAL_ADMIN_PREFIX);
|
|
expect(toInternalAdminPath("/portfolio")).toBe(`${INTERNAL_ADMIN_PREFIX}/portfolio`);
|
|
expect(toInternalAdminPath("portfolio")).toBe(`${INTERNAL_ADMIN_PREFIX}/portfolio`);
|
|
});
|
|
|
|
it("strips the dev /root prefix", () => {
|
|
expect(fromDevelopmentAdminPath("/root")).toBe("/");
|
|
expect(fromDevelopmentAdminPath("/root/portfolio")).toBe("/portfolio");
|
|
expect(fromDevelopmentAdminPath("/portfolio")).toBe("/portfolio");
|
|
});
|
|
});
|
|
|
|
describe("getAdminAppPath", () => {
|
|
it("returns bare paths when a dedicated admin host exists", () => {
|
|
// default env: admin host != site host -> dedicated host branch
|
|
expect(getAdminAppPath("/")).toBe("/");
|
|
expect(getAdminAppPath("/smtp")).toBe("/smtp");
|
|
});
|
|
|
|
it("uses the /root dev prefix when no dedicated host and not production", () => {
|
|
vi.stubEnv("ADMIN_HOST", "example.com");
|
|
vi.stubEnv("NEXT_PUBLIC_SITE_URL", "https://example.com");
|
|
vi.stubEnv("NODE_ENV", "development");
|
|
expect(getAdminAppPath("/")).toBe("/root");
|
|
expect(getAdminAppPath("/portfolio")).toBe("/root/portfolio");
|
|
});
|
|
|
|
it("returns bare paths in production even without a dedicated host", () => {
|
|
vi.stubEnv("ADMIN_HOST", "example.com");
|
|
vi.stubEnv("NEXT_PUBLIC_SITE_URL", "https://example.com");
|
|
vi.stubEnv("NODE_ENV", "production");
|
|
expect(getAdminAppPath("/portfolio")).toBe("/portfolio");
|
|
});
|
|
});
|
|
|
|
describe("url builders", () => {
|
|
it("builds admin urls from NEXT_PUBLIC_ADMIN_URL", () => {
|
|
expect(getAdminBaseUrl()).toBe("https://root.mohfarawati.de");
|
|
expect(buildAdminUrl("/smtp")).toBe("https://root.mohfarawati.de/smtp");
|
|
});
|
|
|
|
it("trims trailing slashes from configured base urls", () => {
|
|
vi.stubEnv("NEXT_PUBLIC_ADMIN_URL", "https://admin.example.com/");
|
|
expect(getAdminBaseUrl()).toBe("https://admin.example.com");
|
|
});
|
|
|
|
it("builds site urls from NEXT_PUBLIC_SITE_URL", () => {
|
|
expect(getSiteBaseUrl()).toBe("https://mohfarawati.de");
|
|
expect(buildSiteUrl("/about")).toBe("https://mohfarawati.de/about");
|
|
expect(buildSiteUrl("/")).toBe("https://mohfarawati.de/");
|
|
});
|
|
});
|