Files
wehub-resource-sync e30e75b5d4
Changesets / Create Version PR (push) Has been cancelled
Deploy Shadcn Registry / Deploy Production (push) Has been cancelled
Template Metrics / LOC + Bundle Size (push) Has been cancelled
Code Quality / Oxlint + Oxfmt (push) Has been cancelled
Code Quality / Template Sync (push) Has been cancelled
Code Quality / Build Changed Packages (push) Has been cancelled
Code Quality / Test Changed Packages (push) Has been cancelled
Deploy Expo Example / Deploy Production (push) Has been cancelled
Deploy Ink Example / Deploy Production (push) Has been cancelled
Python Tests / pytest (assistant-stream, 3.10) (push) Has been cancelled
Python Tests / pytest (assistant-stream, 3.12) (push) Has been cancelled
Python Tests / pytest (assistant-ui-sync-server-api, 3.10) (push) Has been cancelled
Python Tests / pytest (assistant-ui-sync-server-api, 3.12) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:40:13 +08:00

110 lines
4.0 KiB
TypeScript

import { describe, expect, it } from "vitest";
import { buildXuluxMcpCatalog } from "./mcp-catalog";
import { GET } from "@/app/api/xulux/mcp-catalog/route";
const ORIGIN = "https://docs.example.com";
describe("buildXuluxMcpCatalog", () => {
const catalog = buildXuluxMcpCatalog(ORIGIN);
it("returns a versioned payload with the docs origin", () => {
expect(catalog.version).toBe(1);
expect(catalog.docsOrigin).toBe(ORIGIN);
expect(typeof catalog.generatedAt).toBe("string");
expect(Array.isArray(catalog.templates)).toBe(true);
});
it("includes the required template ids", () => {
const ids = catalog.templates.map((t) => t.templateId);
expect(ids).toContain("base-assistant-ui");
expect(ids).toContain("webpage-assistant");
expect(ids).toContain("product-page-assistant");
expect(ids).toContain("expo-react-native");
});
it("does not duplicate template ids", () => {
const ids = catalog.templates.map((t) => t.templateId);
expect(new Set(ids).size).toBe(ids.length);
});
it("resolves fixed demo relative URLs to absolute URLs", () => {
const fixedDemos = catalog.templates.filter((t) => t.kind === "example");
expect(fixedDemos.length).toBeGreaterThan(0);
for (const demo of fixedDemos) {
if (demo.previewUrl) {
expect(demo.previewUrl).toMatch(/^https?:\/\//);
}
if (demo.downloadUrl) {
expect(demo.downloadUrl).toMatch(/^https?:\/\//);
}
}
});
it("absolutizes docs-relative demo URLs against the request origin", () => {
const base = catalog.templates.find((t) => t.templateId === "base");
expect(base).toBeDefined();
expect(base!.previewUrl).toBe(`${ORIGIN}/demos/base`);
expect(base!.downloadUrl).toBe(
`${ORIGIN}/api/xulux/demo-download?slug=base`,
);
});
it("includes the expo-react-native special case with hosted preview", () => {
const expo = catalog.templates.find(
(t) => t.templateId === "expo-react-native",
);
expect(expo).toBeDefined();
expect(expo!.kind).toBe("example");
expect(expo!.previewUrl).toMatch(/^https:\/\//);
expect(expo!.name).toBe("Expo React Native Assistant");
});
it("includes authoring metadata for configurable templates", () => {
for (const id of [
"base-assistant-ui",
"webpage-assistant",
"product-page-assistant",
]) {
const template = catalog.templates.find((t) => t.templateId === id);
expect(template, id).toBeDefined();
expect(template!.kind).toBe("template");
expect(template!.configRoots).toBeDefined();
expect(template!.rules?.required.length).toBeGreaterThan(0);
expect(template!.tools?.builtIn.length).toBeGreaterThan(0);
expect(template!.customizable.length).toBeGreaterThan(0);
expect(template!.sandboxBaseUrl).toMatch(/^https:\/\//);
}
});
it("includes per-version preview/download URLs with entry ids", () => {
const webpage = catalog.templates.find(
(t) => t.templateId === "webpage-assistant",
);
expect(webpage!.versions.length).toBeGreaterThan(0);
for (const version of webpage!.versions) {
expect(version.entryId).toBe(`webpage-assistant-${version.id}`);
expect(version.previewUrl).toMatch(/^https?:\/\//);
expect(version.downloadUrl).toMatch(/^https?:\/\//);
}
});
it("does not leak frontend-only fields", () => {
for (const template of catalog.templates) {
expect(template).not.toHaveProperty("gradient");
expect(template).not.toHaveProperty("categoryName");
expect(template).not.toHaveProperty("featured");
expect(template).not.toHaveProperty("previewFrame");
}
});
it("serves the public route with cache headers", async () => {
const response = GET(new Request(`${ORIGIN}/api/xulux/mcp-catalog`));
expect(response.headers.get("Cache-Control")).toBe(
"public, s-maxage=300, stale-while-revalidate=300",
);
const payload = await response.json();
expect(payload.docsOrigin).toBe(ORIGIN);
expect(payload.templates.length).toBeGreaterThan(0);
});
});