From 85b48744cec5504fda8f35799896b99cf2e51441 Mon Sep 17 00:00:00 2001 From: Mehdi Benouhoud <mehdi.benouhoud@polymtl.ca> Date: Tue, 16 Apr 2024 19:21:42 -0400 Subject: [PATCH 1/8] debut tests --- .../classes/rooms/random/random.room.spec.ts | 127 +++++++++++++++--- 1 file changed, 105 insertions(+), 22 deletions(-) diff --git a/server/app/game/classes/rooms/random/random.room.spec.ts b/server/app/game/classes/rooms/random/random.room.spec.ts index 5951b01b..620e9ab3 100644 --- a/server/app/game/classes/rooms/random/random.room.spec.ts +++ b/server/app/game/classes/rooms/random/random.room.spec.ts @@ -1,41 +1,124 @@ +import { RandomRoom } from '@app/game/classes/rooms/random/random.room'; +import * as TimerModule from '@app/game/classes/timer/timer.class'; import { Game } from '@common/game'; +import { QuestionType } from '@common/question'; import { Quiz } from '@common/quiz'; +import { RANDOM_GAME_DURATION, RANDOM_GAME_ID, RANDOM_GAME_TITLE } from '@common/random-game'; import * as sinon from 'sinon'; -import { Server } from 'socket.io'; -import { RandomRoom } from './random.room'; +import { BroadcastOperator, Server, Socket } from 'socket.io'; +import type { DefaultEventsMap } from 'socket.io/dist/typed-events'; +import { HOST_USERNAME } from './random.room.constants'; +import { Answer } from '@common/player'; +import { AnswerManager } from '../../managers/answer/answer.manager'; -describe('RandomRoom', () => { - let randomRoom: RandomRoom; +class TestableRandomRoom extends RandomRoom { + startWithDelay = this.startWithDelay; + sendResults = this.sendResults; + sendFinalResults = this.sendFinalResults; + finalize = this.finalize; + continueWithDelay = this.continueWithDelay; + onQuestionEnd = this.onQuestionEnd; +} - let server: sinon.SinonStubbedInstance<Server>; +class MockTimer { + constructorSpy = sinon.spy(); + dispose = sinon.spy(); + start = sinon.spy(); + + constructor(...args: unknown[]) { + this.constructorSpy(...args); + } +} - let quiz: Quiz; - let game: Game; +(TimerModule.Timer as unknown) = MockTimer; +describe('RandomRoom', () => { + let randomRoom: TestableRandomRoom; + let server: sinon.SinonStubbedInstance<Server>; + let serverRoom: sinon.SinonStubbedInstance<Socket>; + let answerManager: sinon.SinonStubbedInstance<AnswerManager>; + let randomRoomQuizMock: Quiz; + let randomRoomGameMock: Game; beforeEach(() => { - server = sinon.createStubInstance<Server>(Server); + randomRoomGameMock = { + id: '1234', + pin: '1234', + duration: 60, + nQuestions: 5, + title: 'randomGameTitle', + }; - quiz = { - _id: 'testQuizId', - title: 'foo', - duration: 10, - questions: [], + randomRoomQuizMock = { + _id: RANDOM_GAME_ID, isAvailable: true, + questions: [ + { + _id: '1234', + type: QuestionType.Qcm, + choices: [], + text: 'testQuestion', + points: 10, + }, + { + _id: '1235', + type: QuestionType.Qcm, + choices: [], + text: 'testQuestion2', + points: 10, + }, + ], lastModification: new Date(), - description: 'Test Quiz Description', - } as Quiz; + title: RANDOM_GAME_TITLE, + description: 'partie aleatoire testee', + duration: RANDOM_GAME_DURATION, + }; - game = { - id: 'testGameId', - pin: '1234', - title: 'Test Game', - duration: 60, - } as Game; + server = sinon.createStubInstance<Server>(Server); + serverRoom = sinon.createStubInstance<Socket>(Socket); + answerManager = sinon.createStubInstance<AnswerManager>(AnswerManager); + server.to.callsFake(() => serverRoom as unknown as BroadcastOperator<DefaultEventsMap, unknown>); + + randomRoom = new TestableRandomRoom(randomRoomGameMock, randomRoomQuizMock, server); - randomRoom = new RandomRoom(game, quiz, server); + randomRoom['answers'] = answerManager; + }); + + afterEach(() => { + jest.restoreAllMocks(); }); it('should create', () => { expect(randomRoom).toBeTruthy(); }); + + describe('sendResults', () => { + beforeEach(() => { + randomRoom['currentQuestionIndex'] = 0; + }); + it('should call super.sendResults', () => { + const sendResultsSpy = jest.spyOn(randomRoom, 'sendResults'); + randomRoom['sendResults'](); + expect(sendResultsSpy).toHaveBeenCalled(); + }); + + it('should call continueWithDelay', () => { + const continueSpy = jest.spyOn(randomRoom, 'continueWithDelay'); + randomRoom['sendResults'](); + expect(continueSpy).toHaveBeenCalled(); + }); + }); + + describe('demoteHostPlayer', () => { + it("should call players.add with the host's id and HOST_USERNAME", () => { + const addSpy = jest.spyOn(randomRoom['players'], 'add'); + randomRoom['hostId'] = 'testHostId'; + randomRoom['demoteHostToPlayer'](); + expect(addSpy).toHaveBeenCalledWith('testHostId', HOST_USERNAME); + }); + it('should set hostId to a blank string', () => { + randomRoom['hostId'] = 'testHostId'; + randomRoom['demoteHostToPlayer'](); + expect(randomRoom['hostId']).toBe(''); + }); + }); }); -- GitLab From e43963c705a0b461571a2c5a6afeb85494f60928 Mon Sep 17 00:00:00 2001 From: Mehdi Benouhoud <mehdi.benouhoud@polymtl.ca> Date: Tue, 16 Apr 2024 19:39:23 -0400 Subject: [PATCH 2/8] sovled things --- .../classes/rooms/random/random.room.spec.ts | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/server/app/game/classes/rooms/random/random.room.spec.ts b/server/app/game/classes/rooms/random/random.room.spec.ts index 620e9ab3..2a8060d8 100644 --- a/server/app/game/classes/rooms/random/random.room.spec.ts +++ b/server/app/game/classes/rooms/random/random.room.spec.ts @@ -76,6 +76,27 @@ describe('RandomRoom', () => { server = sinon.createStubInstance<Server>(Server); serverRoom = sinon.createStubInstance<Socket>(Socket); answerManager = sinon.createStubInstance<AnswerManager>(AnswerManager); + answerManager.getAll.returns([{ + score: 1, + finalizedTimestamp: 1, + answerTimestamp: 1, + forceFinalize: true, + type: QuestionType.Qcm, + isCorrect: true, + choices: [true, true, false, false], + bonusObtained: true + }, + { + score: 1, + finalizedTimestamp: 1, + answerTimestamp: 1, + forceFinalize: true, + type: QuestionType.Qcm, + isCorrect: true, + choices: [true, true, false, false], + bonusObtained: true + } + ] as Answer[]); server.to.callsFake(() => serverRoom as unknown as BroadcastOperator<DefaultEventsMap, unknown>); randomRoom = new TestableRandomRoom(randomRoomGameMock, randomRoomQuizMock, server); @@ -108,6 +129,10 @@ describe('RandomRoom', () => { }); }); + describe('sendFinalResults', () => { + + }); + describe('demoteHostPlayer', () => { it("should call players.add with the host's id and HOST_USERNAME", () => { const addSpy = jest.spyOn(randomRoom['players'], 'add'); -- GitLab From bb6ade1f9b716bd82b71a44a53136d27877cf3b5 Mon Sep 17 00:00:00 2001 From: Caaf14 <cata-araya@outlook.com> Date: Tue, 16 Apr 2024 19:51:57 -0400 Subject: [PATCH 3/8] start done --- .../classes/rooms/random/random.room.spec.ts | 88 +++++++++++++------ 1 file changed, 63 insertions(+), 25 deletions(-) diff --git a/server/app/game/classes/rooms/random/random.room.spec.ts b/server/app/game/classes/rooms/random/random.room.spec.ts index 2a8060d8..da38527d 100644 --- a/server/app/game/classes/rooms/random/random.room.spec.ts +++ b/server/app/game/classes/rooms/random/random.room.spec.ts @@ -1,15 +1,17 @@ +import { AnswerManager } from '@app/game/classes/managers/answer/answer.manager'; +import { DELAY_BEFORE_START_S } from '@app/game/classes/rooms/game/game.room.constants'; import { RandomRoom } from '@app/game/classes/rooms/random/random.room'; import * as TimerModule from '@app/game/classes/timer/timer.class'; import { Game } from '@common/game'; +import { Answer } from '@common/player'; import { QuestionType } from '@common/question'; import { Quiz } from '@common/quiz'; import { RANDOM_GAME_DURATION, RANDOM_GAME_ID, RANDOM_GAME_TITLE } from '@common/random-game'; +import { WsException } from '@nestjs/websockets'; import * as sinon from 'sinon'; import { BroadcastOperator, Server, Socket } from 'socket.io'; import type { DefaultEventsMap } from 'socket.io/dist/typed-events'; import { HOST_USERNAME } from './random.room.constants'; -import { Answer } from '@common/player'; -import { AnswerManager } from '../../managers/answer/answer.manager'; class TestableRandomRoom extends RandomRoom { startWithDelay = this.startWithDelay; @@ -76,26 +78,27 @@ describe('RandomRoom', () => { server = sinon.createStubInstance<Server>(Server); serverRoom = sinon.createStubInstance<Socket>(Socket); answerManager = sinon.createStubInstance<AnswerManager>(AnswerManager); - answerManager.getAll.returns([{ - score: 1, - finalizedTimestamp: 1, - answerTimestamp: 1, - forceFinalize: true, - type: QuestionType.Qcm, - isCorrect: true, - choices: [true, true, false, false], - bonusObtained: true - }, - { - score: 1, - finalizedTimestamp: 1, - answerTimestamp: 1, - forceFinalize: true, - type: QuestionType.Qcm, - isCorrect: true, - choices: [true, true, false, false], - bonusObtained: true - } + answerManager.getAll.returns([ + { + score: 1, + finalizedTimestamp: 1, + answerTimestamp: 1, + forceFinalize: true, + type: QuestionType.Qcm, + isCorrect: true, + choices: [true, true, false, false], + bonusObtained: true, + }, + { + score: 1, + finalizedTimestamp: 1, + answerTimestamp: 1, + forceFinalize: true, + type: QuestionType.Qcm, + isCorrect: true, + choices: [true, true, false, false], + bonusObtained: true, + }, ] as Answer[]); server.to.callsFake(() => serverRoom as unknown as BroadcastOperator<DefaultEventsMap, unknown>); @@ -112,6 +115,43 @@ describe('RandomRoom', () => { expect(randomRoom).toBeTruthy(); }); + describe('start', () => { + let host: Socket; + let nonHost: Socket; + let demoteHostToPlayerStub: sinon.SinonStub; + let startWithDelayStub: sinon.SinonStub; + + beforeEach(() => { + host = { id: 'hostId' } as Socket; + nonHost = { id: 'nonHostId' } as Socket; + randomRoom['hostId'] = 'hostId'; + randomRoom['isLocked'] = true; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + demoteHostToPlayerStub = sinon.stub(randomRoom as any, 'demoteHostToPlayer'); + startWithDelayStub = sinon.stub(randomRoom, 'startWithDelay'); + }); + + it('should throw an error if a non-host tries to start the game', () => { + expect(() => randomRoom.start(nonHost)).toThrow(WsException); + }); + + it('should throw an error if the game is not locked', () => { + randomRoom['isLocked'] = false; + expect(() => randomRoom.start(host)).toThrow(WsException); + }); + + it('should set the start timestamp, demote the host to player, and start the game with delay', () => { + const now = Date.now(); + sinon.useFakeTimers(now); + + randomRoom.start(host); + + expect(randomRoom['startTimestamp']).toBe(now); + expect(demoteHostToPlayerStub.calledOnce).toBeTruthy(); + expect(startWithDelayStub.calledWith(DELAY_BEFORE_START_S)).toBeTruthy(); + }); + }); + describe('sendResults', () => { beforeEach(() => { randomRoom['currentQuestionIndex'] = 0; @@ -129,9 +169,7 @@ describe('RandomRoom', () => { }); }); - describe('sendFinalResults', () => { - - }); + describe('sendFinalResults', () => {}); describe('demoteHostPlayer', () => { it("should call players.add with the host's id and HOST_USERNAME", () => { -- GitLab From ab362c73f0416495e075e91bb737f8e6cc43ea33 Mon Sep 17 00:00:00 2001 From: Caaf14 <cata-araya@outlook.com> Date: Tue, 16 Apr 2024 20:18:28 -0400 Subject: [PATCH 4/8] timer fixed --- server/app/game/classes/rooms/random/random.room.spec.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/server/app/game/classes/rooms/random/random.room.spec.ts b/server/app/game/classes/rooms/random/random.room.spec.ts index da38527d..d003ae9c 100644 --- a/server/app/game/classes/rooms/random/random.room.spec.ts +++ b/server/app/game/classes/rooms/random/random.room.spec.ts @@ -184,4 +184,13 @@ describe('RandomRoom', () => { expect(randomRoom['hostId']).toBe(''); }); }); + + it('should dispose the timer when sendFinalResults is called', () => { + const oldTimer = { dispose: sinon.spy() }; + randomRoom['timer'] = oldTimer as unknown as TimerModule.Timer; + + randomRoom.sendFinalResults(); + + expect(oldTimer.dispose.called).toBe(true); + }); }); -- GitLab From d6da6918c4208c06e828ffcff675cfc6e6c36d3b Mon Sep 17 00:00:00 2001 From: Mehdi Benouhoud <mehdi.benouhoud@polymtl.ca> Date: Tue, 16 Apr 2024 19:47:16 -0400 Subject: [PATCH 5/8] continue sendfinalresults --- .../classes/rooms/random/random.room.spec.ts | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/server/app/game/classes/rooms/random/random.room.spec.ts b/server/app/game/classes/rooms/random/random.room.spec.ts index d003ae9c..f7ccf6b3 100644 --- a/server/app/game/classes/rooms/random/random.room.spec.ts +++ b/server/app/game/classes/rooms/random/random.room.spec.ts @@ -11,7 +11,10 @@ import { WsException } from '@nestjs/websockets'; import * as sinon from 'sinon'; import { BroadcastOperator, Server, Socket } from 'socket.io'; import type { DefaultEventsMap } from 'socket.io/dist/typed-events'; -import { HOST_USERNAME } from './random.room.constants'; +import { DELAY_BEFORE_END_S, HOST_USERNAME } from './random.room.constants'; +import { Answer } from '@common/player'; +import { AnswerManager } from '../../managers/answer/answer.manager'; +import exp from 'constants'; class TestableRandomRoom extends RandomRoom { startWithDelay = this.startWithDelay; @@ -169,7 +172,25 @@ describe('RandomRoom', () => { }); }); - describe('sendFinalResults', () => {}); + describe('sendFinalResults', () => { + it('should instantiate a new Timer', () => { + const timer = randomRoom['timer'] as unknown as MockTimer; + expect(timer.constructorSpy.called).toBe(true); + }); + + it('should start the timer and super.sendFinalResults afterwards', () => { + const endSpy = jest.spyOn(TestableRandomRoom.prototype, 'end').mockImplementation(jest.fn()); + randomRoom.sendFinalResults(); + + const timer = randomRoom['timer'] as unknown as MockTimer; + expect(timer.start.called).toBe(true); + + expect(endSpy).not.toHaveBeenCalled(); + const callback = timer.start.getCall(0).args[0] as () => void; + callback(); + expect(endSpy).toHaveBeenCalled(); + }); + }); describe('demoteHostPlayer', () => { it("should call players.add with the host's id and HOST_USERNAME", () => { -- GitLab From 874f2dffe5c51006902a3927f98e6a5d113943aa Mon Sep 17 00:00:00 2001 From: Caaf14 <cata-araya@outlook.com> Date: Tue, 16 Apr 2024 20:22:10 -0400 Subject: [PATCH 6/8] fix timer good version --- .../classes/rooms/random/random.room.spec.ts | 25 ++----------------- 1 file changed, 2 insertions(+), 23 deletions(-) diff --git a/server/app/game/classes/rooms/random/random.room.spec.ts b/server/app/game/classes/rooms/random/random.room.spec.ts index f7ccf6b3..d003ae9c 100644 --- a/server/app/game/classes/rooms/random/random.room.spec.ts +++ b/server/app/game/classes/rooms/random/random.room.spec.ts @@ -11,10 +11,7 @@ import { WsException } from '@nestjs/websockets'; import * as sinon from 'sinon'; import { BroadcastOperator, Server, Socket } from 'socket.io'; import type { DefaultEventsMap } from 'socket.io/dist/typed-events'; -import { DELAY_BEFORE_END_S, HOST_USERNAME } from './random.room.constants'; -import { Answer } from '@common/player'; -import { AnswerManager } from '../../managers/answer/answer.manager'; -import exp from 'constants'; +import { HOST_USERNAME } from './random.room.constants'; class TestableRandomRoom extends RandomRoom { startWithDelay = this.startWithDelay; @@ -172,25 +169,7 @@ describe('RandomRoom', () => { }); }); - describe('sendFinalResults', () => { - it('should instantiate a new Timer', () => { - const timer = randomRoom['timer'] as unknown as MockTimer; - expect(timer.constructorSpy.called).toBe(true); - }); - - it('should start the timer and super.sendFinalResults afterwards', () => { - const endSpy = jest.spyOn(TestableRandomRoom.prototype, 'end').mockImplementation(jest.fn()); - randomRoom.sendFinalResults(); - - const timer = randomRoom['timer'] as unknown as MockTimer; - expect(timer.start.called).toBe(true); - - expect(endSpy).not.toHaveBeenCalled(); - const callback = timer.start.getCall(0).args[0] as () => void; - callback(); - expect(endSpy).toHaveBeenCalled(); - }); - }); + describe('sendFinalResults', () => {}); describe('demoteHostPlayer', () => { it("should call players.add with the host's id and HOST_USERNAME", () => { -- GitLab From e6652f4d04dfd0166ca9598d1b84eeb77bf63388 Mon Sep 17 00:00:00 2001 From: Mehdi Benouhoud <mehdi.benouhoud@polymtl.ca> Date: Tue, 16 Apr 2024 20:25:31 -0400 Subject: [PATCH 7/8] removed s** tests --- server/app/game/classes/rooms/random/random.room.spec.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/server/app/game/classes/rooms/random/random.room.spec.ts b/server/app/game/classes/rooms/random/random.room.spec.ts index d003ae9c..e6c64407 100644 --- a/server/app/game/classes/rooms/random/random.room.spec.ts +++ b/server/app/game/classes/rooms/random/random.room.spec.ts @@ -169,8 +169,6 @@ describe('RandomRoom', () => { }); }); - describe('sendFinalResults', () => {}); - describe('demoteHostPlayer', () => { it("should call players.add with the host's id and HOST_USERNAME", () => { const addSpy = jest.spyOn(randomRoom['players'], 'add'); -- GitLab From 91e41789d9f528476dd00f14d4265405ca19ed45 Mon Sep 17 00:00:00 2001 From: Mehdi Benouhoud <mehdi.benouhoud@polymtl.ca> Date: Tue, 16 Apr 2024 20:49:02 -0400 Subject: [PATCH 8/8] fix lint --- server/app/game/classes/rooms/random/random.room.spec.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/server/app/game/classes/rooms/random/random.room.spec.ts b/server/app/game/classes/rooms/random/random.room.spec.ts index e6c64407..e52f1c82 100644 --- a/server/app/game/classes/rooms/random/random.room.spec.ts +++ b/server/app/game/classes/rooms/random/random.room.spec.ts @@ -1,3 +1,4 @@ +/* eslint-disable max-classes-per-file */ import { AnswerManager } from '@app/game/classes/managers/answer/answer.manager'; import { DELAY_BEFORE_START_S } from '@app/game/classes/rooms/game/game.room.constants'; import { RandomRoom } from '@app/game/classes/rooms/random/random.room'; -- GitLab