Files
Evandro Fonseca Junior f8545cd442 feat(home): ofertas que vendem o título, WhatsApp no hero e menu do celular acessível
Três ofertas (site que traz pedidos pelo WhatsApp, sistema para tirar a operação da planilha, revisão de sistema existente) com miniatura e formulário com o tipo escolhido; botão principal do hero abre o WhatsApp; moldura da SEV no hero do celular; menu fecha ao navegar, Esc, foco preso incluindo a barra de cookies e espaço para ela; CinematicHome como componente de servidor com ilha cliente; /ia com H1 de oferta e cartão do que você recebe; botão flutuante em aside com transform; AVIF antes de WebP; copy sem repetir contato direto.
2026-10-14 17:01:36 -03:00

100 lines
3.2 KiB
TypeScript

import type { ReactElement } from "react";
import { portfolio } from "@/lib/portfolio-data";
import { loadFeaturedProjects } from "@/lib/portfolio-data.server";
import { clientNames, testimonials } from "@/lib/proof";
import CinematicHome from "./components/cinematic/CinematicHome";
import Home from "./page";
/**
* Testes de caminhos-base de Home e de yearsOfExperience (que não é exportada, então passa por Home):
* os anos vêm do texto do portfólio, e a home mostra só projetos de cliente.
*/
jest.mock("./components/cinematic/CinematicHome", () => ({
__esModule: true,
default: jest.fn(() => null),
}));
jest.mock("@/lib/portfolio-data.server", () => ({
loadFeaturedProjects: jest.fn(),
}));
type HomeProps = React.ComponentProps<typeof CinematicHome>;
type Loaded = Awaited<ReturnType<typeof loadFeaturedProjects>>;
const originalSummary = portfolio.personal.summary;
function mockProjects(projects: Array<{ id: string; kind?: string }>) {
jest
.mocked(loadFeaturedProjects)
.mockResolvedValue(projects as unknown as Loaded);
}
async function renderHome() {
const element = (await Home()) as ReactElement<HomeProps>;
expect(element.type).toBe(CinematicHome);
return element.props;
}
beforeEach(() => {
mockProjects([]);
});
afterEach(() => {
portfolio.personal.summary = originalSummary;
});
describe("Home: anos de experiência", () => {
it("path: the summary says '5 anos de experiência' -> 5", async () => {
portfolio.personal.summary = "Desenvolvedor com 5 anos de experiência.";
expect((await renderHome()).heroStats).toEqual({ years: 5 });
});
it("path: more than one digit and different case -> the whole number", async () => {
portfolio.personal.summary = "Atuo há 12 ANOS DE EXPERIÊNCIA em web.";
expect((await renderHome()).heroStats).toEqual({ years: 12 });
});
it("path: the summary has no such stretch -> no number, the hero hides it", async () => {
portfolio.personal.summary = "Desenvolvedor de software em Garuva-SC.";
expect((await renderHome()).heroStats).toEqual({ years: undefined });
});
it("path: a number that is not followed by the experience wording -> ignored", async () => {
portfolio.personal.summary = "Formado há 5 anos, com 3 projetos entregues.";
expect((await renderHome()).heroStats?.years).toBeUndefined();
});
});
describe("Home: projetos e provas", () => {
it("path: client, laboratory and unlabelled projects -> only the client ones reach the page", async () => {
mockProjects([
{ id: "a", kind: "cliente" },
{ id: "b", kind: "laboratorio" },
{ id: "c" },
{ id: "d", kind: "cliente" },
]);
const props = await renderHome();
expect(props.projects.map(({ id }) => id)).toEqual(["a", "d"]);
});
it("path: no featured project at all -> an empty list, the page still renders", async () => {
mockProjects([]);
expect((await renderHome()).projects).toEqual([]);
});
it("path: the proof comes straight from its module, and the home no longer carries the service links (the offers do not list them)", async () => {
const props = await renderHome();
expect(props.clients).toBe(clientNames);
expect(props.testimonials).toBe(testimonials);
expect(props).not.toHaveProperty("serviceLinks");
});
});