import { afterEach, describe, expect, it } from "@effect/vitest"; import { setAnalyticsClient, trackEvent, type AnalyticsEventName, type AnalyticsEvents, } from "./analytics"; afterEach(() => { setAnalyticsClient(null); }); describe("analytics seam", () => { it("is a no-op when no client is mounted", () => { expect(() => trackEvent("integration_browse_opened", { via: "header" })).not.toThrow(); }); it("forwards name and properties to the mounted client", () => { const seen: Array<{ name: AnalyticsEventName; properties: unknown }> = []; setAnalyticsClient((name, properties) => { seen.push({ name, properties }); }); trackEvent("integration_added", { plugin_key: "openapi", integration_slug: "github" }); expect(seen).toEqual([ { name: "integration_added", properties: { plugin_key: "openapi", integration_slug: "github" }, }, ]); }); it("sends an empty properties object when none are given", () => { const seen: Array = []; setAnalyticsClient((_name, properties) => { seen.push(properties); }); trackEvent("support_opened"); expect(seen).toEqual([{}]); }); it("stops forwarding after the client is unset", () => { let calls = 0; setAnalyticsClient(() => { calls += 1; }); trackEvent("support_opened"); setAnalyticsClient(null); trackEvent("support_opened"); expect(calls).toBe(1); }); it("event property values stay primitive (catalog sanity)", () => { // Compile-time catalog checks: a property bag is always an object of // primitives — no nested user data structures sneak in. const sample: AnalyticsEvents["tool_run_submitted"] = { integration_slug: "github", tool_name: "issues_list", args_mode: "form", result: "completed", is_error: false, }; expect(Object.values(sample).every((v) => typeof v !== "object")).toBe(true); }); });