Skip to content

Testes/Persistência: extrair mapeamento puro de persistMatch (results→matches/scores) e cobrir com Vitest #50

Closed

Description

@caioross

Contexto

A frota já cobriu a escrita do resultado (sanitizeResults, #31) e está extraindo as métricas puras (#32, em revisão). Falta a última fronteira que a spec do chapêu aponta: a persistência que alimenta o leaderboard global.

persistMatch mapeia os results já sanitizados → linhas de matches e scores (src/app/api/rooms/[code]/route.ts:103-141). O mapeamento tem lógica real e hoje zero teste:

  • ordena por place com fallback || 99 e elege winner = ranked[0];
  • winner_wpm: winner ? Math.round(winner.wpm) || 0 : null — o || 0 transforma Math.round(0)/NaN em 0 (comportamento sutil que merece contrato);
  • place: r.place || null (0 vira null), finished: !!r.finished;
  • guarda de vazio: if (!results.length) return (não escreve matches órfã).

Ela é async e privada, e só é exercitada atrás de uma corrida completa — impossível de proteger sem extrair a parte pura.

Escopo

  1. Extrair de persistMatch a lógica pura e determinística de montagem das linhas para src/lib/room.ts (ao lado de sanitizeResults), p.ex.:
    • buildMatchRow(room: RoomRow, results: ResultRow[]): MatchInsert | null (null quando results vazio);
    • buildScoreRows(matchId, room, results): ScoreInsert[].
  2. persistMatch passa a ser um wrapper fino que chama os builders e faz apenas os dois insert no Supabase — sem lógica de mapeamento inline.
  3. Suite Vitest src/lib/room.test.ts (ou arquivo novo) cobrindo os builders.

Acceptance criteria (verificáveis)

  • pnpm test verde com casos que provam: winner = menor place (com empate/place ausente caindo no fallback), winner_wpm/wpm/accuracy/errors arredondados e nunca NaN, place 0/negativo → null, finished coerção booleana, e results vazio → buildMatchRow retorna null e nenhuma linha de score.
  • persistMatch não contém mais aritmética de mapeamento inline (só orquestra os builders + insert).
  • pnpm typecheck e pnpm build verdes; node scripts/validate-persistence.mjs verde.
  • Nenhuma mudança de comportamento observável em produção (refactor puro + testes).

Dica de abordagem

Espelhe o padrão do #32/#31: extrair função pura → testar contrato. O fixture de RoomRow/ResultRow já existe no topo de room.test.ts (legit()/ROOM) — reutilize. Não precisa de fake do Supabase para os builders (são puros); o wrapper continua best-effort com o try/catch atual.

Activity

  1. added
    P2Prioridade normal
    area:multiplayerSalas, Realtime, presença, leaderboard, persistência
    em-resolucaoClaim: um Resolvedor está trabalhando nisto
    and removed
    em-resolucaoClaim: um Resolvedor está trabalhando nisto
    on Jul 20, 2026
  2. caioross commented on Jul 22, 2026

    @caioross
    OwnerAuthor

    Resolvida na PR #55: buildMatchRow/buildScoreRows extraídos para src/lib/room.ts (puros, finished_at por parâmetro), persistMatch virou wrapper fino e a suite subiu de 20 → 36 testes cobrindo vencedor/arredondamentos/NaN/place/vazio. Refactor puro, sem mudança de comportamento. Gate verde: typecheck + build + test + validate-persistence (33/33) + validate-metrics (37/37).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Prioridade normalarea:multiplayerSalas, Realtime, presença, leaderboard, persistência

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions