Files
Evandro Fonseca Junior 318a764190 perf(movimento): sem tela vazia, passagens em CSS e vitrine leve
Projetos sobem sobre o palco do hero e o celular tem hero de uma tela sem mergulho; passagens com animation-timeline em CSS, sem GSAP nem motion; troca da vitrine sem texto duplicado; moldura de celular só com pôster e scrub reencodado em 960 px (9,4 para 5,2 MB); 3D monta na primeira interação e para quando parado; transição entre páginas do mesmo segmento; foco em anel duplo; texto de 15 px no celular; código morto removido.
2026-10-14 14:15:50 -03:00

93 lines
2.8 KiB
TypeScript

import { act, renderHook } from "@testing-library/react";
import { createElement } from "react";
import { renderToString } from "react-dom/server";
import { useReducedMotion } from "./useReducedMotion";
type Listener = () => void;
/** matchMedia que responde só à consulta de movimento reduzido e deixa o teste mudar a preferência depois. */
function mockPreference(initial: boolean) {
const listeners = new Set<Listener>();
const query = {
matches: initial,
media: "(prefers-reduced-motion: reduce)",
addEventListener: jest.fn((_: string, listener: Listener) =>
listeners.add(listener),
),
removeEventListener: jest.fn((_: string, listener: Listener) =>
listeners.delete(listener),
),
};
window.matchMedia = jest.fn().mockReturnValue(query);
return {
query,
change(value: boolean) {
query.matches = value;
for (const listener of listeners) listener();
},
};
}
const original = window.matchMedia;
afterEach(() => {
window.matchMedia = original;
});
describe("useReducedMotion", () => {
it("is false when the system does not ask for reduced motion", () => {
mockPreference(false);
const { result } = renderHook(() => useReducedMotion());
expect(result.current).toBe(false);
});
it("is true when the system asks for reduced motion", () => {
mockPreference(true);
const { result } = renderHook(() => useReducedMotion());
expect(result.current).toBe(true);
expect(window.matchMedia).toHaveBeenCalledWith(
"(prefers-reduced-motion: reduce)",
);
});
it("follows the preference when it changes while the page is open", () => {
const preference = mockPreference(false);
const { result } = renderHook(() => useReducedMotion());
expect(result.current).toBe(false);
act(() => preference.change(true));
expect(result.current).toBe(true);
act(() => preference.change(false));
expect(result.current).toBe(false);
});
it("stops listening when the component unmounts", () => {
const preference = mockPreference(false);
const { unmount } = renderHook(() => useReducedMotion());
unmount();
expect(preference.query.removeEventListener).toHaveBeenCalledTimes(1);
});
it("is false on the server and in browsers without matchMedia, so the HTML always hydrates the same", () => {
mockPreference(true);
function Probe() {
return createElement("i", { "data-reduced": String(useReducedMotion()) });
}
expect(renderToString(createElement(Probe))).toContain(
'data-reduced="false"',
);
// biome-ignore lint/suspicious/noExplicitAny: simula um navegador sem a API
(window as any).matchMedia = undefined;
const { result } = renderHook(() => useReducedMotion());
expect(result.current).toBe(false);
});
});