Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Send scores #165

Open
wants to merge 2 commits into
base: add-scores-in-matches
Choose a base branch
from
Open
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
4 changes: 2 additions & 2 deletions backend/match-reporter/MatchReporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,9 @@ MatchReportDecoration => {
}

const createMatchResultMessage = (match: Match, decorations: MatchReportDecoration[]): string => {
const { team1, team2, team1Won, winningTeamRatingChange, losingTeamRatingChange } = match
const { team1, team2, score, winningTeamRatingChange, losingTeamRatingChange } = match
let winningTeam, losingTeam
if (team1Won) {
if (score.team1Score > score.team2Score) {
[winningTeam, losingTeam] = [team1, team2]
} else {
[winningTeam, losingTeam] = [team2, team1]
Expand Down
7 changes: 4 additions & 3 deletions backend/repositories/MatchRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,12 @@ Promise<Match> => {
const {
winningTeamRatingChange,
losingTeamRatingChange,
} = getRatingChanges(team1, team2, matchDescription.team1Won)
} = getRatingChanges(team1, team2, matchDescription.team1Score > matchDescription.team2Score)
const date = new Date()
return new Match(
team1,
team2,
matchDescription.team1Won? { team1Score: 1, team2Score: 0 } : { team1Score: 0, team2Score: 1 },
{ team1Score: matchDescription.team1Score, team2Score: matchDescription.team2Score },
date,
winningTeamRatingChange,
losingTeamRatingChange,
Expand All @@ -64,7 +64,8 @@ const getElapsedSecondsSinceLatestMatch = async (gameId: number): Promise<number
* @param matchDescription Description of the match to record.
* @param {Array<number>} matchDescription.team1 Array of 1 or 2 elements containing IDs of players from team1.
* @param {Array<number>} matchDescription.team2 Array of 1 or 2 elements containing IDs of players from team2.
* @param {boolean} matchDescription.team1Won True if team1 won, false if team2 won.
* @param {number} matchDescription.team1Score non-negative integer
* @param {number} matchDescription.team2Score non-negative integer
*/
export const recordMatch = async (gameName: string, matchDescription: unknown):
Promise<Match> => {
Expand Down
3 changes: 2 additions & 1 deletion backend/storage/db/db-transformations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,11 @@ export const createMatchFromDbRow = (matchRow: QueryResultRow): MatchWithId => {
},
...team2Player2Array,
],
matchRow.Team1Score > matchRow.Team2Score,
matchRow.Date,
Number(matchRow.WinningTeamRatingChange),
Number(matchRow.LosingTeamRatingChange),
matchRow.Team1Score,
matchRow.Team2Score
)
}

Expand Down
3 changes: 2 additions & 1 deletion backend/tests/TestData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ export const FOOSBALL_MATCH_ROW: MatchRow = {
export const FOOSBALL_MATCH_DESCRIPTION: MatchDescription = {
team1: [ 1 ],
team2: [ 3, 4 ],
team1Won: true,
team1Score: 1,
team2Score: 0,
}

export const FOOSBALL_MATCH_WITH_ID = new MatchWithId(
Expand Down
3 changes: 2 additions & 1 deletion backend/types/Match.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,10 @@ export class MatchWithId {
readonly id: number,
readonly team1: UserInMatches[],
readonly team2: UserInMatches[],
readonly team1Won: boolean,
readonly date: Date,
readonly winningTeamRatingChange: number,
readonly losingTeamRatingChange: number,
readonly team1Score: number,
readonly team2Score: number
) {}
}
21 changes: 11 additions & 10 deletions backend/types/MatchDescription.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,26 @@ import { isMatchDescription } from './MatchDescription'

const team1 = [ 1, 2 ]
const team2 = [ 3 ]
const team1Won = true
const score = { team1Score: 1, team2Score: 2 }

describe('MatchDescription', () => {
describe('isMatchDescription', () => {
it.each([
['is an empty object', {}],
['has no team1', { team2, team1Won }],
['has no team2', { team1, team1Won }],
['has no team1Won', { team1, team2 }],
['has team1 as not an array', { team1: {}, team2, team1Won }],
['has team2 as an array of objects', { team1, team2: [{}], team1Won }],
['has an empty team1', { team1: [], team2, team1Won }],
['has too many ids in team1', { team1: [ 1, 2, 5 ], team2, team1Won }],
['has team1Won as an integer', { team1, team2, team1Won: 1 }],
['has no team1', { team2, ...score }],
['has no team2', { team1, ...score }],
['has no score', { team1, team2 }],
['has team1 as not an array', { team1: {}, team2, ...score }],
['has team2 as an array of objects', { team1, team2: [{}], ...score }],
['has an empty team1', { team1: [], team2, ...score }],
['has too many ids in team1', { team1: [ 1, 2, 5 ], team2, ...score }],
['has score as a float', { team1, team2, team1Score: 1.5, team2Score: 1 }],
['has a negative score', { team1, team2, team1Score: 1, team2Score: -1 }],
])('evaluates to false when %s', (desc, matchData) => {
expect(isMatchDescription(matchData)).toEqual(false)
})
it('evaluates to true when data is correct', () => {
expect(isMatchDescription({ team1, team2, team1Won })).toEqual(true)
expect(isMatchDescription({ team1, team2, ...score })).toEqual(true)
})
})
})
12 changes: 10 additions & 2 deletions backend/types/MatchDescription.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
export interface MatchDescription {
readonly team1: Array<number>;
readonly team2: Array<number>;
readonly team1Won: boolean;
readonly team1Score: number;
readonly team2Score: number;
}

const isArrayOfTeamIds = (teamIds: unknown): teamIds is Array<number> => {
Expand All @@ -10,9 +11,16 @@ const isArrayOfTeamIds = (teamIds: unknown): teamIds is Array<number> => {
teamIds.every(playerId => typeof playerId === 'number')
}

const isNonNegativeInteger = (num: unknown): num is number => {
return typeof num === 'number' &&
Number.isInteger(num) &&
num >= 0
}

export const isMatchDescription = (matchData: unknown): matchData is MatchDescription => {
const matchDescription = matchData as MatchDescription
return isArrayOfTeamIds(matchDescription.team1) &&
isArrayOfTeamIds(matchDescription.team2) &&
typeof matchDescription.team1Won === 'boolean'
isNonNegativeInteger(matchDescription.team1Score) &&
isNonNegativeInteger(matchDescription.team2Score)
}
15 changes: 15 additions & 0 deletions cypress/integration/components/MatchRecord.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Player } from '../types/Player'

export class MatchRecord {
constructor(private count: number) {}

locateWonPlayer(player: Player): MatchRecord {
cy.get(`#battle-history > :nth-child(${this.count})`).find('a').first().contains(player.name)
return this
}

locateLostPlayer(player: Player): MatchRecord {
cy.get(`#battle-history > :nth-child(${this.count})`).find('a').last().contains(player.name)
return this
}
}
5 changes: 5 additions & 0 deletions cypress/integration/pages/DashboardPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { SelectGamePage } from './SelectGamePage'
import { AddMatchPage } from './AddMatchPage'
import { MatchListPage } from './MatchListPage'
import { LeaderboardPage } from './LeaderboardPage'
import { MatchRecord } from '../components/MatchRecord'

export class DashboardPage extends Page {
constructor(private gameName: string) {
Expand All @@ -23,6 +24,10 @@ export class DashboardPage extends Page {
.should('contain.text', 'Add Match')
}

getLastMatch(): MatchRecord {
return new MatchRecord(1)
}

goToAddMatch(): AddMatchPage {
cy.get('#add-match-button').click()
return new AddMatchPage(this.gameName)
Expand Down
12 changes: 10 additions & 2 deletions cypress/integration/pages/LeaderboardPage.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
import { Page } from './Page'
import { Player } from '../types/Player'
import { DashboardPage } from './DashboardPage'

export class LeaderboardPage extends Page {
constructor(private gameName: string) {
super(`/${gameName}/leaderboard`)
}

locatePlayerWithScore(player: Player, score: number): void {
locatePlayerWithScore(player: Player, score: number): LeaderboardPage {
this.getContent().should('contain.text', `${player.name} (${score})`)
return this
}
missPlayerWithScore(player: Player, score: number): void {
missPlayerWithScore(player: Player, score: number): LeaderboardPage {
this.getContent().should('not.contain.text', `${player.name} (${score})`)
return this
}

goToDashboard(): DashboardPage {
this.getHeader().get('#title-link').click()
return new DashboardPage(this.gameName)
}
}
11 changes: 11 additions & 0 deletions cypress/integration/pages/MatchListPage.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
import { Page } from './Page'
import { MatchRecord } from '../components/MatchRecord'
import { DashboardPage } from './DashboardPage'

export class MatchListPage extends Page {
constructor(private gameName: string) {
super(`/${gameName}/match-list`)
}

getLastMatch(): MatchRecord {
return new MatchRecord(1)
}

goToDashboard(): DashboardPage {
this.getHeader().get('#title-link').click()
return new DashboardPage(this.gameName)
}
}
36 changes: 27 additions & 9 deletions cypress/integration/tests/add-match.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { AddMatchPage } from '../pages/AddMatchPage'
import { FOOSBALL_GAME } from '../utils/data'
import { AddPlayerPage } from '../pages/AddPlayerPage'
import { generateRandomPlayer } from '../utils/gen'
import { LeaderboardPage } from '../pages/LeaderboardPage'
import { DashboardPage } from '../pages/DashboardPage'

describe('Create match page', () => {
const addMatchPage = new AddMatchPage(FOOSBALL_GAME.name)
Expand All @@ -14,17 +14,20 @@ describe('Create match page', () => {
})
})

describe('Leaderboard', () => {
describe('Foosball', () => {
const player1 = generateRandomPlayer()
const player1score = 1010
const player1newscore= 1026
const player2 = generateRandomPlayer()
const player2score = 1020
const player2newscore= 1004
describe('when player 1 and player 2 exist in foosball and first wins once over second', () => {
let leaderboard: LeaderboardPage
beforeEach(() => {
leaderboard = new AddPlayerPage(FOOSBALL_GAME.name)
let dashboard: DashboardPage
before(() => {
dashboard = new DashboardPage(FOOSBALL_GAME.name).visit()
})
before(() => {
dashboard = new AddPlayerPage(FOOSBALL_GAME.name)
.visit()
.addPlayer(player1, player1score)
.addPlayer(player2, player2score)
Expand All @@ -34,11 +37,26 @@ describe('Leaderboard', () => {
.selectTeam1Player1(player1)
.selectTeam2Player1(player2)
.team1Wins()
.goToLeaderboard()
})
it('contains players with resulting scores', () => {
leaderboard.locatePlayerWithScore(player1, player1newscore)
leaderboard.locatePlayerWithScore(player2, player2newscore)
it('contains players with resulting scores in leaderboard', () => {
dashboard = dashboard.goToLeaderboard()
.locatePlayerWithScore(player1, player1newscore)
.locatePlayerWithScore(player2, player2newscore)
.goToDashboard()
})
it('contains a match record in dashboard', () => {
dashboard.getLastMatch()
.locateWonPlayer(player1)
.locateLostPlayer(player2)
})
it('contains a match record in the matches list', () => {
const matchesList = dashboard.goToMatchesList()
matchesList
.getLastMatch()
.locateWonPlayer(player1)
.locateLostPlayer(player2)
matchesList
.goToDashboard()
})
})
})
2 changes: 1 addition & 1 deletion frontend/src/app/components/BattleHistory/BattleHistory.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
import { BattleHistoryRow } from './BattleHistoryRow'

export const BattleHistory = ({ maxItems, lastMatches }) =>
<ListCon>
<ListCon id="battle-history">
{lastMatches.slice(0, maxItems).map(match =>
<BattleHistoryRow key={match.id} match={match} />,
)}
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/app/components/BattleHistory/BattleHistoryRow.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Team } from './Team'

export const BattleHistoryRow = ({ match }) =>
<ListItem Display="grid" Column="2fr 1fr 2fr">
<Team team={match.team1} didWin={match.team1Won} />
<Team team={match.team1} didWin={match.team1Score > match.team2Score} />
<BattleLabel textAlign="center">VS</BattleLabel>
<Team team={match.team2} didWin={!match.team1Won} />
<Team team={match.team2} didWin={match.team1Score < match.team2Score} />
</ListItem>
3 changes: 2 additions & 1 deletion frontend/src/app/components/CreateMatch/CreateMatch.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ export class CreateMatchComponent extends Component {
this.props.createMatch({
team1: this.state.team1,
team2: this.state.team2,
team1Won,
team1Score: team1Won? 1 : 0,
team2Score: team1Won? 0 : 1,
})
}

Expand Down
2 changes: 1 addition & 1 deletion frontend/src/app/modules/matches/matches-computations.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const didPlayerWin = (playerId, match) => {
const winningTeam = match.team1Won ? match.team1 : match.team2
const winningTeam = match.team1Score > match.team2Score ? match.team1 : match.team2
return Boolean(winningTeam.find(player => player.id === playerId))
}

Expand Down