Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion __test__/backend/routes/socket/game-schemas.schema.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { assassinateSchema } from "../../../../routes/socket/game/assassination.schema";
import { selectChancellorSchema } from "../../../../routes/socket/game/election-util.schema";
import { voteSchema, policySelectionSchema } from "../../../../routes/socket/game/election.schema";
import { voteSchema, policySelectionSchema, tdOutSchema } from "../../../../routes/socket/game/election.schema";
import { playerIndexSchema, voteSchema as ppVoteSchema } from "../../../../routes/socket/game/policy-powers.schema";

// Each game handler used to deref a wire field directly (seatedPlayers[data.playerIndex],
Expand Down Expand Up @@ -66,3 +66,17 @@ describe("policySelectionSchema (integer selection field)", () => {
expect(policySelectionSchema.safeParse({ uid: "g" }).success).toBe(false);
});
});

describe("tdOutSchema (boolean tdOutStatus field)", () => {
it("accepts boolean TD-out toggles from the client", () => {
expect(tdOutSchema.safeParse({ tdOutStatus: true, uid: "g" }).success).toBe(true);
expect(tdOutSchema.safeParse({ tdOutStatus: false, uid: "g" }).success).toBe(true);
});

it("rejects non-boolean / missing tdOutStatus and non-object data", () => {
expect(tdOutSchema.safeParse({ tdOutStatus: "yes" }).success).toBe(false);
expect(tdOutSchema.safeParse({ tdOutStatus: 1 }).success).toBe(false);
expect(tdOutSchema.safeParse({ uid: "g" }).success).toBe(false);
expect(tdOutSchema.safeParse(undefined).success).toBe(false);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ describe("every schema-guarded socket handler has its schema wired", () => {
// game/ handlers
it.each([
["selectVoting", () => election.selectVoting(P, game(), D, null, false)],
["selectTdOut", () => election.selectTdOut(P, game(), D, null)],
["selectPresidentVoteOnVeto", () => election.selectPresidentVoteOnVeto(P, game(), D, null)],
["selectChancellorVoteOnVeto", () => election.selectChancellorVoteOnVeto(P, game(), D, null)],
["selectChancellorPolicy", () => election.selectChancellorPolicy(P, game(), D, false, null)],
Expand Down
85 changes: 85 additions & 0 deletions __test__/backend/routes/socket/td-out-state.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
const {
clearTdOutVotes,
getTdOutPublicState,
hasTdOutVote,
isTdOutAvailable,
pruneTdOutVotes,
} = require("../../../../routes/socket/game/td-out-state");

const makeGame = ({
playerCount = 6,
deadSeats = [],
electionTrackerCount = 2,
phase = "selectingChancellor",
status = phase === "voting" ? "Vote on election #3 now." : "Election #3: president to select chancellor.",
isTracksFlipped = true,
isCompleted = false,
isGameFrozen = false,
isRemade = false,
} = {}) => ({
general: {
isRemade,
isTourny: false,
status,
},
gameState: {
phase,
isTracksFlipped,
isCompleted,
isGameFrozen,
},
trackState: {
electionTrackerCount,
},
private: {
seatedPlayers: Array.from({ length: playerCount }, (_value, index) => ({
userName: `p${index}`,
isDead: deadSeats.includes(index),
})),
tdOutVotes: {},
},
});

describe("td-out state", () => {
it("is available after two failed elections with an even number of living players", () => {
expect(isTdOutAvailable(makeGame())).toBe(true);
expect(isTdOutAvailable(makeGame({ phase: "voting" }))).toBe(true);
});

it("is not available for the wrong tracker count, odd living count, or inactive phase", () => {
expect(isTdOutAvailable(makeGame({ electionTrackerCount: 1 }))).toBe(false);
expect(isTdOutAvailable(makeGame({ deadSeats: [0] }))).toBe(false);
expect(isTdOutAvailable(makeGame({ phase: "presidentSelectingPolicy" }))).toBe(false);
expect(isTdOutAvailable(makeGame({ phase: "voting", status: "Tallying results of ballots.." }))).toBe(false);
});

it("prunes dead-player votes and reports the public vote count", () => {
const game = makeGame({ deadSeats: [1] });
game.private.tdOutVotes = {
p0: true,
p1: true,
p2: true,
};

pruneTdOutVotes(game);

expect(game.private.tdOutVotes).toEqual({
p0: true,
p2: true,
});
expect(getTdOutPublicState(game)).toEqual({
isAvailable: false,
voteCount: 2,
requiredVotes: 5,
});
});

it("tracks and clears an individual player's vote", () => {
const game = makeGame();
game.private.tdOutVotes.p0 = true;

expect(hasTdOutVote(game, "p0")).toBe(true);
clearTdOutVotes(game);
expect(hasTdOutVote(game, "p0")).toBe(false);
});
});
Loading