Use the dedicated TJWATER_AGENT_URL and Responses stream protocol. Keep running turns active while users steer or queue follow-ups and edit pending delivery. Refresh the model catalog before generation and preserve approval mode selection. Integrate scoped investigation messaging/presentation, geographic place selection, current Agent composer styles and supporting workbench contracts. Validation: 77 focused Vitest checks, 21 browser cases, lint, typecheck and production build. Preserve direct Server/Agent routing and project authentication.
117 lines
4.7 KiB
TypeScript
117 lines
4.7 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
|
|
import { parseRuntimeConfig } from "./env";
|
|
|
|
describe("runtime frontend configuration", () => {
|
|
it("uses container-provided values without relying on Vite build variables", () => {
|
|
expect(
|
|
parseRuntimeConfig({
|
|
TJWATER_AUTH_MODE: "required",
|
|
TJWATER_KEYCLOAK_ISSUER: "https://auth.example.test/realms/tjwater/",
|
|
TJWATER_KEYCLOAK_CLIENT_ID: "next-tjwater",
|
|
TJWATER_MAPBOX_ACCESS_TOKEN: "token",
|
|
TJWATER_TIANDITU_TOKEN: "tianditu-token",
|
|
TJWATER_MAP_URL: "https://maps.example.test/geoserver",
|
|
TJWATER_GEOSERVER_WORKSPACE: "project-a",
|
|
TJWATER_SERVER_API_BASE_URL: "https://server.example.test",
|
|
TJWATER_AGENT_URL: "https://agent.example.test",
|
|
TJWATER_WORKBENCH_RUNTIME_MODE: "backend",
|
|
TJWATER_PERIPHERAL_SAMPLE_API_BASE_URL: "https://peripheral.example.test/",
|
|
TJWATER_PERIPHERAL_SAMPLE_TIME_MODE: "recent",
|
|
TJWATER_PERIPHERAL_SAMPLE_DEMO_START: "2026-04-30T08:00:00Z",
|
|
TJWATER_PERIPHERAL_SAMPLE_DEMO_END: "2026-04-30T16:00:00Z",
|
|
TJWATER_PERIPHERAL_SAMPLE_RECENT_HOURS: "6",
|
|
TJWATER_ENABLE_DEV_PANEL: "true",
|
|
TJWATER_ENABLE_MSW: "false"
|
|
})
|
|
).toEqual({
|
|
TJWATER_AUTH_MODE: "required",
|
|
TJWATER_KEYCLOAK_ISSUER: "https://auth.example.test/realms/tjwater",
|
|
TJWATER_KEYCLOAK_CLIENT_ID: "next-tjwater",
|
|
TJWATER_MAPBOX_ACCESS_TOKEN: "token",
|
|
TJWATER_TIANDITU_TOKEN: "tianditu-token",
|
|
TJWATER_MAP_URL: "https://maps.example.test/geoserver",
|
|
TJWATER_GEOSERVER_WORKSPACE: "project-a",
|
|
TJWATER_SERVER_API_BASE_URL: "https://server.example.test",
|
|
TJWATER_AGENT_URL: "https://agent.example.test",
|
|
TJWATER_WORKBENCH_RUNTIME_MODE: "backend",
|
|
TJWATER_PERIPHERAL_SAMPLE_API_BASE_URL: "https://peripheral.example.test",
|
|
TJWATER_PERIPHERAL_SAMPLE_TIME_MODE: "recent",
|
|
TJWATER_PERIPHERAL_SAMPLE_DEMO_START: "2026-04-30T08:00:00Z",
|
|
TJWATER_PERIPHERAL_SAMPLE_DEMO_END: "2026-04-30T16:00:00Z",
|
|
TJWATER_PERIPHERAL_SAMPLE_RECENT_HOURS: 6,
|
|
TJWATER_ENABLE_DEV_PANEL: true,
|
|
TJWATER_ENABLE_MSW: false
|
|
});
|
|
});
|
|
|
|
it("applies typed defaults for optional feature flags", () => {
|
|
expect(parseRuntimeConfig({ TJWATER_AUTH_MODE: "disabled" })).toMatchObject({
|
|
TJWATER_AUTH_MODE: "disabled",
|
|
TJWATER_KEYCLOAK_CLIENT_ID: "next-tjwater",
|
|
TJWATER_TIANDITU_TOKEN: "",
|
|
TJWATER_WORKBENCH_RUNTIME_MODE: "auto",
|
|
TJWATER_PERIPHERAL_SAMPLE_API_BASE_URL: "",
|
|
TJWATER_PERIPHERAL_SAMPLE_TIME_MODE: "demo",
|
|
TJWATER_PERIPHERAL_SAMPLE_DEMO_START: "2026-09-17T00:00:00Z",
|
|
TJWATER_PERIPHERAL_SAMPLE_DEMO_END: "2026-09-17T12:00:00Z",
|
|
TJWATER_PERIPHERAL_SAMPLE_RECENT_HOURS: 8,
|
|
TJWATER_ENABLE_DEV_PANEL: false,
|
|
TJWATER_ENABLE_MSW: false
|
|
});
|
|
});
|
|
|
|
it("accepts the explicit backend history mode", () => {
|
|
expect(
|
|
parseRuntimeConfig({
|
|
TJWATER_AUTH_MODE: "disabled",
|
|
TJWATER_WORKBENCH_RUNTIME_MODE: "history"
|
|
}).TJWATER_WORKBENCH_RUNTIME_MODE
|
|
).toBe("history");
|
|
});
|
|
|
|
it("requires a Realm issuer when authentication is enabled", () => {
|
|
expect(() => parseRuntimeConfig({ TJWATER_AUTH_MODE: "required" })).toThrow();
|
|
});
|
|
|
|
it("rejects invalid runtime URLs before the application starts", () => {
|
|
expect(() => parseRuntimeConfig({ TJWATER_MAP_URL: "not-a-url" })).toThrow();
|
|
});
|
|
|
|
it.each([
|
|
["TJWATER_MAP_URL", "file:///etc/passwd"],
|
|
["TJWATER_AGENT_URL", "https://user:secret@agent.example.test"],
|
|
["TJWATER_AGENT_URL", "https://agent.example.test/#secret"],
|
|
["TJWATER_PERIPHERAL_SAMPLE_API_BASE_URL", "https://user:secret@peripheral.example.test"]
|
|
])("rejects unsafe browser runtime address %s", (key, value) => {
|
|
expect(() => parseRuntimeConfig({ TJWATER_AUTH_MODE: "disabled", [key]: value })).toThrow();
|
|
});
|
|
|
|
it("rejects a Keycloak URL that does not identify a Realm", () => {
|
|
expect(() =>
|
|
parseRuntimeConfig({
|
|
TJWATER_AUTH_MODE: "required",
|
|
TJWATER_KEYCLOAK_ISSUER: "https://auth.example.test/",
|
|
TJWATER_KEYCLOAK_CLIENT_ID: "next-tjwater"
|
|
})
|
|
).toThrow();
|
|
});
|
|
|
|
it("rejects an invalid or oversized peripheral demo window", () => {
|
|
expect(() =>
|
|
parseRuntimeConfig({
|
|
TJWATER_AUTH_MODE: "disabled",
|
|
TJWATER_PERIPHERAL_SAMPLE_DEMO_START: "2026-04-30T16:00:00Z",
|
|
TJWATER_PERIPHERAL_SAMPLE_DEMO_END: "2026-04-30T08:00:00Z"
|
|
})
|
|
).toThrow(/演示窗口/);
|
|
expect(() =>
|
|
parseRuntimeConfig({
|
|
TJWATER_AUTH_MODE: "disabled",
|
|
TJWATER_PERIPHERAL_SAMPLE_DEMO_START: "2026-04-01T00:00:00Z",
|
|
TJWATER_PERIPHERAL_SAMPLE_DEMO_END: "2026-04-30T00:00:00Z"
|
|
})
|
|
).toThrow(/演示窗口/);
|
|
});
|
|
});
|