import { describe, it, expect } from 'vitest' import { eventDrawButtonPosition, eventHandGeometry, eventCardPosition, EVENT_CARD_SCALE } from '../../src/game/objects/eventHandLayout' import { CARD_W, CARD_H } from '../../src/game/objects/cardLayout' // Dimensions de canvas typiques utilisées dans les tests (cohérentes avec // GameFactory.js : width = innerWidth, height = innerHeight - 60). const CANVAS_W = 1920 const CANVAS_H = 1080 describe('game/objects/eventHandLayout', () => { describe('EVENT_CARD_SCALE', () => { it('reste suffisamment proche de 1 pour garder le texte lisible (pas 0.55 comme l\'ancien placement)', () => { expect(EVENT_CARD_SCALE).toBeGreaterThanOrEqual(0.7) expect(EVENT_CARD_SCALE).toBeLessThanOrEqual(1) }) }) describe('eventDrawButtonPosition', () => { it('positionne le bouton dans le quart bas-droit du canvas', () => { const { x, y } = eventDrawButtonPosition(CANVAS_W, CANVAS_H) expect(x).toBeGreaterThan(CANVAS_W / 2) expect(y).toBeGreaterThan(CANVAS_H / 2) }) it('reste entièrement à l\'intérieur du canvas (ne déborde jamais à droite ni en bas)', () => { const buttonWidth = 190 const buttonHeight = 30 const { x, y } = eventDrawButtonPosition(CANVAS_W, CANVAS_H, buttonWidth) expect(x + buttonWidth / 2).toBeLessThanOrEqual(CANVAS_W) expect(x - buttonWidth / 2).toBeGreaterThanOrEqual(0) expect(y + buttonHeight / 2).toBeLessThanOrEqual(CANVAS_H) }) it('est positionné strictement au-dessus de la main de cartes événement (pas de chevauchement)', () => { const buttonHeight = 30 const { y: btnY } = eventDrawButtonPosition(CANVAS_W, CANVAS_H) const { y: handY } = eventHandGeometry(CANVAS_W, CANVAS_H, 1) const cardH = CARD_H * EVENT_CARD_SCALE const buttonBottom = btnY + buttonHeight / 2 const handTop = handY - cardH / 2 expect(buttonBottom).toBeLessThanOrEqual(handTop) }) it('reste bien à droite du bouton "CONFIRMER MA CARTE" (centré, ~280px de large) — pas de chevauchement', () => { const confirmButtonWidth = 280 const confirmButtonRightEdge = CANVAS_W / 2 + confirmButtonWidth / 2 const drawButtonWidth = 190 const { x } = eventDrawButtonPosition(CANVAS_W, CANVAS_H, drawButtonWidth) const drawButtonLeftEdge = x - drawButtonWidth / 2 // Régression du bug signalé : l'ancien placement (x = width/2 + 210, // même Y que le bouton confirmer) chevauchait physiquement son bord // droit de ~25px. Le nouveau placement bas-droite doit être // verticalement séparé (voir test précédent) ET ne pas non plus se // chevaucher horizontalement s'ils finissaient à la même hauteur. expect(drawButtonLeftEdge).toBeGreaterThanOrEqual(confirmButtonRightEdge) }) it('accepte une largeur de bouton personnalisée', () => { const narrow = eventDrawButtonPosition(CANVAS_W, CANVAS_H, 100) const wide = eventDrawButtonPosition(CANVAS_W, CANVAS_H, 300) // Un bouton plus large doit être centré plus loin du bord droit expect(narrow.x).toBeGreaterThan(wide.x) }) }) describe('eventHandGeometry', () => { it('positionne la main dans la moitié basse du canvas', () => { const { y } = eventHandGeometry(CANVAS_W, CANVAS_H, 2) expect(y).toBeGreaterThan(CANVAS_H / 2) }) it('la dernière carte est ancrée sur le bord droit du canvas (avec la marge)', () => { const { startX, spacing, scale } = eventHandGeometry(CANVAS_W, CANVAS_H, 2) const cardW = CARD_W * scale const lastCardCenterX = startX + spacing // index 1 = dernière carte pour cardCount=2 const lastCardRightEdge = lastCardCenterX + cardW / 2 expect(lastCardRightEdge).toBeLessThanOrEqual(CANVAS_W) expect(lastCardRightEdge).toBeGreaterThan(CANVAS_W - 40) // proche du bord (marge ~20px) }) it('avec 1 carte, elle est ancrée sur le bord droit (pas de décalage vers la gauche)', () => { const { startX } = eventHandGeometry(CANVAS_W, CANVAS_H, 1) const { startX: startXTwo } = eventHandGeometry(CANVAS_W, CANVAS_H, 2) // La position de la DERNIÈRE carte doit être identique quel que soit // le nombre de cartes (ancrage à droite stable) — avec 1 carte, // startX doit correspondre à la position de la dernière carte du cas à 2. const { spacing } = eventHandGeometry(CANVAS_W, CANVAS_H, 2) expect(startX).toBeCloseTo(startXTwo + spacing, 5) }) it('gère cardCount=0 sans produire de position invalide (NaN/Infinity)', () => { const { startX, y, spacing } = eventHandGeometry(CANVAS_W, CANVAS_H, 0) expect(Number.isFinite(startX)).toBe(true) expect(Number.isFinite(y)).toBe(true) expect(Number.isFinite(spacing)).toBe(true) }) it('l\'espacement entre cartes est toujours positif et couvre au moins la largeur d\'une carte', () => { const { spacing, scale } = eventHandGeometry(CANVAS_W, CANVAS_H, 2) expect(spacing).toBeGreaterThan(CARD_W * scale) }) it('les 2 cartes ne se chevauchent jamais (distance entre centres >= largeur d\'une carte)', () => { const { spacing, scale } = eventHandGeometry(CANVAS_W, CANVAS_H, 2) const cardW = CARD_W * scale expect(spacing).toBeGreaterThanOrEqual(cardW) }) it('reste entièrement dans le canvas sur une petite résolution (1280x720)', () => { const { startX, y, spacing, scale } = eventHandGeometry(1280, 720, 2) const cardW = CARD_W * scale const cardH = CARD_H * scale const firstCardLeftEdge = startX - cardW / 2 const lastCardRightEdge = startX + spacing + cardW / 2 expect(firstCardLeftEdge).toBeGreaterThanOrEqual(0) expect(lastCardRightEdge).toBeLessThanOrEqual(1280) expect(y + cardH / 2).toBeLessThanOrEqual(720) expect(y - cardH / 2).toBeGreaterThanOrEqual(0) }) }) describe('eventCardPosition', () => { it('retourne la même position que eventHandGeometry pour un index donné', () => { const { startX, y, spacing } = eventHandGeometry(CANVAS_W, CANVAS_H, 2) const pos0 = eventCardPosition(CANVAS_W, CANVAS_H, 2, 0) const pos1 = eventCardPosition(CANVAS_W, CANVAS_H, 2, 1) expect(pos0).toEqual({ x: startX, y }) expect(pos1).toEqual({ x: startX + spacing, y }) }) it('les positions de 2 cartes sont distinctes', () => { const pos0 = eventCardPosition(CANVAS_W, CANVAS_H, 2, 0) const pos1 = eventCardPosition(CANVAS_W, CANVAS_H, 2, 1) expect(pos0.x).not.toBe(pos1.x) }) }) describe('non-régression : séparation avec la légende d\'attributs (bas-gauche)', () => { it('la zone événement (bas-droite) ne recouvre pas la zone légende (bas-gauche, x proche de 0)', () => { const { startX, scale } = eventHandGeometry(CANVAS_W, CANVAS_H, 2) const cardW = CARD_W * scale const firstCardLeftEdge = startX - cardW / 2 // La légende occupe le coin bas-gauche (x ancré à 10px du bord gauche, // largeur de texte ~180px max) — la zone événement doit rester dans // la moitié droite du canvas pour ne jamais s'en approcher. expect(firstCardLeftEdge).toBeGreaterThan(CANVAS_W / 2) }) }) })