/*
Unit tests for trusted types covering werkstatt trusted-types policy. It also guards the documented public contract and regression-sensitive edge cases.
- Not a contract source of truth — the module under test owns the authoritative behavior; fixtures are minimal scaffolding only.
- RFC-1311: Compass header sweep — declares the trusted suite's contract for test-file scaffold coverage.
*/
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
/**
* WebIDL-faithful TrustedTypes factory stub: `createHTML`/`createScriptURL`
* declare `input` as DOMString, so the browser stringifies the argument
* before invoking the policy callback. The mock reproduces that coercion —
* an object brand would arrive as "[object Object]".
*/
function installTrustedTypes() {
const factory = {
createPolicy(
_name: string,
rules: {
createHTML?(input: unknown): string;
createScriptURL?(input: unknown): string;
},
) {
return {
createHTML: (input: unknown) => rules.createHTML?.(String(input)),
createScriptURL: (input: unknown) => rules.createScriptURL?.(String(input)),
};
},
};
(globalThis as { trustedTypes?: unknown }).trustedTypes = factory;
return factory;
}
async function importModule() {
return import("../trusted-types.ts");
}
describe("werkstatt trusted-types policy", () => {
beforeEach(() => {
vi.resetModules();
});
afterEach(() => {
delete (globalThis as { trustedTypes?: unknown }).trustedTypes;
});
it("ttScriptURL returns a minted trusted URL that round-trips the policy", async () => {
installTrustedTypes();
const { ttScriptURL } = await importModule();
expect(ttScriptURL("https://matomo-proxy.example/m.js")).toBe(
"https://matomo-proxy.example/m.js",
);
});
it("rejects unbranded input passed straight to the policy", async () => {
installTrustedTypes();
const mod = await importModule();
expect(() => mod.werkstattPolicy?.createScriptURL("https://evil.example/x.js")).toThrow(
/refusing unbranded input/,
);
});
it("each minted value is single-use — replaying it throws", async () => {
installTrustedTypes();
const mod = await importModule();
mod.ttScriptURL("https://a.example/one.js");
expect(() => mod.werkstattPolicy?.createScriptURL("https://a.example/one.js")).toThrow(
/refusing unbranded input/,
);
});
it("double-minting the same URL allows two consecutive passes", async () => {
installTrustedTypes();
const mod = await importModule();
expect(mod.ttScriptURL("https://a.example/dup.js")).toBe("https://a.example/dup.js");
expect(mod.ttScriptURL("https://a.example/dup.js")).toBe("https://a.example/dup.js");
expect(() => mod.werkstattPolicy?.createScriptURL("https://a.example/dup.js")).toThrow(
/refusing unbranded input/,
);
});
it("ttHTML returns minted HTML and rejects raw strings", async () => {
installTrustedTypes();
const mod = await importModule();
expect(mod.ttHTML("ok")).toBe("ok");
expect(() => mod.werkstattPolicy?.createHTML("ok")).toThrow(/refusing unbranded input/);
});
it("falls back to a raw string pass-through without TrustedTypes support", async () => {
const mod = await importModule();
expect(mod.werkstattPolicy).toBeUndefined();
expect(mod.ttScriptURL("https://a.example/x.js")).toBe("https://a.example/x.js");
expect(mod.ttHTML("y")).toBe("y");
});
it("ttMaybeHTML mints strings and passes non-strings through untouched", async () => {
installTrustedTypes();
const mod = await importModule();
const el = { tag: "div" } as const;
expect(mod.ttMaybeHTML(el)).toBe(el);
expect(mod.ttMaybeHTML("minted")).toBe("minted");
expect(() => mod.werkstattPolicy?.createHTML("minted")).toThrow(
/refusing unbranded input/,
);
});
});