test(api): cover API URL contract and prefix resolution

This commit is contained in:
Arthur Bassi 2026-06-17 09:35:56 -03:00
parent 74b73620b3
commit 43b53bb610
3 changed files with 90 additions and 1 deletions

View file

@ -0,0 +1,41 @@
import { readFileSync } from "node:fs";
import path from "node:path";
import { describe, expect, it } from "vitest";
import { assertAbsoluteApiUrlHasApiSegment } from "./api-url-contract";
describe("assertAbsoluteApiUrlHasApiSegment", () => {
it("allows relative /api", () => {
expect(() => assertAbsoluteApiUrlHasApiSegment("/api")).not.toThrow();
});
it("allows empty or undefined", () => {
expect(() => assertAbsoluteApiUrlHasApiSegment(undefined)).not.toThrow();
expect(() => assertAbsoluteApiUrlHasApiSegment("")).not.toThrow();
});
it("allows absolute URL ending with /api", () => {
expect(() =>
assertAbsoluteApiUrlHasApiSegment("https://api.seahavenindustries.com/api"),
).not.toThrow();
});
it("rejects absolute URL without /api", () => {
expect(() => assertAbsoluteApiUrlHasApiSegment("https://api.seahavenindustries.com")).toThrow(
/must end with \/api/,
);
});
});
describe(".env.example contract", () => {
it("documents an absolute VITE_API_URL that includes /api", () => {
const envExample = readFileSync(path.resolve(process.cwd(), ".env.example"), "utf8");
const match = envExample.match(/^VITE_API_URL=(.+)$/m);
expect(match).not.toBeNull();
const value = match![1]!.trim();
if (value.startsWith("http")) {
expect(() => assertAbsoluteApiUrlHasApiSegment(value)).not.toThrow();
}
});
});

View file

@ -0,0 +1,44 @@
import { describe, expect, it } from "vitest";
import { resolveApiBaseUrl, resolveApiPrefixUrl } from "@/lib/resolve-api-prefix-url";
const ORIGIN = "http://localhost:3000";
describe("resolveApiPrefixUrl", () => {
it("joins relative /api with origin", () => {
expect(resolveApiPrefixUrl("/api", ORIGIN)).toBe(`${ORIGIN}/api/`);
});
it("normalizes relative api without leading slash", () => {
expect(resolveApiPrefixUrl("api", ORIGIN)).toBe(`${ORIGIN}/api/`);
});
it("preserves absolute URL with /api and adds trailing slash", () => {
expect(resolveApiPrefixUrl("https://api.seahavenindustries.com/api", ORIGIN)).toBe(
"https://api.seahavenindustries.com/api/",
);
});
it("preserves absolute URL with /api/ trailing slash", () => {
expect(resolveApiPrefixUrl("https://api.seahavenindustries.com/api/", ORIGIN)).toBe(
"https://api.seahavenindustries.com/api/",
);
});
it("uses absolute host without /api as-is (invalid for production)", () => {
expect(resolveApiPrefixUrl("https://api.seahavenindustries.com", ORIGIN)).toBe(
"https://api.seahavenindustries.com/",
);
});
it("falls back to /api when empty", () => {
expect(resolveApiPrefixUrl("", ORIGIN)).toBe(`${ORIGIN}/api/`);
expect(resolveApiPrefixUrl(" ", ORIGIN)).toBe(`${ORIGIN}/api/`);
});
});
describe("resolveApiBaseUrl", () => {
it("strips trailing slash from prefix", () => {
expect(resolveApiBaseUrl("/api", ORIGIN)).toBe(`${ORIGIN}/api`);
expect(resolveApiBaseUrl("https://host/api/", ORIGIN)).toBe("https://host/api");
});
});

View file

@ -13,7 +13,11 @@ export default defineConfig({
environment: "jsdom",
setupFiles: ["./src/test/setup.ts"],
globals: false,
include: ["src/test/**/*.test.{ts,tsx}", "src/test/**/*.integration.test.{ts,tsx}"],
include: [
"src/test/**/*.test.{ts,tsx}",
"src/test/**/*.integration.test.{ts,tsx}",
"config/**/*.test.ts",
],
exclude: ["e2e/**", "node_modules/**"],
},
});