From 3749d6d63d9fb10ba161e29dc49990e93ea803c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Garapich?= Date: Tue, 10 Dec 2024 15:13:48 +0100 Subject: [PATCH] fix: cleanup queue page (#98) --- src/queue/apply-map-cooldown.ts | 2 + src/queue/config.ts | 2 + src/queue/get-map-winner.ts | 2 +- src/queue/join.ts | 8 +- src/queue/kick.ts | 2 +- src/queue/leave.ts | 2 +- src/queue/mark-as-friend.ts | 2 +- src/queue/ready-up.ts | 3 +- src/queue/reset.ts | 1 + src/queue/set-state.ts | 2 + src/queue/unready.ts | 2 + src/queue/views/html/queue-slot.tsx | 183 +++++++++--------- .../views/html/{queue.css => queue.page.css} | 135 ++++++++----- src/queue/views/html/queue.page.tsx | 2 +- src/queue/views/html/ready-up-dialog.tsx | 10 +- src/queue/vote-map.ts | 2 + src/websocket/gateway.ts | 8 +- tests/00-misc/03-accept-rules.spec.ts | 5 - tests/10-queue/01-update-player-count.spec.ts | 5 + tests/10-queue/02-vote-for-map.spec.ts | 4 - tests/10-queue/03-mark-as-friend.spec.ts | 24 +-- tests/10-queue/05-late-for-ready-up.spec.ts | 4 +- tests/20-game/02-free-players.spec.ts | 38 ++-- tests/pages/queue.page.ts | 22 +-- 24 files changed, 252 insertions(+), 218 deletions(-) rename src/queue/views/html/{queue.css => queue.page.css} (57%) diff --git a/src/queue/apply-map-cooldown.ts b/src/queue/apply-map-cooldown.ts index 5b67b60e..d37d58a6 100644 --- a/src/queue/apply-map-cooldown.ts +++ b/src/queue/apply-map-cooldown.ts @@ -1,7 +1,9 @@ import { configuration } from '../configuration' import { collections } from '../database/collections' +import { logger } from '../logger' export async function applyMapCooldown(map: string) { + logger.trace({ map }, 'queue.applyMapCooldown()') await collections.maps.updateMany( { name: { $ne: map }, cooldown: { $gt: 0 } }, { $inc: { cooldown: -1 } }, diff --git a/src/queue/config.ts b/src/queue/config.ts index f9b6a1a4..f456d710 100644 --- a/src/queue/config.ts +++ b/src/queue/config.ts @@ -1,4 +1,6 @@ import { environment } from '../environment' +import { logger } from '../logger' import { queueConfigs } from './configs' +logger.info(`using queue config: ${environment.QUEUE_CONFIG}`) export const config = queueConfigs[environment.QUEUE_CONFIG] diff --git a/src/queue/get-map-winner.ts b/src/queue/get-map-winner.ts index 224e5f09..5f91beec 100644 --- a/src/queue/get-map-winner.ts +++ b/src/queue/get-map-winner.ts @@ -34,7 +34,7 @@ export async function getMapWinner(): Promise { }, ]) .toArray() - logger.trace({ mapsWithVotes }) + logger.trace({ mapsWithVotes }, 'queue.getMapWinner()') const maxVotes = maxBy(mapsWithVotes, r => r.votes)?.votes ?? 0 const mapsWithMaxVotes = mapsWithVotes.filter(m => m.votes === maxVotes) return sample(mapsWithMaxVotes)!.name diff --git a/src/queue/join.ts b/src/queue/join.ts index d26c043e..c6c063b9 100644 --- a/src/queue/join.ts +++ b/src/queue/join.ts @@ -9,15 +9,15 @@ import { mutex } from './mutex' export async function join(slotId: number, steamId: SteamId64): Promise { return await mutex.runExclusive(async () => { - logger.trace({ steamId, slotId }, `join queue`) + logger.trace({ steamId, slotId }, `queue.join()`) const player = await collections.players.findOne({ steamId }) if (!player) { throw new Error(`player does not exist: ${steamId}`) } - // if (!player.hasAcceptedRules) { - // throw new Error(`player has not accepted rules`) - // } + if (!player.hasAcceptedRules) { + throw new Error(`player has not accepted rules`) + } if (player.activeGame) { throw new Error(`player has active game`) diff --git a/src/queue/kick.ts b/src/queue/kick.ts index 40891848..66f94556 100644 --- a/src/queue/kick.ts +++ b/src/queue/kick.ts @@ -11,7 +11,7 @@ import { preReady } from './pre-ready' export async function kick(...steamIds: SteamId64[]): Promise { return await mutex.runExclusive(async () => { - logger.debug({ steamIds }, 'kick from queue') + logger.trace({ steamIds }, 'queue.kick()') const state = await getState() if (state === QueueState.launching) { throw new Error('invalid queue state') diff --git a/src/queue/leave.ts b/src/queue/leave.ts index 23f26a06..e507e674 100644 --- a/src/queue/leave.ts +++ b/src/queue/leave.ts @@ -11,7 +11,7 @@ import { preReady } from './pre-ready' export async function leave(steamId: SteamId64): Promise { return await mutex.runExclusive(async () => { - logger.debug({ steamId }, 'leave queue') + logger.trace({ steamId }, 'queue.leave()') const state = await getState() if (state === QueueState.launching) { throw new Error('invalid queue state') diff --git a/src/queue/mark-as-friend.ts b/src/queue/mark-as-friend.ts index 547cbe6e..ef4aeda4 100644 --- a/src/queue/mark-as-friend.ts +++ b/src/queue/mark-as-friend.ts @@ -12,7 +12,7 @@ export async function markAsFriend( target: SteamId64 | null, ): Promise { return await mutex.runExclusive(async () => { - logger.info(`marking ${source} as friend of ${target}`) + logger.trace({ source, target }, `queue.markAsFriend()`) const queueState = await getState() if (queueState === QueueState.launching) { diff --git a/src/queue/ready-up.ts b/src/queue/ready-up.ts index 07d6a68a..d19b63e2 100644 --- a/src/queue/ready-up.ts +++ b/src/queue/ready-up.ts @@ -9,13 +9,12 @@ import { mutex } from './mutex' export async function readyUp(steamId: SteamId64): Promise { return await mutex.runExclusive(async () => { + logger.trace({ steamId }, 'queue.readyUp()') const state = await getState() if (state !== QueueState.ready) { throw new Error('wrong queue state') } - logger.info(`player ${steamId} ready`) - const slot = await collections.queueSlots.findOneAndUpdate( { player: steamId }, { $set: { ready: true } }, diff --git a/src/queue/reset.ts b/src/queue/reset.ts index 7a993712..1c7c6da0 100644 --- a/src/queue/reset.ts +++ b/src/queue/reset.ts @@ -11,6 +11,7 @@ import { getState } from './get-state' import { mapPool } from './map-pool' export async function reset() { + logger.trace('queue.reset()') const slots = generateEmptyQueue() await collections.queueSlots.deleteMany({}) await collections.queueSlots.insertMany(slots) diff --git a/src/queue/set-state.ts b/src/queue/set-state.ts index 36c975e1..5477498c 100644 --- a/src/queue/set-state.ts +++ b/src/queue/set-state.ts @@ -1,10 +1,12 @@ import { collections } from '../database/collections' import { QueueState } from '../database/models/queue-state.model' import { events } from '../events' +import { logger } from '../logger' import { mutex } from './mutex' export async function setState(state: QueueState) { return await mutex.runExclusive(async () => { + logger.trace({ state }, 'queue.setState()') await collections.queueState.updateOne({}, { $set: { state } }) if (state === QueueState.ready) { diff --git a/src/queue/unready.ts b/src/queue/unready.ts index d1e6fd72..88720bee 100644 --- a/src/queue/unready.ts +++ b/src/queue/unready.ts @@ -1,11 +1,13 @@ import { collections } from '../database/collections' import type { QueueSlotModel } from '../database/models/queue-slot.model' import { events } from '../events' +import { logger } from '../logger' import type { SteamId64 } from '../shared/types/steam-id-64' import { mutex } from './mutex' export async function unready(...steamIds: SteamId64[]): Promise { return await mutex.runExclusive(async () => { + logger.trace({ steamIds }, 'queue.unready()') const slots: QueueSlotModel[] = [] for (const steamId of steamIds) { const slot = await collections.queueSlots.findOneAndUpdate( diff --git a/src/queue/views/html/queue-slot.tsx b/src/queue/views/html/queue-slot.tsx index 219ad2fb..1b4bf462 100644 --- a/src/queue/views/html/queue-slot.tsx +++ b/src/queue/views/html/queue-slot.tsx @@ -1,5 +1,4 @@ import { collections } from '../../../database/collections' -import type { PlayerModel } from '../../../database/models/player.model' import type { QueueSlotModel } from '../../../database/models/queue-slot.model' import { IconHeart, @@ -10,7 +9,8 @@ import { } from '../../../html/components/icons' import type { SteamId64 } from '../../../shared/types/steam-id-64' -enum MarkAsFriendButtonState { +const enum MarkAsFriendButtonState { + none, enabled, disabled, // marked by another player selected, // marked by me @@ -19,37 +19,7 @@ enum MarkAsFriendButtonState { export async function QueueSlot(props: { slot: QueueSlotModel; actor?: SteamId64 | undefined }) { let slotContent = <> if (props.slot.player) { - const player = await collections.players.findOne({ steamId: props.slot.player }) - if (!player) { - throw new Error(`player does not exist: ${props.slot.player}`) - } - - let markAsFriendButtonState: MarkAsFriendButtonState | undefined = undefined - - if (props.actor) { - const actorsSlot = await collections.queueSlots.findOne({ player: props.actor }) - if (actorsSlot?.canMakeFriendsWith?.includes(props.slot.gameClass)) { - const friendship = await collections.queueFriends.findOne({ - target: props.slot.player, - }) - if (friendship === null) { - markAsFriendButtonState = MarkAsFriendButtonState.enabled - } else if (friendship.source === props.actor) { - markAsFriendButtonState = MarkAsFriendButtonState.selected - } else { - markAsFriendButtonState = MarkAsFriendButtonState.disabled - } - } - } - - slotContent = ( - - ) + slotContent = } else if (props.actor) { const actor = await collections.players.findOne({ steamId: props.actor }) if (!actor) { @@ -61,7 +31,6 @@ export async function QueueSlot(props: { slot: QueueSlotModel; actor?: SteamId64 end: { $gt: new Date() }, }) const disabled = Boolean(actor.activeGame) || activeBans > 0 - slotContent = } @@ -82,80 +51,106 @@ function JoinButton(props: { slotId: number; disabled: boolean }) { class="join-queue-button" name="join" value={`${props.slotId}`} - aria-label={`Join queue on slot ${props.slotId}`} disabled={props.disabled} > + Join queue on slot {props.slotId} {props.disabled ? : } ) } -function PlayerInfo(props: { - player: PlayerModel - isActorsSlot: boolean - ready: boolean - markAsFriendButtonState: MarkAsFriendButtonState | undefined -}) { - let slotButton = <> - if (props.isActorsSlot && !props.ready) { - slotButton = ( - ) - } else if (props.markAsFriendButtonState !== undefined) { - slotButton = ( - - ) + } else { + slotActionButton = } return ( -
- {`${props.player.name}'s - - {props.player.name} +
+ {`${player.name}'s + + {player.name} -
{slotButton}
+ {slotActionButton}
) } + +async function MarkAsFriendButton(props: { slot: QueueSlotModel; actor?: SteamId64 | undefined }) { + const markAsFriendButtonState = await determineMarkAsFriendButtonState(props.slot, props.actor) + if (markAsFriendButtonState === MarkAsFriendButtonState.none) { + return <> + } + + return ( + + ) +} + +async function determineMarkAsFriendButtonState( + slot: QueueSlotModel, + actor?: SteamId64, +): Promise { + if (!slot.player) { + return MarkAsFriendButtonState.none + } + + if (!actor) { + return MarkAsFriendButtonState.none + } + + const actorsSlot = await collections.queueSlots.findOne({ player: actor }) + if (actorsSlot?.canMakeFriendsWith?.includes(slot.gameClass)) { + const friendship = await collections.queueFriends.findOne({ + target: slot.player, + }) + if (friendship === null) { + return MarkAsFriendButtonState.enabled + } else if (friendship.source === actor) { + return MarkAsFriendButtonState.selected + } else { + return MarkAsFriendButtonState.disabled + } + } + + return MarkAsFriendButtonState.none +} diff --git a/src/queue/views/html/queue.css b/src/queue/views/html/queue.page.css similarity index 57% rename from src/queue/views/html/queue.css rename to src/queue/views/html/queue.page.css index c7533a3a..820c9dbe 100644 --- a/src/queue/views/html/queue.css +++ b/src/queue/views/html/queue.page.css @@ -28,67 +28,110 @@ } } - .leave-queue-button { - @apply transition-colors; - @apply duration-75; - - display: flex; - flex: 1 1 0%; + .player-info { + padding: 8px; + flex: 1; + display: grid; + grid-template-columns: 42px 1fr 42px; align-items: center; - justify-content: center; - - height: 34px; - width: 34px; - border-radius: 4px; + background-color: theme(colors.abru.light.60); - background-color: theme(colors.abru.light.30); - color: theme(colors.white); + img { + border-radius: 4px; + } - &:hover:enabled { - background-color: theme(colors.abru.light.35); + a { + flex-grow: 1; + overflow: hidden; + white-space: nowrap; + text-align: center; + font-size: 20px; + font-weight: 700; + color: theme(colors.abru.dark.3); + + &:hover { + text-decoration: underline; + } } - } - .mark-as-friend-button { - @apply transition-colors; - @apply duration-75; + &:has(.leave-queue-button) { + background-color: theme(colors.abru.light.75); + } - display: flex; - align-items: center; - justify-content: center; + &[data-player-ready='true'] { + background-color: #0a955b; + } - height: 34px; - width: 34px; + .leave-queue-button { + @apply transition-colors; + @apply duration-75; - border-radius: 4px; + display: flex; + flex: 1 1 0%; + align-items: center; + justify-content: center; - color: theme(colors.black); - background-color: theme(colors.abru.light.75); + height: 34px; + width: 34px; + border-radius: 4px; - &:disabled { - color: theme(colors.abru.light.60); - } + background-color: theme(colors.abru.light.30); + color: theme(colors.white); - &:hover { - background-color: theme(colors.abru.light.70); + &:hover:enabled { + background-color: theme(colors.abru.light.35); + } } - &.selected { - color: theme(colors.accent.600); + .mark-as-friend-button { + display: block; + position: relative; + cursor: pointer; + user-select: none; + + height: 34px; + width: 34px; + + input[type='checkbox'] { + appearance: none; + opacity: 0; + width: 100%; + height: 100%; + border-radius: 4px; + overflow: hidden; + } + + .mark { + @apply transition-colors; + @apply duration-75; + + color: theme(colors.abru.dark.20); + background-color: theme(colors.abru.light.75); + display: flex; + align-items: center; + justify-content: center; + + position: absolute; + top: 0; + left: 0; + height: 100%; + width: 100%; + border-radius: 4px; + + &:hover { + background-color: theme(colors.abru.light.70); + } + } + + input:checked ~ .mark { + color: theme(colors.accent.600); + } + + input:disabled ~ .mark { + color: theme(colors.abru.light.60); + } } } - - .taken { - background-color: theme(colors.abru.light.60); - } - - .my-slot { - background-color: theme(colors.abru.light.75); - } - - .ready { - background-color: #0a955b; - } } .map-vote-button { diff --git a/src/queue/views/html/queue.page.tsx b/src/queue/views/html/queue.page.tsx index f57a81fa..85856a6a 100644 --- a/src/queue/views/html/queue.page.tsx +++ b/src/queue/views/html/queue.page.tsx @@ -32,7 +32,7 @@ export async function QueuePage(props: { user?: User | undefined }) { return ( diff --git a/src/queue/views/html/ready-up-dialog.tsx b/src/queue/views/html/ready-up-dialog.tsx index 8fd4e076..5eb02f12 100644 --- a/src/queue/views/html/ready-up-dialog.tsx +++ b/src/queue/views/html/ready-up-dialog.tsx @@ -5,7 +5,7 @@ const dialogId = 'ready-up-dialog' export function ReadyUpDialog() { return ( then me.showModal() end @@ -17,7 +17,7 @@ export function ReadyUpDialog() { ws-send _={`on submit add [@disabled] to <#${dialogId} button/>`} > -
+
Game is starting! Are you ready to play?
@@ -26,7 +26,7 @@ export function ReadyUpDialog() {
diff --git a/src/queue/vote-map.ts b/src/queue/vote-map.ts index 53690bea..9f572c87 100644 --- a/src/queue/vote-map.ts +++ b/src/queue/vote-map.ts @@ -1,11 +1,13 @@ import { collections } from '../database/collections' import { events } from '../events' +import { logger } from '../logger' import type { SteamId64 } from '../shared/types/steam-id-64' import { getMapVoteResults } from './get-map-vote-results' import { mutex } from './mutex' export async function voteMap(steamId: SteamId64, map: string): Promise> { return await mutex.runExclusive(async () => { + logger.trace({ steamId, map }, 'queue.voteMap()') const mapCount = await collections.queueMapOptions.countDocuments({ name: map }) if (mapCount === 0) { throw new Error('this map not an option in the vote') diff --git a/src/websocket/gateway.ts b/src/websocket/gateway.ts index 55bc08e0..f5735caa 100644 --- a/src/websocket/gateway.ts +++ b/src/websocket/gateway.ts @@ -48,7 +48,7 @@ const voteMap = z.object({ }) const markAsFriend = z.object({ - markasfriend: z.union([z.string(), z.literal('')]), + markasfriend: z.union([z.string(), z.null()]), HEADERS: htmxHeaders, }) @@ -184,11 +184,7 @@ export class Gateway extends EventEmitter implements Broadcaster { } else if ('votemap' in parsed) { this.emit('queue:votemap', socket, parsed.votemap) } else if ('markasfriend' in parsed) { - this.emit( - 'queue:markasfriend', - socket, - parsed.markasfriend === '' ? null : parsed.markasfriend, - ) + this.emit('queue:markasfriend', socket, parsed.markasfriend) } else if ('prereadytoggle' in parsed) { this.emit('queue:togglepreready', socket) } diff --git a/tests/00-misc/03-accept-rules.spec.ts b/tests/00-misc/03-accept-rules.spec.ts index 382f41d6..d88cd78f 100644 --- a/tests/00-misc/03-accept-rules.spec.ts +++ b/tests/00-misc/03-accept-rules.spec.ts @@ -1,12 +1,7 @@ -import { users } from '../data' import { authUsers, expect } from '../fixtures/auth-users' import { mergeTests } from '@playwright/test' import { accessMongoDb } from '../fixtures/access-mongo-db' -const user = users[0] - -authUsers.use({ steamIds: [user.steamId] }) - const test = mergeTests(authUsers, accessMongoDb) test.describe('when user has not accepted the rules yet', () => { diff --git a/tests/10-queue/01-update-player-count.spec.ts b/tests/10-queue/01-update-player-count.spec.ts index 3109e9cc..272eb27d 100644 --- a/tests/10-queue/01-update-player-count.spec.ts +++ b/tests/10-queue/01-update-player-count.spec.ts @@ -9,13 +9,18 @@ authUsers('update player count', async ({ page, users }) => { const p2 = await users.getNext().queuePage() await expect(queuePage.header()).toContainText('0/12') + await expect(queuePage.page).toHaveTitle(/\[0\/12\]/) await p1.joinQueue(0) await expect(queuePage.header()).toContainText('1/12') + await expect(queuePage.page).toHaveTitle(/\[1\/12\]/) await p2.joinQueue(1) await expect(queuePage.header()).toContainText('2/12') + await expect(queuePage.page).toHaveTitle(/\[2\/12\]/) await p1.leaveQueue() await expect(queuePage.header()).toContainText('1/12') + await expect(queuePage.page).toHaveTitle(/\[1\/12\]/) await p2.leaveQueue() await expect(queuePage.header()).toContainText('0/12') + await expect(queuePage.page).toHaveTitle(/\[0\/12\]/) }) diff --git a/tests/10-queue/02-vote-for-map.spec.ts b/tests/10-queue/02-vote-for-map.spec.ts index c523675a..d0988071 100644 --- a/tests/10-queue/02-vote-for-map.spec.ts +++ b/tests/10-queue/02-vote-for-map.spec.ts @@ -1,9 +1,5 @@ -import { users } from '../data' import { authUsers, expect } from '../fixtures/auth-users' -const user = users[0] - -authUsers.use({ steamIds: [user.steamId] }) authUsers('vote for map', async ({ users }) => { const page = await users.getFirst().queuePage() const mapBtn = page.voteForMapButton(0) diff --git a/tests/10-queue/03-mark-as-friend.spec.ts b/tests/10-queue/03-mark-as-friend.spec.ts index 140c43cd..2796c985 100644 --- a/tests/10-queue/03-mark-as-friend.spec.ts +++ b/tests/10-queue/03-mark-as-friend.spec.ts @@ -1,31 +1,23 @@ -import { users } from '../data' import { authUsers, expect } from '../fixtures/auth-users' import type { QueuePage } from '../pages/queue.page' -authUsers.use({ steamIds: [users[0].steamId, users[1].steamId, users[2].steamId] }) - authUsers('mark as friend', async ({ users }) => { const [medic1, medic2, soldier] = (await Promise.all( users.getMany(3).map(async user => await user.queuePage()), )) as [QueuePage, QueuePage, QueuePage] - await medic1.joinQueue(10) - await medic2.joinQueue(11) - await soldier.joinQueue(4) + await medic1.slot(10).join() + await medic2.slot(11).join() + await soldier.slot(4).join() - await expect(soldier.markAsFriendButton(10)).not.toBeVisible() + await expect(soldier.slot(10).markAsFriendButton()).not.toBeVisible() - const markAsFriendBtn1Medic1 = medic1.markAsFriendButton(4) + const markAsFriendBtn1Medic1 = medic1.slot(4).markAsFriendButton() await expect(markAsFriendBtn1Medic1).toBeVisible() await expect(markAsFriendBtn1Medic1).toBeEnabled() - await expect(markAsFriendBtn1Medic1).not.toHaveClass(/selected/) - await markAsFriendBtn1Medic1.click() - - const unfriendButton = medic1.unfriendButton(4) - await expect(unfriendButton).toBeVisible() - await expect(unfriendButton).toBeEnabled() - await expect(unfriendButton).toHaveClass(/selected/) + await markAsFriendBtn1Medic1.check({ force: true }) + await expect(markAsFriendBtn1Medic1).toBeChecked() - const markAsFriendBtn1Medic2 = medic2.markAsFriendButton(4) + const markAsFriendBtn1Medic2 = medic2.slot(4).markAsFriendButton() await expect(markAsFriendBtn1Medic2).toBeVisible() await expect(markAsFriendBtn1Medic2).toBeDisabled() diff --git a/tests/10-queue/05-late-for-ready-up.spec.ts b/tests/10-queue/05-late-for-ready-up.spec.ts index bb1c274f..e48b5d73 100644 --- a/tests/10-queue/05-late-for-ready-up.spec.ts +++ b/tests/10-queue/05-late-for-ready-up.spec.ts @@ -23,8 +23,8 @@ authUsers('player is late for ready up', async ({ steamIds, users, page }) => { await expect(page.getByRole('heading', { name: /^Players:/ })).toHaveText('Players: 11/12', { timeout: 60000, }) - const kickedUserPage = await users.bySteamId(queueUsers[0]!).page() - await expect(kickedUserPage.getByLabel(`Join queue on slot 0`, { exact: true })).toBeVisible() + const kickedUserPage = await users.bySteamId(queueUsers[0]!).queuePage() + await expect(kickedUserPage.slot(0).joinButton()).toBeVisible() // everybody leaves the queue await Promise.all( diff --git a/tests/20-game/02-free-players.spec.ts b/tests/20-game/02-free-players.spec.ts index a9bcdc07..c3af66cc 100644 --- a/tests/20-game/02-free-players.spec.ts +++ b/tests/20-game/02-free-players.spec.ts @@ -31,22 +31,26 @@ launchGameAndInitialize( .map(async player => { const page = await player.queuePage() await page.goto() - await expect(page.goBackToGameLink()).not.toBeVisible({ - timeout: secondsToMilliseconds(1), - }) - for (let i = 0; i < 12; ++i) { - await expect(page.slot(i).joinButton()).toBeEnabled() - } + await Promise.all([ + expect(page.goBackToGameLink()).not.toBeVisible({ + timeout: secondsToMilliseconds(1), + }), + ...Array.from(Array(12).keys()).map( + async i => await expect(page.slot(i).joinButton()).toBeEnabled(), + ), + ]) }), ...players .filter(p => !medics.includes(p.playerName)) .map(async player => { const page = await player.queuePage() await page.goto() - await expect(page.goBackToGameLink()).toBeVisible() - for (let i = 0; i < 12; ++i) { - await expect(page.slot(i).joinButton()).toBeDisabled() - } + await Promise.all([ + expect(page.goBackToGameLink()).toBeVisible(), + ...Array.from(Array(12).keys()).map( + async i => await expect(page.slot(i).joinButton()).toBeDisabled(), + ), + ]) }), ]) @@ -57,12 +61,14 @@ launchGameAndInitialize( .map(async player => { const page = await player.queuePage() await page.goto() - await expect(page.goBackToGameLink()).not.toBeVisible({ - timeout: secondsToMilliseconds(5), - }) - for (let i = 0; i < 12; ++i) { - await expect(page.slot(i).joinButton()).toBeEnabled() - } + await Promise.all([ + expect(page.goBackToGameLink()).not.toBeVisible({ + timeout: secondsToMilliseconds(5), + }), + ...Array.from(Array(12).keys()).map( + async i => await expect(page.slot(i).joinButton()).toBeEnabled(), + ), + ]) }), ) }, diff --git a/tests/pages/queue.page.ts b/tests/pages/queue.page.ts index 84609bcd..f0207371 100644 --- a/tests/pages/queue.page.ts +++ b/tests/pages/queue.page.ts @@ -1,4 +1,4 @@ -import { errors, type Locator, type Page } from '@playwright/test' +import { errors, expect, type Locator, type Page } from '@playwright/test' import { secondsToMilliseconds } from 'date-fns' class QueueSlot { @@ -12,15 +12,19 @@ class QueueSlot { } joinButton() { - return this.page.getByLabel(`Join queue on slot ${this.slotNumber}`, { exact: true }) + return this.locator.getByRole('button', { + name: `Join queue on slot ${this.slotNumber}`, + exact: true, + }) } async join() { await this.joinButton().click() + await expect(this.joinButton()).not.toBeVisible() } markAsFriendButton() { - return this.locator.getByRole('button', { name: 'Mark as friend' }) + return this.locator.getByLabel('Mark as friend') } } @@ -43,7 +47,7 @@ class ReadyUpDialog { } async notReady() { - await this.page.getByRole('button', { name: `Can't play right now` }).click() + await this.page.getByRole('button', { name: `No, I can't play now` }).click() } } @@ -59,7 +63,7 @@ export class QueuePage { } async leaveQueue(timeout = secondsToMilliseconds(5)) { - await this.page.getByLabel(`Leave queue`, { exact: true }).click({ timeout }) + await this.page.getByRole('button', { name: 'Leave queue' }).click({ timeout }) } header() { @@ -74,14 +78,6 @@ export class QueuePage { return this.page.getByLabel(`Queue slot ${slot}`, { exact: true }) } - markAsFriendButton(slot: number) { - return this.queueSlot(slot).getByRole('button', { name: 'Mark as friend' }) - } - - unfriendButton(slot: number) { - return this.queueSlot(slot).getByRole('button', { name: 'Unfriend' }) - } - voteForMapButton(mapNo: number) { return this.page.getByLabel('Vote for map').locator(`nth=${mapNo}`) }