a3cb917ec7
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 10s
CI / integration (pull_request) Successful in 17s
CI / ui (pull_request) Successful in 45s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 58s
Review fixes for open-game auto-match: decodeMatchResult dropped the game when matched=false (an open game awaiting an opponent), so the client never navigated into it - decode the game whenever present. The lobby grouped open games (status != 'active') into 'finished'; treat 'open' as in progress in groupGames/isMyTurn and resultBadge. The under-board status bar now reads "Opponent's turn" while the empty opponent seat is to move (instead of the searching placeholder). The New Game rule toggle is shown from the start when a Russian variant is available, so selecting a variant no longer shifts the layout. Regression tests: codec (game decoded with matched=false), lobbysort + result (open is in progress), and the new-game e2e updated. UI-only; no backend or schema change.
84 lines
2.5 KiB
TypeScript
84 lines
2.5 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
import { groupGames, isMyTurn } from './lobbysort';
|
|
import type { GameView, Seat } from './model';
|
|
|
|
const ME = 'me';
|
|
const seat = (s: number, accountId: string): Seat => ({
|
|
seat: s,
|
|
accountId,
|
|
displayName: accountId,
|
|
score: 0,
|
|
hintsUsed: 0,
|
|
isWinner: false,
|
|
});
|
|
|
|
function game(id: string, status: GameView['status'], toMove: number, lastActivityUnix: number): GameView {
|
|
return {
|
|
id,
|
|
variant: 'scrabble_en',
|
|
dictVersion: 'v1',
|
|
status,
|
|
players: 2,
|
|
toMove,
|
|
turnTimeoutSecs: 0,
|
|
multipleWordsPerTurn: true,
|
|
moveCount: 0,
|
|
endReason: '',
|
|
lastActivityUnix,
|
|
seats: [seat(0, ME), seat(1, 'opp')],
|
|
};
|
|
}
|
|
|
|
describe('groupGames', () => {
|
|
it('partitions into your-turn, their-turn and finished', () => {
|
|
const g = groupGames(
|
|
[
|
|
game('a', 'active', 0, 100), // toMove 0 == my seat -> my turn
|
|
game('b', 'active', 1, 100), // their turn
|
|
game('c', 'finished', 0, 100),
|
|
],
|
|
ME,
|
|
);
|
|
expect(g.yourTurn.map((x) => x.id)).toEqual(['a']);
|
|
expect(g.theirTurn.map((x) => x.id)).toEqual(['b']);
|
|
expect(g.finished.map((x) => x.id)).toEqual(['c']);
|
|
});
|
|
|
|
it('orders your-turn oldest-first, the other two newest-first', () => {
|
|
const g = groupGames(
|
|
[
|
|
game('y_new', 'active', 0, 200),
|
|
game('y_old', 'active', 0, 100),
|
|
game('t_new', 'active', 1, 200),
|
|
game('t_old', 'active', 1, 100),
|
|
game('f_new', 'finished', 0, 200),
|
|
game('f_old', 'finished', 0, 100),
|
|
],
|
|
ME,
|
|
);
|
|
expect(g.yourTurn.map((x) => x.id)).toEqual(['y_old', 'y_new']);
|
|
expect(g.theirTurn.map((x) => x.id)).toEqual(['t_new', 't_old']);
|
|
expect(g.finished.map((x) => x.id)).toEqual(['f_new', 'f_old']);
|
|
});
|
|
|
|
it('isMyTurn is false for a finished game even at my seat', () => {
|
|
expect(isMyTurn(game('x', 'finished', 0, 0), ME)).toBe(false);
|
|
expect(isMyTurn(game('x', 'active', 0, 0), ME)).toBe(true);
|
|
expect(isMyTurn(game('x', 'active', 1, 0), ME)).toBe(false);
|
|
});
|
|
|
|
it('treats an open game (awaiting an opponent) as in progress, not finished', () => {
|
|
const g = groupGames(
|
|
[
|
|
game('open_mine', 'open', 0, 100), // my turn while waiting
|
|
game('open_wait', 'open', 1, 100), // the empty seat's turn
|
|
],
|
|
ME,
|
|
);
|
|
expect(g.yourTurn.map((x) => x.id)).toEqual(['open_mine']);
|
|
expect(g.theirTurn.map((x) => x.id)).toEqual(['open_wait']);
|
|
expect(g.finished).toEqual([]);
|
|
expect(isMyTurn(game('x', 'open', 0, 0), ME)).toBe(true);
|
|
});
|
|
});
|