diff --git a/src/__tests__/statisticsKeeper/PlayerStatisticService/updatePlayerStatistic.test.ts b/src/__tests__/statisticsKeeper/PlayerStatisticService/updatePlayerStatistic.test.ts new file mode 100644 index 000000000..1244f2692 --- /dev/null +++ b/src/__tests__/statisticsKeeper/PlayerStatisticService/updatePlayerStatistic.test.ts @@ -0,0 +1,205 @@ +import { ObjectId } from 'mongodb'; +import { MongooseError } from 'mongoose'; +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 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; + 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(); + + const gameStatistics = gameStatisticsBuilder.setWonBattles(0).build(); + + let player: Player; + + beforeEach(async () => { + playerStatisticService = + await StatisticsKeeperModule.getPlayerStatisticService(); + + playerService = await StatisticsKeeperModule.getPlayerService(); + + player = playerBuilder + .setName(playerName) + .setId(playerId) + .setGameStatistics(gameStatistics) + .build(); + 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, + ); + + 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 [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 [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 ServiceError if have not read the player from the DB | PlayerEvent.MESSAGE_SENT', async () => { + await playerModel.findByIdAndDelete(playerId); + + const [result, error] = await playerStatisticService.updatePlayerStatistic( + playerId, + PlayerEvent.MESSAGE_SENT, + ); + + expect(result).toBe(false); + expect(error).toContainSE_NOT_FOUND(); + + jest.restoreAllMocks(); + }); + + it('Should return with ServiceError if the players metadata not valid | PlayerEvent.MESSAGE_SENT', async () => { + 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).toContainSE_NOT_FOUND(); + + jest.restoreAllMocks(); + }); + + 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'; + + const message: Message = { + date: new Date(), + count: 1, + } as unknown as Message; + + const newGameStatistics = gameStatisticsBuilder + .setWonBattles(1) + .setMessages([message]) + .build(); + + const newPlayer = playerBuilder + .setUniqueIdentifier('unique-id-123') + .setName(player_Name) + .setId(player_Id) + .setGameStatistics(newGameStatistics) + .build(); + + await playerModel.create(newPlayer); + + const [result, error] = await playerStatisticService.updatePlayerStatistic( + player_Id, + PlayerEvent.MESSAGE_SENT, + ); + + const updatedPlayer = await playerModel.findById(player_Id); + + expect(result).toBe(true); + expect(error).toBeNull(); + expect(updatedPlayer.name).toBe(player_Name); + expect(updatedPlayer.gameStatistics.messages[0].count).toBe(2); + }); + + 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, + ); + + 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 () => { + 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 [result, error] = await playerStatisticService.updatePlayerStatistic( + playerId, + -1 as unknown as PlayerEvent, + ); + + expect(result).toBe(null); + expect(error).toContainSE_UNEXPECTED(); + }); +}); diff --git a/src/__tests__/statisticsKeeper/modules/statisticsKeeper.module.ts b/src/__tests__/statisticsKeeper/modules/statisticsKeeper.module.ts new file mode 100644 index 000000000..bd8818aa8 --- /dev/null +++ b/src/__tests__/statisticsKeeper/modules/statisticsKeeper.module.ts @@ -0,0 +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 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 new file mode 100644 index 000000000..4f38c3334 --- /dev/null +++ b/src/__tests__/statisticsKeeper/modules/statisticsKeeperCommon.module.ts @@ -0,0 +1,35 @@ +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 { 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 { PlayerModule } from '../../../player/player.module'; + +export default class StatisticsKeeperCommonModule { + 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, + PlayerModule, + RequestHelperModule, + ], + providers: [PlayerStatisticService], + }).compile(); + + return StatisticsKeeperCommonModule.module; + } +} 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 [