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:
Evandro Fonseca Junior committed 2026-08-27 10:55:21 -03:00
1 parent 0920370f30
commit b791b7de9e
94 files changed
+2621 -2889

No files matched your search

+58 -287
View File
@@ -1,326 +1,97 @@
import { render, screen } from "@testing-library/react";
import Footer from "./Footer";
describe("Footer Component - Contact Information", () => {
it("should render contact section heading", () => {
describe("Footer contact and navigation", () => {
it("renders the contact card and a mailto link", () => {
render(<Footer />);
const contactHeading = screen.getByText("Contato direto");
expect(contactHeading).toBeInTheDocument();
expect(contactHeading.tagName).toBe("H3");
});
expect(screen.getByText("Contato")).toBeInTheDocument();
expect(
screen.getByRole("heading", {
name: "Engenharia com menos ruído e mais clareza de execução",
}),
).toBeInTheDocument();
it("should render email address", () => {
render(<Footer />);
const emailLink = screen.getByText("[email protected]");
expect(emailLink).toBeInTheDocument();
expect(emailLink.tagName).toBe("A");
});
it("should have mailto link for email", () => {
render(<Footer />);
const emailLink = screen.getByText("[email protected]");
const emailLink = screen.getByRole("link", {
name: "[email protected]",
});
expect(emailLink).toHaveAttribute(
"href",
"mailto:[email protected]",
);
expect(emailLink).not.toHaveAttribute("target", "_blank");
});
it("should apply correct styling classes to email link", () => {
it("renders quick links as same-tab navigation", () => {
render(<Footer />);
const emailLink = screen.getByText("[email protected]");
const classes = emailLink.className;
expect(classes).toContain("text-[12px]");
expect(classes).toContain("hover:text-[var(--slash)]");
const servicesLink = screen.getByRole("link", { name: "Hub de serviços" });
expect(servicesLink).toHaveAttribute("href", "/servicos");
expect(servicesLink).not.toHaveAttribute("target", "_blank");
});
});
describe("Footer Component - Social Links", () => {
it("should render social links section heading", () => {
describe("Footer social links", () => {
it("renders each social link with an accessible name", () => {
render(<Footer />);
const connectHeading = screen.getByText("Redes profissionais");
expect(connectHeading).toBeInTheDocument();
expect(connectHeading.tagName).toBe("H3");
const socialLinks = Array.from(
document.querySelectorAll("footer a[aria-label]"),
);
expect(socialLinks.map((link) => link.getAttribute("aria-label"))).toEqual([
"Visit GitHub profile",
"Visit LinkedIn profile",
"Visit Instagram profile",
]);
expect(
new Set(socialLinks.map((link) => link.getAttribute("aria-label"))).size,
).toBe(socialLinks.length);
});
it("should render GitHub social link", () => {
it("opens social links securely in a new tab", () => {
render(<Footer />);
const githubLink = screen.getByLabelText("Visit GitHub profile");
expect(githubLink).toBeInTheDocument();
expect(githubLink.tagName).toBe("A");
});
const socialLinks = Array.from(
document.querySelectorAll("footer a[aria-label]"),
);
it("should render LinkedIn social link", () => {
render(<Footer />);
for (const link of socialLinks) {
expect(link).toHaveAttribute("target", "_blank");
expect(link).toHaveAttribute("rel", "noopener noreferrer");
expect(link.querySelector("svg")).toHaveAttribute("aria-hidden", "true");
}
const linkedinLink = screen.getByLabelText("Visit LinkedIn profile");
expect(linkedinLink).toBeInTheDocument();
expect(linkedinLink.tagName).toBe("A");
});
it("should have correct href for GitHub link", () => {
render(<Footer />);
const githubLink = screen.getByLabelText("Visit GitHub profile");
expect(githubLink).toHaveAttribute(
expect(screen.getByLabelText("Visit GitHub profile")).toHaveAttribute(
"href",
"https://github.com/evandrodevbr",
);
});
it("should have correct href for LinkedIn link", () => {
render(<Footer />);
const linkedinLink = screen.getByLabelText("Visit LinkedIn profile");
expect(linkedinLink).toHaveAttribute(
"href",
"https://linkedin.com/in/evandrodevbr",
);
});
it('should open social links in new tab with target="_blank"', () => {
render(<Footer />);
const githubLink = screen.getByLabelText("Visit GitHub profile");
const linkedinLink = screen.getByLabelText("Visit LinkedIn profile");
expect(githubLink).toHaveAttribute("target", "_blank");
expect(linkedinLink).toHaveAttribute("target", "_blank");
});
it('should have rel="noopener noreferrer" for security', () => {
render(<Footer />);
const githubLink = screen.getByLabelText("Visit GitHub profile");
const linkedinLink = screen.getByLabelText("Visit LinkedIn profile");
expect(githubLink).toHaveAttribute("rel", "noopener noreferrer");
expect(linkedinLink).toHaveAttribute("rel", "noopener noreferrer");
});
it("should have aria-label for accessibility", () => {
render(<Footer />);
const githubLink = screen.getByLabelText("Visit GitHub profile");
const linkedinLink = screen.getByLabelText("Visit LinkedIn profile");
expect(githubLink).toHaveAttribute("aria-label", "Visit GitHub profile");
expect(linkedinLink).toHaveAttribute(
"aria-label",
"Visit LinkedIn profile",
);
});
it("should render SVG icons for social links", () => {
render(<Footer />);
const githubLink = screen.getByLabelText("Visit GitHub profile");
const linkedinLink = screen.getByLabelText("Visit LinkedIn profile");
const githubSvg = githubLink.querySelector("svg");
const linkedinSvg = linkedinLink.querySelector("svg");
expect(githubSvg).toBeInTheDocument();
expect(linkedinSvg).toBeInTheDocument();
});
it('should have aria-hidden="true" on SVG icons', () => {
render(<Footer />);
const githubLink = screen.getByLabelText("Visit GitHub profile");
const linkedinLink = screen.getByLabelText("Visit LinkedIn profile");
const githubSvg = githubLink.querySelector("svg");
const linkedinSvg = linkedinLink.querySelector("svg");
expect(githubSvg).toHaveAttribute("aria-hidden", "true");
expect(linkedinSvg).toHaveAttribute("aria-hidden", "true");
expect(
screen.getByLabelText("Visit LinkedIn profile").getAttribute("href"),
).toContain("https://www.linkedin.com/in/evandrodevbr/");
});
});
describe("Footer Component - Copyright", () => {
it("should render copyright section heading", () => {
render(<Footer />);
describe("Footer structure", () => {
it("uses the current design-system shell and two-card grid", () => {
const { container } = render(<Footer />);
const footer = container.querySelector("footer");
const copyrightHeading = screen.getByText("Informacoes legais");
expect(copyrightHeading).toBeInTheDocument();
expect(copyrightHeading.tagName).toBe("H3");
expect(footer).toHaveClass("ds-section");
expect(footer?.querySelector(".ds-section-shell")).toBeInTheDocument();
expect(footer?.querySelector(".ds-grid-2")).toBeInTheDocument();
expect(footer?.querySelectorAll(":scope .ds-card")).toHaveLength(2);
expect(footer?.querySelectorAll("h3")).toHaveLength(2);
});
it("should display current year in copyright text", () => {
it("renders the current year without hardcoded copyright text", () => {
render(<Footer />);
const currentYear = new Date().getFullYear();
const copyrightText = screen.getByText(
new RegExp(`© ${currentYear} Evandro Fonseca Junior`),
);
expect(copyrightText).toBeInTheDocument();
});
it("should update copyright year dynamically", () => {
// Test that the component uses new Date().getFullYear() dynamically
// by verifying it shows the current year (not a hardcoded value)
const currentYear = new Date().getFullYear();
render(<Footer />);
// Verify the copyright includes the current year
const copyrightText = screen.getByText(
new RegExp(`© ${currentYear} Evandro Fonseca Junior`),
);
expect(copyrightText).toBeInTheDocument();
// Verify it's not hardcoded to a specific year like 2023 or 2024
// by checking that the year matches the actual current year
expect(currentYear).toBeGreaterThanOrEqual(2024);
});
it("should apply correct styling to copyright text", () => {
render(<Footer />);
const currentYear = new Date().getFullYear();
const copyrightText = screen.getByText(
new RegExp(`© ${currentYear} Evandro Fonseca Junior`),
);
const classes = copyrightText.className;
expect(classes).toContain("text-[12px]");
expect(classes).toContain("text-[rgba(255,255,255,0.5)]");
});
});
describe("Footer Component - Responsive Layout", () => {
beforeEach(() => {
// Mock window.matchMedia for responsive tests
Object.defineProperty(window, "matchMedia", {
writable: true,
value: jest.fn().mockImplementation((query) => ({
matches: false,
media: query,
onchange: null,
addListener: jest.fn(),
removeListener: jest.fn(),
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
dispatchEvent: jest.fn(),
})),
});
});
it("should have responsive grid layout classes", () => {
const { container } = render(<Footer />);
const gridContainer = container.querySelector(".grid");
expect(gridContainer).toBeInTheDocument();
const classes = gridContainer?.className || "";
expect(classes).toContain("grid-cols-1");
expect(classes).toContain("md:grid-cols-2");
expect(classes).toContain("lg:grid-cols-3");
});
it("should have responsive padding classes on container", () => {
const { container } = render(<Footer />);
const innerContainer = container.querySelector(".ds-section-shell");
expect(innerContainer).toBeInTheDocument();
// The ds-section class handles responsive padding via CSS
const footer = container.querySelector("footer");
const classes = footer?.className || "";
expect(classes).toContain("ds-section");
});
it("should have responsive gap classes on grid", () => {
const { container } = render(<Footer />);
const gridContainer = container.querySelector(".grid");
const classes = gridContainer?.className || "";
expect(classes).toContain("gap-sp-6");
});
it("should have responsive column span for copyright section", () => {
const { container } = render(<Footer />);
// Find the copyright section by its heading
const copyrightHeading = screen.getByText("Informacoes legais");
const copyrightSection = copyrightHeading.closest(".ds-card");
expect(copyrightSection).toBeInTheDocument();
const classes = copyrightSection?.className || "";
expect(classes).toContain("md:col-span-2");
expect(classes).toContain("lg:col-span-1");
});
});
describe("Footer Component - Design System Consistency", () => {
it("should use design system kicker class for section labels", () => {
render(<Footer />);
const kickers = document.querySelectorAll(".ds-kicker");
expect(kickers.length).toBeGreaterThan(0);
});
it("should have ds-section class on footer element", () => {
const { container } = render(<Footer />);
const footer = container.querySelector("footer");
expect(footer).toBeInTheDocument();
const classes = footer?.className || "";
expect(classes).toContain("ds-section");
});
it("should have ds-section-dark class for dark background", () => {
const { container } = render(<Footer />);
const footer = container.querySelector("footer");
const classes = footer?.className || "";
expect(classes).toContain("ds-section-dark");
});
it("should use design system shell class for container", () => {
const { container } = render(<Footer />);
const shell = container.querySelector(".ds-section-shell");
expect(shell).toBeInTheDocument();
});
});
describe("Footer Component - Structure", () => {
it("should render as footer semantic element", () => {
const { container } = render(<Footer />);
const footer = container.querySelector("footer");
expect(footer).toBeInTheDocument();
});
it("should have three main sections", () => {
render(<Footer />);
const contactHeading = screen.getByText("Contato direto");
const connectHeading = screen.getByText("Redes profissionais");
const copyrightHeading = screen.getByText("Informacoes legais");
expect(contactHeading).toBeInTheDocument();
expect(connectHeading).toBeInTheDocument();
expect(copyrightHeading).toBeInTheDocument();
});
it("should have design system shell container", () => {
const { container } = render(<Footer />);
const innerContainer = container.querySelector(".ds-section-shell");
expect(innerContainer).toBeInTheDocument();
expect(
screen.getByText(
new RegExp(`Copyright ${currentYear} Evandro Fonseca Junior`),
),
).toBeInTheDocument();
});
});