From 011bbde8407be172753341f9c95be29acd72b415 Mon Sep 17 00:00:00 2001 From: Asger Geel Weirsoee Date: Sun, 1 Mar 2026 20:10:50 +0000 Subject: [PATCH] fix(spa): keep scoreboard phase in derived gameplay state --- .../src/app/gameplay-phase-machine.spec.ts | 96 +++++++++++++++++++ frontend/src/spa/gameplay-phase-machine.ts | 2 +- 2 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 frontend/angular/src/app/gameplay-phase-machine.spec.ts diff --git a/frontend/angular/src/app/gameplay-phase-machine.spec.ts b/frontend/angular/src/app/gameplay-phase-machine.spec.ts new file mode 100644 index 0000000..fe4c709 --- /dev/null +++ b/frontend/angular/src/app/gameplay-phase-machine.spec.ts @@ -0,0 +1,96 @@ +import { describe, expect, it } from 'vitest'; + +import { deriveGameplayPhase, transitionGameplayPhase } from '../../../src/spa/gameplay-phase-machine'; + +describe('gameplay phase machine sync guards', () => { + it('keeps explicit scoreboard status as scoreboard phase', () => { + const phase = deriveGameplayPhase({ + session: { + code: 'ABCD12', + status: 'scoreboard', + host_id: 1, + current_round: 1, + players_count: 2, + }, + round_question: null, + players: [], + phase_view_model: { + status: 'scoreboard', + round_number: 1, + players_count: 2, + constraints: { + min_players_to_start: 2, + max_players_mvp: 8, + min_players_reached: true, + max_players_allowed: true, + }, + host: { + can_start_round: false, + can_show_question: false, + can_mix_answers: false, + can_calculate_scores: false, + can_reveal_scoreboard: false, + can_start_next_round: true, + can_finish_game: true, + }, + player: { + can_join: false, + can_submit_lie: false, + can_submit_guess: false, + can_view_final_result: false, + }, + }, + }); + + expect(phase).toBe('scoreboard'); + }); + + it('maps finished status to scoreboard phase fallback', () => { + const phase = deriveGameplayPhase({ + session: { + code: 'ABCD12', + status: 'finished', + host_id: 1, + current_round: 1, + players_count: 2, + }, + round_question: null, + players: [], + phase_view_model: { + status: 'finished', + round_number: 1, + players_count: 2, + constraints: { + min_players_to_start: 2, + max_players_mvp: 8, + min_players_reached: true, + max_players_allowed: true, + }, + host: { + can_start_round: false, + can_show_question: false, + can_mix_answers: false, + can_calculate_scores: false, + can_reveal_scoreboard: false, + can_start_next_round: false, + can_finish_game: false, + }, + player: { + can_join: false, + can_submit_lie: false, + can_submit_guess: false, + can_view_final_result: true, + }, + }, + }); + + expect(phase).toBe('scoreboard'); + }); + + it('transitions reveal -> scoreboard on SCOREBOARD_READY', () => { + expect(transitionGameplayPhase('reveal', 'SCOREBOARD_READY')).toEqual({ + phase: 'scoreboard', + changed: true, + }); + }); +}); diff --git a/frontend/src/spa/gameplay-phase-machine.ts b/frontend/src/spa/gameplay-phase-machine.ts index a2c24a1..f0ba252 100644 --- a/frontend/src/spa/gameplay-phase-machine.ts +++ b/frontend/src/spa/gameplay-phase-machine.ts @@ -46,7 +46,7 @@ export function deriveGameplayPhase(session: SessionDetailResponse | null): Game return null; } - if (status === 'lie' || status === 'guess' || status === 'reveal') { + if (status === 'lie' || status === 'guess' || status === 'reveal' || status === 'scoreboard') { return status; }