146 lines
4.3 KiB
TypeScript
146 lines
4.3 KiB
TypeScript
import { act, render, screen } from "@testing-library/react";
|
|
import type { ReactNode } from "react";
|
|
import Projects from "./Projects";
|
|
|
|
/**
|
|
* "Ver os cases" na coluna dos botões da vitrine: na vitrine fixa o conjunto de aparelhos (`.ds-reel-set`, com a legenda
|
|
* e os botões no canto esquerdo dele) fica centrado no palco, e esse canto muda com a altura da janela. Projects mede o
|
|
* canto e dá ao bloco do link o mesmo recuo; sem vitrine fixa (celular, movimento reduzido) o recuo é zero.
|
|
*/
|
|
|
|
jest.mock("next/link", () => ({
|
|
__esModule: true,
|
|
default: ({
|
|
children,
|
|
prefetch: _prefetch,
|
|
...props
|
|
}: { children?: ReactNode; prefetch?: boolean | null } & Record<
|
|
string,
|
|
unknown
|
|
>) => <a {...props}>{children}</a>,
|
|
}));
|
|
|
|
jest.mock("./Section", () => ({
|
|
Section: ({ children, title }: { children: ReactNode; title: string }) => (
|
|
<section>
|
|
<h2>{title}</h2>
|
|
{children}
|
|
</section>
|
|
),
|
|
}));
|
|
|
|
jest.mock("./showcase/ShowcaseProvider", () => ({
|
|
ShowcaseProvider: ({ children }: { children: ReactNode }) => <>{children}</>,
|
|
}));
|
|
|
|
let pinned = true;
|
|
jest.mock("./showcase/ProjectReel", () => ({
|
|
ProjectReel: () => (pinned ? <div className="ds-reel-set" /> : <ul />),
|
|
}));
|
|
|
|
/** Os cantos esquerdos que a página teria: o do bloco do link e o do conjunto de aparelhos. */
|
|
const lefts = { exit: 100, set: 503 };
|
|
|
|
class FakeResizeObserver {
|
|
static instances: FakeResizeObserver[] = [];
|
|
observed = new Set<Element>();
|
|
constructor(private readonly callback: () => void) {
|
|
FakeResizeObserver.instances.push(this);
|
|
}
|
|
observe(target: Element) {
|
|
this.observed.add(target);
|
|
}
|
|
unobserve(target: Element) {
|
|
this.observed.delete(target);
|
|
}
|
|
disconnect() {
|
|
this.observed.clear();
|
|
}
|
|
fire() {
|
|
this.callback();
|
|
}
|
|
}
|
|
|
|
const originalRect = Element.prototype.getBoundingClientRect;
|
|
const originalObserver = global.ResizeObserver;
|
|
|
|
beforeEach(() => {
|
|
pinned = true;
|
|
lefts.exit = 100;
|
|
lefts.set = 503;
|
|
FakeResizeObserver.instances = [];
|
|
global.ResizeObserver =
|
|
FakeResizeObserver as unknown as typeof ResizeObserver;
|
|
Element.prototype.getBoundingClientRect = function rect(this: Element) {
|
|
const left = this.classList.contains("ds-reel-set")
|
|
? lefts.set
|
|
: this.getAttribute("data-reel-stagger") === "left"
|
|
? lefts.exit
|
|
: 0;
|
|
return {
|
|
left,
|
|
right: left,
|
|
top: 0,
|
|
bottom: 0,
|
|
width: 0,
|
|
height: 0,
|
|
} as DOMRect;
|
|
};
|
|
});
|
|
|
|
afterEach(() => {
|
|
Element.prototype.getBoundingClientRect = originalRect;
|
|
global.ResizeObserver = originalObserver;
|
|
});
|
|
|
|
const exitBlock = () =>
|
|
screen.getByRole("link", { name: "Ver os cases" })
|
|
.parentElement as HTMLElement;
|
|
|
|
describe("Projects: saída da vitrine", () => {
|
|
it("indents the link to the left corner of the pinned reel, where the caption and the buttons start", () => {
|
|
render(<Projects projects={[]} />);
|
|
|
|
expect(exitBlock().style.paddingLeft).toBe("403px");
|
|
});
|
|
|
|
it("follows the reel when the window changes size (the stage measures itself), and when the reel is observed", () => {
|
|
render(<Projects projects={[]} />);
|
|
expect(exitBlock().style.paddingLeft).toBe("403px");
|
|
|
|
lefts.set = 567;
|
|
act(() => {
|
|
for (const observer of FakeResizeObserver.instances) observer.fire();
|
|
});
|
|
|
|
expect(exitBlock().style.paddingLeft).toBe("467px");
|
|
// observa a seção (largura da janela) e o conjunto de aparelhos (a barra de cookies muda a altura do palco)
|
|
const observed = FakeResizeObserver.instances.flatMap((observer) => [
|
|
...observer.observed,
|
|
]);
|
|
expect(observed.some((element) => element.tagName === "SECTION")).toBe(
|
|
true,
|
|
);
|
|
expect(
|
|
observed.some((element) => element.classList.contains("ds-reel-set")),
|
|
).toBe(true);
|
|
});
|
|
|
|
it("keeps the link at the start of the column without a pinned reel (phone, reduced motion, short window)", () => {
|
|
pinned = false;
|
|
|
|
render(<Projects projects={[]} />);
|
|
|
|
expect(exitBlock().style.paddingLeft).toBe("");
|
|
});
|
|
|
|
it("never indents to the left of its own column, and works where there is no ResizeObserver", () => {
|
|
lefts.set = 40;
|
|
global.ResizeObserver = undefined as unknown as typeof ResizeObserver;
|
|
|
|
render(<Projects projects={[]} />);
|
|
|
|
expect(exitBlock().style.paddingLeft).toBe("");
|
|
});
|
|
});
|