Files
regnum/client/test/unit/hudUtils.test.js
T
Kevin L'Hereec 11cba0467b feat: écran de fin de partie + tests unitaires client et E2E Playwright
- Fix: UIScene n'était jamais lancée (active: false, jamais scene.launch)
  donc l'event 'game-over' du serveur n'était jamais affiché — la partie
  semblait ne pas avoir de fin. Remplacé par un panneau Vue dans GameView
  (vainqueur, classement trié, bouton Quitter via vue-router). UIScene.js
  supprimée (code mort).
- Extraction de client/src/utils/hudUtils.js (constantes ATTRS/couleurs et
  gaugePercent) depuis GameView.vue pour les rendre testables isolément.
- Tests unitaires client (Vitest) : store Pinia (game.js) et hudUtils
  (24 tests, client/test/unit/).
- Tests d'intégration E2E (Playwright, e2e/) avec de vrais clients
  Socket.io et rendu Phaser réel dans Chromium :
  * game-flow.spec.js : lobby → démarrage → main de 4 cartes → résolution
  * item-shop.spec.js : boutique, bouton désactivé si jauge insuffisante,
    achat retire l'objet pour tous + effet appliqué + affiché sur la table
  * game-over.spec.js : partie complète (12 tours) → panneau de fin
  webServer démarre automatiquement client+serveur ; ajout d'une route
  GET /health côté Express pour permettre à Playwright de détecter un
  serveur déjà démarré.
- README : documentation des 3 niveaux de tests (unitaires serveur,
  unitaires client, intégration E2E) et de la nouvelle arborescence.
2026-08-21 15:27:44 +02:00

64 lines
2.1 KiB
JavaScript

import { describe, it, expect } from 'vitest'
import { ATTRS, ATTR_ICON, ATTR_COLOR, TEAM_CSS, PHASE_LABEL, gaugePercent } from '../../src/utils/hudUtils'
describe('utils/hudUtils', () => {
describe('constantes', () => {
it('ATTRS contient les 4 attributs du jeu', () => {
expect(ATTRS).toEqual(['food', 'war', 'health', 'diplo'])
})
it('ATTR_ICON a une icône pour chaque attribut', () => {
ATTRS.forEach(attr => expect(ATTR_ICON[attr]).toBeTruthy())
})
it('ATTR_COLOR a une couleur pour chaque attribut', () => {
ATTRS.forEach(attr => expect(ATTR_COLOR[attr]).toMatch(/^#[0-9a-f]{6}$/i))
})
it('TEAM_CSS couvre les 4 emplacements d\'équipe possibles (0 à 3, max 4 joueurs)', () => {
expect(Object.keys(TEAM_CSS)).toEqual(['0', '1', '2', '3'])
})
it('PHASE_LABEL couvre toutes les phases de jeu émises par le serveur', () => {
expect(Object.keys(PHASE_LABEL).sort()).toEqual(
['end', 'resolve', 'selecting', 'waiting'].sort()
)
})
})
describe('gaugePercent', () => {
it('retourne 0 pour une valeur de 0', () => {
expect(gaugePercent(0)).toBe(0)
})
it('retourne 100 pour la valeur maximale théorique (6 * 12 = 72)', () => {
expect(gaugePercent(72)).toBe(100)
})
it('calcule un pourcentage proportionnel pour une valeur intermédiaire', () => {
expect(gaugePercent(36)).toBe(50) // 36/72 = 50%
})
it('borne à 100 même si la valeur dépasse le maximum théorique', () => {
expect(gaugePercent(200)).toBe(100)
})
it('ne retourne jamais de pourcentage négatif pour une valeur négative', () => {
expect(gaugePercent(-10)).toBe(0)
})
it('accepte des paramètres maxAttrPerTurn/maxTurns personnalisés', () => {
expect(gaugePercent(5, 5, 10)).toBe(10) // 5 / (5*10) = 10%
})
it('ne divise pas par zéro si max=0', () => {
expect(gaugePercent(5, 0, 12)).toBe(0)
})
it('arrondit au pourcentage entier le plus proche', () => {
// 10/72 = 13.888...% → arrondi à 14
expect(gaugePercent(10)).toBe(14)
})
})
})