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).
142 lines
4.5 KiB
TypeScript
142 lines
4.5 KiB
TypeScript
import { fireEvent, render, screen } from "@testing-library/react";
|
|
import type { ReactNode } from "react";
|
|
|
|
import Hero from "./Hero";
|
|
|
|
const clients = [
|
|
{ id: "sev-modaintima", name: "SEV Moda Íntima" },
|
|
{ id: "lavacao-047", name: "Lavação 047" },
|
|
{ id: "sc-plus", name: "SC Plus Aquicultura" },
|
|
{ id: "as-servicos", name: "AS Serviços" },
|
|
];
|
|
|
|
jest.mock("motion/react", () => {
|
|
const React = require("react");
|
|
|
|
const motion = new Proxy(
|
|
{},
|
|
{
|
|
get: (_, tag: string) => {
|
|
const Component = ({
|
|
children,
|
|
initial: _initial,
|
|
animate: _animate,
|
|
transition: _transition,
|
|
...props
|
|
}: { children?: ReactNode } & Record<string, unknown>) =>
|
|
React.createElement(tag, props, children);
|
|
Component.displayName = `motion.${tag}`;
|
|
return Component;
|
|
},
|
|
},
|
|
);
|
|
|
|
return { motion, useReducedMotion: () => false };
|
|
});
|
|
|
|
describe("Hero", () => {
|
|
beforeEach(() => {
|
|
jest.spyOn(window, "open").mockImplementation(() => null);
|
|
});
|
|
|
|
afterEach(() => {
|
|
jest.restoreAllMocks();
|
|
});
|
|
|
|
it("routes project conversations to contact without opening an external service", () => {
|
|
render(<Hero />);
|
|
|
|
const contactLink = screen.getByRole("link", {
|
|
name: /conversar/i,
|
|
});
|
|
expect(contactLink).toHaveAttribute("href", "/#contact");
|
|
expect(contactLink).not.toHaveAttribute("target", "_blank");
|
|
fireEvent.click(contactLink);
|
|
expect(window.open).not.toHaveBeenCalled();
|
|
expect(screen.getByRole("link", { name: /ver projetos/i })).toHaveAttribute(
|
|
"href",
|
|
"/cases",
|
|
);
|
|
});
|
|
|
|
it("keeps the headline as one readable sentence despite the per-word animation", () => {
|
|
render(<Hero />);
|
|
|
|
expect(screen.getByRole("heading", { level: 1 })).toHaveTextContent(
|
|
"Sistemas sob medida para operações que não cabem em soluções prontas.",
|
|
);
|
|
});
|
|
|
|
it("keeps the single LinkedIn profile and the e-mail, with no GitHub link", () => {
|
|
render(<Hero />);
|
|
|
|
expect(screen.getByRole("link", { name: "LinkedIn" })).toHaveAttribute(
|
|
"href",
|
|
"https://www.linkedin.com/in/evandrodevbr/",
|
|
);
|
|
expect(screen.getByRole("link", { name: "Email" })).toHaveAttribute(
|
|
"href",
|
|
"mailto:[email protected]",
|
|
);
|
|
const linkedin = screen.getByRole("link", { name: "LinkedIn" });
|
|
expect(linkedin).toHaveAttribute("target", "_blank");
|
|
expect(linkedin).toHaveAttribute("rel", "noopener noreferrer");
|
|
expect(screen.queryByRole("link", { name: "GitHub" })).toBeNull();
|
|
for (const link of screen.getAllByRole("link")) {
|
|
expect(link.getAttribute("href") ?? "").not.toMatch(/github\.com/);
|
|
}
|
|
});
|
|
|
|
it("states who the work is for and how the contact works", () => {
|
|
render(<Hero />);
|
|
|
|
expect(
|
|
screen.getByText(
|
|
"Para empresas que cresceram além das planilhas e dos sistemas prontos: sites, sistemas web, aplicativos e integrações, com contato direto com quem desenvolve.",
|
|
),
|
|
).toBeInTheDocument();
|
|
expect(screen.getByRole("link", { name: /conversar/i })).toHaveAttribute(
|
|
"id",
|
|
"hero-contact-cta",
|
|
);
|
|
});
|
|
|
|
it("shows only the years of experience, with no repository numbers", () => {
|
|
render(<Hero stats={{ years: 5 }} />);
|
|
|
|
expect(screen.getByText("anos de experiência")).toBeInTheDocument();
|
|
expect(screen.getByText("5")).toBeInTheDocument();
|
|
expect(screen.queryByText(/projetos desenvolvidos/i)).toBeNull();
|
|
expect(screen.queryByText(/públicos|privados|mais de/i)).toBeNull();
|
|
});
|
|
|
|
it("lists the delivered clients, each linking to its case", () => {
|
|
render(<Hero clients={clients} />);
|
|
|
|
expect(screen.getByText("Já entregue para:")).toBeInTheDocument();
|
|
for (const { id, name } of clients) {
|
|
expect(screen.getByRole("link", { name })).toHaveAttribute(
|
|
"href",
|
|
`/cases/${id}`,
|
|
);
|
|
}
|
|
});
|
|
|
|
it("renders the work column with lazy posters that stay out of small screens", () => {
|
|
render(<Hero clients={clients} />);
|
|
|
|
const work = screen.getByTestId("hero-work");
|
|
expect(work).toHaveClass("hidden", "lg:block");
|
|
const images = work.querySelectorAll("img");
|
|
expect(images).toHaveLength(2);
|
|
for (const image of images) {
|
|
expect(image).toHaveAttribute("loading", "lazy");
|
|
}
|
|
expect(images[0]).toHaveAttribute(
|
|
"src",
|
|
"/videos/lavacao-047/desktop.webp",
|
|
);
|
|
expect(images[1]).toHaveAttribute("src", "/videos/as-servicos/mobile.webp");
|
|
});
|
|
});
|