From b66d0b8c37f50adb60100743aa03efb6012dbbc6 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 29 Sep 2026 19:31:55 +0000 Subject: [PATCH] golf: crown winners from the winners list only golf.smithy's GameEnded requires winners, so the fallback to comparing the display string is dead. Pinned with a test: winner alone crowns nobody. Closes #231 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01FMAEXAt4rbVe5dSsKvvws4 --- src/apps/golf/components/GolfTable.tsx | 7 ++----- .../golf/components/__tests__/GolfTable.test.tsx | 12 ++++++++++++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/apps/golf/components/GolfTable.tsx b/src/apps/golf/components/GolfTable.tsx index e4829bb7..e3c03cab 100644 --- a/src/apps/golf/components/GolfTable.tsx +++ b/src/apps/golf/components/GolfTable.tsx @@ -29,11 +29,8 @@ const GolfTable = ({ playerId, connected, view, table, shareUrl = null }: GolfTa const acting = isMyTurn && connected const inPlay = view.gamePhase === 'playing' || view.gamePhase === 'knocked' - const isWinner = (player: Player | undefined) => { - if (player === undefined || ended === null) return false - if (ended.winners.length > 0) return ended.winners.includes(player.id) - return player.id === ended.winner - } + const isWinner = (player: Player | undefined) => + player !== undefined && ended !== null && ended.winners.includes(player.id) useEffect(() => { if (view.gamePhase === 'ended') { diff --git a/src/apps/golf/components/__tests__/GolfTable.test.tsx b/src/apps/golf/components/__tests__/GolfTable.test.tsx index 782f4cb8..a19abb96 100644 --- a/src/apps/golf/components/__tests__/GolfTable.test.tsx +++ b/src/apps/golf/components/__tests__/GolfTable.test.tsx @@ -147,6 +147,18 @@ describe('GolfTable', () => { expect(screen.getAllByText('👑')).toHaveLength(2) }) + // The contract requires winners (golf.smithy GameEnded); winner is only + // display text, so it never crowns anyone on its own. + it('only the winners list crowns; the display string does not', () => { + vi.useFakeTimers() + const t = table({ ended: { winner: 'alice', winners: [] } }) + render() + expect(screen.queryByText('You won!')).toBeNull() + expect(screen.getByText('alice wins!')).toBeTruthy() + act(() => vi.advanceTimersByTime(3000)) + expect(screen.queryByText('👑')).toBeNull() + }) + it('an ended table with no result yet is just over', () => { render() expect(screen.getByText('Game over')).toBeTruthy()