Foco cai no destino ao chegar de outra página; âncoras ignoram ?tipo=; movimento reduzido salta em todos os cliques; cronômetro da janela ampliada; degradê no topo de Projetos e legendas do mergulho com intervalos testados; vitrine acima da barra de cookies e com 2 paradas por projeto; reel-list.css no global; 3D montado em tarefas curtas, limitado a ~30 qps e estático com WebGL por software; pôsteres da vitrine de 330 para 158 KB; SC Plus regravado; scripts sem funções acima de complexidade 10.
105 lines
3.2 KiB
TypeScript
105 lines
3.2 KiB
TypeScript
import { render, screen } from "@testing-library/react";
|
|
import {
|
|
resetFocusOnNavigation,
|
|
useFocusOnNavigation,
|
|
} from "./useFocusOnNavigation";
|
|
|
|
function Probe({ pathname }: { pathname: string }) {
|
|
useFocusOnNavigation(pathname);
|
|
return null;
|
|
}
|
|
|
|
beforeEach(() => {
|
|
resetFocusOnNavigation();
|
|
document.body.innerHTML = "";
|
|
});
|
|
|
|
function mountMain() {
|
|
const main = document.createElement("div");
|
|
main.id = "main-content";
|
|
main.tabIndex = -1;
|
|
document.body.append(main);
|
|
return main;
|
|
}
|
|
|
|
describe("useFocusOnNavigation", () => {
|
|
it("does nothing on the first load, even with #main-content on the page", () => {
|
|
const main = mountMain();
|
|
render(<Probe pathname="/" />);
|
|
expect(main).not.toHaveFocus();
|
|
});
|
|
|
|
it("focuses #main-content once per path change, never scrolling", () => {
|
|
const main = mountMain();
|
|
const focus = jest.spyOn(main, "focus");
|
|
const { rerender } = render(<Probe pathname="/" />);
|
|
|
|
rerender(<Probe pathname="/cases" />);
|
|
expect(main).toHaveFocus();
|
|
expect(focus).toHaveBeenCalledTimes(1);
|
|
expect(focus).toHaveBeenCalledWith({ preventScroll: true });
|
|
|
|
rerender(<Probe pathname="/cases" />);
|
|
expect(focus).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
describe("with a #hash in the URL (from /privacidade to /#contact)", () => {
|
|
afterEach(() => {
|
|
window.history.replaceState(null, "", "/");
|
|
});
|
|
|
|
function mountContact() {
|
|
const contact = document.createElement("section");
|
|
contact.id = "contact";
|
|
contact.tabIndex = -1;
|
|
document.body.append(contact);
|
|
return contact;
|
|
}
|
|
|
|
it("leaves the focus to the anchor target when the new page has it", () => {
|
|
const main = mountMain();
|
|
const contact = mountContact();
|
|
const focus = jest.spyOn(main, "focus");
|
|
const { rerender } = render(<Probe pathname="/privacidade" />);
|
|
|
|
window.history.replaceState(null, "", "/#contact");
|
|
contact.focus({ preventScroll: true });
|
|
rerender(<Probe pathname="/" />);
|
|
|
|
expect(focus).not.toHaveBeenCalled();
|
|
expect(contact).toHaveFocus();
|
|
});
|
|
|
|
it("still focuses #main-content when the hash points to nothing on the new page", () => {
|
|
const main = mountMain();
|
|
mountContact();
|
|
const { rerender } = render(<Probe pathname="/privacidade" />);
|
|
|
|
window.history.replaceState(null, "", "/#nada");
|
|
rerender(<Probe pathname="/" />);
|
|
|
|
expect(main).toHaveFocus();
|
|
});
|
|
});
|
|
|
|
it("still tells a navigation from the first load when the component remounts (first segment changed)", () => {
|
|
const main = mountMain();
|
|
const first = render(<Probe pathname="/" />);
|
|
first.unmount();
|
|
render(<Probe pathname="/cases" />);
|
|
expect(main).toHaveFocus();
|
|
});
|
|
|
|
it("survives a page without #main-content (a 404 shell, an error boundary)", () => {
|
|
const { rerender } = render(<Probe pathname="/" />);
|
|
expect(() => rerender(<Probe pathname="/nada" />)).not.toThrow();
|
|
expect(screen.queryByRole("main")).toBeNull();
|
|
});
|
|
|
|
it("is not fooled by the double effect of React StrictMode", () => {
|
|
const main = mountMain();
|
|
render(<Probe pathname="/" />, { reactStrictMode: true });
|
|
expect(main).not.toHaveFocus();
|
|
});
|
|
});
|