import { GA_DISABLE_KEY, readConsent, trackEmailClick, trackSocialClick, trackWhatsAppOpen, } from "./analytics"; /** * Testes de caminhos-base de lib/analytics.ts (complemento de analytics.test.ts): * modelo de rota de cada página (analyticsPagePath), cada condição que silencia o envio (sendEvent) * e a conversão do Google Ads (sendAdsConversion) com e sem etiqueta, com e sem consentimento. */ const CONSENT_KEY = "evandro.analytics-consent.v1"; const ADS_LABEL = "NEXT_PUBLIC_GOOGLE_ADS_CONVERSION_LABEL"; beforeEach(() => { jest.replaceProperty(process.env, "NODE_ENV", "production"); localStorage.setItem(CONSENT_KEY, "granted"); delete window[GA_DISABLE_KEY]; window.gtag = jest.fn(); window.history.replaceState({}, "", "/"); }); afterEach(() => { jest.restoreAllMocks(); localStorage.clear(); delete window.gtag; delete process.env[ADS_LABEL]; window.history.replaceState({}, "", "/"); }); function gtagCalls() { return (window.gtag as jest.Mock).mock.calls; } describe("analyticsPagePath (via the page_path sent with each event)", () => { it.each([ ["/", "/"], ["/servicos", "/servicos"], ["/cases", "/cases"], ["/curriculo", "/curriculo"], ["/privacidade", "/privacidade"], ["/ia", "/ia"], ["/cases/", "/cases"], ["/ia/?utm=x#y", "/ia"], ["/servicos/criacao-de-sites", "/servicos/[slug]"], ["/servicos/qualquer/coisa/mais", "/servicos/[slug]"], ["/cases/sev-modaintima", "/cases/[slug]"], ["/cases/ana%40example.com?x=1", "/cases/[slug]"], ["/servicos-extra", "/other"], ["/cases-extra/abc", "/other"], ["/nao-existe", "/other"], ])("path: location %s -> page_path %s", (location, expected) => { window.history.replaceState({}, "", location); trackSocialClick({ network: "linkedin" }); expect(gtagCalls()).toHaveLength(1); expect(gtagCalls()[0][2]).toMatchObject({ page_path: expected, page_location: `https://evandro.dev.br${expected}`, page_referrer: "", }); }); }); describe("sendEvent: cada condição que silencia o envio", () => { it("path: gtag exists but is not a function -> nothing sent, no conversion, no error", () => { process.env[ADS_LABEL] = "abc123"; window.gtag = "not-a-function" as never; expect(() => trackWhatsAppOpen({ service: "S", placement: "p" }), ).not.toThrow(); expect(() => trackEmailClick({ placement: "p" })).not.toThrow(); }); it("path: stored consent is an unknown value -> treated as no consent", () => { localStorage.setItem(CONSENT_KEY, "yes"); trackSocialClick({ network: "linkedin" }); expect(readConsent()).toBeNull(); expect(gtagCalls()).toHaveLength(0); }); it("path: storage throws -> readConsent returns null and nothing is sent", () => { jest.spyOn(Storage.prototype, "getItem").mockImplementation(() => { throw new Error("storage blocked"); }); expect(readConsent()).toBeNull(); trackSocialClick({ network: "linkedin" }); expect(gtagCalls()).toHaveLength(0); }); it("path: event counted -> one gtag call carrying the static params and the route template", () => { window.history.replaceState({}, "", "/cases/sev-modaintima?q=1#x"); trackEmailClick({ placement: "footer" }); expect(gtagCalls()).toEqual([ [ "event", "email_click", { send_to: "G-QTT9QT0T3S", placement: "footer", page_path: "/cases/[slug]", page_location: "https://evandro.dev.br/cases/[slug]", page_referrer: "", }, ], ]); }); }); describe("sendAdsConversion: etiqueta x consentimento", () => { it.each([ ["is unset", undefined], ["is an empty string", ""], ])( "path: label %s, consent granted -> only the GA4 event goes out", (_l, label) => { if (label !== undefined) process.env[ADS_LABEL] = label; trackWhatsAppOpen({ service: "Contato", placement: "floating" }); trackEmailClick({ placement: "footer" }); expect(gtagCalls().map(([, name]) => name)).toEqual([ "whatsapp_open", "email_click", ]); }, ); it("path: label set, consent denied -> nothing at all, not even the conversion", () => { process.env[ADS_LABEL] = "abc123"; localStorage.setItem(CONSENT_KEY, "denied"); trackWhatsAppOpen({ service: "Contato", placement: "floating" }); trackEmailClick({ placement: "footer" }); expect(gtagCalls()).toHaveLength(0); }); it("path: label set, consent granted -> the conversion uses the Ads id and the label", () => { process.env[ADS_LABEL] = "xyz-789"; trackWhatsAppOpen({ service: "Contato", placement: "floating" }); expect(gtagCalls().map(([, name]) => name)).toEqual([ "whatsapp_open", "conversion", ]); expect(gtagCalls()[1][2]).toEqual({ send_to: "AW-18432694647/xyz-789", }); }); it("path: the conversion call throws -> the click handler still returns normally", () => { process.env[ADS_LABEL] = "abc123"; window.gtag = jest.fn((_command: unknown, name: unknown) => { if (name === "conversion") throw new Error("ads blocked"); }); expect(() => trackWhatsAppOpen({ service: "Contato", placement: "floating" }), ).not.toThrow(); expect(gtagCalls().map(([, name]) => name)).toEqual([ "whatsapp_open", "conversion", ]); }); it("path: gtag disappears right after the event was counted -> the conversion is skipped silently", () => { process.env[ADS_LABEL] = "abc123"; const gtag = jest.fn(() => { delete window.gtag; }); window.gtag = gtag; expect(() => trackEmailClick({ placement: "footer" })).not.toThrow(); expect(gtag).toHaveBeenCalledTimes(1); }); });