Files
HiveGrid-Wireframes/hivegrid-cloud/apps/web/app/locale/i18next.server.test.ts
T

98 lines
3.1 KiB
TypeScript

// @vitest-environment node
import { describe, expect, it, vi } from "vitest";
type TestWebConfig = {
nodeEnv: string;
sessionSecret: string;
routing: {
appBaseDomain: string;
protocol: "http" | "https";
};
};
const testWebConfig: TestWebConfig = {
nodeEnv: "production",
sessionSecret: "production-session-secret-with-enough-entropy",
routing: {
appBaseDomain: "example.com",
protocol: "https",
},
};
vi.doMock("@toolctrl/config", async () => {
const actual = await vi.importActual<typeof import("@toolctrl/config")>("@toolctrl/config");
return {
...actual,
loadRequiredWebConfig: () => testWebConfig,
};
});
async function importI18nextServerWithConfig(config: typeof testWebConfig) {
Object.assign(testWebConfig, config);
vi.resetModules();
return await import("./i18next.server");
}
describe("i18n cookie policy", () => {
it("resolves locale files from the workspace path when running from a bundled server file", async () => {
const { resolveServerLocalePath } = await importI18nextServerWithConfig(testWebConfig);
const resolved = resolveServerLocalePath({
moduleUrl: "file:///myapp/apps/web/build/server/assets/server-build.js",
cwd: "/myapp",
exists: (candidate) => candidate === "/myapp/apps/web/public/locales",
});
expect(resolved).toBe("/myapp/apps/web/public/locales");
});
it("keeps source-relative locale resolution for local source execution", async () => {
const { resolveServerLocalePath } = await importI18nextServerWithConfig(testWebConfig);
const resolved = resolveServerLocalePath({
moduleUrl: "file:///repo/apps/web/app/locale/i18next.server.ts",
cwd: "/repo",
exists: (candidate) => candidate === "/repo/apps/web/public/locales",
});
expect(resolved).toBe("/repo/apps/web/public/locales");
});
it("serializes hardened production i18n cookie attributes without exposing the session secret", async () => {
const productionSecret = "production-session-secret-with-enough-entropy";
const { i18nCookie } = await importI18nextServerWithConfig({
nodeEnv: "production",
sessionSecret: productionSecret,
routing: {
appBaseDomain: "example.com",
protocol: "https",
},
});
const header = await i18nCookie.serialize("de");
expect(header).toContain("_i18n=");
expect(header).toContain("Domain=example.com");
expect(header).toContain("SameSite=Lax");
expect(header).toContain("Secure");
expect(header).toContain("HttpOnly");
expect(header).toContain("Path=/");
expect(header).not.toContain(productionSecret);
});
it("keeps local i18n cookies domainless", async () => {
const { i18nCookie } = await importI18nextServerWithConfig({
nodeEnv: "test",
sessionSecret: "local-session-secret-with-enough-entropy",
routing: {
appBaseDomain: "localhost",
protocol: "http",
},
});
const header = await i18nCookie.serialize("de");
expect(header).toContain("_i18n=");
expect(header).not.toContain("Domain=");
expect(header).not.toContain("Secure");
});
});