import { act, fireEvent, render, screen } from "@testing-library/react"; import { HOME_SUBJECT } from "@/lib/whatsapp"; import FloatingWhatsApp from "./FloatingWhatsApp"; const CONSENT_KEY = "evandro.analytics-consent.v1"; type Entry = Pick; let notify: (entries: Entry[]) => void = () => {}; const originalObserver = global.IntersectionObserver; class FakeObserver { constructor(callback: IntersectionObserverCallback) { notify = (entries) => callback(entries as IntersectionObserverEntry[], this as never); } observe = jest.fn(); unobserve = jest.fn(); disconnect = jest.fn(); takeRecords = () => []; } function Page({ withInvites = true }: { withInvites?: boolean }) { return ( <> {withInvites && ( <> Conversar sobre meu projeto
)} ); } function setVisibility(hero: boolean, contact: boolean) { act(() => notify([ { target: document.getElementById("hero-contact-cta") as Element, isIntersecting: hero, }, { target: document.getElementById("contact") as Element, isIntersecting: contact, }, ]), ); } const floatingLink = () => screen.queryByRole("link", { name: "Chamar no WhatsApp" }); beforeEach(() => { global.IntersectionObserver = FakeObserver as unknown as typeof IntersectionObserver; jest.replaceProperty(process.env, "NODE_ENV", "production"); localStorage.setItem(CONSENT_KEY, "granted"); window.gtag = jest.fn(); }); afterEach(() => { global.IntersectionObserver = originalObserver; jest.restoreAllMocks(); localStorage.clear(); delete window.gtag; }); it("stays hidden until the observer reports, then shows a 56px WhatsApp shortcut for small screens", () => { render(); expect(floatingLink()).toBeNull(); setVisibility(false, false); const link = floatingLink(); expect(link).toBeInTheDocument(); expect(link).toHaveAttribute("target", "_blank"); expect(link).toHaveAttribute("rel", "noopener noreferrer"); const url = new URL(link?.getAttribute("href") ?? ""); expect(url.origin).toBe("https://wa.me"); // o dublê central de next/navigation abre na home ("/"): o botão fala do assunto da home expect(url.searchParams.get("text")).toContain( `Quero conversar sobre ${HOME_SUBJECT}.`, ); // alvo de 56 px, canto inferior direito, só abaixo de 768 px expect(link).toHaveClass("h-14", "w-14"); expect(link?.parentElement).toHaveClass("fixed", "right-sp-4", "md:hidden"); }); it("hides while the hero button is on screen", () => { render(); setVisibility(true, false); expect(floatingLink()).toBeNull(); setVisibility(false, false); expect(floatingLink()).toBeInTheDocument(); }); it("hides while the contact section is on screen", () => { render(); setVisibility(false, true); expect(floatingLink()).toBeNull(); setVisibility(false, false); expect(floatingLink()).toBeInTheDocument(); }); it("shows right away on a page that has neither the hero button nor the contact section", () => { render(); expect(floatingLink()).toBeInTheDocument(); }); it("hides by CSS while the cookie bar is open (the data-cookie-bar mark on ), instead of sitting on top of it", () => { render(); setVisibility(false, false); const className = floatingLink()?.parentElement?.className ?? ""; expect(className).toContain("[[data-cookie-bar=open]_&]:hidden"); // não sobe mais pela altura da barra: some enquanto ela está aberta expect(className).not.toContain("--cookie-bar-height"); expect(className).toContain( "bottom-[calc(var(--sp-4)+env(safe-area-inset-bottom))]", ); }); it("sits in a named complementary region (the 'region' landmark rule), which only exists while the shortcut shows", () => { render(); expect(screen.queryByRole("complementary")).toBeNull(); setVisibility(false, false); const region = screen.getByRole("complementary", { name: "Contato rápido" }); expect(region.tagName).toBe("ASIDE"); expect(region).toContainElement(floatingLink()); }); it("reports the click as a floating WhatsApp handoff", () => { render(); setVisibility(false, false); fireEvent.click(floatingLink() as HTMLElement, { button: 0 }); expect(window.gtag).toHaveBeenCalledTimes(1); expect(window.gtag).toHaveBeenCalledWith( "event", "whatsapp_open", expect.objectContaining({ placement: "floating" }), ); });