Files
portifolio-evandrodevbr/app/jogo/controle.test.ts
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

244 lines
7.2 KiB
TypeScript

import { fireEvent } from "@testing-library/react";
import { criarControle } from "./controle";
let alvo: HTMLDivElement;
let travaDo: Element | null;
beforeEach(() => {
alvo = document.createElement("div");
document.body.append(alvo);
travaDo = null;
Object.defineProperty(document, "pointerLockElement", {
configurable: true,
get: () => travaDo,
});
});
afterEach(() => {
alvo.remove();
});
function travar() {
travaDo = alvo;
document.dispatchEvent(new Event("pointerlockchange"));
}
function mover(movementX: number, movementY: number) {
const e = new MouseEvent("mousemove");
Object.defineProperty(e, "movementX", { value: movementX });
Object.defineProperty(e, "movementY", { value: movementY });
document.dispatchEvent(e);
}
describe("criarControle: teclado", () => {
it("W e as setas movem; teclas opostas se anulam", () => {
const c = criarControle(alvo);
fireEvent.keyDown(window, { code: "KeyW" });
fireEvent.keyDown(window, { code: "ArrowRight" });
expect(c.ler().mover).toEqual([1, 1]);
fireEvent.keyDown(window, { code: "KeyS" });
fireEvent.keyDown(window, { code: "KeyA" });
expect(c.ler().mover).toEqual([0, 0]);
fireEvent.keyUp(window, { code: "KeyS" });
fireEvent.keyUp(window, { code: "KeyA" });
expect(c.ler().mover).toEqual([1, 1]);
c.descartar();
});
it("soma o direcional de toque ao teclado", () => {
const c = criarControle(alvo);
c.definirMover(-1, 0.5);
fireEvent.keyDown(window, { code: "KeyD" });
expect(c.ler().mover).toEqual([0, 0.5]);
c.descartar();
});
it("1, 2 e 3 escolhem a arma", () => {
const c = criarControle(alvo);
expect(c.ler().arma).toBe(0);
fireEvent.keyDown(window, { code: "Digit3" });
expect(c.ler().arma).toBe(2);
fireEvent.keyDown(window, { code: "Digit2" });
expect(c.ler().arma).toBe(1);
fireEvent.keyDown(window, { code: "Digit1" });
expect(c.ler().arma).toBe(0);
c.descartar();
});
it("a roda troca para a próxima e para a anterior, em volta", () => {
const c = criarControle(alvo);
fireEvent.wheel(window, { deltaY: 100 });
expect(c.ler().arma).toBe(1);
fireEvent.wheel(window, { deltaY: -100 });
fireEvent.wheel(window, { deltaY: -100 });
expect(c.ler().arma).toBe(2);
fireEvent.wheel(window, { deltaY: 100 });
expect(c.ler().arma).toBe(0);
c.descartar();
});
it("perder o foco da janela solta as teclas", () => {
const c = criarControle(alvo);
fireEvent.keyDown(window, { code: "KeyW" });
fireEvent.blur(window);
expect(c.ler().mover).toEqual([0, 0]);
c.descartar();
});
it("ignora tecla com o foco num campo de texto ou botão", () => {
const c = criarControle(alvo);
const campo = document.createElement("input");
const botao = document.createElement("button");
document.body.append(campo, botao);
fireEvent.keyDown(campo, { code: "KeyW" });
fireEvent.keyDown(botao, { code: "Digit3" });
const entrada = c.ler();
expect(entrada.mover).toEqual([0, 0]);
expect(entrada.arma).toBe(0);
campo.remove();
botao.remove();
c.descartar();
});
});
describe("criarControle: mouse", () => {
it("clicar no alvo pede a trava do ponteiro", () => {
alvo.requestPointerLock = jest.fn();
const c = criarControle(alvo);
fireEvent.click(alvo);
expect(alvo.requestPointerLock).toHaveBeenCalledTimes(1);
c.descartar();
});
it("clicar não falha onde não há trava do ponteiro", () => {
const c = criarControle(alvo);
expect(() => fireEvent.click(alvo)).not.toThrow();
c.descartar();
});
it("avisa quando a trava muda", () => {
const aoMudarTrava = jest.fn();
const c = criarControle(alvo, { aoMudarTrava });
travar();
travaDo = null;
document.dispatchEvent(new Event("pointerlockchange"));
expect(aoMudarTrava.mock.calls).toEqual([[true], [false]]);
c.descartar();
});
it("sem a trava, o mouse não gira nem atira", () => {
const c = criarControle(alvo);
mover(100, 100);
fireEvent.mouseDown(document, { button: 0 });
const entrada = c.ler();
expect(entrada.olhar).toEqual([0, 0]);
expect(entrada.atirar).toBe(false);
c.descartar();
});
it("com a trava, soma o giro e o ler o zera", () => {
const c = criarControle(alvo);
travar();
mover(100, -50);
mover(100, 0);
const [rumo, inclinacao] = c.ler().olhar;
expect(rumo).toBeCloseTo(-200 * 0.0022);
expect(inclinacao).toBeCloseTo(50 * 0.0022);
expect(c.ler().olhar).toEqual([0, 0]);
c.descartar();
});
it("botão esquerdo pressionado atira; outro botão e soltar não", () => {
const c = criarControle(alvo);
travar();
fireEvent.mouseDown(document, { button: 2 });
expect(c.ler().atirar).toBe(false);
fireEvent.mouseDown(document, { button: 0 });
expect(c.ler().atirar).toBe(true);
fireEvent.mouseUp(document, { button: 2 });
expect(c.ler().atirar).toBe(true);
fireEvent.mouseUp(document, { button: 0 });
expect(c.ler().atirar).toBe(false);
c.descartar();
});
it("clique inteiro entre duas leituras ainda dá um tiro, e só um", () => {
const c = criarControle(alvo);
travar();
fireEvent.mouseDown(document, { button: 0 });
fireEvent.mouseUp(document, { button: 0 });
expect(c.ler().atirar).toBe(true);
expect(c.ler().atirar).toBe(false);
c.descartar();
});
});
describe("criarControle: toque, soltar e descartar", () => {
it("junta o giro, o tiro e a arma vindos do toque", () => {
const c = criarControle(alvo);
c.somarOlhar(0.1, 0.2);
c.somarOlhar(0.1, 0);
c.definirAtirar(true);
c.definirArma(2);
expect(c.ler()).toEqual({
mover: [0, 0],
olhar: [0.2, 0.2],
atirar: true,
arma: 2,
});
c.descartar();
});
it("toque no botão de tiro entre duas leituras ainda dá um tiro, e só um", () => {
const c = criarControle(alvo);
c.definirAtirar(true);
c.definirAtirar(false);
expect(c.ler().atirar).toBe(true);
expect(c.ler().atirar).toBe(false);
c.descartar();
});
it("soltar zera movimento, tiro e giro, e mantém a arma", () => {
const c = criarControle(alvo);
travar();
fireEvent.keyDown(window, { code: "KeyW" });
fireEvent.mouseDown(document, { button: 0 });
c.definirMover(1, 1);
c.definirAtirar(true);
c.somarOlhar(1, 1);
c.definirArma(1);
c.soltar();
expect(c.ler()).toEqual({
mover: [0, 0],
olhar: [0, 0],
atirar: false,
arma: 1,
});
c.descartar();
});
it("descartar remove todos os ouvintes", () => {
alvo.requestPointerLock = jest.fn();
const aoMudarTrava = jest.fn();
const c = criarControle(alvo, { aoMudarTrava });
travar();
aoMudarTrava.mockClear();
c.descartar();
fireEvent.keyDown(window, { code: "KeyW" });
fireEvent.keyDown(window, { code: "Digit3" });
fireEvent.wheel(window, { deltaY: 100 });
fireEvent.mouseDown(document, { button: 0 });
mover(100, 100);
fireEvent.click(alvo);
document.dispatchEvent(new Event("pointerlockchange"));
expect(c.ler()).toEqual({
mover: [0, 0],
olhar: [0, 0],
atirar: false,
arma: 0,
});
expect(alvo.requestPointerLock).not.toHaveBeenCalled();
expect(aoMudarTrava).not.toHaveBeenCalled();
});
});