From dfd609cda2c96291336252dcaea7f3773b82862c Mon Sep 17 00:00:00 2001 From: jkrizsan <57282556+jkrizsan@users.noreply.github.com> Date: Tue, 27 May 2025 22:20:30 +0300 Subject: [PATCH 1/8] Add StatisticsKeeper test module. --- .../modules/statisticsKeeper.module.ts | 11 +++++ .../modules/statisticsKeeperCommon.module.ts | 43 +++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 src/__tests__/statisticsKeeper/modules/statisticsKeeper.module.ts create mode 100644 src/__tests__/statisticsKeeper/modules/statisticsKeeperCommon.module.ts diff --git a/src/__tests__/statisticsKeeper/modules/statisticsKeeper.module.ts b/src/__tests__/statisticsKeeper/modules/statisticsKeeper.module.ts new file mode 100644 index 000000000..8f6319ca8 --- /dev/null +++ b/src/__tests__/statisticsKeeper/modules/statisticsKeeper.module.ts @@ -0,0 +1,11 @@ +import StatisticsKeeperCommonModule from './statisticsKeeperCommon.module'; +import { PlayerStatisticService } from 'src/statisticsKeeper/playerStatisticKeeper/playerStatisticKeeper.service'; + +export default class StatisticsKeeperModule { + private constructor() {} + + static async getPlayerStatisticService() { + const module = await StatisticsKeeperCommonModule.getModule(); + return await module.resolve(PlayerStatisticService); + } +} diff --git a/src/__tests__/statisticsKeeper/modules/statisticsKeeperCommon.module.ts b/src/__tests__/statisticsKeeper/modules/statisticsKeeperCommon.module.ts new file mode 100644 index 000000000..18abc42dd --- /dev/null +++ b/src/__tests__/statisticsKeeper/modules/statisticsKeeperCommon.module.ts @@ -0,0 +1,43 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { MongooseModule } from '@nestjs/mongoose'; +import { mongooseOptions, mongoString } from '../../test_utils/const/db'; +import { ModelName } from '../../../common/enum/modelName.enum'; +import { PlayerSchema } from '../../../player/schemas/player.schema'; +import { PlayerService } from '../../../player/player.service'; +import { PlayerStatisticService } from '../../../statisticsKeeper/playerStatisticKeeper/playerStatisticKeeper.service'; +import { StatisticsKeeperModule } from '../../../statisticsKeeper/statisticsKeeper.module'; +import { CustomCharacterSchema } from '../../../player/customCharacter/customCharacter.schema'; +import { RequestHelperModule } from '../../../requestHelper/requestHelper.module'; +import { CustomCharacterService } from '../../../player/customCharacter/customCharacter.service'; + +export default class StatisticsKeeperCommonModule { + static async getPlayerStatisticService() { + const module = await StatisticsKeeperCommonModule.getModule(); + return await module.resolve(PlayerStatisticService); + } + private constructor() {} + + private static module: TestingModule; + + static async getModule() { + if (!StatisticsKeeperCommonModule.module) + StatisticsKeeperCommonModule.module = await Test.createTestingModule({ + imports: [ + MongooseModule.forRoot(mongoString, mongooseOptions), + MongooseModule.forFeature([ + { name: ModelName.PLAYER, schema: PlayerSchema }, + { name: ModelName.CUSTOM_CHARACTER, schema: CustomCharacterSchema }, + ]), + StatisticsKeeperModule, + RequestHelperModule, + ], + providers: [ + PlayerStatisticService, + PlayerService, + CustomCharacterService, + ], + }).compile(); + + return StatisticsKeeperCommonModule.module; + } +} From a87ae3819d85173e1a323a1861af52afe11c4c67 Mon Sep 17 00:00:00 2001 From: jkrizsan <57282556+jkrizsan@users.noreply.github.com> Date: Thu, 29 May 2025 15:59:16 +0300 Subject: [PATCH 2/8] Implement the PlayerStatisticService.updatePlayerStatistic() test suite --- .../updatePlayerStatistic.test.ts | 308 ++++++++++++++++++ .../modules/statisticsKeeper.module.ts | 8 +- .../modules/statisticsKeeperCommon.module.ts | 9 +- 3 files changed, 322 insertions(+), 3 deletions(-) create mode 100644 src/__tests__/statisticsKeeper/PlayerStatisticService/updatePlayerStatistic.test.ts diff --git a/src/__tests__/statisticsKeeper/PlayerStatisticService/updatePlayerStatistic.test.ts b/src/__tests__/statisticsKeeper/PlayerStatisticService/updatePlayerStatistic.test.ts new file mode 100644 index 000000000..a46dd006e --- /dev/null +++ b/src/__tests__/statisticsKeeper/PlayerStatisticService/updatePlayerStatistic.test.ts @@ -0,0 +1,308 @@ +import { ObjectId, } from 'mongodb'; +import { MongooseError } from 'mongoose'; +import { Message } from '../../../player/message.schema'; +import ServiceError from '../../../common/service/basicService/ServiceError'; +import { ModelName } from '../../../common/enum/modelName.enum'; +import { SEReason } from '../../../common/service/basicService/SEReason'; +import PlayerBuilderFactory from '../../player/data/playerBuilderFactory'; +import { PlayerEvent } from '../../../rewarder/playerRewarder/enum/PlayerEvent.enum'; +import StatisticsKeeperCommonModule from '../modules/statisticsKeeperCommon.module'; +import PlayerModule from '../../player/modules/player.module'; +import { PlayerService } from '../../../player/player.service'; +import { PlayerStatisticService } from '../../../statisticsKeeper/playerStatisticKeeper/playerStatisticKeeper.service'; + +describe('PlayerStatisticService.updatePlayerStatistic() test suite', () => { + let playerStatisticService: PlayerStatisticService; + let playerService: PlayerService; + + const playerModel = PlayerModule.getPlayerModel(); + + const playerBuilder = PlayerBuilderFactory.getBuilder('Player'); + const gameStatisticsBuilder = + PlayerBuilderFactory.getBuilder('GameStatistics'); + + const playerName = 'John'; + + const playerId = new ObjectId()._id.toString(); + + beforeEach(async () => { + playerStatisticService = + await StatisticsKeeperCommonModule.getPlayerStatisticService(); + + playerService = await StatisticsKeeperCommonModule.getPlayerService(); + }); + + it('Should increase the players playedBattles if the input is valid | PlayerEvent.BATTLE_PLAYED', async () => { + + const gameStatistics = gameStatisticsBuilder + .setWonBattles(0) + .build(); + + const player = playerBuilder + .setName(playerName) + .setId(playerId) + .setGameStatistics(gameStatistics) + .build(); + + await playerModel.create(player); + + const [result, error] = await playerStatisticService.updatePlayerStatistic( + playerId, + PlayerEvent.BATTLE_PLAYED, + ); + + const updatedPlayer = await playerModel.findById(playerId); + + expect(result).toBe(true); + expect(error).toBeNull(); + expect(updatedPlayer).toBeDefined(); + expect(updatedPlayer?.gameStatistics.playedBattles).toBe(1); + expect(updatedPlayer?.name).toBe(playerName); + }); + + it('Should increase the players wonBattles if the input is valid | PlayerEvent.BATTLE_WON', async () => { + + const gameStatistics = gameStatisticsBuilder + .setWonBattles(0) + .build(); + + const player = playerBuilder + .setName(playerName) + .setId(playerId) + .setGameStatistics(gameStatistics) + .build(); + + await playerModel.create(player); + + const [result, error] = await playerStatisticService.updatePlayerStatistic( + playerId, + PlayerEvent.BATTLE_WON, + ); + + const updatedPlayer = await playerModel.findById(playerId); + + expect(result).toBe(true); + expect(error).toBeNull(); + expect(updatedPlayer).toBeDefined(); + expect(updatedPlayer?.gameStatistics.wonBattles).toBe(1); + expect(updatedPlayer?.name).toBe(playerName); + }); + + it('Should increase the players participatedVotings if the input is valid | PlayerEvent.VOTE_MADE', async () => { + + const gameStatistics = gameStatisticsBuilder + .setWonBattles(0) + .build(); + + const player = playerBuilder + .setName(playerName) + .setId(playerId) + .setGameStatistics(gameStatistics) + .build(); + + await playerModel.create(player); + + const [result, error] = await playerStatisticService.updatePlayerStatistic( + playerId, + PlayerEvent.VOTE_MADE, + ); + + const updatedPlayer = await playerModel.findById(playerId); + + expect(result).toBe(true); + expect(error).toBeNull(); + expect(updatedPlayer).toBeDefined(); + expect(updatedPlayer?.gameStatistics.participatedVotings).toBe(1); + expect(updatedPlayer?.name).toBe(playerName); + }); + + it('Should return with MongooseError if have not read the player from the DB | PlayerEvent.MESSAGE_SENT', async () => { + + const gameStatistics = gameStatisticsBuilder + .setWonBattles(0) + .build(); + + const player = playerBuilder + .setName(playerName) + .setId(playerId) + .setGameStatistics(gameStatistics) + .build(); + + await playerModel.create(player); + + jest.spyOn(playerService, 'readOneById') + .mockImplementation(async () => { + return new MongooseError('Player not found'); + }); + + const [result, error] = await playerStatisticService.updatePlayerStatistic( + playerId, + PlayerEvent.MESSAGE_SENT + ); + + expect(result).toBe(false); + expect(error).toBeInstanceOf(MongooseError); + + jest.restoreAllMocks(); + }); + + it('Should return with ServiceError if the players metadata not valid | PlayerEvent.MESSAGE_SENT', async () => { + + const gameStatistics = gameStatisticsBuilder + .setWonBattles(0) + .build(); + + const player = playerBuilder + .setName(playerName) + .setId(playerId) + .setGameStatistics(gameStatistics) + .build(); + + await playerModel.create(player); + + jest.spyOn(playerService, 'readOneById') + .mockImplementation(async () => { + return { + data: {[ModelName.BOX]: null,}, + metaData: { + dataType: 'Player' + }, + meta: { dataKey: ModelName.PLAYER } + } as any; + }); + + const [result, error] = await playerStatisticService.updatePlayerStatistic( + playerId, + PlayerEvent.MESSAGE_SENT + ); + + expect(result).toBe(false); + expect(error[0]).toBeInstanceOf(ServiceError); + expect(error[0].reason).toBe(SEReason.NOT_FOUND); + expect(error[0].message).toBe('Could not read the player'); + + jest.restoreAllMocks(); + }); + + it('Should increase the players message counter if found a todays message | PlayerEvent.MESSAGE_SENT', async () => { + + const message: Message = { + date: new Date(), + count: 1 + } as unknown as Message; + + const gameStatistics = gameStatisticsBuilder + .setWonBattles(0) + .setMessages([message]) + .build(); + + const player = playerBuilder + .setName(playerName) + .setId(playerId) + .setGameStatistics(gameStatistics) + .build(); + + await playerModel.create(player); + + const [result, error] = await playerStatisticService.updatePlayerStatistic( + playerId, + PlayerEvent.MESSAGE_SENT + ); + + const updatedPlayer = await playerModel.findById(playerId); + + expect(result).toBe(true); + expect(error).toBeNull(); + expect(updatedPlayer.name).toBe(playerName); + expect(updatedPlayer.gameStatistics.messages[0].count).toBe(2); + + }); + + it('Should add a new message to player with todays date if do not have one yet | PlayerEvent.MESSAGE_SENT', async () => { + + const gameStatistics = gameStatisticsBuilder + .setWonBattles(0) + .setMessages([]) + .build(); + + const player = playerBuilder + .setName(playerName) + .setId(playerId) + .setGameStatistics(gameStatistics) + .build(); + + await playerModel.create(player); + + const [result, error] = await playerStatisticService.updatePlayerStatistic( + playerId, + PlayerEvent.MESSAGE_SENT + ); + + const updatedPlayer = await playerModel.findById(playerId); + + expect(result).toBe(true); + expect(error).toBeNull(); + expect(updatedPlayer.name).toBe(playerName); + expect(updatedPlayer.gameStatistics.messages[0].count).toBe(1); + expect(updatedPlayer.gameStatistics.messages[0].date.toDateString()).toBe( + new Date().toDateString() + ); + expect(updatedPlayer.gameStatistics.messages.length).toBe(1); + }); + + it('Should return with MongooseError if have not updated the player in the DB | PlayerEvent.MESSAGE_SENT', async () => { + + const gameStatistics = gameStatisticsBuilder + .setWonBattles(0) + .build(); + + const player = playerBuilder + .setName(playerName) + .setId(playerId) + .setGameStatistics(gameStatistics) + .build(); + + await playerModel.create(player); + + jest.spyOn(playerService, 'updateOneById') + .mockImplementation(async () => { + return new MongooseError(''); + }); + + const [result, error] = await playerStatisticService.updatePlayerStatistic( + playerId, + PlayerEvent.MESSAGE_SENT + ); + + expect(result).toBe(false); + expect(error).toBeInstanceOf(MongooseError); + + jest.restoreAllMocks(); + }); + + it('Should return with ServiceError if PlayerEvent type is not supported | PlayerEvent.NotSupported', async () => { + + const gameStatistics = gameStatisticsBuilder + .setWonBattles(0) + .build(); + + const player = playerBuilder + .setName(playerName) + .setId(playerId) + .setGameStatistics(gameStatistics) + .build(); + + await playerModel.create(player); + + const [result, error] = await playerStatisticService.updatePlayerStatistic( + playerId, + -1 as unknown as PlayerEvent + ); + + expect(result).toBe(null); + expect(error[0]).toBeInstanceOf(ServiceError); + expect(error[0].message).toBe('Event is not supported'); + }); +}); + + diff --git a/src/__tests__/statisticsKeeper/modules/statisticsKeeper.module.ts b/src/__tests__/statisticsKeeper/modules/statisticsKeeper.module.ts index 8f6319ca8..abca0df59 100644 --- a/src/__tests__/statisticsKeeper/modules/statisticsKeeper.module.ts +++ b/src/__tests__/statisticsKeeper/modules/statisticsKeeper.module.ts @@ -1,5 +1,6 @@ import StatisticsKeeperCommonModule from './statisticsKeeperCommon.module'; -import { PlayerStatisticService } from 'src/statisticsKeeper/playerStatisticKeeper/playerStatisticKeeper.service'; +import { PlayerStatisticService } from '../../../statisticsKeeper/playerStatisticKeeper/playerStatisticKeeper.service'; +import { PlayerService } from '../../../player/player.service'; export default class StatisticsKeeperModule { private constructor() {} @@ -8,4 +9,9 @@ export default class StatisticsKeeperModule { const module = await StatisticsKeeperCommonModule.getModule(); return await module.resolve(PlayerStatisticService); } + + static async getPlayerService() { + const module = await StatisticsKeeperCommonModule.getModule(); + return await module.resolve(PlayerService); + } } diff --git a/src/__tests__/statisticsKeeper/modules/statisticsKeeperCommon.module.ts b/src/__tests__/statisticsKeeper/modules/statisticsKeeperCommon.module.ts index 18abc42dd..3aa5f7908 100644 --- a/src/__tests__/statisticsKeeper/modules/statisticsKeeperCommon.module.ts +++ b/src/__tests__/statisticsKeeper/modules/statisticsKeeperCommon.module.ts @@ -8,13 +8,18 @@ import { PlayerStatisticService } from '../../../statisticsKeeper/playerStatisti import { StatisticsKeeperModule } from '../../../statisticsKeeper/statisticsKeeper.module'; import { CustomCharacterSchema } from '../../../player/customCharacter/customCharacter.schema'; import { RequestHelperModule } from '../../../requestHelper/requestHelper.module'; -import { CustomCharacterService } from '../../../player/customCharacter/customCharacter.service'; +import { PlayerModule } from '../../../player/player.module'; export default class StatisticsKeeperCommonModule { static async getPlayerStatisticService() { const module = await StatisticsKeeperCommonModule.getModule(); return await module.resolve(PlayerStatisticService); } + + static async getPlayerService() { + const module = await StatisticsKeeperCommonModule.getModule(); + return await module.resolve(PlayerService); + } private constructor() {} private static module: TestingModule; @@ -29,12 +34,12 @@ export default class StatisticsKeeperCommonModule { { name: ModelName.CUSTOM_CHARACTER, schema: CustomCharacterSchema }, ]), StatisticsKeeperModule, + PlayerModule, RequestHelperModule, ], providers: [ PlayerStatisticService, PlayerService, - CustomCharacterService, ], }).compile(); From 416f014f272ccbb1c762462f92e25790bf0813bc Mon Sep 17 00:00:00 2001 From: Mikhail Deriabin Date: Fri, 30 May 2025 17:19:06 +0300 Subject: [PATCH 3/8] fix bug in PlayerStatisticService.trackPlayerMessageCount() handling error responses from PlayerService Error was caused by `PlayerService` returning null instead of error in case the player is not found. Bug is fixed by adding if statement which returns ServiceError NOT_FOUND if the service returns null --- .../updatePlayerStatistic.test.ts | 134 ++++++------------ .../playerStatisticKeeper.service.ts | 14 +- 2 files changed, 59 insertions(+), 89 deletions(-) diff --git a/src/__tests__/statisticsKeeper/PlayerStatisticService/updatePlayerStatistic.test.ts b/src/__tests__/statisticsKeeper/PlayerStatisticService/updatePlayerStatistic.test.ts index a46dd006e..35e9481db 100644 --- a/src/__tests__/statisticsKeeper/PlayerStatisticService/updatePlayerStatistic.test.ts +++ b/src/__tests__/statisticsKeeper/PlayerStatisticService/updatePlayerStatistic.test.ts @@ -1,4 +1,4 @@ -import { ObjectId, } from 'mongodb'; +import { ObjectId } from 'mongodb'; import { MongooseError } from 'mongoose'; import { Message } from '../../../player/message.schema'; import ServiceError from '../../../common/service/basicService/ServiceError'; @@ -20,23 +20,21 @@ describe('PlayerStatisticService.updatePlayerStatistic() test suite', () => { const playerBuilder = PlayerBuilderFactory.getBuilder('Player'); const gameStatisticsBuilder = PlayerBuilderFactory.getBuilder('GameStatistics'); - + const playerName = 'John'; const playerId = new ObjectId()._id.toString(); beforeEach(async () => { + jest.clearAllMocks(); playerStatisticService = await StatisticsKeeperCommonModule.getPlayerStatisticService(); - - playerService = await StatisticsKeeperCommonModule.getPlayerService(); + + playerService = await StatisticsKeeperCommonModule.getPlayerService(); }); it('Should increase the players playedBattles if the input is valid | PlayerEvent.BATTLE_PLAYED', async () => { - - const gameStatistics = gameStatisticsBuilder - .setWonBattles(0) - .build(); + const gameStatistics = gameStatisticsBuilder.setWonBattles(0).build(); const player = playerBuilder .setName(playerName) @@ -61,17 +59,14 @@ describe('PlayerStatisticService.updatePlayerStatistic() test suite', () => { }); it('Should increase the players wonBattles if the input is valid | PlayerEvent.BATTLE_WON', async () => { - - const gameStatistics = gameStatisticsBuilder - .setWonBattles(0) - .build(); + const gameStatistics = gameStatisticsBuilder.setWonBattles(0).build(); const player = playerBuilder .setName(playerName) .setId(playerId) .setGameStatistics(gameStatistics) .build(); - + await playerModel.create(player); const [result, error] = await playerStatisticService.updatePlayerStatistic( @@ -89,17 +84,14 @@ describe('PlayerStatisticService.updatePlayerStatistic() test suite', () => { }); it('Should increase the players participatedVotings if the input is valid | PlayerEvent.VOTE_MADE', async () => { - - const gameStatistics = gameStatisticsBuilder - .setWonBattles(0) - .build(); + const gameStatistics = gameStatisticsBuilder.setWonBattles(0).build(); const player = playerBuilder .setName(playerName) .setId(playerId) .setGameStatistics(gameStatistics) .build(); - + await playerModel.create(player); const [result, error] = await playerStatisticService.updatePlayerStatistic( @@ -117,63 +109,41 @@ describe('PlayerStatisticService.updatePlayerStatistic() test suite', () => { }); it('Should return with MongooseError if have not read the player from the DB | PlayerEvent.MESSAGE_SENT', async () => { - - const gameStatistics = gameStatisticsBuilder - .setWonBattles(0) - .build(); - - const player = playerBuilder - .setName(playerName) - .setId(playerId) - .setGameStatistics(gameStatistics) - .build(); - - await playerModel.create(player); - - jest.spyOn(playerService, 'readOneById') - .mockImplementation(async () => { - return new MongooseError('Player not found'); - }); - const [result, error] = await playerStatisticService.updatePlayerStatistic( playerId, - PlayerEvent.MESSAGE_SENT + PlayerEvent.MESSAGE_SENT, ); expect(result).toBe(false); - expect(error).toBeInstanceOf(MongooseError); + expect(error).toContainSE_NOT_FOUND(); jest.restoreAllMocks(); }); it('Should return with ServiceError if the players metadata not valid | PlayerEvent.MESSAGE_SENT', async () => { - - const gameStatistics = gameStatisticsBuilder - .setWonBattles(0) - .build(); + const gameStatistics = gameStatisticsBuilder.setWonBattles(0).build(); const player = playerBuilder .setName(playerName) .setId(playerId) .setGameStatistics(gameStatistics) .build(); - + await playerModel.create(player); - - jest.spyOn(playerService, 'readOneById') - .mockImplementation(async () => { - return { - data: {[ModelName.BOX]: null,}, - metaData: { - dataType: 'Player' - }, - meta: { dataKey: ModelName.PLAYER } - } as any; - }); + + jest.spyOn(playerService, 'readOneById').mockImplementation(async () => { + return { + data: { [ModelName.BOX]: null }, + metaData: { + dataType: 'Player', + }, + meta: { dataKey: ModelName.PLAYER }, + } as any; + }); const [result, error] = await playerStatisticService.updatePlayerStatistic( playerId, - PlayerEvent.MESSAGE_SENT + PlayerEvent.MESSAGE_SENT, ); expect(result).toBe(false); @@ -185,12 +155,11 @@ describe('PlayerStatisticService.updatePlayerStatistic() test suite', () => { }); it('Should increase the players message counter if found a todays message | PlayerEvent.MESSAGE_SENT', async () => { - const message: Message = { date: new Date(), - count: 1 + count: 1, } as unknown as Message; - + const gameStatistics = gameStatisticsBuilder .setWonBattles(0) .setMessages([message]) @@ -201,12 +170,12 @@ describe('PlayerStatisticService.updatePlayerStatistic() test suite', () => { .setId(playerId) .setGameStatistics(gameStatistics) .build(); - + await playerModel.create(player); - + const [result, error] = await playerStatisticService.updatePlayerStatistic( playerId, - PlayerEvent.MESSAGE_SENT + PlayerEvent.MESSAGE_SENT, ); const updatedPlayer = await playerModel.findById(playerId); @@ -215,11 +184,9 @@ describe('PlayerStatisticService.updatePlayerStatistic() test suite', () => { expect(error).toBeNull(); expect(updatedPlayer.name).toBe(playerName); expect(updatedPlayer.gameStatistics.messages[0].count).toBe(2); - }); it('Should add a new message to player with todays date if do not have one yet | PlayerEvent.MESSAGE_SENT', async () => { - const gameStatistics = gameStatisticsBuilder .setWonBattles(0) .setMessages([]) @@ -230,12 +197,12 @@ describe('PlayerStatisticService.updatePlayerStatistic() test suite', () => { .setId(playerId) .setGameStatistics(gameStatistics) .build(); - + await playerModel.create(player); - + const [result, error] = await playerStatisticService.updatePlayerStatistic( playerId, - PlayerEvent.MESSAGE_SENT + PlayerEvent.MESSAGE_SENT, ); const updatedPlayer = await playerModel.findById(playerId); @@ -245,33 +212,29 @@ describe('PlayerStatisticService.updatePlayerStatistic() test suite', () => { expect(updatedPlayer.name).toBe(playerName); expect(updatedPlayer.gameStatistics.messages[0].count).toBe(1); expect(updatedPlayer.gameStatistics.messages[0].date.toDateString()).toBe( - new Date().toDateString() + new Date().toDateString(), ); expect(updatedPlayer.gameStatistics.messages.length).toBe(1); }); - it('Should return with MongooseError if have not updated the player in the DB | PlayerEvent.MESSAGE_SENT', async () => { - - const gameStatistics = gameStatisticsBuilder - .setWonBattles(0) - .build(); + it('Should return with MongooseError if have not updated the player in the DB | PlayerEvent.MESSAGE_SENT', async () => { + const gameStatistics = gameStatisticsBuilder.setWonBattles(0).build(); const player = playerBuilder .setName(playerName) .setId(playerId) .setGameStatistics(gameStatistics) .build(); - + await playerModel.create(player); - - jest.spyOn(playerService, 'updateOneById') - .mockImplementation(async () => { - return new MongooseError(''); - }); + + jest.spyOn(playerService, 'updateOneById').mockImplementation(async () => { + return new MongooseError(''); + }); const [result, error] = await playerStatisticService.updatePlayerStatistic( playerId, - PlayerEvent.MESSAGE_SENT + PlayerEvent.MESSAGE_SENT, ); expect(result).toBe(false); @@ -281,22 +244,19 @@ describe('PlayerStatisticService.updatePlayerStatistic() test suite', () => { }); it('Should return with ServiceError if PlayerEvent type is not supported | PlayerEvent.NotSupported', async () => { - - const gameStatistics = gameStatisticsBuilder - .setWonBattles(0) - .build(); + const gameStatistics = gameStatisticsBuilder.setWonBattles(0).build(); const player = playerBuilder .setName(playerName) .setId(playerId) .setGameStatistics(gameStatistics) .build(); - + await playerModel.create(player); - + const [result, error] = await playerStatisticService.updatePlayerStatistic( playerId, - -1 as unknown as PlayerEvent + -1 as unknown as PlayerEvent, ); expect(result).toBe(null); @@ -304,5 +264,3 @@ describe('PlayerStatisticService.updatePlayerStatistic() test suite', () => { expect(error[0].message).toBe('Event is not supported'); }); }); - - diff --git a/src/statisticsKeeper/playerStatisticKeeper/playerStatisticKeeper.service.ts b/src/statisticsKeeper/playerStatisticKeeper/playerStatisticKeeper.service.ts index f871d2633..976045247 100644 --- a/src/statisticsKeeper/playerStatisticKeeper/playerStatisticKeeper.service.ts +++ b/src/statisticsKeeper/playerStatisticKeeper/playerStatisticKeeper.service.ts @@ -62,7 +62,19 @@ export class PlayerStatisticService { const today = new Date(); const playerResp = await this.playerService.readOneById(player_id); - if (playerResp instanceof MongooseError) return [false, playerResp]; + + if (!playerResp || playerResp instanceof MongooseError) + return [ + false, + [ + new ServiceError({ + message: 'Player is not found', + reason: SEReason.NOT_FOUND, + field: 'player_id', + value: player_id, + }), + ], + ]; if (!playerResp.data[playerResp.metaData.dataKey]) return [ From 2b498104b12387a00d8ff3c79b85a1b41d005b21 Mon Sep 17 00:00:00 2001 From: jkrizsan <57282556+jkrizsan@users.noreply.github.com> Date: Fri, 30 May 2025 22:38:52 +0300 Subject: [PATCH 4/8] Remove unnecessary code. --- .../statisticsKeeper/modules/statisticsKeeper.module.ts | 6 ------ .../modules/statisticsKeeperCommon.module.ts | 1 - 2 files changed, 7 deletions(-) diff --git a/src/__tests__/statisticsKeeper/modules/statisticsKeeper.module.ts b/src/__tests__/statisticsKeeper/modules/statisticsKeeper.module.ts index abca0df59..89e7a8863 100644 --- a/src/__tests__/statisticsKeeper/modules/statisticsKeeper.module.ts +++ b/src/__tests__/statisticsKeeper/modules/statisticsKeeper.module.ts @@ -1,6 +1,5 @@ import StatisticsKeeperCommonModule from './statisticsKeeperCommon.module'; import { PlayerStatisticService } from '../../../statisticsKeeper/playerStatisticKeeper/playerStatisticKeeper.service'; -import { PlayerService } from '../../../player/player.service'; export default class StatisticsKeeperModule { private constructor() {} @@ -9,9 +8,4 @@ export default class StatisticsKeeperModule { const module = await StatisticsKeeperCommonModule.getModule(); return await module.resolve(PlayerStatisticService); } - - static async getPlayerService() { - const module = await StatisticsKeeperCommonModule.getModule(); - return await module.resolve(PlayerService); - } } diff --git a/src/__tests__/statisticsKeeper/modules/statisticsKeeperCommon.module.ts b/src/__tests__/statisticsKeeper/modules/statisticsKeeperCommon.module.ts index 3aa5f7908..157831013 100644 --- a/src/__tests__/statisticsKeeper/modules/statisticsKeeperCommon.module.ts +++ b/src/__tests__/statisticsKeeper/modules/statisticsKeeperCommon.module.ts @@ -39,7 +39,6 @@ export default class StatisticsKeeperCommonModule { ], providers: [ PlayerStatisticService, - PlayerService, ], }).compile(); From 78d3ad13a98fc406ca328a634ff02aebf31784e1 Mon Sep 17 00:00:00 2001 From: jkrizsan <57282556+jkrizsan@users.noreply.github.com> Date: Sat, 31 May 2025 00:05:19 +0300 Subject: [PATCH 5/8] Refactor PlayerStatisticService.updatePlayerStatistic() tests --- .../updatePlayerStatistic.test.ts | 77 +++---------------- 1 file changed, 11 insertions(+), 66 deletions(-) diff --git a/src/__tests__/statisticsKeeper/PlayerStatisticService/updatePlayerStatistic.test.ts b/src/__tests__/statisticsKeeper/PlayerStatisticService/updatePlayerStatistic.test.ts index 35e9481db..4bc3fda1e 100644 --- a/src/__tests__/statisticsKeeper/PlayerStatisticService/updatePlayerStatistic.test.ts +++ b/src/__tests__/statisticsKeeper/PlayerStatisticService/updatePlayerStatistic.test.ts @@ -1,9 +1,7 @@ import { ObjectId } from 'mongodb'; import { MongooseError } from 'mongoose'; import { Message } from '../../../player/message.schema'; -import ServiceError from '../../../common/service/basicService/ServiceError'; import { ModelName } from '../../../common/enum/modelName.enum'; -import { SEReason } from '../../../common/service/basicService/SEReason'; import PlayerBuilderFactory from '../../player/data/playerBuilderFactory'; import { PlayerEvent } from '../../../rewarder/playerRewarder/enum/PlayerEvent.enum'; import StatisticsKeeperCommonModule from '../modules/statisticsKeeperCommon.module'; @@ -25,6 +23,14 @@ describe('PlayerStatisticService.updatePlayerStatistic() test suite', () => { const playerId = new ObjectId()._id.toString(); + const gameStatistics = gameStatisticsBuilder.setWonBattles(0).build(); + + const player = playerBuilder + .setName(playerName) + .setId(playerId) + .setGameStatistics(gameStatistics) + .build(); + beforeEach(async () => { jest.clearAllMocks(); playerStatisticService = @@ -34,14 +40,6 @@ describe('PlayerStatisticService.updatePlayerStatistic() test suite', () => { }); it('Should increase the players playedBattles if the input is valid | PlayerEvent.BATTLE_PLAYED', async () => { - const gameStatistics = gameStatisticsBuilder.setWonBattles(0).build(); - - const player = playerBuilder - .setName(playerName) - .setId(playerId) - .setGameStatistics(gameStatistics) - .build(); - await playerModel.create(player); const [result, error] = await playerStatisticService.updatePlayerStatistic( @@ -59,14 +57,6 @@ describe('PlayerStatisticService.updatePlayerStatistic() test suite', () => { }); it('Should increase the players wonBattles if the input is valid | PlayerEvent.BATTLE_WON', async () => { - const gameStatistics = gameStatisticsBuilder.setWonBattles(0).build(); - - const player = playerBuilder - .setName(playerName) - .setId(playerId) - .setGameStatistics(gameStatistics) - .build(); - await playerModel.create(player); const [result, error] = await playerStatisticService.updatePlayerStatistic( @@ -84,14 +74,6 @@ describe('PlayerStatisticService.updatePlayerStatistic() test suite', () => { }); it('Should increase the players participatedVotings if the input is valid | PlayerEvent.VOTE_MADE', async () => { - const gameStatistics = gameStatisticsBuilder.setWonBattles(0).build(); - - const player = playerBuilder - .setName(playerName) - .setId(playerId) - .setGameStatistics(gameStatistics) - .build(); - await playerModel.create(player); const [result, error] = await playerStatisticService.updatePlayerStatistic( @@ -121,14 +103,6 @@ describe('PlayerStatisticService.updatePlayerStatistic() test suite', () => { }); it('Should return with ServiceError if the players metadata not valid | PlayerEvent.MESSAGE_SENT', async () => { - const gameStatistics = gameStatisticsBuilder.setWonBattles(0).build(); - - const player = playerBuilder - .setName(playerName) - .setId(playerId) - .setGameStatistics(gameStatistics) - .build(); - await playerModel.create(player); jest.spyOn(playerService, 'readOneById').mockImplementation(async () => { @@ -147,10 +121,8 @@ describe('PlayerStatisticService.updatePlayerStatistic() test suite', () => { ); expect(result).toBe(false); - expect(error[0]).toBeInstanceOf(ServiceError); - expect(error[0].reason).toBe(SEReason.NOT_FOUND); - expect(error[0].message).toBe('Could not read the player'); - + expect(error).toContainSE_NOT_FOUND(); + jest.restoreAllMocks(); }); @@ -187,16 +159,6 @@ describe('PlayerStatisticService.updatePlayerStatistic() test suite', () => { }); it('Should add a new message to player with todays date if do not have one yet | PlayerEvent.MESSAGE_SENT', async () => { - const gameStatistics = gameStatisticsBuilder - .setWonBattles(0) - .setMessages([]) - .build(); - - const player = playerBuilder - .setName(playerName) - .setId(playerId) - .setGameStatistics(gameStatistics) - .build(); await playerModel.create(player); @@ -218,14 +180,6 @@ describe('PlayerStatisticService.updatePlayerStatistic() test suite', () => { }); it('Should return with MongooseError if have not updated the player in the DB | PlayerEvent.MESSAGE_SENT', async () => { - const gameStatistics = gameStatisticsBuilder.setWonBattles(0).build(); - - const player = playerBuilder - .setName(playerName) - .setId(playerId) - .setGameStatistics(gameStatistics) - .build(); - await playerModel.create(player); jest.spyOn(playerService, 'updateOneById').mockImplementation(async () => { @@ -244,14 +198,6 @@ describe('PlayerStatisticService.updatePlayerStatistic() test suite', () => { }); it('Should return with ServiceError if PlayerEvent type is not supported | PlayerEvent.NotSupported', async () => { - const gameStatistics = gameStatisticsBuilder.setWonBattles(0).build(); - - const player = playerBuilder - .setName(playerName) - .setId(playerId) - .setGameStatistics(gameStatistics) - .build(); - await playerModel.create(player); const [result, error] = await playerStatisticService.updatePlayerStatistic( @@ -260,7 +206,6 @@ describe('PlayerStatisticService.updatePlayerStatistic() test suite', () => { ); expect(result).toBe(null); - expect(error[0]).toBeInstanceOf(ServiceError); - expect(error[0].message).toBe('Event is not supported'); + expect(error).toContainSE_UNEXPECTED(); }); }); From 5930f0ba4747d904a1504447315c30b2c2630991 Mon Sep 17 00:00:00 2001 From: jkrizsan <57282556+jkrizsan@users.noreply.github.com> Date: Sat, 31 May 2025 10:35:19 +0300 Subject: [PATCH 6/8] PlayerStatisticService.updatePlayerStatistic() tests: additional refactor --- .../updatePlayerStatistic.test.ts | 50 +++++++++---------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/src/__tests__/statisticsKeeper/PlayerStatisticService/updatePlayerStatistic.test.ts b/src/__tests__/statisticsKeeper/PlayerStatisticService/updatePlayerStatistic.test.ts index 4bc3fda1e..c0f991fcb 100644 --- a/src/__tests__/statisticsKeeper/PlayerStatisticService/updatePlayerStatistic.test.ts +++ b/src/__tests__/statisticsKeeper/PlayerStatisticService/updatePlayerStatistic.test.ts @@ -37,11 +37,11 @@ describe('PlayerStatisticService.updatePlayerStatistic() test suite', () => { await StatisticsKeeperCommonModule.getPlayerStatisticService(); playerService = await StatisticsKeeperCommonModule.getPlayerService(); - }); - it('Should increase the players playedBattles if the input is valid | PlayerEvent.BATTLE_PLAYED', async () => { await playerModel.create(player); + }); + it('Should increase the players playedBattles if the input is valid | PlayerEvent.BATTLE_PLAYED', async () => { const [result, error] = await playerStatisticService.updatePlayerStatistic( playerId, PlayerEvent.BATTLE_PLAYED, @@ -57,8 +57,6 @@ describe('PlayerStatisticService.updatePlayerStatistic() test suite', () => { }); it('Should increase the players wonBattles if the input is valid | PlayerEvent.BATTLE_WON', async () => { - await playerModel.create(player); - const [result, error] = await playerStatisticService.updatePlayerStatistic( playerId, PlayerEvent.BATTLE_WON, @@ -74,8 +72,6 @@ describe('PlayerStatisticService.updatePlayerStatistic() test suite', () => { }); it('Should increase the players participatedVotings if the input is valid | PlayerEvent.VOTE_MADE', async () => { - await playerModel.create(player); - const [result, error] = await playerStatisticService.updatePlayerStatistic( playerId, PlayerEvent.VOTE_MADE, @@ -90,7 +86,12 @@ describe('PlayerStatisticService.updatePlayerStatistic() test suite', () => { expect(updatedPlayer?.name).toBe(playerName); }); - it('Should return with MongooseError if have not read the player from the DB | PlayerEvent.MESSAGE_SENT', async () => { + it('Should return with ServiceError if have not read the player from the DB | PlayerEvent.MESSAGE_SENT', async () => { + jest.spyOn(playerService, 'readOneById') + .mockImplementation(async () => { + return new MongooseError('Player not found'); + }); + const [result, error] = await playerStatisticService.updatePlayerStatistic( playerId, PlayerEvent.MESSAGE_SENT, @@ -103,8 +104,6 @@ describe('PlayerStatisticService.updatePlayerStatistic() test suite', () => { }); it('Should return with ServiceError if the players metadata not valid | PlayerEvent.MESSAGE_SENT', async () => { - await playerModel.create(player); - jest.spyOn(playerService, 'readOneById').mockImplementation(async () => { return { data: { [ModelName.BOX]: null }, @@ -127,41 +126,42 @@ describe('PlayerStatisticService.updatePlayerStatistic() test suite', () => { }); it('Should increase the players message counter if found a todays message | PlayerEvent.MESSAGE_SENT', async () => { + const player_Id = new ObjectId()._id.toString(); + const player_Name = 'Jane'; + const message: Message = { date: new Date(), count: 1, } as unknown as Message; - const gameStatistics = gameStatisticsBuilder - .setWonBattles(0) + const newGameStatistics = gameStatisticsBuilder + .setWonBattles(1) .setMessages([message]) .build(); - const player = playerBuilder - .setName(playerName) - .setId(playerId) - .setGameStatistics(gameStatistics) + const newPlayer = playerBuilder + .setUniqueIdentifier('unique-id-123') + .setName(player_Name) + .setId(player_Id) + .setGameStatistics(newGameStatistics) .build(); - await playerModel.create(player); + await playerModel.create(newPlayer); const [result, error] = await playerStatisticService.updatePlayerStatistic( - playerId, + player_Id, PlayerEvent.MESSAGE_SENT, ); - const updatedPlayer = await playerModel.findById(playerId); + const updatedPlayer = await playerModel.findById(player_Id); expect(result).toBe(true); expect(error).toBeNull(); - expect(updatedPlayer.name).toBe(playerName); + expect(updatedPlayer.name).toBe(player_Name); expect(updatedPlayer.gameStatistics.messages[0].count).toBe(2); }); it('Should add a new message to player with todays date if do not have one yet | PlayerEvent.MESSAGE_SENT', async () => { - - await playerModel.create(player); - const [result, error] = await playerStatisticService.updatePlayerStatistic( playerId, PlayerEvent.MESSAGE_SENT, @@ -180,12 +180,10 @@ describe('PlayerStatisticService.updatePlayerStatistic() test suite', () => { }); it('Should return with MongooseError if have not updated the player in the DB | PlayerEvent.MESSAGE_SENT', async () => { - await playerModel.create(player); - jest.spyOn(playerService, 'updateOneById').mockImplementation(async () => { return new MongooseError(''); }); - + const [result, error] = await playerStatisticService.updatePlayerStatistic( playerId, PlayerEvent.MESSAGE_SENT, @@ -198,8 +196,6 @@ describe('PlayerStatisticService.updatePlayerStatistic() test suite', () => { }); it('Should return with ServiceError if PlayerEvent type is not supported | PlayerEvent.NotSupported', async () => { - await playerModel.create(player); - const [result, error] = await playerStatisticService.updatePlayerStatistic( playerId, -1 as unknown as PlayerEvent, From a54a7ffc6da96b404482594d9ca310a8887c5e32 Mon Sep 17 00:00:00 2001 From: Mikhail Deriabin Date: Sat, 31 May 2025 15:01:41 +0300 Subject: [PATCH 7/8] move `getPlayerService()` back to `StatisticsKeeperModule` --- .../modules/statisticsKeeper.module.ts | 8 +++++++- .../modules/statisticsKeeperCommon.module.ts | 14 +------------- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/__tests__/statisticsKeeper/modules/statisticsKeeper.module.ts b/src/__tests__/statisticsKeeper/modules/statisticsKeeper.module.ts index 89e7a8863..bd8818aa8 100644 --- a/src/__tests__/statisticsKeeper/modules/statisticsKeeper.module.ts +++ b/src/__tests__/statisticsKeeper/modules/statisticsKeeper.module.ts @@ -1,11 +1,17 @@ import StatisticsKeeperCommonModule from './statisticsKeeperCommon.module'; import { PlayerStatisticService } from '../../../statisticsKeeper/playerStatisticKeeper/playerStatisticKeeper.service'; +import { PlayerService } from '../../../player/player.service'; export default class StatisticsKeeperModule { private constructor() {} static async getPlayerStatisticService() { const module = await StatisticsKeeperCommonModule.getModule(); - return await module.resolve(PlayerStatisticService); + return module.resolve(PlayerStatisticService); + } + + static async getPlayerService() { + const module = await StatisticsKeeperCommonModule.getModule(); + return module.resolve(PlayerService); } } diff --git a/src/__tests__/statisticsKeeper/modules/statisticsKeeperCommon.module.ts b/src/__tests__/statisticsKeeper/modules/statisticsKeeperCommon.module.ts index 157831013..4f38c3334 100644 --- a/src/__tests__/statisticsKeeper/modules/statisticsKeeperCommon.module.ts +++ b/src/__tests__/statisticsKeeper/modules/statisticsKeeperCommon.module.ts @@ -3,7 +3,6 @@ import { MongooseModule } from '@nestjs/mongoose'; import { mongooseOptions, mongoString } from '../../test_utils/const/db'; import { ModelName } from '../../../common/enum/modelName.enum'; import { PlayerSchema } from '../../../player/schemas/player.schema'; -import { PlayerService } from '../../../player/player.service'; import { PlayerStatisticService } from '../../../statisticsKeeper/playerStatisticKeeper/playerStatisticKeeper.service'; import { StatisticsKeeperModule } from '../../../statisticsKeeper/statisticsKeeper.module'; import { CustomCharacterSchema } from '../../../player/customCharacter/customCharacter.schema'; @@ -11,15 +10,6 @@ import { RequestHelperModule } from '../../../requestHelper/requestHelper.module import { PlayerModule } from '../../../player/player.module'; export default class StatisticsKeeperCommonModule { - static async getPlayerStatisticService() { - const module = await StatisticsKeeperCommonModule.getModule(); - return await module.resolve(PlayerStatisticService); - } - - static async getPlayerService() { - const module = await StatisticsKeeperCommonModule.getModule(); - return await module.resolve(PlayerService); - } private constructor() {} private static module: TestingModule; @@ -37,9 +27,7 @@ export default class StatisticsKeeperCommonModule { PlayerModule, RequestHelperModule, ], - providers: [ - PlayerStatisticService, - ], + providers: [PlayerStatisticService], }).compile(); return StatisticsKeeperCommonModule.module; From d4722886c270de665b2370053f2de2674f19940b Mon Sep 17 00:00:00 2001 From: Mikhail Deriabin Date: Sat, 31 May 2025 15:04:46 +0300 Subject: [PATCH 8/8] move player object creation to `beforeEach` hook in PlayerStatisticService.updatePlayerStatistic() tests --- .../updatePlayerStatistic.test.ts | 32 +++++++++---------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/src/__tests__/statisticsKeeper/PlayerStatisticService/updatePlayerStatistic.test.ts b/src/__tests__/statisticsKeeper/PlayerStatisticService/updatePlayerStatistic.test.ts index c0f991fcb..1244f2692 100644 --- a/src/__tests__/statisticsKeeper/PlayerStatisticService/updatePlayerStatistic.test.ts +++ b/src/__tests__/statisticsKeeper/PlayerStatisticService/updatePlayerStatistic.test.ts @@ -4,10 +4,11 @@ import { Message } from '../../../player/message.schema'; import { ModelName } from '../../../common/enum/modelName.enum'; import PlayerBuilderFactory from '../../player/data/playerBuilderFactory'; import { PlayerEvent } from '../../../rewarder/playerRewarder/enum/PlayerEvent.enum'; -import StatisticsKeeperCommonModule from '../modules/statisticsKeeperCommon.module'; import PlayerModule from '../../player/modules/player.module'; import { PlayerService } from '../../../player/player.service'; import { PlayerStatisticService } from '../../../statisticsKeeper/playerStatisticKeeper/playerStatisticKeeper.service'; +import StatisticsKeeperModule from '../modules/statisticsKeeper.module'; +import { Player } from '../../../player/schemas/player.schema'; describe('PlayerStatisticService.updatePlayerStatistic() test suite', () => { let playerStatisticService: PlayerStatisticService; @@ -25,19 +26,19 @@ describe('PlayerStatisticService.updatePlayerStatistic() test suite', () => { const gameStatistics = gameStatisticsBuilder.setWonBattles(0).build(); - const player = playerBuilder - .setName(playerName) - .setId(playerId) - .setGameStatistics(gameStatistics) - .build(); + let player: Player; beforeEach(async () => { - jest.clearAllMocks(); playerStatisticService = - await StatisticsKeeperCommonModule.getPlayerStatisticService(); + await StatisticsKeeperModule.getPlayerStatisticService(); - playerService = await StatisticsKeeperCommonModule.getPlayerService(); + playerService = await StatisticsKeeperModule.getPlayerService(); + player = playerBuilder + .setName(playerName) + .setId(playerId) + .setGameStatistics(gameStatistics) + .build(); await playerModel.create(player); }); @@ -87,10 +88,7 @@ describe('PlayerStatisticService.updatePlayerStatistic() test suite', () => { }); it('Should return with ServiceError if have not read the player from the DB | PlayerEvent.MESSAGE_SENT', async () => { - jest.spyOn(playerService, 'readOneById') - .mockImplementation(async () => { - return new MongooseError('Player not found'); - }); + await playerModel.findByIdAndDelete(playerId); const [result, error] = await playerStatisticService.updatePlayerStatistic( playerId, @@ -121,11 +119,11 @@ describe('PlayerStatisticService.updatePlayerStatistic() test suite', () => { expect(result).toBe(false); expect(error).toContainSE_NOT_FOUND(); - + jest.restoreAllMocks(); }); - it('Should increase the players message counter if found a todays message | PlayerEvent.MESSAGE_SENT', async () => { + it("Should increase the players message counter if found a today's message | PlayerEvent.MESSAGE_SENT", async () => { const player_Id = new ObjectId()._id.toString(); const player_Name = 'Jane'; @@ -161,7 +159,7 @@ describe('PlayerStatisticService.updatePlayerStatistic() test suite', () => { expect(updatedPlayer.gameStatistics.messages[0].count).toBe(2); }); - it('Should add a new message to player with todays date if do not have one yet | PlayerEvent.MESSAGE_SENT', async () => { + it("Should add a new message to player with today's date if do not have one yet | PlayerEvent.MESSAGE_SENT", async () => { const [result, error] = await playerStatisticService.updatePlayerStatistic( playerId, PlayerEvent.MESSAGE_SENT, @@ -183,7 +181,7 @@ describe('PlayerStatisticService.updatePlayerStatistic() test suite', () => { jest.spyOn(playerService, 'updateOneById').mockImplementation(async () => { return new MongooseError(''); }); - + const [result, error] = await playerStatisticService.updatePlayerStatistic( playerId, PlayerEvent.MESSAGE_SENT,