feat: rebuild landing experience, content and analytics
This commit is contained in:
1 parent
d24ee12299
commit
9aff4d1035
51 files changed
+3023
-2595
No files matched your search
@@ -1,4 +1,11 @@
|
||||
import { act, render, screen, waitFor } from "@testing-library/react";
|
||||
import {
|
||||
act,
|
||||
fireEvent,
|
||||
render,
|
||||
screen,
|
||||
waitFor,
|
||||
within,
|
||||
} from "@testing-library/react";
|
||||
import { getFeaturedProjects } from "@/lib/portfolio-data";
|
||||
import NotebookStory, { canUseNotebook3D } from "./NotebookStory";
|
||||
|
||||
@@ -29,6 +36,7 @@ jest.mock("gsap/ScrollTrigger", () => ({
|
||||
const projects = getFeaturedProjects(null);
|
||||
|
||||
let intersectionCallback: IntersectionObserverCallback | undefined;
|
||||
let reducedMotionListener: (() => void) | undefined;
|
||||
const mockObserve = jest.fn();
|
||||
const mockDisconnect = jest.fn();
|
||||
|
||||
@@ -63,7 +71,11 @@ function mockMatchMedia({
|
||||
(query === "(hover: hover)" && hover),
|
||||
media: query,
|
||||
onchange: null,
|
||||
addEventListener: jest.fn(),
|
||||
addEventListener: jest.fn((event: string, callback: () => void) => {
|
||||
if (query === "(prefers-reduced-motion: reduce)" && event === "change") {
|
||||
reducedMotionListener = callback;
|
||||
}
|
||||
}),
|
||||
removeEventListener: jest.fn(),
|
||||
addListener: jest.fn(),
|
||||
removeListener: jest.fn(),
|
||||
@@ -80,6 +92,7 @@ describe("NotebookStory", () => {
|
||||
});
|
||||
setDocumentHidden(false);
|
||||
intersectionCallback = undefined;
|
||||
reducedMotionListener = undefined;
|
||||
mockObserve.mockReset();
|
||||
mockDisconnect.mockReset();
|
||||
class MockIntersectionObserver {
|
||||
@@ -115,17 +128,53 @@ describe("NotebookStory", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("does not initialize the 3D stage on coarse pointers", async () => {
|
||||
mockMatchMedia({ coarse: true });
|
||||
it("initializes the 3D stage on a narrow touch viewport without hover", async () => {
|
||||
mockMatchMedia({ coarse: true, hover: false });
|
||||
Object.defineProperty(window, "innerWidth", {
|
||||
configurable: true,
|
||||
value: 390,
|
||||
});
|
||||
|
||||
render(<NotebookStory projects={projects} />);
|
||||
|
||||
expect(screen.getByTestId("notebook-fallback")).toBeInTheDocument();
|
||||
await waitFor(() =>
|
||||
expect(screen.queryByTestId("notebook-stage")).not.toBeInTheDocument(),
|
||||
expect(await screen.findByTestId("notebook-stage")).toBeInTheDocument();
|
||||
expect(screen.queryByTestId("notebook-fallback")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("lets touch users select and open a project outside the scaled screen", async () => {
|
||||
mockMatchMedia({ coarse: true, hover: false });
|
||||
render(<NotebookStory projects={projects} />);
|
||||
await screen.findByTestId("notebook-stage");
|
||||
const controls = screen.getByRole("navigation", {
|
||||
name: "Navegar projetos do notebook",
|
||||
});
|
||||
const button = within(controls).getByRole("button", {
|
||||
name: /Mostrar SC/i,
|
||||
});
|
||||
|
||||
fireEvent.click(button);
|
||||
|
||||
expect(button).toHaveAttribute("aria-pressed", "true");
|
||||
expect(
|
||||
within(controls).getByRole("link", { name: /Abrir projeto/i }),
|
||||
).toHaveAttribute(
|
||||
"href",
|
||||
projects.find((project) => project.id === "sc-plus")?.demoUrl,
|
||||
);
|
||||
});
|
||||
it("initializes the 3D stage only on a desktop hover-capable viewport", async () => {
|
||||
|
||||
it("returns to static content if reduced motion is enabled during the story", async () => {
|
||||
mockMatchMedia({ coarse: true, hover: false });
|
||||
render(<NotebookStory projects={projects} />);
|
||||
await screen.findByTestId("notebook-stage");
|
||||
|
||||
mockMatchMedia({ reduced: true, coarse: true, hover: false });
|
||||
act(() => reducedMotionListener?.());
|
||||
|
||||
expect(screen.getByTestId("notebook-fallback")).toBeInTheDocument();
|
||||
expect(screen.queryByTestId("notebook-stage")).not.toBeInTheDocument();
|
||||
});
|
||||
it("initializes the 3D stage on a desktop viewport", async () => {
|
||||
render(<NotebookStory projects={projects} />);
|
||||
|
||||
await waitFor(() =>
|
||||
@@ -155,22 +204,19 @@ describe("NotebookStory", () => {
|
||||
act(() => document.dispatchEvent(new Event("visibilitychange")));
|
||||
expect(stage).toHaveAttribute("data-is-visible", "false");
|
||||
});
|
||||
it("returns to the static fallback when the viewport loses desktop eligibility", async () => {
|
||||
it("keeps the mounted 3D stage when resizing from desktop to touch mobile", async () => {
|
||||
render(<NotebookStory projects={projects} />);
|
||||
await waitFor(() =>
|
||||
expect(screen.getByTestId("notebook-stage")).toBeInTheDocument(),
|
||||
);
|
||||
const stage = await screen.findByTestId("notebook-stage");
|
||||
|
||||
Object.defineProperty(window, "innerWidth", {
|
||||
configurable: true,
|
||||
value: 800,
|
||||
value: 360,
|
||||
});
|
||||
window.dispatchEvent(new Event("resize"));
|
||||
mockMatchMedia({ coarse: true, hover: false });
|
||||
act(() => window.dispatchEvent(new Event("resize")));
|
||||
|
||||
await waitFor(() =>
|
||||
expect(screen.queryByTestId("notebook-stage")).not.toBeInTheDocument(),
|
||||
);
|
||||
expect(screen.getByTestId("notebook-fallback")).toBeInTheDocument();
|
||||
expect(screen.getByTestId("notebook-stage")).toBe(stage);
|
||||
expect(screen.queryByTestId("notebook-fallback")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("keeps the static fallback when no mapped projects are available", async () => {
|
||||
@@ -187,17 +233,15 @@ describe("NotebookStory", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("requires desktop hover input without reduced motion", () => {
|
||||
it("respects reduced motion independently of width and pointer capabilities", () => {
|
||||
const matchMedia = (query: string) =>
|
||||
({
|
||||
matches: query === "(hover: hover)",
|
||||
}) as MediaQueryList;
|
||||
|
||||
expect(canUseNotebook3D({ innerWidth: 1280, matchMedia })).toBe(true);
|
||||
expect(canUseNotebook3D({ innerWidth: 1024, matchMedia })).toBe(false);
|
||||
expect(canUseNotebook3D({ matchMedia })).toBe(true);
|
||||
expect(
|
||||
canUseNotebook3D({
|
||||
innerWidth: 1280,
|
||||
matchMedia: (query) =>
|
||||
({
|
||||
matches:
|
||||
|
||||
Reference in new issue
Block a user