package game import ( "slices" "testing" "time" "github.com/google/uuid" "scrabble/backend/internal/engine" "scrabble/backend/internal/notify" ) // recordingPublisher captures every published intent for assertions. type recordingPublisher struct{ intents []notify.Intent } func (p *recordingPublisher) Publish(in ...notify.Intent) { p.intents = append(p.intents, in...) } // TestEmitMoveNotifiesActor checks a committed move sends opponent_moved to every // seat — including the actor's own account, so the mover's other devices refresh — // and your_turn only to the next mover. func TestEmitMoveNotifiesActor(t *testing.T) { actor, opp := uuid.New(), uuid.New() pub := &recordingPublisher{} svc := &Service{pub: pub} g := Game{ ID: uuid.New(), Status: StatusActive, ToMove: 1, TurnStartedAt: time.Now(), TurnTimeout: time.Hour, Seats: []Seat{{Seat: 0, AccountID: actor}, {Seat: 1, AccountID: opp}}, } svc.emitMove(g, engine.MoveRecord{Player: 0, Action: engine.ActionPlay, Score: 10, Total: 10}) kinds := map[uuid.UUID][]string{} for _, in := range pub.intents { kinds[in.UserID] = append(kinds[in.UserID], in.Kind) } if !slices.Contains(kinds[actor], notify.KindOpponentMoved) { t.Errorf("actor should get opponent_moved, got %v", kinds[actor]) } if !slices.Contains(kinds[opp], notify.KindOpponentMoved) { t.Errorf("opponent should get opponent_moved, got %v", kinds[opp]) } if !slices.Contains(kinds[opp], notify.KindYourTurn) { t.Errorf("next mover should get your_turn, got %v", kinds[opp]) } if slices.Contains(kinds[actor], notify.KindYourTurn) { t.Errorf("actor is not next to move, should not get your_turn") } }