import { fireEvent, render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import WhatsAppLink from "./WhatsAppLink"; const CONSENT_KEY = "evandro.analytics-consent.v1"; const DISABLE_KEY = "ga-disable-G-QTT9QT0T3S"; beforeEach(() => { jest.replaceProperty(process.env, "NODE_ENV", "production"); localStorage.clear(); window.gtag = jest.fn(); delete window[DISABLE_KEY]; window.history.replaceState( {}, "", "/servicos?email=ana@example.com#private", ); }); afterEach(() => { jest.restoreAllMocks(); delete window.gtag; delete window[DISABLE_KEY]; localStorage.clear(); window.history.replaceState({}, "", "/"); }); function renderLink() { render( Conversar no WhatsApp , ); return screen.getByRole("link", { name: "Conversar no WhatsApp" }); } it("talks about the service when one is given", () => { const url = new URL(renderLink().getAttribute("href") || ""); expect(url.searchParams.get("text")).toBe( "Olá, Evandro! Quero conversar sobre Sistemas web. Contato iniciado pelo site evandro.dev.br.", ); }); it("talks about 'um projeto' when no service is given", () => { render(Conversar); const url = new URL( screen.getByRole("link", { name: "Conversar" }).getAttribute("href") || "", ); const text = url.searchParams.get("text"); expect(text).toBe( "Olá, Evandro! Quero conversar sobre um projeto. Contato iniciado pelo site evandro.dev.br.", ); expect(text).not.toContain("Contato."); }); it.each([null, "denied", "{malformed", '"granted"'])( "keeps a native destination without collecting or replaying when consent is %s", async (consent) => { if (consent !== null) localStorage.setItem(CONSENT_KEY, consent); const link = renderLink(); const url = new URL(link.getAttribute("href") || ""); expect(url.origin).toBe("https://wa.me"); expect(url.pathname).toMatch(/^\/\d+$/); expect(url.searchParams.get("text")).toContain("Sistemas web"); expect(link).toHaveAttribute("target", "_blank"); expect(link).toHaveAttribute("rel", "noopener noreferrer"); expect(fireEvent.click(link, { button: 0 })).toBe(true); expect(window.gtag).not.toHaveBeenCalled(); localStorage.setItem(CONSENT_KEY, "granted"); await Promise.resolve(); expect(window.gtag).not.toHaveBeenCalled(); fireEvent.click(link, { button: 0 }); expect(window.gtag).toHaveBeenCalledTimes(1); }, ); it("emits one GA4 handoff per primary, middle or keyboard activation without personal URL data", async () => { const user = userEvent.setup(); localStorage.setItem(CONSENT_KEY, "granted"); const link = renderLink(); await user.click(link); expect(window.gtag).toHaveBeenCalledTimes(1); expect(window.gtag).toHaveBeenLastCalledWith("event", "whatsapp_open", { send_to: "G-QTT9QT0T3S", service: "Sistemas web", placement: "service_hub_hero", page_path: "/servicos", page_location: "https://evandro.dev.br/servicos", page_referrer: "", }); expect( fireEvent( link, new MouseEvent("auxclick", { button: 1, bubbles: true, cancelable: true, }), ), ).toBe(true); expect(window.gtag).toHaveBeenCalledTimes(2); fireEvent(link, new MouseEvent("auxclick", { button: 2, bubbles: true })); expect(window.gtag).toHaveBeenCalledTimes(2); link.focus(); await user.keyboard("{Enter}"); expect(window.gtag).toHaveBeenCalledTimes(3); }); it("stops collecting immediately after revocation and honors the GA disabled flag", () => { localStorage.setItem(CONSENT_KEY, "granted"); const link = renderLink(); fireEvent.click(link, { button: 0 }); expect(window.gtag).toHaveBeenCalledTimes(1); localStorage.setItem(CONSENT_KEY, "denied"); expect(fireEvent.click(link, { button: 0 })).toBe(true); expect(window.gtag).toHaveBeenCalledTimes(1); localStorage.setItem(CONSENT_KEY, "granted"); window[DISABLE_KEY] = true; expect(fireEvent.click(link, { button: 0 })).toBe(true); expect(window.gtag).toHaveBeenCalledTimes(1); }); it("keeps navigation available when storage, analytics or its loader is blocked", () => { localStorage.setItem(CONSENT_KEY, "granted"); const link = renderLink(); const storage = jest .spyOn(Storage.prototype, "getItem") .mockImplementation(() => { throw new Error("storage blocked"); }); expect(fireEvent.click(link, { button: 0 })).toBe(true); expect(window.gtag).not.toHaveBeenCalled(); storage.mockRestore(); delete window.gtag; expect(fireEvent.click(link, { button: 0 })).toBe(true); window.gtag = jest.fn(() => { throw new Error("analytics blocked"); }); expect(fireEvent.click(link, { button: 0 })).toBe(true); }); it("does not collect outside production", () => { jest.replaceProperty(process.env, "NODE_ENV", "development"); localStorage.setItem(CONSENT_KEY, "granted"); expect(fireEvent.click(renderLink(), { button: 0 })).toBe(true); expect(window.gtag).not.toHaveBeenCalled(); }); it("uses a route template rather than collecting arbitrary dynamic path segments", () => { localStorage.setItem(CONSENT_KEY, "granted"); window.history.replaceState( {}, "", "/servicos/ana%40example.com?message=private", ); fireEvent.click(renderLink(), { button: 0 }); expect(window.gtag).toHaveBeenCalledWith("event", "whatsapp_open", { send_to: "G-QTT9QT0T3S", service: "Sistemas web", placement: "service_hub_hero", page_path: "/servicos/[slug]", page_location: "https://evandro.dev.br/servicos/[slug]", page_referrer: "", }); });