Files
portifolio-evandrodevbr/app/jogo/Toque.test.tsx
T
evandro 67b32fcab3
CI / audit (push) Successful in 10m48s
CI / verify (push) Successful in 19m2s
CI / deploy (push) Successful in 2m14s
CI / e2e (push) Failing after 36m15s
feat(jogo): expediente dos mortos, jogo de zumbis em primeira pessoa
Etapa 1 inteira (logica com 100% de cobertura, cena 3D, toque, sons, bancada de desempenho, e2e) e a base da etapa 2 (mapa novo no Tiled, texturas, imagens dos itens, sons conferidos, golpe recortado e medido). Pagina /jogo fora do menu e do sitemap ate a medicao no celular.
2026-11-10 19:37:10 -03:00

252 lines
9.0 KiB
TypeScript

import { fireEvent, render, screen } from "@testing-library/react";
import type { ArmaId } from "@/lib/jogo/tipos";
import type { Controle } from "./contrato";
import { Toque } from "./Toque";
function controleFalso() {
return {
ler: jest.fn(),
definirMover: jest.fn(),
somarOlhar: jest.fn(),
definirAtirar: jest.fn(),
definirArma: jest.fn(),
soltar: jest.fn(),
descartar: jest.fn(),
} satisfies Controle;
}
function montar(
c: Controle,
extra: { arma?: ArmaId; municao?: number; mirando?: boolean } = {},
) {
const props = { arma: 0 as ArmaId, municao: 30, mirando: false, ...extra };
const vista = render(<Toque controle={c} {...props} />);
return {
...vista,
camada: vista.container.firstElementChild as HTMLElement,
de: (novas: Partial<typeof props>) =>
vista.rerender(<Toque controle={c} {...props} {...novas} />),
};
}
// a tela do jsdom tem 1024 px de largura: a metade esquerda vai até 511
const ESQUERDA = 100;
const DIREITA = 800;
describe("Toque: direcional", () => {
it("aparece onde o dedo encosta, move e some ao soltar", () => {
const c = controleFalso();
const { camada } = montar(c);
expect(screen.queryByTestId("direcional")).toBeNull();
fireEvent.pointerDown(camada, {
pointerId: 1,
clientX: ESQUERDA,
clientY: 300,
});
expect(screen.getByTestId("direcional")).toHaveStyle({
left: "100px",
top: "300px",
});
fireEvent.pointerMove(camada, {
pointerId: 1,
clientX: ESQUERDA + 28,
clientY: 300 - 28,
});
const [direita, frente] = c.definirMover.mock.calls.at(-1) ?? [];
expect(direita).toBeCloseTo(0.5);
expect(frente).toBeCloseTo(0.5);
fireEvent.pointerUp(camada, { pointerId: 1 });
expect(c.definirMover).toHaveBeenLastCalledWith(0, 0);
expect(screen.queryByTestId("direcional")).toBeNull();
});
it("um segundo dedo na metade esquerda não rouba o direcional", () => {
const c = controleFalso();
const { camada } = montar(c);
fireEvent.pointerDown(camada, { pointerId: 1, clientX: 100, clientY: 300 });
fireEvent.pointerDown(camada, { pointerId: 2, clientX: 200, clientY: 200 });
fireEvent.pointerMove(camada, { pointerId: 2, clientX: 260, clientY: 200 });
expect(c.definirMover).not.toHaveBeenCalled();
});
it("cancelar o toque também solta o direcional", () => {
const c = controleFalso();
const { camada } = montar(c);
fireEvent.pointerDown(camada, { pointerId: 1, clientX: 100, clientY: 300 });
fireEvent.pointerCancel(camada, { pointerId: 1 });
expect(c.definirMover).toHaveBeenLastCalledWith(0, 0);
});
});
describe("Toque: mira", () => {
it("arrastar na metade direita soma o giro", () => {
const c = controleFalso();
const { camada } = montar(c);
fireEvent.pointerDown(camada, {
pointerId: 1,
clientX: DIREITA,
clientY: 200,
});
fireEvent.pointerMove(camada, {
pointerId: 1,
clientX: DIREITA + 40,
clientY: 210,
});
fireEvent.pointerMove(camada, {
pointerId: 1,
clientX: DIREITA + 60,
clientY: 210,
});
expect(c.somarOlhar).toHaveBeenCalledTimes(2);
const [a, b] = c.somarOlhar.mock.calls;
expect(a[0]).toBeCloseTo(-0.2);
expect(a[1]).toBeCloseTo(-0.05);
expect(b[0]).toBeCloseTo(-0.1);
expect(b[1]).toBeCloseTo(0);
expect(c.definirMover).not.toHaveBeenCalled();
});
it("depois de soltar, mover o ponteiro não gira mais", () => {
const c = controleFalso();
const { camada } = montar(c);
fireEvent.pointerDown(camada, { pointerId: 1, clientX: 800, clientY: 200 });
fireEvent.pointerUp(camada, { pointerId: 1 });
fireEvent.pointerMove(camada, { pointerId: 1, clientX: 900, clientY: 200 });
expect(c.somarOlhar).not.toHaveBeenCalled();
});
it("dois dedos ao mesmo tempo: um anda e o outro mira", () => {
const c = controleFalso();
const { camada } = montar(c);
fireEvent.pointerDown(camada, { pointerId: 1, clientX: 100, clientY: 300 });
fireEvent.pointerDown(camada, { pointerId: 2, clientX: 800, clientY: 200 });
fireEvent.pointerMove(camada, { pointerId: 2, clientX: 810, clientY: 200 });
fireEvent.pointerMove(camada, { pointerId: 1, clientX: 100, clientY: 250 });
expect(c.somarOlhar).toHaveBeenCalledTimes(1);
expect(c.definirMover).toHaveBeenCalledTimes(1);
expect(c.definirMover.mock.calls[0][1]).toBeCloseTo(0.89, 1);
});
it("um segundo dedo na metade direita não vira outra mira", () => {
const c = controleFalso();
const { camada } = montar(c);
fireEvent.pointerDown(camada, { pointerId: 1, clientX: 800, clientY: 200 });
fireEvent.pointerDown(camada, { pointerId: 2, clientX: 900, clientY: 200 });
fireEvent.pointerMove(camada, { pointerId: 2, clientX: 950, clientY: 200 });
expect(c.somarOlhar).not.toHaveBeenCalled();
});
});
describe("Toque: botão Atirar", () => {
it("segurar atira e soltar para", () => {
const c = controleFalso();
montar(c);
c.definirAtirar.mockClear();
const botao = screen.getByRole("button", { name: "Atirar" });
fireEvent.pointerDown(botao, { pointerId: 1, clientX: 900, clientY: 350 });
expect(c.definirAtirar).toHaveBeenLastCalledWith(true);
fireEvent.pointerUp(botao, { pointerId: 1 });
expect(c.definirAtirar).toHaveBeenLastCalledWith(false);
});
it("arrastar o dedo sobre o botão também mira", () => {
const c = controleFalso();
montar(c);
const botao = screen.getByRole("button", { name: "Atirar" });
fireEvent.pointerDown(botao, { pointerId: 1, clientX: 900, clientY: 350 });
fireEvent.pointerMove(botao, { pointerId: 1, clientX: 920, clientY: 330 });
const [rumo, inclinacao] = c.somarOlhar.mock.calls[0];
expect(rumo).toBeCloseTo(-0.1);
expect(inclinacao).toBeCloseTo(0.1);
});
it("tocar no botão não liga o direcional nem a mira da camada", () => {
const c = controleFalso();
const { camada } = montar(c);
const botao = screen.getByRole("button", { name: "Atirar" });
fireEvent.pointerDown(botao, { pointerId: 1, clientX: 100, clientY: 350 });
expect(screen.queryByTestId("direcional")).toBeNull();
fireEvent.pointerUp(camada, { pointerId: 1 });
expect(c.definirMover).not.toHaveBeenCalled();
});
});
describe("Toque: armas", () => {
it("mostra as três armas, com as balas da automática e a escolhida marcada", () => {
montar(controleFalso(), { arma: 1, municao: 42 });
expect(screen.getByRole("button", { name: "Pistola" })).toHaveAttribute(
"aria-pressed",
"false",
);
expect(
screen.getByRole("button", { name: "Automática 42" }),
).toHaveAttribute("aria-pressed", "true");
expect(screen.getByRole("button", { name: "Faca" })).toHaveAttribute(
"aria-pressed",
"false",
);
});
it("tocar numa arma a escolhe, sem mirar nem mover", () => {
const c = controleFalso();
montar(c);
const faca = screen.getByRole("button", { name: "Faca" });
fireEvent.pointerDown(faca, { pointerId: 1, clientX: 700, clientY: 300 });
fireEvent.click(faca);
fireEvent.pointerUp(faca, { pointerId: 1 });
expect(c.definirArma).toHaveBeenCalledWith(2);
expect(c.somarOlhar).not.toHaveBeenCalled();
});
});
describe("Toque: tiro automático", () => {
it("liga enquanto mira e desliga ao deixar de mirar", () => {
const c = controleFalso();
const { de } = montar(c, { mirando: true });
expect(c.definirAtirar).toHaveBeenLastCalledWith(true);
de({ mirando: false });
expect(c.definirAtirar).toHaveBeenLastCalledWith(false);
});
it("não solta o tiro se o botão Atirar está apertado", () => {
const c = controleFalso();
const { de } = montar(c, { mirando: true });
const botao = screen.getByRole("button", { name: "Atirar" });
fireEvent.pointerDown(botao, { pointerId: 1, clientX: 900, clientY: 350 });
de({ mirando: false });
expect(c.definirAtirar).toHaveBeenLastCalledWith(true);
fireEvent.pointerUp(botao, { pointerId: 1 });
expect(c.definirAtirar).toHaveBeenLastCalledWith(false);
});
it("soltar o botão mantém o tiro se ainda está mirando", () => {
const c = controleFalso();
montar(c, { mirando: true });
const botao = screen.getByRole("button", { name: "Atirar" });
fireEvent.pointerDown(botao, { pointerId: 1, clientX: 900, clientY: 350 });
fireEvent.pointerUp(botao, { pointerId: 1 });
expect(c.definirAtirar).toHaveBeenLastCalledWith(true);
});
it("não atira sozinho com a faca", () => {
const c = controleFalso();
const { de } = montar(c, { arma: 2, mirando: true });
expect(c.definirAtirar).not.toHaveBeenCalledWith(true);
de({ arma: 0 });
expect(c.definirAtirar).toHaveBeenLastCalledWith(true);
de({ arma: 2 });
expect(c.definirAtirar).toHaveBeenLastCalledWith(false);
});
});
describe("Toque: camada", () => {
it("cobre a tela sem rolagem por gesto e bloqueia o menu de contexto", () => {
const { camada } = montar(controleFalso());
expect(camada.style.touchAction).toBe("none");
expect(fireEvent.contextMenu(camada)).toBe(false);
});
});