From a7e442640b97164961cd4e533ce3007e24a585c0 Mon Sep 17 00:00:00 2001 From: AlecM33 Date: Sat, 5 Aug 2023 03:12:50 -0400 Subject: [PATCH] add specs --- client/src/modules/game_state/StateBucket.js | 2 +- spec/e2e/game_spec.js | 98 +++++++++++++++++++- spec/support/MockGames.js | 59 +++++++++++- spec/unit/server/modules/Events_Spec.js | 67 +++++++++++++ 4 files changed, 222 insertions(+), 4 deletions(-) diff --git a/client/src/modules/game_state/StateBucket.js b/client/src/modules/game_state/StateBucket.js index 528ecdd..4ce8897 100644 --- a/client/src/modules/game_state/StateBucket.js +++ b/client/src/modules/game_state/StateBucket.js @@ -6,5 +6,5 @@ export const stateBucket = { joinRequestInFlight: true, accessCode: null, currentGameState: null, - environment: null + environment: null, }; diff --git a/spec/e2e/game_spec.js b/spec/e2e/game_spec.js index 162ee71..8774def 100644 --- a/spec/e2e/game_spec.js +++ b/spec/e2e/game_spec.js @@ -15,7 +15,7 @@ describe('game page', () => { } }; - describe('lobby game', () => { + describe('lobby game - moderator view', () => { let mockSocket; beforeEach(async function () { @@ -34,7 +34,7 @@ describe('game page', () => { emit: function (eventName, ...args) { switch (args[0]) { // eventName is currently always "inGameMessage" - the first arg after that is the specific message type case globals.EVENT_IDS.FETCH_GAME_STATE: - args[args.length - 1](deepCopy(mockGames.gameInLobby)); // copy the game object to prevent leaking of state between specs + args[args.length - 1](deepCopy(mockGames.gameInLobbyAsModerator)); // copy the game object to prevent leaking of state between specs } }, removeAllListeners: function (...names) { @@ -46,6 +46,7 @@ describe('game page', () => { }; await gameHandler(mockSocket, XHRUtility, { location: { href: 'host/game/ABCD' } }, gameTemplate); mockSocket.eventHandlers.connect(); + spyOn(mockSocket, 'emit'); }); it('should display the connected client', () => { @@ -69,6 +70,99 @@ describe('game page', () => { expect(document.getElementById('current-info-message').innerText).toEqual('Jane joined!'); }); + it('should display the cards currently in the deck when the Edit Roles button is clicked', () => { + document.getElementById('edit-roles-button').click(); + + expect(document.querySelectorAll('.added-role').length).toEqual(mockGames.gameInLobbyAsModerator.deck.length); + expect(document.getElementById('deck-count').innerText).toEqual(mockGames.gameInLobbyAsModerator.gameSize + ' Players'); + }); + + it('should send an update to the game information if I save changes to the deck', () => { + document.getElementById('edit-roles-button').click(); + document.querySelectorAll('.added-role').item(0).querySelector('.role-remove').click(); + document.getElementById('save-role-changes-button').click(); + + expect(mockSocket.emit).toHaveBeenCalledWith( + globals.SOCKET_EVENTS.IN_GAME_MESSAGE, + globals.EVENT_IDS.UPDATE_GAME_ROLES, + mockGames.gameInLobbyAsModerator.accessCode, + jasmine.any(Object), + jasmine.any(Function) + ); + }); + + afterAll(() => { + document.body.innerHTML = ''; + }); + }); + + describe('lobby game - player view', () => { + let mockSocket; + + beforeEach(async function () { + document.body.innerHTML = ''; + mockSocket = { + eventHandlers: {}, + on: function (message, handler) { + this.eventHandlers[message] = handler; + }, + once: function (message, handler) { + this.eventHandlers[message] = handler; + }, + timeout: (duration) => { + return mockSocket; + }, + emit: function (eventName, ...args) { + switch (args[0]) { // eventName is currently always "inGameMessage" - the first arg after that is the specific message type + case globals.EVENT_IDS.FETCH_GAME_STATE: + args[args.length - 1](deepCopy(mockGames.gameInLobbyAsPlayer)); // copy the game object to prevent leaking of state between specs + } + }, + removeAllListeners: function (...names) { + + }, + hasListeners: function (listener) { + return false; + } + }; + await gameHandler(mockSocket, XHRUtility, { location: { href: 'host/game/ABCD' } }, gameTemplate); + mockSocket.eventHandlers.connect(); + spyOn(mockSocket, 'emit'); + }); + + it('should display the connected client', () => { + expect(document.getElementById('client-name').innerText).toEqual('Lys'); + expect(document.getElementById('client-user-type').innerText).toEqual('player' + globals.USER_TYPE_ICONS.player); + }); + + it('should display the QR Code', () => { + expect(document.getElementById('canvas').innerText).not.toBeNull(); + }); + + it('should display the option to leave the game, and fire the event when it is selected and confirmed', () => { + expect(document.getElementById('leave-game-button')).not.toBeNull(); + document.getElementById('leave-game-button').click(); + document.getElementById('confirmation-yes-button').click(); + expect(mockSocket.emit).toHaveBeenCalledWith( + globals.SOCKET_EVENTS.IN_GAME_MESSAGE, + globals.EVENT_IDS.LEAVE_ROOM, + mockGames.gameInLobbyAsModerator.accessCode, + { personId: mockGames.gameInLobbyAsPlayer.client.id } + ); + }); + + it('should display a new player when they join', () => { + mockSocket.eventHandlers[globals.EVENT_IDS.PLAYER_JOINED]({ + name: 'Jane', + id: '123', + userType: globals.USER_TYPES.PLAYER, + out: false, + revealed: false + }, false); + expect(document.querySelectorAll('.lobby-player').length).toEqual(3); + expect(document.getElementById('current-info-message').innerText).toEqual('Jane joined!'); + }); + afterAll(() => { document.body.innerHTML = ''; }); diff --git a/spec/support/MockGames.js b/spec/support/MockGames.js index 37680e3..edb92de 100644 --- a/spec/support/MockGames.js +++ b/spec/support/MockGames.js @@ -1,5 +1,5 @@ export const mockGames = { - gameInLobby: { + gameInLobbyAsModerator: { accessCode: 'TVV6', status: 'lobby', currentModeratorId: 'w8qarnG6FgAZQvRYsAFefldwU2r6KIeOce3nGaLxnfMlKIBOLj0DhUSC951bQ7yLwbRjDAS72r4', @@ -48,6 +48,63 @@ export const mockGames = { }, isStartable: false }, + gameInLobbyAsPlayer: { + accessCode: 'TVV6', + status: 'lobby', + currentModeratorId: 'w8qarnG6FgAZQvRYsAFefldwU2r6KIeOce3nGaLxnfMlKIBOLj0DhUSC951bQ7yLwbRjDAS72r4', + client: { + name: 'Lys', + hasEnteredName: false, + id: 'v2eOvaYKusGfiUpuZWTCJ0JUiESC29OuH6fpivwMuwcqizpYTCAzetrPl7fF8F5CoR35pTMIKxh', + cookie: '28p80dbhY2k1iP1NuEy8UPFmuOctLx3nR0EMONU4MlJFfVrCzNncdNdsav9wEuGEswLQ70DKqa3', + userType: 'player' + }, + deck: [ + { + role: 'Villager', + team: 'good', + description: 'During the day, find the wolves and kill them.', + id: '52u5w81ryq5h30qu1gri56xxq', + quantity: 6 + }, + { + role: 'Werewolf', + team: 'evil', + description: "During the night, choose a villager to kill. Don't get killed.", + id: '9uk0jcrm1hkhygzb6iw8xh2a7', + quantity: 1 + } + ], + gameSize: 7, + people: [ + { + name: 'Alec', + id: 'w8qarnG6FgAZQvRYsAFefldwU2r6KIeOce3nGaLxnfMlKIBOLj0DhUSC951bQ7yLwbRjDAS72r4', + userType: 'moderator', + gameRole: null, + gameRoleDescription: null, + alignment: null, + out: true, + killed: false, + revealed: false + }, + { + name: 'Lys', + id: 'v2eOvaYKusGfiUpuZWTCJ0JUiESC29OuH6fpivwMuwcqizpYTCAzetrPl7fF8F5CoR35pTMIKxh', + userType: 'player', + out: false, + killed: false, + revealed: false + } + ], + timerParams: { + hours: null, + minutes: 10, + paused: true, + timeRemaining: 600000 + }, + isStartable: false + }, inProgressGame: { accessCode: 'TVV6', status: 'in progress', diff --git a/spec/unit/server/modules/Events_Spec.js b/spec/unit/server/modules/Events_Spec.js index cd7252a..6ce58ec 100644 --- a/spec/unit/server/modules/Events_Spec.js +++ b/spec/unit/server/modules/Events_Spec.js @@ -115,6 +115,73 @@ describe('Events', () => { }); }); + describe(EVENT_IDS.UPDATE_GAME_ROLES, () => { + describe('stateChange', () => { + it('should update the game roles', async () => { + await Events.find((e) => e.id === EVENT_IDS.UPDATE_GAME_ROLES) + .stateChange(game, { + deck: [ + { + role: 'Parity Hunter', + team: 'good', + description: 'You beat a werewolf in a 1v1 situation, winning the game for the village.', + id: '6yh9h70h4tu47tt3ev39jbox6nlckmvmvadpt5r042iq31249l', + quantity: 1 + }, + { + role: 'Seer', + team: 'good', + description: 'Each night, learn if a chosen person is a Werewolf.', + id: 'eat0h7d0a5vzd7h2ddbxi6gy10mqn95u50595dr1eazb47mjm7', + quantity: 1 + }, + { + role: 'Villager', + team: 'good', + description: 'During the day, find the wolves and kill them.', + id: 'i4ora0tj4excnnrmrkm0l6zbqhvlneivnofq908c3vp0n4uof8', + quantity: 1 + }, + { + role: 'Sorceress', + team: 'evil', + description: 'Each night, learn if a chosen person is the Seer.', + id: 'ywl9sqpr0lj4uplu81bvsnutlabtghe2ra41hyfstytnu6t85t', + quantity: 1 + }, + { + role: 'Werewolf', + team: 'evil', + description: "During the night, choose a villager to kill. Don't get killed.", + id: '6wrjy32eqj0171uxmhd6lwql6h7ph90djavtxybfzwbjyal489', + quantity: 1 + } + ] + }, { gameManager: gameManager }); + + expect(game.gameSize).toEqual(5); + expect(game.isStartable).toEqual(false); + }); + }); + }); + + describe(EVENT_IDS.LEAVE_ROOM, () => { + describe('stateChange', () => { + it('should remove a player and mark the game as startable', async () => { + await Events.find((e) => e.id === EVENT_IDS.PLAYER_JOINED) + .stateChange(game, { id: 'd', assigned: true, userType: USER_TYPES.PLAYER }, { gameManager: gameManager }); + await Events.find((e) => e.id === EVENT_IDS.PLAYER_JOINED) + .stateChange(game, { id: 'e', assigned: true, userType: USER_TYPES.PLAYER }, { gameManager: gameManager }); + await Events.find((e) => e.id === EVENT_IDS.LEAVE_ROOM) + .stateChange(game, { personId: 'b' }, { gameManager: gameManager }); + + expect(game.people.find(person => person.id === 'b')).not.toBeDefined(); + expect(game.gameSize).toEqual(2); + expect(game.isStartable).toEqual(true); + }); + }); + }); + describe(EVENT_IDS.FETCH_GAME_STATE, () => { describe('stateChange', () => { it('should find the matching person and update their associated socket id if it is different', async () => {