Files
portifolio-evandrodevbr/app/components/WhatsAppLink.test.tsx
T
Evandro Fonseca Junior 8d07b8c6bb feat(home): prova no topo, contato sem atrito e conversão medida
Home mais curta (hero, vitrine de clientes, sobre, serviços, IA resumida, depoimentos e contato), faixa de clientes e telas reais no hero, sem números do GitHub. Barra de cookies fina, WhatsApp fixo no celular, formulário com e-mail opcional e alternativa por e-mail, página /ia, eventos de e-mail, redes e currículo e conversão do Ads opcional por variável. Rodapé em 3 colunas. Remove componentes órfãos (LighthouseMetrics, Skills, Experience, contagem do GitHub).
2026-10-14 03:32:23 -03:00

172 lines
5.6 KiB
TypeScript

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(
{},
"",
"/[email protected]#private",
);
});
afterEach(() => {
jest.restoreAllMocks();
delete window.gtag;
delete window[DISABLE_KEY];
localStorage.clear();
window.history.replaceState({}, "", "/");
});
function renderLink() {
render(
<WhatsAppLink service="Sistemas web" placement="service_hub_hero">
Conversar no WhatsApp
</WhatsAppLink>,
);
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(<WhatsAppLink placement="contact_direct">Conversar</WhatsAppLink>);
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: "",
});
});