Skip to content

Commit

Permalink
More tests (#7)
Browse files Browse the repository at this point in the history
* starting gameState tests

* copy shared to client before build

* a couple more tests

* fix exchange bug

* more tests

* more tests
  • Loading branch information
lounsbrough authored Sep 11, 2024
1 parent 212d911 commit a4be3ed
Show file tree
Hide file tree
Showing 12 changed files with 405 additions and 55 deletions.
2 changes: 1 addition & 1 deletion client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"copy-shared": "rm -rf ./src/shared && cp -r ../shared ./src/shared",
"lint": "pnpm eslint",
"start": "pnpm copy-shared && react-scripts start",
"build": "react-scripts build",
"build": "pnpm copy-shared && react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
Expand Down
12 changes: 6 additions & 6 deletions client/src/shared/types/game.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export enum Actions {
Exchange = 'Exchange'
}

type ColorMode = 'light' | 'dark';
type ColorMode = 'light' | 'dark'

export const InfluenceAttributes: {
[influence in Influences]: {
Expand Down Expand Up @@ -161,19 +161,19 @@ export const ResponseAttributes: {
}

export type Player = {
influences: Influences[],
coins: number
name: string
id: string
color: string
id: string
influences: Influences[]
name: string
}

export type PublicPlayer = Omit<Player, 'id' | 'influences'> & {
influenceCount: number
};
}

export type GameState = {
deadCards: Influences[],
deadCards: Influences[]
deck: Influences[]
eventLogs: string[]
isStarted: boolean
Expand Down
35 changes: 18 additions & 17 deletions server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import http from 'http'
import express from 'express'
import { json } from 'body-parser'
import cors from 'cors'
import { addPlayerToGame, createNewGame, drawCardFromDeck, getGameState, getNextPlayerTurn, getPublicGameState, promptPlayerToLoseInfluence, logEvent, mutateGameState, processPendingAction, resetGame, shuffle, startGame, killPlayerInfluence } from './utilities/gameState'
import { addPlayerToGame, createNewGame, drawCardFromDeck, getGameState, moveTurnToNextPlayer, getPublicGameState, promptPlayerToLoseInfluence, logEvent, mutateGameState, processPendingAction, resetGame, startGame, killPlayerInfluence, shuffleDeck } from './utilities/gameState'
import { generateRoomId } from './utilities/identifiers'
import { ActionAttributes, Actions, InfluenceAttributes, Influences, Responses } from '../shared/types/game'

Expand Down Expand Up @@ -270,7 +270,7 @@ app.post('/action', async (req, res) => {
} else if (action === Actions.Income) {
await mutateGameState(roomId, (state) => {
state.players.find(({ id }) => id === playerId).coins += 1
state.turnPlayer = getNextPlayerTurn(state)
moveTurnToNextPlayer(state)
logEvent(state, `${player.name} used ${action}`)
})
}
Expand Down Expand Up @@ -458,7 +458,7 @@ app.post('/actionChallengeResponse', async (req, res) => {
actionPlayer.influences.findIndex((i) => i === influence),
1
)[0])
state.deck = shuffle(state.deck)
shuffleDeck(state)
actionPlayer.influences.push(drawCardFromDeck(state))
delete state.pendingActionChallenge
state.pendingAction.claimConfirmed = true
Expand Down Expand Up @@ -486,7 +486,7 @@ app.post('/actionChallengeResponse', async (req, res) => {
const challengePlayer = state.players.find(({ name }) => name === state.pendingActionChallenge.sourcePlayer)
logEvent(state, `${challengePlayer.name} successfully challenged ${state.turnPlayer}`)
killPlayerInfluence(state, actionPlayer.name, influence)
state.turnPlayer = getNextPlayerTurn(state)
moveTurnToNextPlayer(state)
delete state.pendingActionChallenge
delete state.pendingAction
})
Expand Down Expand Up @@ -557,7 +557,7 @@ app.post('/blockResponse', async (req, res) => {
state.players.find(({ name }) => name === state.turnPlayer).coins
-= ActionAttributes.Assassinate.coinsRequired
}
state.turnPlayer = getNextPlayerTurn(state)
moveTurnToNextPlayer(state)
delete state.pendingBlock
delete state.pendingActionChallenge
delete state.pendingAction
Expand Down Expand Up @@ -628,7 +628,7 @@ app.post('/blockChallengeResponse', async (req, res) => {
blockPlayer.influences.findIndex((i) => i === influence),
1
)[0])
state.deck = shuffle(state.deck)
shuffleDeck(state)
blockPlayer.influences.push(drawCardFromDeck(state))
logEvent(state, `${blockPlayer.name} revealed and replaced ${influence}`)
logEvent(state, `${blockPlayer.name} successfully blocked ${state.turnPlayer}`)
Expand Down Expand Up @@ -697,29 +697,30 @@ app.post('/loseInfluence', async (req, res) => {
}

await mutateGameState(roomId, (state) => {
if (state.pendingInfluenceLoss[player.name][0].putBackInDeck) {
const removedInfluence = player.influences.splice(
player.influences.findIndex((i) => i === influence),
const losingPlayer = state.players.find(({ id }) => id === playerId)
if (state.pendingInfluenceLoss[losingPlayer.name][0].putBackInDeck) {
const removedInfluence = losingPlayer.influences.splice(
losingPlayer.influences.findIndex((i) => i === influence),
1
)[0]
state.deck.unshift(removedInfluence)
} else {
killPlayerInfluence(state, player.name, influence)
killPlayerInfluence(state, losingPlayer.name, influence)
}

if (state.pendingInfluenceLoss[player.name].length > 1) {
state.pendingInfluenceLoss[player.name].splice(0, 1)
if (state.pendingInfluenceLoss[losingPlayer.name].length > 1) {
state.pendingInfluenceLoss[losingPlayer.name].splice(0, 1)
} else {
delete state.pendingInfluenceLoss[player.name]
delete state.pendingInfluenceLoss[losingPlayer.name]
}

if (!Object.keys(state.pendingInfluenceLoss).length && !state.pendingAction) {
state.turnPlayer = getNextPlayerTurn(state)
moveTurnToNextPlayer(state)
}

if (!player.influences.length) {
logEvent(state, `${player.name} is out!`)
delete state.pendingInfluenceLoss[player.name]
if (!losingPlayer.influences.length) {
logEvent(state, `${losingPlayer.name} is out!`)
delete state.pendingInfluenceLoss[losingPlayer.name]
}
})

Expand Down
2 changes: 2 additions & 0 deletions server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,13 @@
"devDependencies": {
"@eslint/js": "^9.9.1",
"@types/body-parser": "^1.19.5",
"@types/chance": "^1.1.6",
"@types/cors": "^2.8.17",
"@types/express": "^4.17.21",
"@types/jest": "^29.5.12",
"@types/node": "^22.5.1",
"@types/redis": "^4.0.11",
"chance": "^1.1.12",
"eslint": "^9.9.1",
"globals": "^15.9.0",
"jest": "^29.7.0",
Expand Down
16 changes: 16 additions & 0 deletions server/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 20 additions & 0 deletions server/utilities/array.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Chance } from "chance"
import { shuffle } from "./array"

const chance = new Chance()

describe('array', () => {
it('should throw if input is not iterable', () => {
expect(() => shuffle(null)).toThrow()
})

it('should shuffle original array', () => {
const original = Array.from({ length: 100 }, () => chance.natural())
const shuffled = shuffle(original)
expect(shuffled).not.toEqual(original)
expect(shuffled.length).toBe(original.length)
shuffled.forEach((elementS) => {
expect(original.find((elementO) => elementO === elementS)).not.toBeNull()
})
})
})
10 changes: 10 additions & 0 deletions server/utilities/array.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export const shuffle = <T>(array: T[]): T[] => {
const unShuffled = [...array]
const shuffled: T[] = []

while (unShuffled.length) {
shuffled.push(unShuffled.splice(Math.floor(Math.random() * unShuffled.length), 1)[0])
}

return shuffled
}
Loading

0 comments on commit a4be3ed

Please sign in to comment.