// @vitest-environment jsdom import { cleanup, render, waitFor } from "@testing-library/react"; import { afterEach, describe, expect, it, vi } from "vitest"; import ScriptCrisp from "./ScriptCrisp"; const { hasConsent, isAppOrAdminSurface } = vi.hoisted(() => ({ hasConsent: vi.fn(() => false), isAppOrAdminSurface: vi.fn(() => false), })); vi.mock("react-router", () => ({ useLocation: () => ({ pathname: "/" }), })); vi.mock("~/utils/data/useRootData", () => ({ useRootData: () => ({ chatWebsiteId: "site-id", userSession: { cookies: [] } }), })); vi.mock("~/utils/helpers/CookieHelper", () => ({ default: { hasConsent }, })); vi.mock("~/utils/app/HostAwareSurface", () => ({ isAppOrAdminSurface, })); afterEach(() => { cleanup(); document.querySelectorAll('script[src="https://client.crisp.chat/l.js"]').forEach((node) => node.remove()); delete window.$crisp; delete window.CRISP_WEBSITE_ID; hasConsent.mockReset(); hasConsent.mockReturnValue(false); isAppOrAdminSurface.mockReset(); isAppOrAdminSurface.mockReturnValue(false); }); describe("ScriptCrisp privacy gate", () => { it("does not contact Crisp without functional-cookie consent", () => { render(); expect(document.querySelector('script[src="https://client.crisp.chat/l.js"]')).toBeNull(); }); it("loads Crisp on a public surface after consent and carries the CSP nonce", async () => { hasConsent.mockReturnValue(true); render(); await waitFor(() => { const script = document.querySelector('script[src="https://client.crisp.chat/l.js"]'); expect(script?.nonce).toBe("aBcDeFgHiJkLmNoPqRsTuVwX"); }); }); it("never loads the public chat script on app or admin surfaces", () => { hasConsent.mockReturnValue(true); isAppOrAdminSurface.mockReturnValue(true); render(); expect(document.querySelector('script[src="https://client.crisp.chat/l.js"]')).toBeNull(); }); });