import { act, render, screen } from "@testing-library/react"; import { usePathname } from "next/navigation"; import type { WhatsAppContexts } from "@/lib/whatsapp"; import FloatingWhatsApp from "./FloatingWhatsApp"; /** * O botão vive em app/layout.tsx e vale em todo o site: a mensagem acompanha a página aberta, e a observação * do hero e do contato (que só existem na home) recomeça a cada troca de página. */ const contexts: WhatsAppContexts = { // o whatsappSubject do serviço (lib/site-content.ts): uma frase em minúsculas, que cabe em "Quero conversar sobre {assunto}." services: { "criacao-de-sites": "um site que traz pedidos pelo WhatsApp" }, cases: { "sev-modaintima": "SEV Moda Íntima" }, }; type Entry = Pick; const instances: FakeObserver[] = []; const originalObserver = global.IntersectionObserver; class FakeObserver { disconnect = jest.fn(); constructor(private callback: IntersectionObserverCallback) { instances.push(this); } observe = jest.fn(); unobserve = jest.fn(); takeRecords = () => []; report(entries: Entry[]) { act(() => this.callback(entries as IntersectionObserverEntry[], this as never), ); } } const floatingLink = () => screen.queryByRole("link", { name: "Chamar no WhatsApp" }); const messageOf = (link: HTMLElement | null) => new URL(link?.getAttribute("href") ?? "").searchParams.get("text"); beforeEach(() => { instances.length = 0; global.IntersectionObserver = FakeObserver as unknown as typeof IntersectionObserver; }); afterEach(() => { global.IntersectionObserver = originalObserver; document.getElementById("hero-contact-cta")?.remove(); document.getElementById("contact")?.remove(); }); describe("message by route", () => { it.each([ [ "/servicos/criacao-de-sites", "Quero conversar sobre um site que traz pedidos pelo WhatsApp.", ], [ "/cases/sev-modaintima", "Quero conversar sobre um projeto parecido com o case SEV Moda Íntima.", ], ["/ia", "Quero conversar sobre a revisão de um aplicativo feito com IA."], // a mesma frase do botão do hero e do cabeçalho de cada página ["/", "Quero conversar sobre um site ou sistema para a minha empresa."], ["/servicos", "Quero conversar sobre sites, sistemas e aplicativos."], [ "/cases", "Quero conversar sobre um projeto parecido com os cases do portfólio.", ], [ "/curriculo", "Quero conversar sobre um projeto, depois de ver o seu currículo.", ], ["/privacidade", "Quero conversar sobre um projeto."], ["/servicos/inexistente", "Quero conversar sobre um projeto."], ])("on %s", (pathname, sentence) => { jest.mocked(usePathname).mockReturnValue(pathname); // sem hero nem contato na página, o botão aparece de imediato render(); expect(messageOf(floatingLink())).toContain(sentence); }); it("falls back to a generic message without contexts", () => { jest.mocked(usePathname).mockReturnValue("/servicos/criacao-de-sites"); render(); expect(messageOf(floatingLink())).toContain( "Quero conversar sobre um projeto.", ); }); }); describe("page changes", () => { it("observes the hero and the contact again on every page, hiding the button until the new report", () => { jest.mocked(usePathname).mockReturnValue("/cases/sev-modaintima"); const { rerender } = render(); // páginas de case não têm hero nem contato: o botão está à vista expect(floatingLink()).toBeInTheDocument(); expect(instances).toHaveLength(0); // volta à home, que tem os dois convites document.body.insertAdjacentHTML( "beforeend", 'Conversar
', ); jest.mocked(usePathname).mockReturnValue("/"); rerender(); // sem piscar: some até o observador dizer que o hero saiu da tela expect(floatingLink()).toBeNull(); expect(instances).toHaveLength(1); const hero = document.getElementById("hero-contact-cta") as Element; const contact = document.getElementById("contact") as Element; instances[0].report([ { target: hero, isIntersecting: false }, { target: contact, isIntersecting: false }, ]); expect(floatingLink()).toBeInTheDocument(); expect(messageOf(floatingLink())).toContain( "Quero conversar sobre um site ou sistema para a minha empresa.", ); // sai da home para um serviço: o observador antigo é desligado e o botão passa a falar do serviço document.getElementById("hero-contact-cta")?.remove(); document.getElementById("contact")?.remove(); jest.mocked(usePathname).mockReturnValue("/servicos/criacao-de-sites"); rerender(); expect(instances[0].disconnect).toHaveBeenCalled(); expect(messageOf(floatingLink())).toContain( "Quero conversar sobre um site que traz pedidos pelo WhatsApp.", ); }); });