import { describe, expect, it } from "bun:test"; import { type HostedViewBootstrap, hostedViewBootstrapSchema, } from "@getuserfeedback/protocol/internal/hosted-view-bootstrap"; import { createGeneration } from "./v3-generation.js"; describe("hosted View bootstrap contract", () => { const bootstrap = { loader: { instanceId: "instance-hosted", viewId: "view-hosted", generation: createGeneration(7), debugConfig: false, hideCloseButton: true, }, payload: { survey: { pages: [] } }, themeCss: ':root{--proof:""}', colorScheme: "dark", } satisfies HostedViewBootstrap; it("accepts a complete envelope without interpreting its payload or CSS", () => { expect(hostedViewBootstrapSchema.parse(bootstrap)).toEqual(bootstrap); }); it.each([ "light", "dark", "system", ])("accepts color scheme %s", (colorScheme) => { const envelope = { ...bootstrap, colorScheme }; expect(hostedViewBootstrapSchema.parse(envelope)).toEqual(envelope); }); it.each( [false, true, "", "view:*", [], ["view", "loader"]].map((debugConfig) => ({ debugConfig, })), )("accepts existing debug configuration %j", ({ debugConfig }) => { const envelope = { ...bootstrap, loader: { ...bootstrap.loader, debugConfig }, }; expect(hostedViewBootstrapSchema.parse(envelope)).toEqual(envelope); }); it("preserves zero generation, optional close control, empty CSS and untrimmed IDs", () => { const envelope = { ...bootstrap, loader: { instanceId: " instance-hosted ", viewId: " view-hosted ", generation: 0, debugConfig: false, }, themeCss: "", }; expect(hostedViewBootstrapSchema.parse(envelope)).toEqual(envelope); }); it.each( [null, 7, "opaque", [], { survey: "malformed" }].map((payload) => ({ payload, })), )("leaves payload admission to View: %j", ({ payload }) => { expect( hostedViewBootstrapSchema.parse({ ...bootstrap, payload }).payload, ).toBe(payload); }); it.each([ { instanceId: "" }, { instanceId: 7 }, { instanceId: undefined }, { viewId: "" }, { viewId: null }, { viewId: undefined }, { generation: -1 }, { generation: 1.5 }, { generation: "7" }, { generation: Number.NaN }, { generation: Number.POSITIVE_INFINITY }, { generation: undefined }, { debugConfig: 123 }, { debugConfig: {} }, { debugConfig: [true] }, { debugConfig: undefined }, { hideCloseButton: "true" }, { unknownKey: true }, ])("rejects invalid loader fields %j", (loader) => { expect( hostedViewBootstrapSchema.safeParse({ ...bootstrap, loader: { ...bootstrap.loader, ...loader }, }).success, ).toBe(false); }); it.each([ { loader: null }, { loader: undefined }, { themeCss: {} }, { themeCss: null }, { themeCss: undefined }, { colorScheme: "purple" }, { colorScheme: { autoDetectColorScheme: ["data-theme"] } }, { colorScheme: { mode: "host" } }, { colorScheme: undefined }, { unknownKey: true }, ])("rejects invalid envelope fields %j", (fields) => { expect( hostedViewBootstrapSchema.safeParse({ ...bootstrap, ...fields }).success, ).toBe(false); }); });