- cards com moldura de navegador (endereco real) e brilho na cor do site no card que toca - um video por vez: o do card sob o mouse/foco, ou o mais perto do centro da tela; nada baixa antes de tocar, e um botao pausa os videos que se mexem sozinhos - janela ampliada em <dialog> nativo: troca computador/celular mantendo o ponto do site, capitulos clicaveis, controles proprios, setas entre projetos e foco devolvido ao fechar - dados e capitulos de cada projeto em lib/project-showcase.ts (substitui project-videos.ts) Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
86 lines
3.2 KiB
TypeScript
86 lines
3.2 KiB
TypeScript
import { act, render, screen } from "@testing-library/react";
|
|
import { getShowcaseAssets } from "@/lib/project-showcase";
|
|
import { ProjectVideo } from "./ProjectVideo";
|
|
|
|
let reducedMotion = false;
|
|
jest.mock("@/app/hooks/useReducedMotion", () => ({
|
|
useReducedMotion: () => reducedMotion,
|
|
}));
|
|
|
|
const video = getShowcaseAssets("nutriscan", "desktop");
|
|
|
|
beforeEach(() => {
|
|
reducedMotion = false;
|
|
jest.spyOn(HTMLMediaElement.prototype, "play").mockResolvedValue();
|
|
jest.spyOn(HTMLMediaElement.prototype, "pause").mockImplementation(() => {});
|
|
jest.spyOn(HTMLMediaElement.prototype, "load").mockImplementation(() => {});
|
|
});
|
|
|
|
afterEach(() => {
|
|
jest.restoreAllMocks();
|
|
});
|
|
|
|
describe("ProjectVideo", () => {
|
|
it("renders a muted looping inline video that downloads nothing until it is active", () => {
|
|
const { container } = render(
|
|
<ProjectVideo video={video} title="Demo" active={false} />,
|
|
);
|
|
const element = container.querySelector("video");
|
|
|
|
expect(element).not.toBeNull();
|
|
expect(element).toHaveAttribute("autoplay");
|
|
expect(element).toHaveAttribute("loop");
|
|
expect(element).toHaveAttribute("playsinline");
|
|
expect(element).toHaveAttribute("preload", "none");
|
|
expect(element).toHaveAttribute("poster", video.poster);
|
|
expect(element?.muted).toBe(true);
|
|
expect(element).toHaveAttribute("data-ready", "false");
|
|
expect(container.querySelectorAll("source")).toHaveLength(0);
|
|
expect(HTMLMediaElement.prototype.play).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("attaches the sources and plays when it becomes the active card, then pauses when it stops being", () => {
|
|
const { container, rerender } = render(
|
|
<ProjectVideo video={video} title="Demo" active={false} />,
|
|
);
|
|
|
|
rerender(<ProjectVideo video={video} title="Demo" active />);
|
|
const sources = [...container.querySelectorAll("source")];
|
|
expect(sources.map((source) => source.getAttribute("src"))).toEqual(
|
|
video.sources.map((source) => source.src),
|
|
);
|
|
expect(HTMLMediaElement.prototype.load).toHaveBeenCalled();
|
|
expect(HTMLMediaElement.prototype.play).toHaveBeenCalled();
|
|
|
|
rerender(<ProjectVideo video={video} title="Demo" active={false} />);
|
|
expect(HTMLMediaElement.prototype.pause).toHaveBeenCalled();
|
|
// sai de cena, mas o arquivo já baixado fica: voltar a tocar não baixa de novo
|
|
expect(container.querySelectorAll("source")).toHaveLength(2);
|
|
});
|
|
|
|
it("fades the video in once it is playing", () => {
|
|
const { container } = render(
|
|
<ProjectVideo video={video} title="Demo" active />,
|
|
);
|
|
const element = container.querySelector("video") as HTMLVideoElement;
|
|
|
|
act(() => {
|
|
element.dispatchEvent(new Event("playing"));
|
|
});
|
|
expect(element).toHaveAttribute("data-ready", "true");
|
|
});
|
|
|
|
it("shows only the poster, with no video element, when the user prefers reduced motion", () => {
|
|
reducedMotion = true;
|
|
const { container } = render(
|
|
<ProjectVideo video={video} title="Demo" active />,
|
|
);
|
|
|
|
expect(container.querySelector("video")).toBeNull();
|
|
expect(
|
|
screen.getByRole("img", { name: "Captura de tela de Demo" }),
|
|
).toBeInTheDocument();
|
|
expect(HTMLMediaElement.prototype.play).not.toHaveBeenCalled();
|
|
});
|
|
});
|