feat: control room hero, SEO/AEO optimization and design system fixes
Hero: replace particle field with cobe globe (Capricorn view, multi-axis drag, reduced-motion safe), telemetry HUD with pointer parallax, particle text build effect, Space Grotesk display font. SEO: short titles with template, PT-BR accents, twitter cards on dynamic cases, escaped JSON-LD via lib/jsonld.ts, CSP report-only, 25 service FAQs answer-first. Design: fix TW4 layered reset killing spacing utilities, literal @theme tokens, mobile hero overflow, header overlap, empty case cards. Remove framer-motion (unified on motion/react), header version badge, phone number from hero CTA. Production build verified (24 static pages).
This commit is contained in:
1 parent
0920370f30
commit
b791b7de9e
94 files changed
+2621
-2889
No files matched your search
@@ -0,0 +1,107 @@
|
||||
import { fireEvent, render, screen, within } from "@testing-library/react";
|
||||
import type { ReactNode } from "react";
|
||||
import { Header } from "./Header";
|
||||
|
||||
jest.mock("motion/react", () => {
|
||||
const React = require("react");
|
||||
|
||||
const motion = new Proxy(
|
||||
{},
|
||||
{
|
||||
get: (_, tag: string) => {
|
||||
const Component = ({
|
||||
children,
|
||||
animate: _animate,
|
||||
transition: _transition,
|
||||
whileHover: _whileHover,
|
||||
...props
|
||||
}: { children?: ReactNode } & Record<string, unknown>) =>
|
||||
React.createElement(tag, props, children);
|
||||
Component.displayName = `motion.${tag}`;
|
||||
return Component;
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
return { motion, useReducedMotion: () => false };
|
||||
});
|
||||
|
||||
describe("Header", () => {
|
||||
it("exposes the primary navigation and the existing CV asset", () => {
|
||||
render(<Header />);
|
||||
|
||||
expect(screen.getByRole("link", { name: "Home" })).toHaveAttribute(
|
||||
"href",
|
||||
"/#home",
|
||||
);
|
||||
expect(screen.getByRole("link", { name: "Casos" })).toHaveAttribute(
|
||||
"href",
|
||||
"/cases",
|
||||
);
|
||||
expect(screen.getByRole("link", { name: "Serviços" })).toHaveAttribute(
|
||||
"href",
|
||||
"/servicos",
|
||||
);
|
||||
expect(screen.getByRole("link", { name: "Currículo" })).toHaveAttribute(
|
||||
"href",
|
||||
"/curriculo",
|
||||
);
|
||||
|
||||
const cvLink = screen.getByRole("link", { name: "Download CV" });
|
||||
expect(cvLink).toHaveAttribute("href", "/Profile.pdf");
|
||||
expect(cvLink).toHaveAttribute("download", "Evandro_Fonseca_Junior_CV.pdf");
|
||||
expect(
|
||||
screen.getByRole("navigation", { name: "Navegação principal" }),
|
||||
).toHaveClass("site-header-nav");
|
||||
});
|
||||
|
||||
it("announces and controls the mobile menu", () => {
|
||||
render(<Header />);
|
||||
|
||||
const menuButton = screen.getByRole("button", { name: "Abrir menu" });
|
||||
expect(menuButton).not.toHaveAttribute("aria-controls");
|
||||
expect(menuButton).toHaveAttribute("aria-expanded", "false");
|
||||
expect(menuButton).toHaveClass("site-header-menu-toggle");
|
||||
expect(
|
||||
screen.queryByRole("navigation", { name: "Navegação mobile" }),
|
||||
).not.toBeInTheDocument();
|
||||
|
||||
fireEvent.click(menuButton);
|
||||
|
||||
expect(screen.getByRole("button", { name: "Fechar menu" })).toHaveAttribute(
|
||||
"aria-controls",
|
||||
"site-navigation-menu",
|
||||
);
|
||||
expect(screen.getByRole("button", { name: "Fechar menu" })).toHaveAttribute(
|
||||
"aria-expanded",
|
||||
"true",
|
||||
);
|
||||
const mobileNavigation = screen.getByRole("navigation", {
|
||||
name: "Navegação mobile",
|
||||
});
|
||||
expect(mobileNavigation).toHaveAttribute("id", "site-navigation-menu");
|
||||
expect(mobileNavigation).toHaveAttribute("aria-hidden", "false");
|
||||
|
||||
const closeButton = screen.getByRole("button", { name: "Fechar menu" });
|
||||
fireEvent.keyDown(closeButton, { key: "Escape" });
|
||||
const openButton = screen.getByRole("button", { name: "Abrir menu" });
|
||||
expect(openButton).toHaveAttribute("aria-expanded", "false");
|
||||
expect(document.activeElement).toBe(openButton);
|
||||
});
|
||||
|
||||
it("returns focus after closing the menu from a mobile link", () => {
|
||||
render(<Header />);
|
||||
|
||||
fireEvent.click(screen.getByRole("button", { name: "Abrir menu" }));
|
||||
const mobileNavigation = screen.getByRole("navigation", {
|
||||
name: "Navegação mobile",
|
||||
});
|
||||
fireEvent.click(
|
||||
within(mobileNavigation).getByRole("link", { name: "Home" }),
|
||||
);
|
||||
|
||||
const openButton = screen.getByRole("button", { name: "Abrir menu" });
|
||||
expect(openButton).toHaveAttribute("aria-expanded", "false");
|
||||
expect(document.activeElement).toBe(openButton);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user