O botão das ofertas rola até o contato com o tipo marcado e não quebra mais as âncoras; ofertas com o que você recebe e primeiro passo, logo depois da vitrine; bloco de IA fora da home; cartão largo da SEV no hero do celular; separador da faixa de clientes só entre itens; favicon de 13 para 1,8 KB; pré-carregamento só no hover e nunca de /#... fora da home; X do menu e cabeçalho opaco; WhatsApp com "o case"; /ia com 3 passos e modelo de relatório ilustrativo; Sobre alinhado ao currículo; CSP Report-Only com os domínios do Ads.
161 lines
5.8 KiB
TypeScript
161 lines
5.8 KiB
TypeScript
import { fireEvent, render, screen, within } from "@testing-library/react";
|
|
import { OPEN_COOKIE_PREFERENCES_EVENT } from "@/lib/analytics";
|
|
import { serviceHubLinks } from "@/lib/site-content";
|
|
import Footer from "./Footer";
|
|
|
|
// o Link do Next, trocado por um <a> que mostra o `prefetch` recebido: HoverPrefetchLink começa em false
|
|
jest.mock("next/link", () => ({
|
|
__esModule: true,
|
|
default: ({
|
|
children,
|
|
prefetch,
|
|
...props
|
|
}: { children?: React.ReactNode; prefetch?: boolean | null } & Record<
|
|
string,
|
|
unknown
|
|
>) => (
|
|
<a data-prefetch={String(prefetch)} {...props}>
|
|
{children}
|
|
</a>
|
|
),
|
|
}));
|
|
|
|
describe("Footer contact and navigation", () => {
|
|
it("offers a direct mailto link without repeating the contact call to action", () => {
|
|
render(<Footer />);
|
|
|
|
// o convite principal fica na secao Contato, logo acima do rodape
|
|
expect(
|
|
screen.queryByRole("link", { name: "Falar sobre meu projeto" }),
|
|
).not.toBeInTheDocument();
|
|
|
|
const emailLink = screen.getByRole("link", {
|
|
name: "[email protected]",
|
|
});
|
|
expect(emailLink).toHaveAttribute(
|
|
"href",
|
|
"mailto:[email protected]",
|
|
);
|
|
expect(emailLink).not.toHaveAttribute("target", "_blank");
|
|
});
|
|
|
|
it("offers WhatsApp in the contact column, in a new tab", () => {
|
|
render(<Footer />);
|
|
|
|
const contact = screen.getByRole("region", { name: "Contato" });
|
|
const whatsApp = within(contact).getByRole("link", { name: "WhatsApp" });
|
|
expect(whatsApp.getAttribute("href")).toMatch(/^https:\/\/wa\.me\/\d+\?/);
|
|
expect(whatsApp).toHaveAttribute("target", "_blank");
|
|
expect(whatsApp).toHaveAttribute("rel", "noopener noreferrer");
|
|
});
|
|
|
|
it("lists the six services from the services hub as same-tab links", () => {
|
|
render(<Footer serviceLinks={serviceHubLinks} />);
|
|
|
|
expect(serviceHubLinks).toHaveLength(6);
|
|
const services = screen.getByRole("navigation", { name: "Serviços" });
|
|
const links = within(services).getAllByRole("link");
|
|
expect(links.map((link) => link.getAttribute("href"))).toEqual(
|
|
serviceHubLinks.map((service) => service.href),
|
|
);
|
|
expect(links.map((link) => link.textContent)).toEqual(
|
|
serviceHubLinks.map((service) => service.label),
|
|
);
|
|
for (const link of links) expect(link).not.toHaveAttribute("target");
|
|
});
|
|
|
|
it("links Cases, Privacidade and a discreet Currículo, with no PDF download", () => {
|
|
render(<Footer />);
|
|
|
|
const more = screen.getByRole("navigation", { name: "Mais" });
|
|
expect(within(more).getByRole("link", { name: "Cases" })).toHaveAttribute(
|
|
"href",
|
|
"/cases",
|
|
);
|
|
expect(
|
|
within(more).getByRole("link", { name: "Revisão de app feito com IA" }),
|
|
).toHaveAttribute("href", "/ia");
|
|
expect(
|
|
within(more).getByRole("link", { name: "Privacidade" }),
|
|
).toHaveAttribute("href", "/privacidade");
|
|
const resume = within(more).getByRole("link", { name: "Currículo" });
|
|
expect(resume).toHaveAttribute("href", "/curriculo");
|
|
expect(within(more).getAllByRole("link").at(-1)).toBe(resume);
|
|
expect(screen.queryByRole("link", { name: /baixar|pdf/i })).toBeNull();
|
|
for (const link of screen.getAllByRole("link")) {
|
|
expect(link).not.toHaveAttribute("download");
|
|
}
|
|
});
|
|
|
|
it("reopens the cookie preferences from a button", () => {
|
|
const reopen = jest.fn();
|
|
window.addEventListener(OPEN_COOKIE_PREFERENCES_EVENT, reopen);
|
|
render(<Footer />);
|
|
|
|
fireEvent.click(
|
|
screen.getByRole("button", { name: "Preferências de cookies" }),
|
|
);
|
|
|
|
expect(reopen).toHaveBeenCalledTimes(1);
|
|
window.removeEventListener(OPEN_COOKIE_PREFERENCES_EVENT, reopen);
|
|
});
|
|
|
|
it("states the location and rights in Portuguese", () => {
|
|
render(<Footer />);
|
|
|
|
expect(
|
|
screen.getByText("Garuva, SC · Atendimento remoto em todo o Brasil"),
|
|
).toBeInTheDocument();
|
|
expect(
|
|
screen.getByText(/Todos os direitos\s+reservados/),
|
|
).toBeInTheDocument();
|
|
expect(screen.queryByText(/remote worldwide|all rights/i)).toBeNull();
|
|
});
|
|
});
|
|
|
|
describe("Footer social links", () => {
|
|
it("keeps one LinkedIn profile in a new tab and no GitHub link", () => {
|
|
render(<Footer />);
|
|
|
|
const linkedin = screen.getByRole("link", { name: "LinkedIn" });
|
|
expect(linkedin).toHaveAttribute(
|
|
"href",
|
|
"https://www.linkedin.com/in/evandrodevbr/",
|
|
);
|
|
expect(linkedin).toHaveAttribute("target", "_blank");
|
|
expect(linkedin).toHaveAttribute("rel", "noopener noreferrer");
|
|
for (const link of screen.getAllByRole("link")) {
|
|
expect(link.getAttribute("href") ?? "").not.toMatch(/github\.com/);
|
|
}
|
|
expect(screen.queryByRole("link", { name: /github/i })).toBeNull();
|
|
});
|
|
|
|
it("keeps Instagram in the contact column, in a new tab", () => {
|
|
render(<Footer />);
|
|
|
|
const contact = screen.getByRole("region", { name: "Contato" });
|
|
const instagram = within(contact).getByRole("link", { name: "Instagram" });
|
|
expect(instagram).toHaveAttribute(
|
|
"href",
|
|
"https://www.instagram.com/evandrodevbr/",
|
|
);
|
|
expect(instagram).toHaveAttribute("target", "_blank");
|
|
expect(instagram).toHaveAttribute("rel", "noopener noreferrer");
|
|
});
|
|
|
|
it("pre-fetches the internal links only when the visitor reaches them, never by viewport (services, cases, /ia, privacy, résumé, home)", () => {
|
|
render(<Footer serviceLinks={serviceHubLinks} />);
|
|
|
|
const internal = screen
|
|
.getAllByRole("link")
|
|
.filter((link) => (link.getAttribute("href") ?? "").startsWith("/"));
|
|
// serviços do hub + Cases, /ia, Privacidade, Currículo + o logo para /#home
|
|
expect(internal.length).toBeGreaterThanOrEqual(serviceHubLinks.length + 5);
|
|
for (const link of internal) {
|
|
expect(link).toHaveAttribute("data-prefetch", "false");
|
|
fireEvent.mouseEnter(link);
|
|
expect(link).toHaveAttribute("data-prefetch", "null");
|
|
}
|
|
});
|
|
});
|