- 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.
163 lines
5.5 KiB
JavaScript
163 lines
5.5 KiB
JavaScript
import { describe, it, expect, beforeEach } from 'vitest'
|
|
import { setActivePinia, createPinia } from 'pinia'
|
|
import { useGameStore } from '../../src/stores/game'
|
|
|
|
describe('stores/game (Pinia)', () => {
|
|
beforeEach(() => {
|
|
setActivePinia(createPinia())
|
|
})
|
|
|
|
it('a un état initial vide/par défaut', () => {
|
|
const store = useGameStore()
|
|
expect(store.playerName).toBe('')
|
|
expect(store.players).toEqual([])
|
|
expect(store.currentTurn).toBe(0)
|
|
expect(store.maxTurns).toBe(12)
|
|
expect(store.phase).toBe('idle')
|
|
expect(store.hand).toEqual([])
|
|
expect(store.myTeamIndex).toBe(0)
|
|
expect(store.selectedCard).toBeNull()
|
|
expect(store.myItems).toEqual([])
|
|
expect(store.pendingBuyItemId).toBeNull()
|
|
expect(store.availableItems).toEqual([])
|
|
expect(store.firstPlayerName).toBeNull()
|
|
expect(store.gameOverResults).toBeNull()
|
|
})
|
|
|
|
it('setPlayer met à jour playerName', () => {
|
|
const store = useGameStore()
|
|
store.setPlayer('Alice')
|
|
expect(store.playerName).toBe('Alice')
|
|
})
|
|
|
|
describe('updateState', () => {
|
|
it('met à jour tous les champs de base depuis un game-state serveur', () => {
|
|
const store = useGameStore()
|
|
store.updateState({
|
|
players: [{ name: 'Alice', score: 5 }],
|
|
currentTurn: 3,
|
|
maxTurns: 12,
|
|
phase: 'selecting',
|
|
hand: [{ id: 'queen' }],
|
|
myTeamIndex: 1
|
|
})
|
|
|
|
expect(store.players).toEqual([{ name: 'Alice', score: 5 }])
|
|
expect(store.currentTurn).toBe(3)
|
|
expect(store.maxTurns).toBe(12)
|
|
expect(store.phase).toBe('selecting')
|
|
expect(store.hand).toEqual([{ id: 'queen' }])
|
|
expect(store.myTeamIndex).toBe(1)
|
|
})
|
|
|
|
it('retombe sur les valeurs par défaut si les champs sont absents (sauf hand/items qui restent inchangés)', () => {
|
|
const store = useGameStore()
|
|
store.updateState({})
|
|
|
|
expect(store.players).toEqual([])
|
|
expect(store.currentTurn).toBe(0)
|
|
expect(store.maxTurns).toBe(12)
|
|
expect(store.phase).toBe('idle')
|
|
expect(store.myTeamIndex).toBe(0)
|
|
})
|
|
|
|
it('ne touche PAS à hand si state.hand est undefined (évite d\'effacer la main en cours)', () => {
|
|
const store = useGameStore()
|
|
store.updateState({ hand: [{ id: 'prince' }] })
|
|
store.updateState({ phase: 'waiting' }) // pas de champ hand cette fois
|
|
|
|
expect(store.hand).toEqual([{ id: 'prince' }])
|
|
})
|
|
|
|
it('met à jour les champs liés aux objets uniquement s\'ils sont fournis', () => {
|
|
const store = useGameStore()
|
|
store.updateState({
|
|
myItems: ['trebuchet'],
|
|
pendingBuyItemId: 'plow',
|
|
availableItems: ['medkit', 'royal_seal'],
|
|
firstPlayerName: 'Bob'
|
|
})
|
|
|
|
expect(store.myItems).toEqual(['trebuchet'])
|
|
expect(store.pendingBuyItemId).toBe('plow')
|
|
expect(store.availableItems).toEqual(['medkit', 'royal_seal'])
|
|
expect(store.firstPlayerName).toBe('Bob')
|
|
|
|
// Un second appel sans ces champs ne doit pas les réinitialiser
|
|
store.updateState({ phase: 'resolve' })
|
|
expect(store.myItems).toEqual(['trebuchet'])
|
|
expect(store.pendingBuyItemId).toBe('plow')
|
|
})
|
|
|
|
it('accepte explicitement pendingBuyItemId=null (achat annulé/résolu) sans le confondre avec "absent"', () => {
|
|
const store = useGameStore()
|
|
store.updateState({ pendingBuyItemId: 'plow' })
|
|
store.updateState({ pendingBuyItemId: null })
|
|
expect(store.pendingBuyItemId).toBeNull()
|
|
})
|
|
})
|
|
|
|
describe('selectCard / clearSelection', () => {
|
|
it('selectCard définit la carte sélectionnée', () => {
|
|
const store = useGameStore()
|
|
const card = { id: 'knight', war: 5 }
|
|
store.selectCard(card)
|
|
expect(store.selectedCard).toEqual(card)
|
|
})
|
|
|
|
it('clearSelection remet selectedCard à null', () => {
|
|
const store = useGameStore()
|
|
store.selectCard({ id: 'knight' })
|
|
store.clearSelection()
|
|
expect(store.selectedCard).toBeNull()
|
|
})
|
|
})
|
|
|
|
describe('setGameOver', () => {
|
|
it('définit gameOverResults avec les résultats fournis', () => {
|
|
const store = useGameStore()
|
|
const results = [{ name: 'Alice', score: 42 }, { name: 'Bob', score: 30 }]
|
|
store.setGameOver(results)
|
|
expect(store.gameOverResults).toEqual(results)
|
|
})
|
|
})
|
|
|
|
describe('reset', () => {
|
|
it('remet tout l\'état à ses valeurs par défaut', () => {
|
|
const store = useGameStore()
|
|
store.setPlayer('Alice')
|
|
store.updateState({
|
|
players: [{ name: 'Alice' }],
|
|
currentTurn: 5,
|
|
phase: 'resolve',
|
|
hand: [{ id: 'queen' }],
|
|
myTeamIndex: 2,
|
|
myItems: ['trebuchet'],
|
|
pendingBuyItemId: 'plow',
|
|
availableItems: ['medkit'],
|
|
firstPlayerName: 'Bob'
|
|
})
|
|
store.selectCard({ id: 'queen' })
|
|
store.setGameOver([{ name: 'Alice', score: 10 }])
|
|
|
|
store.reset()
|
|
|
|
expect(store.players).toEqual([])
|
|
expect(store.currentTurn).toBe(0)
|
|
expect(store.maxTurns).toBe(12)
|
|
expect(store.phase).toBe('idle')
|
|
expect(store.hand).toEqual([])
|
|
expect(store.myTeamIndex).toBe(0)
|
|
expect(store.selectedCard).toBeNull()
|
|
expect(store.myItems).toEqual([])
|
|
expect(store.pendingBuyItemId).toBeNull()
|
|
expect(store.availableItems).toEqual([])
|
|
expect(store.firstPlayerName).toBeNull()
|
|
expect(store.gameOverResults).toBeNull()
|
|
// playerName n'est PAS réinitialisé par reset() (comportement existant :
|
|
// le nom du joueur est conservé pour rejouer une partie sans le re-saisir)
|
|
expect(store.playerName).toBe('Alice')
|
|
})
|
|
})
|
|
})
|