import { servicePages } from "./site-content"; import { AI_REVIEW_SUBJECT, buildWhatsAppUrl, CASES_SUBJECT, HOME_SUBJECT, headerOpensWhatsApp, isServiceOrCasePath, OFFER_SUBJECTS, RESUME_SUBJECT, SERVICES_SUBJECT, similarProjectSubject, type WhatsAppContexts, whatsAppSubjectForPath, } from "./whatsapp"; const contexts: WhatsAppContexts = { // o whatsappSubject do serviço, como app/layout.tsx o monta: uma frase em minúsculas, e não o nome do serviço services: { "criacao-de-sites": "um site que traz pedidos pelo WhatsApp" }, cases: { "sev-modaintima": "SEV Moda Íntima" }, }; describe("whatsAppSubjectForPath", () => { it("cites the service on /servicos/ with its whatsappSubject, a lowercase phrase, so the message reads as a sentence", () => { const subject = whatsAppSubjectForPath( "/servicos/criacao-de-sites", contexts, ); expect(subject).toBe("um site que traz pedidos pelo WhatsApp"); expect(`Quero conversar sobre ${subject}.`).not.toMatch( /sobre Sites profissionais/, ); }); it("has a whatsappSubject, in lowercase and with no final period, for every service page and offer of site-content", () => { expect(servicePages.length).toBeGreaterThan(0); for (const { slug, navLabel, whatsappSubject } of servicePages) { // não é o nome do serviço (que tem inicial maiúscula): é uma frase que entra depois de "sobre" expect(whatsappSubject).toMatch(/^[a-zà-ú].*[^.]$/); expect(whatsappSubject).not.toBe(navLabel); expect( whatsAppSubjectForPath(`/servicos/${slug}`, { services: { [slug]: whatsappSubject }, cases: {}, }), ).toBe(whatsappSubject); } for (const subject of Object.values(OFFER_SUBJECTS)) { expect(subject).toMatch(/^[a-zà-ú].*[^.]$/); } }); it("cites the case on /cases/, with the phrase every page uses for a similar project", () => { expect(whatsAppSubjectForPath("/cases/sev-modaintima", contexts)).toBe( "um projeto parecido com o case SEV Moda Íntima", ); expect(similarProjectSubject("Lavação 047")).toBe( "um projeto parecido com o case Lavação 047", ); }); it("speaks of the page itself on the home and the index pages, the same as the body buttons of /cases and /servicos", () => { expect(whatsAppSubjectForPath("/", contexts)).toBe(HOME_SUBJECT); expect(whatsAppSubjectForPath("/cases", contexts)).toBe(CASES_SUBJECT); expect(CASES_SUBJECT).toBe("um projeto parecido com os cases do portfólio"); expect(whatsAppSubjectForPath("/servicos", contexts)).toBe( SERVICES_SUBJECT, ); expect(SERVICES_SUBJECT).toBe("sites, sistemas e aplicativos"); // nenhum assunto fixo começa em maiúscula: "Quero conversar sobre Sites, sistemas..." era o erro for (const subject of [ AI_REVIEW_SUBJECT, HOME_SUBJECT, CASES_SUBJECT, SERVICES_SUBJECT, RESUME_SUBJECT, ]) { expect(subject).toMatch(/^[a-zà-ú]/); } expect(whatsAppSubjectForPath("/curriculo", contexts)).toBe(RESUME_SUBJECT); // sem contextos, a página-índice continua falando de si expect(whatsAppSubjectForPath("/cases/")).toBe(CASES_SUBJECT); expect(whatsAppSubjectForPath("/curriculo/")).toBe(RESUME_SUBJECT); }); it("cites the AI review on /ia", () => { expect(whatsAppSubjectForPath("/ia", contexts)).toBe(AI_REVIEW_SUBJECT); expect(whatsAppSubjectForPath("/ia/", undefined)).toBe(AI_REVIEW_SUBJECT); }); it("ignores a trailing slash", () => { expect( whatsAppSubjectForPath("/servicos/criacao-de-sites/", contexts), ).toBe("um site que traz pedidos pelo WhatsApp"); }); it.each([ "/privacidade", "/notebook-smoke", "/servicos/inexistente", "/cases/inexistente", "/servicos/criacao-de-sites/extra", // nomes que existem em todo objeto não podem virar assunto "/servicos/constructor", "/cases/__proto__", "/cases/toString", ])("falls back to a generic message on %s", (pathname) => { expect(whatsAppSubjectForPath(pathname, contexts)).toBeUndefined(); }); it("treats an empty or blank name as missing, so the message never reads 'sobre .'", () => { const blank: WhatsAppContexts = { services: { vazio: "", espacos: " " }, cases: { vazio: "", espacos: " " }, }; for (const pathname of [ "/servicos/vazio", "/servicos/espacos", "/cases/vazio", "/cases/espacos", ]) { expect(whatsAppSubjectForPath(pathname, blank)).toBeUndefined(); } }); it("is generic without contexts, without a pathname or outside the router", () => { expect( whatsAppSubjectForPath("/servicos/criacao-de-sites"), ).toBeUndefined(); expect(whatsAppSubjectForPath(null, contexts)).toBeUndefined(); expect(whatsAppSubjectForPath(undefined, contexts)).toBeUndefined(); }); }); describe("isServiceOrCasePath", () => { it.each([ ["/servicos/criacao-de-sites", true], ["/servicos/qualquer-coisa/", true], ["/cases/sev-modaintima", true], ["/", false], ["/servicos", false], ["/cases", false], ["/ia", false], ["/servicos/a/b", false], [null, false], [undefined, false], ])("%s -> %s", (pathname, expected) => { expect(isServiceOrCasePath(pathname)).toBe(expected); }); }); describe("headerOpensWhatsApp", () => { it.each([ ["/servicos/criacao-de-sites", true], ["/servicos/inexistente", true], ["/cases/sev-modaintima", true], ["/ia", true], ["/ia/", true], ["/cases", true], ["/servicos", true], ["/curriculo", true], ["/curriculo/", true], // a home já tem o formulário na própria página; as demais rotas não têm assunto ["/", false], ["/privacidade", false], ["/cases/a/b", false], ["/ia/extra", false], [null, false], [undefined, false], ])("%s -> %s", (pathname, expected) => { expect(headerOpensWhatsApp(pathname)).toBe(expected); }); }); describe("buildWhatsAppUrl", () => { it("encodes the message in the text parameter of a wa.me link", () => { const url = new URL(buildWhatsAppUrl("Olá & tudo? #1")); expect(url.origin).toBe("https://wa.me"); expect(url.pathname).toMatch(/^\/\d{12,13}$/); expect(url.searchParams.get("text")).toBe("Olá & tudo? #1"); }); });