assert(body[0].reason === "the new rack is not at the right size", "oversized rack should explain size mismatch");
}
+/* A new player can join a game that already has state and players. */
+async function testSecondPlayerJoinsStartedGame() {
+ const firstPlayer = randomPlayer("started-a");
+ const secondPlayer = randomPlayer("started-b");
+
+ const join = await postJson({playerName: firstPlayer, cmds: [{cmd: "joinGame"}]});
+ const joinBody = JSON.parse(join.body);
+ const gameNumber = joinBody[0].gameNumber;
+
+ await postJson({
+ playerName: firstPlayer,
+ gameNumber,
+ cmds: [{cmd: "moveLetter", from: "bag", to: "rack", indexTo: 0}]
+ });
+
+ await postJson({
+ playerName: firstPlayer,
+ gameNumber,
+ cmds: [{cmd: "moveLetter", from: "rack", indexFrom: 0, to: "board", indexTo: 0}]
+ });
+
+ await postJson({
+ playerName: firstPlayer,
+ gameNumber,
+ cmds: [{cmd: "score", player: firstPlayer, score: 17}]
+ });
+
+ const secondJoin = await postJson({playerName: secondPlayer, gameNumber, cmds: [{cmd: "joinGame"}]});
+ const secondJoinBody = JSON.parse(secondJoin.body);
+ const state = secondJoinBody[0];
+
+ assert(state.error === 0, "second player joinGame should succeed on an existing game");
+ assert(state.gameNumber === gameNumber, "second player should join the existing game number");
+ assert(Array.isArray(state.rack), "second player should receive a rack array");
+ assert(Array.isArray(state.board), "second player should receive the current board");
+ assert(state.board[0] !== "", "second player should see letters already placed on the board");
+ assert(state.remainingLetters >= 0, "second player should receive the remaining bag size");
+ assert(state.chatHistory !== undefined, "second player should receive chat history information");
+
+ const firstPlayerState = await postJson({playerName: firstPlayer, gameNumber, cmds: [{cmd: "joinGame"}]});
+ const firstPlayerStateBody = JSON.parse(firstPlayerState.body)[0];
+ assert(firstPlayerStateBody.board[0] === state.board[0], "existing board state should be shared across players");
+}
+
/* A player can leave and later rejoin the same game. */
async function testLeaveGameRemovesPlayer() {
const gameNumber = `leave-${Date.now()}-${Math.floor(Math.random() * 1e6)}`;
testMoveValidation,
testChangePlayerNameValidation,
testSetRackValidation,
+ testSecondPlayerJoinsStartedGame,
testLeaveGameRemovesPlayer,
testChatTruncation,
testChatHistoryRollsOver,