Files
SnapOtter/tests/integration/platform/docs-i18n.test.ts
T

120 lines
4.4 KiB
TypeScript
Raw Normal View History

// tests/integration/platform/docs-i18n.test.ts
import rateLimit from "@fastify/rate-limit";
import Fastify from "fastify";
import { afterAll, beforeAll, describe, expect, it } from "vitest";
import { env } from "../../../apps/api/src/config.js";
import { docsRoutes } from "../../../apps/api/src/routes/docs.js";
import { buildTestApp, type TestApp } from "../test-server";
describe("API docs i18n serving", () => {
let testApp: TestApp;
beforeAll(async () => {
testApp = await buildTestApp();
});
afterAll(async () => {
await testApp.cleanup();
});
it("serves the German spec for ?lang=de", async () => {
const res = await testApp.app.inject({ method: "GET", url: "/api/v1/openapi.yaml?lang=de" });
expect(res.statusCode).toBe(200);
expect(res.headers["content-type"]).toContain("text/yaml");
expect(res.body).toContain("Bildgröße ändern");
expect(res.body).toContain("locale: de");
});
it("falls back to English for an unsupported lang", async () => {
const res = await testApp.app.inject({ method: "GET", url: "/api/v1/openapi.yaml?lang=zz" });
expect(res.statusCode).toBe(200);
// English spec has the English summary, not the German one.
expect(res.body).toContain("openapi: 3.1.0");
expect(res.body).not.toContain("Bildgröße ändern");
});
it("serves another committed locale spec without falling back to English", async () => {
const res = await testApp.app.inject({ method: "GET", url: "/api/v1/openapi.yaml?lang=fr" });
expect(res.statusCode).toBe(200);
expect(res.body).toContain("locale: fr");
expect(res.body).not.toContain("locale: de");
});
it("keeps the default (no lang) response ASCII-only", async () => {
const res = await testApp.app.inject({ method: "GET", url: "/api/v1/openapi.yaml" });
const offending = [...res.body].find((ch) => ch.charCodeAt(0) > 0x7f);
expect(offending).toBeUndefined();
});
it("serves a localized llms.de.txt using translated tool strings", async () => {
const res = await testApp.app.inject({ method: "GET", url: "/llms.de.txt" });
expect(res.statusCode).toBe(200);
expect(res.headers["content-type"]).toContain("text/plain");
expect(res.body).toContain("## Tools");
// Tag prose comes from the committed German spec.
expect(res.body).toContain("Datei-Verarbeitungstools");
// Tool lines come from shared i18n; the Resize tool id is present with a mode.
expect(res.body).toContain("Bildgröße ändern - Größe nach Pixeln");
expect(res.body).toContain("(resize, sync)");
});
it("rate-limits request-time localized docs work even when global limiting is disabled", async () => {
const app = Fastify();
await app.register(rateLimit, {
max: 50_000,
timeWindow: "1 minute",
allowList: (request) => !request.url.startsWith("/api/"),
});
await docsRoutes(app);
await app.ready();
try {
for (const url of ["/api/v1/openapi.yaml?lang=de", "/llms.de.txt"]) {
for (let request = 0; request < 60; request++) {
const response = await app.inject({ method: "GET", url });
expect(response.statusCode).toBe(200);
expect(response.headers["x-ratelimit-limit"]).toBe("60");
}
const limited = await app.inject({ method: "GET", url });
expect(limited.statusCode).toBe(429);
const head = await app.inject({ method: "HEAD", url });
expect(head.statusCode).toBe(404);
}
} finally {
await app.close();
}
});
it("does not loosen a stricter operator rate limit", async () => {
const previousLimit = env.RATE_LIMIT_PER_MIN;
env.RATE_LIMIT_PER_MIN = 2;
const app = Fastify();
try {
await app.register(rateLimit, {
max: env.RATE_LIMIT_PER_MIN,
timeWindow: "1 minute",
allowList: (request) => !request.url.startsWith("/api/"),
});
await docsRoutes(app);
await app.ready();
for (const url of ["/api/v1/openapi.yaml?lang=de", "/llms.de.txt"]) {
for (let request = 0; request < 2; request++) {
const response = await app.inject({ method: "GET", url });
expect(response.statusCode).toBe(200);
expect(response.headers["x-ratelimit-limit"]).toBe("2");
}
const limited = await app.inject({ method: "GET", url });
expect(limited.statusCode).toBe(429);
}
} finally {
env.RATE_LIMIT_PER_MIN = previousLimit;
await app.close();
}
});
});