diff --git a/config/eslint/flat-configs/eslint-configs-config.js b/config/eslint/flat-configs/eslint-configs-config.js index 9bfb1337e..ba083af2b 100644 --- a/config/eslint/flat-configs/eslint-configs-config.js +++ b/config/eslint/flat-configs/eslint-configs-config.js @@ -2,12 +2,17 @@ const { OFF } = require("../eslint.constants"); const ESLINT_CONFIGS_CONFIG = Object.freeze({ name: "configs", - files: ["config/**/*.ts", "config/**/*.js"], + files: [ + "eslint.config.js", + "config/**/*.ts", + "config/**/*.js", + ], rules: { "no-magic-numbers": OFF, "@typescript-eslint/no-require-imports": OFF, "@typescript-eslint/no-restricted-imports": OFF, "import/no-default-export": OFF, + "import/no-internal-modules": OFF, "import/no-relative-parent-imports": OFF, }, }); diff --git a/config/eslint/flat-configs/eslint.dto-config.js b/config/eslint/flat-configs/eslint.dto-config.js index ba4771df4..3aa3d2874 100644 --- a/config/eslint/flat-configs/eslint.dto-config.js +++ b/config/eslint/flat-configs/eslint.dto-config.js @@ -1,10 +1,11 @@ -const { OFF } = require("../eslint.constants"); +const { OFF, ERROR } = require("../eslint.constants"); + const ESLINT_DTO_CONFIG = Object.freeze({ name: "dto", files: ["**/*.dto.ts"], rules: { "@stylistic/max-len": OFF, - // "import/max-dependencies": [ERROR, { max: 30 }], + "import/max-dependencies": [ERROR, { max: 30 }], }, }); diff --git a/config/eslint/flat-configs/eslint.factories-config.js b/config/eslint/flat-configs/eslint.factories-config.js index 2afcd88d8..be40c259c 100644 --- a/config/eslint/flat-configs/eslint.factories-config.js +++ b/config/eslint/flat-configs/eslint.factories-config.js @@ -1,16 +1,11 @@ +const { OFF } = require("../eslint.constants"); + const ESLINT_FACTORIES_CONFIG = Object.freeze({ name: "factories", - files: ["*.factory.ts"], - /* - * rules: { - * "import/max-dependencies": [ - * eRROR, { - * max: 30, - * ignoreTypeImports: true, - * }, - * ], - * }, - */ + files: ["**/*.factory.ts"], + rules: { + "import/max-dependencies": OFF, + }, }); module.exports = ESLINT_FACTORIES_CONFIG; \ No newline at end of file diff --git a/config/eslint/flat-configs/eslint.import-config.js b/config/eslint/flat-configs/eslint.import-config.js index 54d6fc209..ce9f11c67 100644 --- a/config/eslint/flat-configs/eslint.import-config.js +++ b/config/eslint/flat-configs/eslint.import-config.js @@ -1,6 +1,9 @@ -const { OFF, ERROR } = require("../eslint.constants"); +const ImportPlugin = require("eslint-plugin-import"); + +const { OFF, ERROR, ESLINT_IGNORES, NEVER, ALWAYS } = require("../eslint.constants"); const ESLINT_IMPORT_CONFIG = Object.freeze({ + ...ImportPlugin.flatConfigs.recommended, name: "import", languageOptions: { parserOptions: { @@ -8,29 +11,21 @@ const ESLINT_IMPORT_CONFIG = Object.freeze({ sourceType: "module", }, }, - settings: { - "import/parsers": { espree: [".js", ".cjs", ".mjs", ".jsx"] }, - "import/resolver": { - typescript: true, - node: true, - }, - }, + ignores: ESLINT_IGNORES, rules: { /* * ---- ESLint Import Rules ----- * - Static analysis (https://github.com/import-js/eslint-plugin-import#static-analysis) - * TODO: Modify webpack for this */ "import/no-unresolved": OFF, - // TODO: Need to check config of this rule + "import/consistent-type-specifier-style": [ERROR, "prefer-top-level"], "import/default": ERROR, "import/named": OFF, "import/namespace": ERROR, "import/no-restricted-paths": ERROR, "import/no-absolute-path": ERROR, - // TODO: Need to check config of this rule "import/no-dynamic-require": ERROR, - // TODO: Need to check config of this rule + "import/no-empty-named-blocks": ERROR, "import/no-internal-modules": ERROR, "import/no-webpack-loader-syntax": ERROR, "import/no-self-import": ERROR, @@ -38,27 +33,47 @@ const ESLINT_IMPORT_CONFIG = Object.freeze({ "import/no-useless-path-segments": ERROR, "import/no-relative-parent-imports": ERROR, "import/no-relative-packages": ERROR, - // - Helpful warnings (https://github.com/import-js/eslint-plugin-import#helpful-warnings) + // helpful warnings (https://github.com/import-js/eslint-plugin-import#helpful-warnings) "import/export": ERROR, "import/no-named-as-default": ERROR, "import/no-named-as-default-member": ERROR, "import/no-deprecated": ERROR, "import/no-extraneous-dependencies": [ERROR, { peerDependencies: false }], "import/no-mutable-exports": ERROR, - "import/no-unused-modules": [ERROR, { unusedExports: true }], - // - Module systems (https://github.com/import-js/eslint-plugin-import#module-systems) + "import/no-unused-modules": ERROR, + // module systems (https://github.com/import-js/eslint-plugin-import#module-systems) "import/unambiguous": OFF, "import/no-commonjs": OFF, "import/no-amd": ERROR, "import/no-nodejs-modules": OFF, "import/no-import-module-exports": ERROR, - // - Style guide (https://github.com/import-js/eslint-plugin-import#style-guide) + // style guide (https://github.com/import-js/eslint-plugin-import#style-guide) "import/first": ERROR, "import/exports-last": ERROR, "import/no-duplicates": ERROR, "import/no-namespace": ERROR, - // TODO: Check this rule config - "import/extensions": OFF, + "import/extensions": [ + ERROR, NEVER, { + factory: ALWAYS, + helpers: ALWAYS, + enums: ALWAYS, + types: ALWAYS, + transformer: ALWAYS, + constants: ALWAYS, + class: ALWAYS, + schema: ALWAYS, + service: ALWAYS, + mutators: ALWAYS, + repository: ALWAYS, + dto: ALWAYS, + decorator: ALWAYS, + mappers: ALWAYS, + controller: ALWAYS, + module: ALWAYS, + pipe: ALWAYS, + json: ALWAYS, + }, + ], "import/order": [ ERROR, { "warnOnUnassignedImports": true, @@ -73,6 +88,7 @@ const ESLINT_IMPORT_CONFIG = Object.freeze({ "newlines-between": "always", }, ], + "import/newline-after-import": ERROR, "import/prefer-default-export": OFF, "import/max-dependencies": [ @@ -81,13 +97,12 @@ const ESLINT_IMPORT_CONFIG = Object.freeze({ ignoreTypeImports: true, }, ], - "import/no-unassigned-import": [ERROR, { allow: ["**/*.css"] }], + "import/no-unassigned-import": ERROR, "import/no-named-default": ERROR, "import/no-default-export": ERROR, "import/no-named-export": OFF, "import/no-anonymous-default-export": OFF, "import/group-exports": ERROR, - // TODO: Check this rule "import/dynamic-import-chunkname": OFF, }, }); diff --git a/config/eslint/flat-configs/eslint.modules-config.js b/config/eslint/flat-configs/eslint.modules-config.js new file mode 100644 index 000000000..5203ad8a3 --- /dev/null +++ b/config/eslint/flat-configs/eslint.modules-config.js @@ -0,0 +1,11 @@ +const { ERROR } = require("../eslint.constants"); + +const ESLINT_MODULE_CONFIG = Object.freeze({ + name: "modules", + files: ["**/*.module.ts"], + rules: { + "import/max-dependencies": [ERROR, { max: 30 }], + }, +}); + +module.exports = ESLINT_MODULE_CONFIG; \ No newline at end of file diff --git a/config/eslint/flat-configs/eslint.schemas-config.js b/config/eslint/flat-configs/eslint.schemas-config.js index 47786275c..f682f4549 100644 --- a/config/eslint/flat-configs/eslint.schemas-config.js +++ b/config/eslint/flat-configs/eslint.schemas-config.js @@ -1,8 +1,9 @@ +const { ERROR } = require("../eslint.constants"); + const ESLINT_SCHEMAS_CONFIG = Object.freeze({ name: "schemas", files: ["**/*.schema.ts"], - rules: {}, - // rules: {"import/max-dependencies": [ERROR, { max: 30 }],}, + rules: { "import/max-dependencies": [ERROR, { max: 30 }] }, }); module.exports = ESLINT_SCHEMAS_CONFIG; \ No newline at end of file diff --git a/config/eslint/flat-configs/eslint.stylistic-config.js b/config/eslint/flat-configs/eslint.stylistic-config.js index f6e9d8a78..2d0af12db 100644 --- a/config/eslint/flat-configs/eslint.stylistic-config.js +++ b/config/eslint/flat-configs/eslint.stylistic-config.js @@ -1,7 +1,6 @@ const StylisticPlugin = require("@stylistic/eslint-plugin"); -const { ALWAYS, ERROR, INDENT_SPACE_COUNT, MAX_LENGTH_DEFAULT_CONFIG, NEVER, OFF } = require("../eslint.constants.js"); -const { ESLINT_IGNORES } = require("../eslint.constants"); +const { ALWAYS, ERROR, INDENT_SPACE_COUNT, MAX_LENGTH_DEFAULT_CONFIG, NEVER, OFF, ESLINT_IGNORES } = require("../eslint.constants"); const ESLINT_STYLISTIC_CONFIG = { name: "stylistic", @@ -166,6 +165,12 @@ const ESLINT_STYLISTIC_CONFIG = { "@stylistic/switch-colon-spacing": ERROR, "@stylistic/template-curly-spacing": ERROR, "@stylistic/template-tag-spacing": ERROR, + "@stylistic/curly-newline": [ + ERROR, { + multiline: true, + consistent: true, + }, + ], "@stylistic/type-annotation-spacing": ERROR, "@stylistic/type-generic-spacing": ERROR, "@stylistic/type-named-tuple-spacing": ERROR, diff --git a/config/eslint/flat-configs/eslint.tests-config.js b/config/eslint/flat-configs/eslint.tests-config.js index bd4f9176d..45c818c57 100644 --- a/config/eslint/flat-configs/eslint.tests-config.js +++ b/config/eslint/flat-configs/eslint.tests-config.js @@ -1,4 +1,5 @@ const JestPlugin = require("eslint-plugin-jest"); + const { OFF, ERROR } = require("../eslint.constants"); const ESLINT_TESTS_CONFIG = Object.freeze({ @@ -10,6 +11,8 @@ const ESLINT_TESTS_CONFIG = Object.freeze({ "@typescript-eslint/init-declarations": OFF, "@typescript-eslint/no-magic-numbers": OFF, "@typescript-eslint/unbound-method": OFF, + "import/no-namespace": OFF, + "import/max-dependencies": OFF, "@stylistic/max-len": OFF, /* * ---- Test Rules ----- @@ -42,6 +45,14 @@ const ESLINT_TESTS_CONFIG = Object.freeze({ "jest/no-test-prefixes": ERROR, "jest/no-test-return-statement": ERROR, "jest/no-untyped-mock-factory": ERROR, + "jest/padding-around-after-all-blocks": ERROR, + "jest/padding-around-after-each-blocks": ERROR, + "jest/padding-around-all": ERROR, + "jest/padding-around-before-all-blocks": ERROR, + "jest/padding-around-before-each-blocks": ERROR, + "jest/padding-around-describe-blocks": ERROR, + "jest/padding-around-expect-groups": ERROR, + "jest/padding-around-test-blocks": ERROR, "jest/prefer-called-with": ERROR, "jest/prefer-comparison-matcher": ERROR, "jest/prefer-each": ERROR, diff --git a/config/eslint/flat-configs/eslint.typescript-config.js b/config/eslint/flat-configs/eslint.typescript-config.js index d514fdb57..8fa80cd0a 100644 --- a/config/eslint/flat-configs/eslint.typescript-config.js +++ b/config/eslint/flat-configs/eslint.typescript-config.js @@ -1,5 +1,6 @@ const TypeScriptParser = require("@typescript-eslint/parser"); const TypeScriptPlugin = require("@typescript-eslint/eslint-plugin"); + const { ERROR, OFF, NAMING_CONVENTION_DEFAULT_CONFIG, MAX_PARAMS, ESLINT_IGNORES } = require("../eslint.constants"); const ESLINT_TYPESCRIPT_CONFIG = Object.freeze({ @@ -64,6 +65,7 @@ const ESLINT_TYPESCRIPT_CONFIG = Object.freeze({ "@typescript-eslint/no-base-to-string": ERROR, "@typescript-eslint/no-confusing-non-null-assertion": ERROR, "@typescript-eslint/no-confusing-void-expression": [ERROR, { ignoreArrowShorthand: true }], + "@typescript-eslint/no-deprecated": ERROR, "@typescript-eslint/no-dupe-class-members": ERROR, "@typescript-eslint/no-duplicate-enum-values": ERROR, "@typescript-eslint/no-duplicate-type-constituents": ERROR, diff --git a/eslint.config.js b/eslint.config.js index 6e3bf8dfa..ce2ad08ed 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -15,7 +15,8 @@ const { ESLINT_CUCUMBER_CONTEXT_HELPERS_CONFIG } = require("./config/eslint/flat const { OFF } = require("./config/eslint/eslint.constants"); const ESLINT_REPOSITORIES_CONFIG = require("./config/eslint/flat-configs/eslint.repositories-config"); const ESLINT_STYLISTIC_CONFIG = require("./config/eslint/flat-configs/eslint.stylistic-config"); -// const ESLINT_IMPORT_CONFIG = require("./rules/eslint.import-config"); +const ESLINT_IMPORT_CONFIG = require("./config/eslint/flat-configs/eslint.import-config"); +const ESLINT_MODULES_CONFIG = require("./config/eslint/flat-configs/eslint.modules-config"); module.exports = [ { @@ -25,10 +26,7 @@ module.exports = [ ESLINT_GLOBAL_CONFIG, ESLINT_STYLISTIC_CONFIG, ESLINT_TYPESCRIPT_CONFIG, - /* - * TODO: Uncomment the following line when import plugin supports eslint v9 - * - ESLINT_IMPORT_CONFIG, - */ + ESLINT_IMPORT_CONFIG, ESLINT_CONFIGS_CONFIG, ESLINT_CONSTANTS_CONFIG, ESLINT_DTO_CONFIG, @@ -36,10 +34,11 @@ module.exports = [ ESLINT_PIPES_CONFIG, ESLINT_DECORATORS_CONFIG, ESLINT_TESTS_CONFIG, - ESLINT_FACTORIES_CONFIG, + ESLINT_MODULES_CONFIG, ESLINT_SERVICES_CONFIG, ESLINT_REPOSITORIES_CONFIG, ESLINT_CONTROLLERS_CONFIG, ESLINT_CUCUMBER_STEPS_AND_HOOKS_CONFIG, ESLINT_CUCUMBER_CONTEXT_HELPERS_CONFIG, + ESLINT_FACTORIES_CONFIG, ]; \ No newline at end of file diff --git a/src/modules/game/constants/game.constants.ts b/src/modules/game/constants/game.constants.ts index 05a1ecc5e..cf08ce096 100644 --- a/src/modules/game/constants/game.constants.ts +++ b/src/modules/game/constants/game.constants.ts @@ -1,6 +1,6 @@ -import type { Game } from "@/modules/game/schemas/game.schema"; import type { ReadonlyDeep } from "type-fest"; +import type { Game } from "@/modules/game/schemas/game.schema"; import { PLAYER_GROUPS } from "@/modules/game/constants/player/player.constants"; import type { GamePlay } from "@/modules/game/schemas/game-play/game-play.schema"; import type { PlayerAttributeName } from "@/modules/game/types/player/player-attribute/player-attribute.types"; diff --git a/src/modules/game/controllers/game.controller.ts b/src/modules/game/controllers/game.controller.ts index ad17b7f35..a71e38e92 100644 --- a/src/modules/game/controllers/game.controller.ts +++ b/src/modules/game/controllers/game.controller.ts @@ -1,7 +1,7 @@ -import { CreateGameFeedbackDto } from "@/modules/game/dto/create-game-feedback/create-game-feedback.dto"; import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Param, Post, Query } from "@nestjs/common"; import { ApiOperation, ApiResponse, ApiTags } from "@nestjs/swagger"; +import { CreateGameFeedbackDto } from "@/modules/game/dto/create-game-feedback/create-game-feedback.dto"; import { GetGameHistoryDto } from "@/modules/game/dto/get-game-history/get-game-history.dto"; import { ApiGameIdParam } from "@/modules/game/controllers/decorators/api-game-id-param.decorator"; import { ApiGameNotFoundResponse } from "@/modules/game/controllers/decorators/api-game-not-found-response.decorator"; diff --git a/src/modules/game/dto/base/decorators/additional-cards/additional-cards-for-actor-size.decorator.ts b/src/modules/game/dto/base/decorators/additional-cards/additional-cards-for-actor-size.decorator.ts index 698946199..9bfa59c36 100644 --- a/src/modules/game/dto/base/decorators/additional-cards/additional-cards-for-actor-size.decorator.ts +++ b/src/modules/game/dto/base/decorators/additional-cards/additional-cards-for-actor-size.decorator.ts @@ -1,8 +1,8 @@ -import { MAX_ADDITIONAL_CARDS_COUNT_FOR_RECIPIENT } from "@/modules/game/constants/game-additional-card/game-additional-card.constants"; import type { ValidationArguments, ValidationOptions } from "class-validator"; import { registerDecorator } from "class-validator"; import { has } from "lodash"; +import { MAX_ADDITIONAL_CARDS_COUNT_FOR_RECIPIENT } from "@/modules/game/constants/game-additional-card/game-additional-card.constants"; import type { CreateGameDto } from "@/modules/game/dto/create-game/create-game.dto"; function isAdditionalCardsForActorSizeRespected(value: unknown, validationArguments: ValidationArguments): boolean { diff --git a/src/modules/game/dto/base/decorators/additional-cards/additional-cards-for-thief-size.decorator.ts b/src/modules/game/dto/base/decorators/additional-cards/additional-cards-for-thief-size.decorator.ts index b2f3fa5bb..eaaba0689 100644 --- a/src/modules/game/dto/base/decorators/additional-cards/additional-cards-for-thief-size.decorator.ts +++ b/src/modules/game/dto/base/decorators/additional-cards/additional-cards-for-thief-size.decorator.ts @@ -1,8 +1,8 @@ -import { MAX_ADDITIONAL_CARDS_COUNT_FOR_RECIPIENT } from "@/modules/game/constants/game-additional-card/game-additional-card.constants"; import type { ValidationArguments, ValidationOptions } from "class-validator"; import { registerDecorator } from "class-validator"; import { has } from "lodash"; +import { MAX_ADDITIONAL_CARDS_COUNT_FOR_RECIPIENT } from "@/modules/game/constants/game-additional-card/game-additional-card.constants"; import type { CreateGameDto } from "@/modules/game/dto/create-game/create-game.dto"; function isAdditionalCardsForThiefSizeRespected(value: unknown, validationArguments: ValidationArguments): boolean { diff --git a/src/modules/game/dto/create-game-feedback/create-game-feedback.dto.ts b/src/modules/game/dto/create-game-feedback/create-game-feedback.dto.ts index 75e563522..5850aac70 100644 --- a/src/modules/game/dto/create-game-feedback/create-game-feedback.dto.ts +++ b/src/modules/game/dto/create-game-feedback/create-game-feedback.dto.ts @@ -1,6 +1,7 @@ -import { GAME_FEEDBACK_FIELDS_SPECS } from "@/modules/game/schemas/game-feedback/game-feedback.schema.constants"; import { IsBoolean, IsInt, IsOptional, IsString, Max, MaxLength, Min } from "class-validator"; +import { GAME_FEEDBACK_FIELDS_SPECS } from "@/modules/game/schemas/game-feedback/game-feedback.schema.constants"; + class CreateGameFeedbackDto { @IsInt() @Min(GAME_FEEDBACK_FIELDS_SPECS.score.min) diff --git a/src/modules/game/dto/create-game/create-game-options/create-roles-game-options/create-actor-game-options.dto.ts b/src/modules/game/dto/create-game/create-game-options/create-roles-game-options/create-actor-game-options.dto.ts index 4923519ce..18cd6b5a5 100644 --- a/src/modules/game/dto/create-game/create-game-options/create-roles-game-options/create-actor-game-options.dto.ts +++ b/src/modules/game/dto/create-game/create-game-options/create-roles-game-options/create-actor-game-options.dto.ts @@ -1,8 +1,9 @@ -import { ACTOR_GAME_OPTIONS_API_PROPERTIES, ACTOR_GAME_OPTIONS_FIELDS_SPECS } from "@/modules/game/schemas/game-options/roles-game-options/actor-game-options/actor-game-options.schema.constants"; import type { ApiPropertyOptions } from "@nestjs/swagger"; import { ApiProperty } from "@nestjs/swagger"; import { IsBoolean, IsOptional } from "class-validator"; +import { ACTOR_GAME_OPTIONS_API_PROPERTIES, ACTOR_GAME_OPTIONS_FIELDS_SPECS } from "@/modules/game/schemas/game-options/roles-game-options/actor-game-options/actor-game-options.schema.constants"; + class CreateActorGameOptionsDto { @ApiProperty({ ...ACTOR_GAME_OPTIONS_API_PROPERTIES.isPowerlessOnWerewolvesSide, diff --git a/src/modules/game/dto/create-game/create-game-options/create-roles-game-options/create-roles-game-options.dto.ts b/src/modules/game/dto/create-game/create-game-options/create-roles-game-options/create-roles-game-options.dto.ts index 1b2318a8e..a3f300944 100644 --- a/src/modules/game/dto/create-game/create-game-options/create-roles-game-options/create-roles-game-options.dto.ts +++ b/src/modules/game/dto/create-game/create-game-options/create-roles-game-options/create-roles-game-options.dto.ts @@ -1,9 +1,9 @@ -import { CreateWerewolfGameOptionsDto } from "@/modules/game/dto/create-game/create-game-options/create-roles-game-options/create-werewolf-game-options.dto"; import type { ApiPropertyOptions } from "@nestjs/swagger"; import { ApiProperty } from "@nestjs/swagger"; import { Type } from "class-transformer"; import { IsBoolean, IsOptional, ValidateNested } from "class-validator"; +import { CreateWerewolfGameOptionsDto } from "@/modules/game/dto/create-game/create-game-options/create-roles-game-options/create-werewolf-game-options.dto"; import { CreateActorGameOptionsDto } from "@/modules/game/dto/create-game/create-game-options/create-roles-game-options/create-actor-game-options.dto"; import { CreatePrejudicedManipulatorGameOptionsDto } from "@/modules/game/dto/create-game/create-game-options/create-roles-game-options/create-prejudiced-manipulator-game-options.dto"; import { CreateCupidGameOptionsDto } from "@/modules/game/dto/create-game/create-game-options/create-roles-game-options/create-cupid-game-options/create-cupid-game-options.dto"; diff --git a/src/modules/game/dto/create-game/create-game-options/create-roles-game-options/create-thief-game-options.dto.ts b/src/modules/game/dto/create-game/create-game-options/create-roles-game-options/create-thief-game-options.dto.ts index 9b2937a9d..dbff78468 100644 --- a/src/modules/game/dto/create-game/create-game-options/create-roles-game-options/create-thief-game-options.dto.ts +++ b/src/modules/game/dto/create-game/create-game-options/create-roles-game-options/create-thief-game-options.dto.ts @@ -1,8 +1,9 @@ -import { THIEF_GAME_OPTIONS_API_PROPERTIES, THIEF_GAME_OPTIONS_FIELDS_SPECS } from "@/modules/game/schemas/game-options/roles-game-options/thief-game-options/thief-game-options.schema.constants"; import type { ApiPropertyOptions } from "@nestjs/swagger"; import { ApiProperty } from "@nestjs/swagger"; import { IsBoolean, IsOptional } from "class-validator"; +import { THIEF_GAME_OPTIONS_API_PROPERTIES, THIEF_GAME_OPTIONS_FIELDS_SPECS } from "@/modules/game/schemas/game-options/roles-game-options/thief-game-options/thief-game-options.schema.constants"; + class CreateThiefGameOptionsDto { @ApiProperty({ ...THIEF_GAME_OPTIONS_API_PROPERTIES.mustChooseBetweenWerewolves, diff --git a/src/modules/game/dto/create-game/create-game-options/create-roles-game-options/create-werewolf-game-options.dto.ts b/src/modules/game/dto/create-game/create-game-options/create-roles-game-options/create-werewolf-game-options.dto.ts index d4c908b91..84d4f4b2b 100644 --- a/src/modules/game/dto/create-game/create-game-options/create-roles-game-options/create-werewolf-game-options.dto.ts +++ b/src/modules/game/dto/create-game/create-game-options/create-roles-game-options/create-werewolf-game-options.dto.ts @@ -1,8 +1,9 @@ -import { WEREWOLF_GAME_OPTIONS_API_PROPERTIES, WEREWOLF_GAME_OPTIONS_FIELDS_SPECS } from "@/modules/game/schemas/game-options/roles-game-options/werewolf-game-options/werewolf-game-options.schema.constants"; import type { ApiPropertyOptions } from "@nestjs/swagger"; import { ApiProperty } from "@nestjs/swagger"; import { IsBoolean, IsOptional } from "class-validator"; +import { WEREWOLF_GAME_OPTIONS_API_PROPERTIES, WEREWOLF_GAME_OPTIONS_FIELDS_SPECS } from "@/modules/game/schemas/game-options/roles-game-options/werewolf-game-options/werewolf-game-options.schema.constants"; + class CreateWerewolfGameOptionsDto { @ApiProperty({ ...WEREWOLF_GAME_OPTIONS_API_PROPERTIES.canEatEachOther, diff --git a/src/modules/game/dto/make-game-play/make-game-play-target/make-game-play-target-with-relations.dto.ts b/src/modules/game/dto/make-game-play/make-game-play-target/make-game-play-target-with-relations.dto.ts index fa322f27a..85df26a02 100644 --- a/src/modules/game/dto/make-game-play/make-game-play-target/make-game-play-target-with-relations.dto.ts +++ b/src/modules/game/dto/make-game-play/make-game-play-target/make-game-play-target-with-relations.dto.ts @@ -1,9 +1,10 @@ -import { toJSON } from "@/shared/misc/helpers/object.helpers"; import { OmitType } from "@nestjs/swagger"; import { Expose, plainToInstance, Type } from "class-transformer"; import { MakeGamePlayTargetDto } from "@/modules/game/dto/make-game-play/make-game-play-target/make-game-play-target.dto"; import { Player } from "@/modules/game/schemas/player/player.schema"; + +import { toJSON } from "@/shared/misc/helpers/object.helpers"; import { DEFAULT_PLAIN_TO_INSTANCE_OPTIONS } from "@/shared/validation/constants/validation.constants"; class MakeGamePlayTargetWithRelationsDto extends OmitType(MakeGamePlayTargetDto, ["playerId"] as const) { diff --git a/src/modules/game/game.module.ts b/src/modules/game/game.module.ts index aa4ce593a..55dd5da02 100644 --- a/src/modules/game/game.module.ts +++ b/src/modules/game/game.module.ts @@ -1,12 +1,12 @@ +import { Module } from "@nestjs/common"; +import { MongooseModule } from "@nestjs/mongoose"; + import { GameFeedbackRepository } from "@/modules/game/providers/repositories/game-feedback/game-feedback.repository"; import { GameHistoryRecordRepository } from "@/modules/game/providers/repositories/game-history-record/game-history-record.repository"; import { GameEventsGeneratorService } from "@/modules/game/providers/services/game-event/game-events-generator.service"; import { GameFeedbackService } from "@/modules/game/providers/services/game-feedback/game-feedback.service"; import { GameHistoryRecordToInsertGeneratorService } from "@/modules/game/providers/services/game-history/game-history-record-to-insert-generator.service"; import { GAME_FEEDBACK_SCHEMA, GameFeedback } from "@/modules/game/schemas/game-feedback/game-feedback.schema"; -import { Module } from "@nestjs/common"; -import { MongooseModule } from "@nestjs/mongoose"; - import { DevotedServantGamePlayMakerService } from "@/modules/game/providers/services/game-play/game-play-maker/devoted-servant-game-play-maker.service"; import { GamePlayAugmenterService } from "@/modules/game/providers/services/game-play/game-play-augmenter.service"; import { GameVictoryService } from "@/modules/game/providers/services/game-victory/game-victory.service"; diff --git a/src/modules/game/helpers/game-event/game-event.factory.ts b/src/modules/game/helpers/game-event/game-event.factory.ts index 96365e524..7b00e23d4 100644 --- a/src/modules/game/helpers/game-event/game-event.factory.ts +++ b/src/modules/game/helpers/game-event/game-event.factory.ts @@ -1,8 +1,9 @@ +import { plainToInstance } from "class-transformer"; + import { GameEvent } from "@/modules/game/schemas/game-event/game-event.schema"; import { toJSON } from "@/shared/misc/helpers/object.helpers"; import { DEFAULT_PLAIN_TO_INSTANCE_OPTIONS } from "@/shared/validation/constants/validation.constants"; -import { plainToInstance } from "class-transformer"; function createGameEvent(gameEvent: GameEvent): GameEvent { return plainToInstance(GameEvent, toJSON(gameEvent), { ...DEFAULT_PLAIN_TO_INSTANCE_OPTIONS, excludeExtraneousValues: true }); diff --git a/src/modules/game/helpers/game-feedback/game-feedback.factory.ts b/src/modules/game/helpers/game-feedback/game-feedback.factory.ts index 910224313..76371dc06 100644 --- a/src/modules/game/helpers/game-feedback/game-feedback.factory.ts +++ b/src/modules/game/helpers/game-feedback/game-feedback.factory.ts @@ -1,8 +1,10 @@ +import { plainToInstance } from "class-transformer"; + import { GameFeedback } from "@/modules/game/schemas/game-feedback/game-feedback.schema"; import { GameFeedbackToInsert } from "@/modules/game/types/game-feedback/game-feedback.types"; + import { toJSON } from "@/shared/misc/helpers/object.helpers"; import { DEFAULT_PLAIN_TO_INSTANCE_OPTIONS } from "@/shared/validation/constants/validation.constants"; -import { plainToInstance } from "class-transformer"; function createGameFeedbackToInsert(gameFeedbackToInsert: GameFeedbackToInsert): GameFeedbackToInsert { return plainToInstance(GameFeedbackToInsert, toJSON(gameFeedbackToInsert), DEFAULT_PLAIN_TO_INSTANCE_OPTIONS); diff --git a/src/modules/game/helpers/game-history-record/game-history-record-play/game-history-record-play-source/game-history-record-play-source.factory.ts b/src/modules/game/helpers/game-history-record/game-history-record-play/game-history-record-play-source/game-history-record-play-source.factory.ts index dbe299ac4..729a44f39 100644 --- a/src/modules/game/helpers/game-history-record/game-history-record-play/game-history-record-play-source/game-history-record-play-source.factory.ts +++ b/src/modules/game/helpers/game-history-record/game-history-record-play/game-history-record-play-source/game-history-record-play-source.factory.ts @@ -1,7 +1,9 @@ +import { plainToInstance } from "class-transformer"; + import { GameHistoryRecordPlaySource } from "@/modules/game/schemas/game-history-record/game-history-record-play/game-history-record-play-source/game-history-record-play-source.schema"; + import { toJSON } from "@/shared/misc/helpers/object.helpers"; import { DEFAULT_PLAIN_TO_INSTANCE_OPTIONS } from "@/shared/validation/constants/validation.constants"; -import { plainToInstance } from "class-transformer"; function createGameHistoryRecordPlaySource(gameHistoryRecordPlaySource: GameHistoryRecordPlaySource): GameHistoryRecordPlaySource { return plainToInstance(GameHistoryRecordPlaySource, toJSON(gameHistoryRecordPlaySource), DEFAULT_PLAIN_TO_INSTANCE_OPTIONS); diff --git a/src/modules/game/helpers/game-history-record/game-history-record-play/game-history-record-play-voting/game-history-record-play-voting.factory.ts b/src/modules/game/helpers/game-history-record/game-history-record-play/game-history-record-play-voting/game-history-record-play-voting.factory.ts index b3ce95c6a..17addb204 100644 --- a/src/modules/game/helpers/game-history-record/game-history-record-play/game-history-record-play-voting/game-history-record-play-voting.factory.ts +++ b/src/modules/game/helpers/game-history-record/game-history-record-play/game-history-record-play-voting/game-history-record-play-voting.factory.ts @@ -1,7 +1,9 @@ +import { plainToInstance } from "class-transformer"; + import { GameHistoryRecordPlayVoting } from "@/modules/game/schemas/game-history-record/game-history-record-play/game-history-record-play-voting/game-history-record-play-voting.schema"; + import { toJSON } from "@/shared/misc/helpers/object.helpers"; import { DEFAULT_PLAIN_TO_INSTANCE_OPTIONS } from "@/shared/validation/constants/validation.constants"; -import { plainToInstance } from "class-transformer"; function createGameHistoryRecordPlayVoting(gameHistoryRecordPlayVoting: GameHistoryRecordPlayVoting): GameHistoryRecordPlayVoting { return plainToInstance(GameHistoryRecordPlayVoting, toJSON(gameHistoryRecordPlayVoting), DEFAULT_PLAIN_TO_INSTANCE_OPTIONS); diff --git a/src/modules/game/helpers/game-history-record/game-history-record-play/game-history-record-play.factory.ts b/src/modules/game/helpers/game-history-record/game-history-record-play/game-history-record-play.factory.ts index b508891e3..0b6709397 100644 --- a/src/modules/game/helpers/game-history-record/game-history-record-play/game-history-record-play.factory.ts +++ b/src/modules/game/helpers/game-history-record/game-history-record-play/game-history-record-play.factory.ts @@ -1,7 +1,9 @@ +import { plainToInstance } from "class-transformer"; + import { GameHistoryRecordPlay } from "@/modules/game/schemas/game-history-record/game-history-record-play/game-history-record-play.schema"; + import { toJSON } from "@/shared/misc/helpers/object.helpers"; import { DEFAULT_PLAIN_TO_INSTANCE_OPTIONS } from "@/shared/validation/constants/validation.constants"; -import { plainToInstance } from "class-transformer"; function createGameHistoryRecordPlay(gameHistoryRecordPlay: GameHistoryRecordPlay): GameHistoryRecordPlay { return plainToInstance(GameHistoryRecordPlay, toJSON(gameHistoryRecordPlay), DEFAULT_PLAIN_TO_INSTANCE_OPTIONS); diff --git a/src/modules/game/helpers/game-history-record/game-history-record-player-attribute-alteration/game-history-record-player-attribute-alteration.factory.ts b/src/modules/game/helpers/game-history-record/game-history-record-player-attribute-alteration/game-history-record-player-attribute-alteration.factory.ts index 94147c236..322ce2dd8 100644 --- a/src/modules/game/helpers/game-history-record/game-history-record-player-attribute-alteration/game-history-record-player-attribute-alteration.factory.ts +++ b/src/modules/game/helpers/game-history-record/game-history-record-player-attribute-alteration/game-history-record-player-attribute-alteration.factory.ts @@ -1,7 +1,9 @@ +import { plainToInstance } from "class-transformer"; + import { GameHistoryRecordPlayerAttributeAlteration } from "@/modules/game/schemas/game-history-record/game-history-record-player-attribute-alteration/game-history-record-player-attribute-alteration.schema"; + import { toJSON } from "@/shared/misc/helpers/object.helpers"; import { DEFAULT_PLAIN_TO_INSTANCE_OPTIONS } from "@/shared/validation/constants/validation.constants"; -import { plainToInstance } from "class-transformer"; function createGameHistoryRecordPlayerAttributeAlteration(playerAttributeAlteration: GameHistoryRecordPlayerAttributeAlteration): GameHistoryRecordPlayerAttributeAlteration { return plainToInstance(GameHistoryRecordPlayerAttributeAlteration, toJSON(playerAttributeAlteration), DEFAULT_PLAIN_TO_INSTANCE_OPTIONS); diff --git a/src/modules/game/helpers/game-history-record/game-history-record.factory.ts b/src/modules/game/helpers/game-history-record/game-history-record.factory.ts index b8fdbf8e7..fcb524114 100644 --- a/src/modules/game/helpers/game-history-record/game-history-record.factory.ts +++ b/src/modules/game/helpers/game-history-record/game-history-record.factory.ts @@ -1,7 +1,9 @@ +import { plainToInstance } from "class-transformer"; + import { GameHistoryRecordToInsert } from "@/modules/game/types/game-history-record/game-history-record.types"; + import { toJSON } from "@/shared/misc/helpers/object.helpers"; import { DEFAULT_PLAIN_TO_INSTANCE_OPTIONS } from "@/shared/validation/constants/validation.constants"; -import { plainToInstance } from "class-transformer"; function createGameHistoryRecordToInsert(gameHistoryRecordToInsert: GameHistoryRecordToInsert): GameHistoryRecordToInsert { return plainToInstance(GameHistoryRecordToInsert, toJSON(gameHistoryRecordToInsert), DEFAULT_PLAIN_TO_INSTANCE_OPTIONS); diff --git a/src/modules/game/helpers/game-play/game-play.helpers.ts b/src/modules/game/helpers/game-play/game-play.helpers.ts index 4d24951a6..e744de24f 100644 --- a/src/modules/game/helpers/game-play/game-play.helpers.ts +++ b/src/modules/game/helpers/game-play/game-play.helpers.ts @@ -17,7 +17,7 @@ import type { Game } from "@/modules/game/schemas/game.schema"; import type { GameWithCurrentPlay } from "@/modules/game/types/game-with-current-play.types"; import { ApiResources } from "@/shared/api/enums/api.enums"; -import { ResourceNotFoundReasons } from "@/shared/exception/enums/resource-not-found-error.enum"; +import { ResourceNotFoundReasons } from "@/shared/exception/enums/resource-not-found-error.enums"; import { ResourceNotFoundException } from "@/shared/exception/types/resource-not-found-exception.types"; import { DEFAULT_PLAIN_TO_INSTANCE_OPTIONS } from "@/shared/validation/constants/validation.constants"; diff --git a/src/modules/game/providers/repositories/game-feedback/game-feedback.repository.ts b/src/modules/game/providers/repositories/game-feedback/game-feedback.repository.ts index 90665d891..918ee31ac 100644 --- a/src/modules/game/providers/repositories/game-feedback/game-feedback.repository.ts +++ b/src/modules/game/providers/repositories/game-feedback/game-feedback.repository.ts @@ -1,9 +1,10 @@ -import { GameFeedback } from "@/modules/game/schemas/game-feedback/game-feedback.schema"; -import { GameFeedbackDocument, GameFeedbackToInsert } from "@/modules/game/types/game-feedback/game-feedback.types"; import { Injectable } from "@nestjs/common"; import { InjectModel } from "@nestjs/mongoose"; import { Model } from "mongoose"; +import { GameFeedbackDocument, GameFeedbackToInsert } from "@/modules/game/types/game-feedback/game-feedback.types"; +import { GameFeedback } from "@/modules/game/schemas/game-feedback/game-feedback.schema"; + @Injectable() export class GameFeedbackRepository { public constructor(@InjectModel(GameFeedback.name) private readonly gameFeedbackModel: Model) {} diff --git a/src/modules/game/providers/repositories/game.repository.ts b/src/modules/game/providers/repositories/game.repository.ts index d8d2e28aa..77d809da0 100644 --- a/src/modules/game/providers/repositories/game.repository.ts +++ b/src/modules/game/providers/repositories/game.repository.ts @@ -1,9 +1,9 @@ -import { GAME_POPULATED_FIELDS } from "@/modules/game/constants/game.constants"; import { Injectable } from "@nestjs/common"; import { InjectModel } from "@nestjs/mongoose"; import { Model } from "mongoose"; import type { FilterQuery, QueryOptions } from "mongoose"; +import { GAME_POPULATED_FIELDS } from "@/modules/game/constants/game.constants"; import type { GameDocument } from "@/modules/game/types/game.types"; import type { CreateGameDto } from "@/modules/game/dto/create-game/create-game.dto"; import { Game } from "@/modules/game/schemas/game.schema"; diff --git a/src/modules/game/providers/services/game-event/game-events-generator.service.ts b/src/modules/game/providers/services/game-event/game-events-generator.service.ts index aaced3d52..77f026500 100644 --- a/src/modules/game/providers/services/game-event/game-events-generator.service.ts +++ b/src/modules/game/providers/services/game-event/game-events-generator.service.ts @@ -1,3 +1,5 @@ +import { Injectable } from "@nestjs/common"; + import { GAME_EVENT_PRIORITY_LIST_ON_DAYS, GAME_EVENT_PRIORITY_LIST_ON_NIGHTS } from "@/modules/game/constants/game-event/game-event.constants"; import { createGameEvent } from "@/modules/game/helpers/game-event/game-event.factory"; import { doesHavePlayerAttributeAlterationWithNameAndStatus, doesHavePlayerAttributeAlterationWithNameSourceAndStatus } from "@/modules/game/helpers/game-history-record/game-history-record.helpers"; @@ -8,7 +10,6 @@ import { GameHistoryRecord } from "@/modules/game/schemas/game-history-record/ga import { Game } from "@/modules/game/schemas/game.schema"; import { Player } from "@/modules/game/schemas/player/player.schema"; import { GamePlaySourceName } from "@/modules/game/types/game-play/game-play.types"; -import { Injectable } from "@nestjs/common"; @Injectable() export class GameEventsGeneratorService { diff --git a/src/modules/game/providers/services/game-feedback/game-feedback.service.ts b/src/modules/game/providers/services/game-feedback/game-feedback.service.ts index 041c91f4b..179489ac4 100644 --- a/src/modules/game/providers/services/game-feedback/game-feedback.service.ts +++ b/src/modules/game/providers/services/game-feedback/game-feedback.service.ts @@ -1,12 +1,14 @@ +import { Injectable } from "@nestjs/common"; + import { CreateGameFeedbackDto } from "@/modules/game/dto/create-game-feedback/create-game-feedback.dto"; import { createGameFeedbackToInsert } from "@/modules/game/helpers/game-feedback/game-feedback.factory"; import { GameFeedbackRepository } from "@/modules/game/providers/repositories/game-feedback/game-feedback.repository"; import { GameFeedback } from "@/modules/game/schemas/game-feedback/game-feedback.schema"; import { Game } from "@/modules/game/schemas/game.schema"; + import { ApiResources } from "@/shared/api/enums/api.enums"; -import { BadResourceMutationReasons } from "@/shared/exception/enums/bad-resource-mutation-error.enum"; +import { BadResourceMutationReasons } from "@/shared/exception/enums/bad-resource-mutation-error.enums"; import { BadResourceMutationException } from "@/shared/exception/types/bad-resource-mutation-exception.types"; -import { Injectable } from "@nestjs/common"; @Injectable() export class GameFeedbackService { diff --git a/src/modules/game/providers/services/game-history/game-history-record-to-insert-generator.service.ts b/src/modules/game/providers/services/game-history/game-history-record-to-insert-generator.service.ts index 58b814055..1a021312c 100644 --- a/src/modules/game/providers/services/game-history/game-history-record-to-insert-generator.service.ts +++ b/src/modules/game/providers/services/game-history/game-history-record-to-insert-generator.service.ts @@ -1,3 +1,5 @@ +import { Injectable } from "@nestjs/common"; + import { MakeGamePlayTargetWithRelationsDto } from "@/modules/game/dto/make-game-play/make-game-play-target/make-game-play-target-with-relations.dto"; import type { MakeGamePlayWithRelationsDto } from "@/modules/game/dto/make-game-play/make-game-play-with-relations.dto"; import { createGameHistoryRecordPlaySource } from "@/modules/game/helpers/game-history-record/game-history-record-play/game-history-record-play-source/game-history-record-play-source.factory"; @@ -18,8 +20,8 @@ import type { DeadPlayer } from "@/modules/game/schemas/player/dead-player.schem import type { Player } from "@/modules/game/schemas/player/player.schema"; import { GameHistoryRecordToInsert, GameHistoryRecordVotingResult } from "@/modules/game/types/game-history-record/game-history-record.types"; import type { GameWithCurrentPlay } from "@/modules/game/types/game-with-current-play.types"; + import { createNoCurrentGamePlayUnexpectedException } from "@/shared/exception/helpers/unexpected-exception.factory"; -import { Injectable } from "@nestjs/common"; @Injectable() export class GameHistoryRecordToInsertGeneratorService { diff --git a/src/modules/game/providers/services/game-history/game-history-record.service.ts b/src/modules/game/providers/services/game-history/game-history-record.service.ts index ae2f72af3..59139798c 100644 --- a/src/modules/game/providers/services/game-history/game-history-record.service.ts +++ b/src/modules/game/providers/services/game-history/game-history-record.service.ts @@ -1,3 +1,6 @@ +import { Injectable } from "@nestjs/common"; +import type { Types } from "mongoose"; + import type { GetGameHistoryDto } from "@/modules/game/dto/get-game-history/get-game-history.dto"; import { getAdditionalCardWithId, getNonexistentPlayer } from "@/modules/game/helpers/game.helpers"; import { GameHistoryRecordRepository } from "@/modules/game/providers/repositories/game-history-record/game-history-record.repository"; @@ -12,10 +15,8 @@ import { GamePhaseName } from "@/modules/game/types/game-phase/game-phase.types" import { GamePlayAction, WitchPotion } from "@/modules/game/types/game-play/game-play.types"; import { ApiResources } from "@/shared/api/enums/api.enums"; -import { ResourceNotFoundReasons } from "@/shared/exception/enums/resource-not-found-error.enum"; +import { ResourceNotFoundReasons } from "@/shared/exception/enums/resource-not-found-error.enums"; import { ResourceNotFoundException } from "@/shared/exception/types/resource-not-found-exception.types"; -import { Injectable } from "@nestjs/common"; -import type { Types } from "mongoose"; @Injectable() export class GameHistoryRecordService { diff --git a/src/modules/game/providers/services/game-phase/game-phase.service.ts b/src/modules/game/providers/services/game-phase/game-phase.service.ts index c8cac253b..d6acfedae 100644 --- a/src/modules/game/providers/services/game-phase/game-phase.service.ts +++ b/src/modules/game/providers/services/game-phase/game-phase.service.ts @@ -1,6 +1,6 @@ -import { GamePlayAction, GamePlaySourceName } from "@/modules/game/types/game-play/game-play.types"; import { Injectable } from "@nestjs/common"; +import { GamePlayAction, GamePlaySourceName } from "@/modules/game/types/game-play/game-play.types"; import { createGame } from "@/modules/game/helpers/game.factory"; import { doesGameHaveCurrentOrUpcomingPlaySourceAndAction, getPlayerWithIdOrThrow } from "@/modules/game/helpers/game.helpers"; import { updatePlayerInGame } from "@/modules/game/helpers/game.mutators"; diff --git a/src/modules/game/providers/services/game-play/game-play-validator.service.ts b/src/modules/game/providers/services/game-play/game-play-validator.service.ts index b5e11665f..a31146843 100644 --- a/src/modules/game/providers/services/game-play/game-play-validator.service.ts +++ b/src/modules/game/providers/services/game-play/game-play-validator.service.ts @@ -15,7 +15,7 @@ import { GamePlaySourceName, GamePlayType } from "@/modules/game/types/game-play import type { GameWithCurrentPlay } from "@/modules/game/types/game-with-current-play.types"; import { PlayerInteractionType } from "@/modules/game/types/player/player-interaction/player-interaction.types"; -import { BadGamePlayPayloadReasons } from "@/shared/exception/enums/bad-game-play-payload-error.enum"; +import { BadGamePlayPayloadReasons } from "@/shared/exception/enums/bad-game-play-payload-error.enums"; import { createCantFindPlayerWithCurrentRoleUnexpectedException, createNoCurrentGamePlayUnexpectedException } from "@/shared/exception/helpers/unexpected-exception.factory"; import { BadGamePlayPayloadException } from "@/shared/exception/types/bad-game-play-payload-exception.types"; diff --git a/src/modules/game/providers/services/game-play/game-play.service.ts b/src/modules/game/providers/services/game-play/game-play.service.ts index 8f10d9a8f..fec8d2a42 100644 --- a/src/modules/game/providers/services/game-play/game-play.service.ts +++ b/src/modules/game/providers/services/game-play/game-play.service.ts @@ -1,3 +1,5 @@ +import { Injectable } from "@nestjs/common"; + import { DAY_GAME_PLAYS_PRIORITY_LIST, NIGHT_GAME_PLAYS_PRIORITY_LIST } from "@/modules/game/constants/game.constants"; import { CreateGamePlayerDto } from "@/modules/game/dto/create-game/create-game-player/create-game-player.dto"; import { CreateGameDto } from "@/modules/game/dto/create-game/create-game.dto"; @@ -13,14 +15,12 @@ import type { GameHistoryRecord } from "@/modules/game/schemas/game-history-reco import type { SheriffGameOptions } from "@/modules/game/schemas/game-options/roles-game-options/sheriff-game-options/sheriff-game-options.schema"; import type { GamePlay } from "@/modules/game/schemas/game-play/game-play.schema"; import type { Game } from "@/modules/game/schemas/game.schema"; - import { GamePhaseName } from "@/modules/game/types/game-phase/game-phase.types"; import type { GameWithCurrentPlay } from "@/modules/game/types/game-with-current-play.types"; import { PlayerGroup } from "@/modules/game/types/player/player.types"; import { RoleName } from "@/modules/role/types/role.types"; import { createNoGamePlayPriorityUnexpectedException } from "@/shared/exception/helpers/unexpected-exception.factory"; -import { Injectable } from "@nestjs/common"; @Injectable() export class GamePlayService { diff --git a/src/modules/game/providers/services/game-victory/game-victory.service.ts b/src/modules/game/providers/services/game-victory/game-victory.service.ts index baa355567..32b50c961 100644 --- a/src/modules/game/providers/services/game-victory/game-victory.service.ts +++ b/src/modules/game/providers/services/game-victory/game-victory.service.ts @@ -1,6 +1,6 @@ -import { isInNightOrTwilightPhase } from "@/modules/game/helpers/game-phase/game-phase.helpers"; import { Injectable } from "@nestjs/common"; +import { isInNightOrTwilightPhase } from "@/modules/game/helpers/game-phase/game-phase.helpers"; import { createAngelGameVictory, createLoversGameVictory, createNoneGameVictory, createPiedPiperGameVictory, createPrejudicedManipulatorGameVictory, createVillagersGameVictory, createWerewolvesGameVictory, createWhiteWerewolfGameVictory } from "@/modules/game/helpers/game-victory/game-victory.factory"; import { areAllPlayersDead, doesGameHaveCurrentOrUpcomingPlaySourceAndAction, getEligiblePiedPiperTargets, getPlayersWithActiveAttributeName, getPlayersWithCurrentSide, getPlayerWithCurrentRole } from "@/modules/game/helpers/game.helpers"; import { doesPlayerHaveActiveAttributeWithName } from "@/modules/game/helpers/player/player-attribute/player-attribute.helpers"; diff --git a/src/modules/game/providers/services/game.service.ts b/src/modules/game/providers/services/game.service.ts index db95d14d0..6d9877aa8 100644 --- a/src/modules/game/providers/services/game.service.ts +++ b/src/modules/game/providers/services/game.service.ts @@ -1,5 +1,8 @@ -import { CreateGameFeedbackDto } from "@/modules/game/dto/create-game-feedback/create-game-feedback.dto"; +import { Injectable } from "@nestjs/common"; +import { plainToInstance } from "class-transformer"; +import type { Types } from "mongoose"; +import { CreateGameFeedbackDto } from "@/modules/game/dto/create-game-feedback/create-game-feedback.dto"; import { CreateGameDto } from "@/modules/game/dto/create-game/create-game.dto"; import type { MakeGamePlayDto } from "@/modules/game/dto/make-game-play/make-game-play.dto"; import { isGamePhaseOver } from "@/modules/game/helpers/game-phase/game-phase.helpers"; @@ -21,13 +24,10 @@ import type { Game } from "@/modules/game/schemas/game.schema"; import type { GameWithCurrentPlay } from "@/modules/game/types/game-with-current-play.types"; import { ApiResources } from "@/shared/api/enums/api.enums"; -import { BadResourceMutationReasons } from "@/shared/exception/enums/bad-resource-mutation-error.enum"; +import { BadResourceMutationReasons } from "@/shared/exception/enums/bad-resource-mutation-error.enums"; import { createCantGenerateGamePlaysUnexpectedException } from "@/shared/exception/helpers/unexpected-exception.factory"; import { BadResourceMutationException } from "@/shared/exception/types/bad-resource-mutation-exception.types"; import { ResourceNotFoundException } from "@/shared/exception/types/resource-not-found-exception.types"; -import { Injectable } from "@nestjs/common"; -import { plainToInstance } from "class-transformer"; -import type { Types } from "mongoose"; @Injectable() export class GameService { diff --git a/src/modules/game/schemas/game-event/game-event.schema.constants.ts b/src/modules/game/schemas/game-event/game-event.schema.constants.ts index 1cc3c008a..18785278a 100644 --- a/src/modules/game/schemas/game-event/game-event.schema.constants.ts +++ b/src/modules/game/schemas/game-event/game-event.schema.constants.ts @@ -1,10 +1,12 @@ +import type { ApiPropertyOptions } from "@nestjs/swagger"; +import type { ReadonlyDeep } from "type-fest"; + import { GAME_EVENT_TYPES } from "@/modules/game/constants/game-event/game-event.constants"; import type { GameEvent } from "@/modules/game/schemas/game-event/game-event.schema"; import { PLAYER_SCHEMA } from "@/modules/game/schemas/player/player.schema"; + import { convertMongoosePropOptionsToApiPropertyOptions } from "@/shared/api/helpers/api.helpers"; import type { MongoosePropOptions } from "@/shared/mongoose/types/mongoose.types"; -import type { ApiPropertyOptions } from "@nestjs/swagger"; -import type { ReadonlyDeep } from "type-fest"; const GAME_EVENT_FIELDS_SPECS = { type: { diff --git a/src/modules/game/schemas/game-event/game-event.schema.ts b/src/modules/game/schemas/game-event/game-event.schema.ts index e880dd405..0872bc6b2 100644 --- a/src/modules/game/schemas/game-event/game-event.schema.ts +++ b/src/modules/game/schemas/game-event/game-event.schema.ts @@ -1,9 +1,11 @@ +import { Prop, Schema, SchemaFactory } from "@nestjs/mongoose"; +import { ApiProperty } from "@nestjs/swagger"; +import type { ApiPropertyOptions } from "@nestjs/swagger"; +import { Expose, Type } from "class-transformer"; + import { GAME_EVENT_API_PROPERTIES, GAME_EVENT_FIELDS_SPECS } from "@/modules/game/schemas/game-event/game-event.schema.constants"; import { Player } from "@/modules/game/schemas/player/player.schema"; import { GameEventType } from "@/modules/game/types/game-event/game-event.types"; -import { Prop, Schema, SchemaFactory } from "@nestjs/mongoose"; -import { ApiProperty, type ApiPropertyOptions } from "@nestjs/swagger"; -import { Expose, Type } from "class-transformer"; @Schema({ versionKey: false, diff --git a/src/modules/game/schemas/game-feedback/game-feedback.schema.constants.ts b/src/modules/game/schemas/game-feedback/game-feedback.schema.constants.ts index 0b28ecb8e..0f46be443 100644 --- a/src/modules/game/schemas/game-feedback/game-feedback.schema.constants.ts +++ b/src/modules/game/schemas/game-feedback/game-feedback.schema.constants.ts @@ -1,10 +1,12 @@ -import type { GameFeedback } from "@/modules/game/schemas/game-feedback/game-feedback.schema"; -import { convertMongoosePropOptionsToApiPropertyOptions } from "@/shared/api/helpers/api.helpers"; -import type { MongoosePropOptions } from "@/shared/mongoose/types/mongoose.types"; import type { ApiPropertyOptions } from "@nestjs/swagger"; import { SchemaTypes } from "mongoose"; import type { ReadonlyDeep } from "type-fest"; +import type { GameFeedback } from "@/modules/game/schemas/game-feedback/game-feedback.schema"; + +import { convertMongoosePropOptionsToApiPropertyOptions } from "@/shared/api/helpers/api.helpers"; +import type { MongoosePropOptions } from "@/shared/mongoose/types/mongoose.types"; + const GAME_FEEDBACK_FIELDS_SPECS = { _id: { required: true }, gameId: { diff --git a/src/modules/game/schemas/game-feedback/game-feedback.schema.ts b/src/modules/game/schemas/game-feedback/game-feedback.schema.ts index 41f8ed7d0..99e76f1b3 100644 --- a/src/modules/game/schemas/game-feedback/game-feedback.schema.ts +++ b/src/modules/game/schemas/game-feedback/game-feedback.schema.ts @@ -1,10 +1,13 @@ -import { GAME_FEEDBACK_API_PROPERTIES, GAME_FEEDBACK_FIELDS_SPECS } from "@/modules/game/schemas/game-feedback/game-feedback.schema.constants"; -import { toObjectId } from "@/shared/validation/transformers/validation.transformer"; import { Prop, Schema, SchemaFactory } from "@nestjs/mongoose"; -import { ApiProperty, type ApiPropertyOptions } from "@nestjs/swagger"; +import { ApiProperty } from "@nestjs/swagger"; +import type { ApiPropertyOptions } from "@nestjs/swagger"; import { Expose, Transform, Type } from "class-transformer"; import { Types } from "mongoose"; +import { GAME_FEEDBACK_API_PROPERTIES, GAME_FEEDBACK_FIELDS_SPECS } from "@/modules/game/schemas/game-feedback/game-feedback.schema.constants"; + +import { toObjectId } from "@/shared/validation/transformers/validation.transformer"; + @Schema({ timestamps: { createdAt: true, diff --git a/src/modules/game/schemas/game-history-record/game-history-record-player-attribute-alteration/game-history-record-player-attribute-alteration.constants.ts b/src/modules/game/schemas/game-history-record/game-history-record-player-attribute-alteration/game-history-record-player-attribute-alteration.constants.ts index 3a8148a60..bec5970e0 100644 --- a/src/modules/game/schemas/game-history-record/game-history-record-player-attribute-alteration/game-history-record-player-attribute-alteration.constants.ts +++ b/src/modules/game/schemas/game-history-record/game-history-record-player-attribute-alteration/game-history-record-player-attribute-alteration.constants.ts @@ -1,11 +1,13 @@ +import type { ApiPropertyOptions } from "@nestjs/swagger"; +import type { ReadonlyDeep } from "type-fest"; + import { GAME_HISTORY_RECORD_PLAYER_ATTRIBUTE_ALTERATION_STATUSES } from "@/modules/game/constants/game-history-record/game-history-record.constants"; import { GAME_SOURCES } from "@/modules/game/constants/game.constants"; import { PLAYER_ATTRIBUTE_NAMES } from "@/modules/game/constants/player/player-attribute/player-attribute.constants"; import type { GameHistoryRecordPlayerAttributeAlteration } from "@/modules/game/schemas/game-history-record/game-history-record-player-attribute-alteration/game-history-record-player-attribute-alteration.schema"; + import { convertMongoosePropOptionsToApiPropertyOptions } from "@/shared/api/helpers/api.helpers"; import type { MongoosePropOptions } from "@/shared/mongoose/types/mongoose.types"; -import type { ApiPropertyOptions } from "@nestjs/swagger"; -import type { ReadonlyDeep } from "type-fest"; const GAME_HISTORY_RECORD_PLAYER_ATTRIBUTE_ALTERATION_FIELDS_SPECS = { name: { diff --git a/src/modules/game/schemas/game-history-record/game-history-record-player-attribute-alteration/game-history-record-player-attribute-alteration.schema.ts b/src/modules/game/schemas/game-history-record/game-history-record-player-attribute-alteration/game-history-record-player-attribute-alteration.schema.ts index 0c6f2f90f..e64510455 100644 --- a/src/modules/game/schemas/game-history-record/game-history-record-player-attribute-alteration/game-history-record-player-attribute-alteration.schema.ts +++ b/src/modules/game/schemas/game-history-record/game-history-record-player-attribute-alteration/game-history-record-player-attribute-alteration.schema.ts @@ -1,10 +1,12 @@ +import { Prop, Schema, SchemaFactory } from "@nestjs/mongoose"; +import { ApiProperty } from "@nestjs/swagger"; +import type { ApiPropertyOptions } from "@nestjs/swagger"; +import { Expose } from "class-transformer"; + import { GAME_HISTORY_RECORD_PLAYER_ATTRIBUTE_ALTERATION_API_PROPERTIES, GAME_HISTORY_RECORD_PLAYER_ATTRIBUTE_ALTERATION_FIELDS_SPECS } from "@/modules/game/schemas/game-history-record/game-history-record-player-attribute-alteration/game-history-record-player-attribute-alteration.constants"; import { GameHistoryRecordPlayerAttributeAlterationStatus } from "@/modules/game/types/game-history-record/game-history-record.types"; import { GameSource } from "@/modules/game/types/game.types"; import { PlayerAttributeName } from "@/modules/game/types/player/player-attribute/player-attribute.types"; -import { Prop, Schema, SchemaFactory } from "@nestjs/mongoose"; -import { ApiProperty, type ApiPropertyOptions } from "@nestjs/swagger"; -import { Expose } from "class-transformer"; @Schema({ versionKey: false, diff --git a/src/modules/game/schemas/game-history-record/game-history-record.schema.constants.ts b/src/modules/game/schemas/game-history-record/game-history-record.schema.constants.ts index d694ff880..2826f61c0 100644 --- a/src/modules/game/schemas/game-history-record/game-history-record.schema.constants.ts +++ b/src/modules/game/schemas/game-history-record/game-history-record.schema.constants.ts @@ -1,9 +1,9 @@ -import { GAME_EVENT_SCHEMA } from "@/modules/game/schemas/game-event/game-event.schema"; -import { GAME_HISTORY_RECORD_PLAYER_ATTRIBUTE_ALTERATION_SCHEMA } from "@/modules/game/schemas/game-history-record/game-history-record-player-attribute-alteration/game-history-record-player-attribute-alteration.schema"; import type { ApiPropertyOptions } from "@nestjs/swagger"; import { SchemaTypes } from "mongoose"; import type { ReadonlyDeep } from "type-fest"; +import { GAME_HISTORY_RECORD_PLAYER_ATTRIBUTE_ALTERATION_SCHEMA } from "@/modules/game/schemas/game-history-record/game-history-record-player-attribute-alteration/game-history-record-player-attribute-alteration.schema"; +import { GAME_EVENT_SCHEMA } from "@/modules/game/schemas/game-event/game-event.schema"; import { GAME_PHASE_SCHEMA } from "@/modules/game/schemas/game-phase/game-phase.schema"; import { DEAD_PLAYER_SCHEMA } from "@/modules/game/schemas/player/dead-player.schema"; import { PLAYER_SCHEMA } from "@/modules/game/schemas/player/player.schema"; diff --git a/src/modules/game/schemas/game-history-record/game-history-record.schema.ts b/src/modules/game/schemas/game-history-record/game-history-record.schema.ts index 277032c26..4eebd6b41 100644 --- a/src/modules/game/schemas/game-history-record/game-history-record.schema.ts +++ b/src/modules/game/schemas/game-history-record/game-history-record.schema.ts @@ -1,11 +1,11 @@ -import { GameEvent } from "@/modules/game/schemas/game-event/game-event.schema"; -import { GameHistoryRecordPlayerAttributeAlteration } from "@/modules/game/schemas/game-history-record/game-history-record-player-attribute-alteration/game-history-record-player-attribute-alteration.schema"; import { Prop, Schema, SchemaFactory } from "@nestjs/mongoose"; import type { ApiPropertyOptions } from "@nestjs/swagger"; import { ApiProperty } from "@nestjs/swagger"; import { Expose, Transform, Type } from "class-transformer"; import { Types } from "mongoose"; +import { GameHistoryRecordPlayerAttributeAlteration } from "@/modules/game/schemas/game-history-record/game-history-record-player-attribute-alteration/game-history-record-player-attribute-alteration.schema"; +import { GameEvent } from "@/modules/game/schemas/game-event/game-event.schema"; import { GamePhase } from "@/modules/game/schemas/game-phase/game-phase.schema"; import { DeadPlayer } from "@/modules/game/schemas/player/dead-player.schema"; import { GAME_HISTORY_RECORD_API_PROPERTIES, GAME_HISTORY_RECORD_FIELDS_SPECS } from "@/modules/game/schemas/game-history-record/game-history-record.schema.constants"; diff --git a/src/modules/game/schemas/game-options/roles-game-options/roles-game-options.schema.constants.ts b/src/modules/game/schemas/game-options/roles-game-options/roles-game-options.schema.constants.ts index e2cd813fc..1ee8fb970 100644 --- a/src/modules/game/schemas/game-options/roles-game-options/roles-game-options.schema.constants.ts +++ b/src/modules/game/schemas/game-options/roles-game-options/roles-game-options.schema.constants.ts @@ -1,7 +1,7 @@ -import { WEREWOLF_GAME_OPTIONS_SCHEMA } from "@/modules/game/schemas/game-options/roles-game-options/werewolf-game-options/werewolf-game-options.schema"; import type { ApiPropertyOptions } from "@nestjs/swagger"; import type { ReadonlyDeep } from "type-fest"; +import { WEREWOLF_GAME_OPTIONS_SCHEMA } from "@/modules/game/schemas/game-options/roles-game-options/werewolf-game-options/werewolf-game-options.schema"; import { ACTOR_GAME_OPTIONS_SCHEMA } from "@/modules/game/schemas/game-options/roles-game-options/actor-game-options/actor-game-options.schema"; import { PREJUDICED_MANIPULATOR_GAME_OPTIONS_SCHEMA } from "@/modules/game/schemas/game-options/roles-game-options/prejudiced-manipulator-game-options/prejudiced-manipulator-game-options.schema"; import { CUPID_GAME_OPTIONS_SCHEMA } from "@/modules/game/schemas/game-options/roles-game-options/cupid-game-options/cupid-game-options.schema"; diff --git a/src/modules/game/schemas/game-options/roles-game-options/roles-game-options.schema.ts b/src/modules/game/schemas/game-options/roles-game-options/roles-game-options.schema.ts index 25275bc26..0d26d4f70 100644 --- a/src/modules/game/schemas/game-options/roles-game-options/roles-game-options.schema.ts +++ b/src/modules/game/schemas/game-options/roles-game-options/roles-game-options.schema.ts @@ -1,9 +1,9 @@ -import { WerewolfGameOptions } from "@/modules/game/schemas/game-options/roles-game-options/werewolf-game-options/werewolf-game-options.schema"; import { Prop, Schema, SchemaFactory } from "@nestjs/mongoose"; import type { ApiPropertyOptions } from "@nestjs/swagger"; import { ApiProperty } from "@nestjs/swagger"; import { Expose, Type } from "class-transformer"; +import { WerewolfGameOptions } from "@/modules/game/schemas/game-options/roles-game-options/werewolf-game-options/werewolf-game-options.schema"; import { ActorGameOptions } from "@/modules/game/schemas/game-options/roles-game-options/actor-game-options/actor-game-options.schema"; import { PrejudicedManipulatorGameOptions } from "@/modules/game/schemas/game-options/roles-game-options/prejudiced-manipulator-game-options/prejudiced-manipulator-game-options.schema"; import { CupidGameOptions } from "@/modules/game/schemas/game-options/roles-game-options/cupid-game-options/cupid-game-options.schema"; diff --git a/src/modules/game/schemas/game-options/roles-game-options/werewolf-game-options/werewolf-game-options.schema.constants.ts b/src/modules/game/schemas/game-options/roles-game-options/werewolf-game-options/werewolf-game-options.schema.constants.ts index 18e453b64..76fb84010 100644 --- a/src/modules/game/schemas/game-options/roles-game-options/werewolf-game-options/werewolf-game-options.schema.constants.ts +++ b/src/modules/game/schemas/game-options/roles-game-options/werewolf-game-options/werewolf-game-options.schema.constants.ts @@ -1,9 +1,11 @@ +import type { ApiPropertyOptions } from "@nestjs/swagger"; +import type { ReadonlyDeep } from "type-fest"; + import { DEFAULT_GAME_OPTIONS } from "@/modules/game/constants/game-options/game-options.constants"; import type { WerewolfGameOptions } from "@/modules/game/schemas/game-options/roles-game-options/werewolf-game-options/werewolf-game-options.schema"; + import { convertMongoosePropOptionsToApiPropertyOptions } from "@/shared/api/helpers/api.helpers"; import type { MongoosePropOptions } from "@/shared/mongoose/types/mongoose.types"; -import type { ApiPropertyOptions } from "@nestjs/swagger"; -import type { ReadonlyDeep } from "type-fest"; const WEREWOLF_GAME_OPTIONS_FIELDS_SPECS = { canEatEachOther: { diff --git a/src/modules/game/schemas/game-options/roles-game-options/werewolf-game-options/werewolf-game-options.schema.ts b/src/modules/game/schemas/game-options/roles-game-options/werewolf-game-options/werewolf-game-options.schema.ts index 8f325f316..56363b9bb 100644 --- a/src/modules/game/schemas/game-options/roles-game-options/werewolf-game-options/werewolf-game-options.schema.ts +++ b/src/modules/game/schemas/game-options/roles-game-options/werewolf-game-options/werewolf-game-options.schema.ts @@ -1,8 +1,10 @@ -import { WEREWOLF_GAME_OPTIONS_API_PROPERTIES, WEREWOLF_GAME_OPTIONS_FIELDS_SPECS } from "@/modules/game/schemas/game-options/roles-game-options/werewolf-game-options/werewolf-game-options.schema.constants"; import { Prop, Schema, SchemaFactory } from "@nestjs/mongoose"; -import { ApiProperty, type ApiPropertyOptions } from "@nestjs/swagger"; +import { ApiProperty } from "@nestjs/swagger"; +import type { ApiPropertyOptions } from "@nestjs/swagger"; import { Expose } from "class-transformer"; +import { WEREWOLF_GAME_OPTIONS_API_PROPERTIES, WEREWOLF_GAME_OPTIONS_FIELDS_SPECS } from "@/modules/game/schemas/game-options/roles-game-options/werewolf-game-options/werewolf-game-options.schema.constants"; + @Schema({ versionKey: false, id: false, diff --git a/src/modules/game/schemas/game.schema.constants.ts b/src/modules/game/schemas/game.schema.constants.ts index a5375cc0b..87511efbd 100644 --- a/src/modules/game/schemas/game.schema.constants.ts +++ b/src/modules/game/schemas/game.schema.constants.ts @@ -1,9 +1,9 @@ -import { GAME_EVENT_SCHEMA } from "@/modules/game/schemas/game-event/game-event.schema"; -import { GAME_FEEDBACK_SCHEMA } from "@/modules/game/schemas/game-feedback/game-feedback.schema"; -import { GAME_HISTORY_RECORD_SCHEMA } from "@/modules/game/schemas/game-history-record/game-history-record.schema"; import type { ApiPropertyOptions } from "@nestjs/swagger"; import type { ReadonlyDeep } from "type-fest"; +import { GAME_EVENT_SCHEMA } from "@/modules/game/schemas/game-event/game-event.schema"; +import { GAME_FEEDBACK_SCHEMA } from "@/modules/game/schemas/game-feedback/game-feedback.schema"; +import { GAME_HISTORY_RECORD_SCHEMA } from "@/modules/game/schemas/game-history-record/game-history-record.schema"; import { GAME_PHASE_SCHEMA } from "@/modules/game/schemas/game-phase/game-phase.schema"; import { GAME_STATUSES } from "@/modules/game/constants/game.constants"; import { DEFAULT_GAME_OPTIONS } from "@/modules/game/constants/game-options/game-options.constants"; diff --git a/src/modules/game/schemas/game.schema.ts b/src/modules/game/schemas/game.schema.ts index 9d85f74d7..cad1e07ff 100644 --- a/src/modules/game/schemas/game.schema.ts +++ b/src/modules/game/schemas/game.schema.ts @@ -1,12 +1,12 @@ -import { GameEvent } from "@/modules/game/schemas/game-event/game-event.schema"; -import { GameFeedback } from "@/modules/game/schemas/game-feedback/game-feedback.schema"; -import { GameHistoryRecord } from "@/modules/game/schemas/game-history-record/game-history-record.schema"; import { Prop, Schema, SchemaFactory } from "@nestjs/mongoose"; import type { ApiPropertyOptions } from "@nestjs/swagger"; import { ApiProperty } from "@nestjs/swagger"; import { Expose, Transform, Type } from "class-transformer"; import { Types } from "mongoose"; +import { GameHistoryRecord } from "@/modules/game/schemas/game-history-record/game-history-record.schema"; +import { GameFeedback } from "@/modules/game/schemas/game-feedback/game-feedback.schema"; +import { GameEvent } from "@/modules/game/schemas/game-event/game-event.schema"; import { GamePhase } from "@/modules/game/schemas/game-phase/game-phase.schema"; import { GameAdditionalCard } from "@/modules/game/schemas/game-additional-card/game-additional-card.schema"; import { GameOptions } from "@/modules/game/schemas/game-options/game-options.schema"; diff --git a/src/modules/game/types/game-event/game-event.types.ts b/src/modules/game/types/game-event/game-event.types.ts index 7579f5563..fed321136 100644 --- a/src/modules/game/types/game-event/game-event.types.ts +++ b/src/modules/game/types/game-event/game-event.types.ts @@ -1,6 +1,7 @@ -import type { GAME_EVENT_TYPES } from "@/modules/game/constants/game-event/game-event.constants"; import type { TupleToUnion } from "type-fest"; +import type { GAME_EVENT_TYPES } from "@/modules/game/constants/game-event/game-event.constants"; + type GameEventType = TupleToUnion; export type { GameEventType }; \ No newline at end of file diff --git a/src/modules/game/types/game-feedback/game-feedback.types.ts b/src/modules/game/types/game-feedback/game-feedback.types.ts index 54a59f54e..73cef1bbc 100644 --- a/src/modules/game/types/game-feedback/game-feedback.types.ts +++ b/src/modules/game/types/game-feedback/game-feedback.types.ts @@ -1,7 +1,8 @@ -import { GameFeedback } from "@/modules/game/schemas/game-feedback/game-feedback.schema"; import { OmitType } from "@nestjs/swagger"; import type { HydratedDocument } from "mongoose"; +import { GameFeedback } from "@/modules/game/schemas/game-feedback/game-feedback.schema"; + class GameFeedbackToInsert extends OmitType(GameFeedback, ["_id", "createdAt"] as const) {} type GameFeedbackDocument = HydratedDocument; diff --git a/src/shared/exception/enums/bad-game-play-payload-error.enum.ts b/src/shared/exception/enums/bad-game-play-payload-error.enums.ts similarity index 100% rename from src/shared/exception/enums/bad-game-play-payload-error.enum.ts rename to src/shared/exception/enums/bad-game-play-payload-error.enums.ts diff --git a/src/shared/exception/enums/bad-resource-mutation-error.enum.ts b/src/shared/exception/enums/bad-resource-mutation-error.enums.ts similarity index 100% rename from src/shared/exception/enums/bad-resource-mutation-error.enum.ts rename to src/shared/exception/enums/bad-resource-mutation-error.enums.ts diff --git a/src/shared/exception/enums/resource-not-found-error.enum.ts b/src/shared/exception/enums/resource-not-found-error.enums.ts similarity index 100% rename from src/shared/exception/enums/resource-not-found-error.enum.ts rename to src/shared/exception/enums/resource-not-found-error.enums.ts diff --git a/src/shared/exception/enums/unexpected-exception.enum.ts b/src/shared/exception/enums/unexpected-exception.enums.ts similarity index 100% rename from src/shared/exception/enums/unexpected-exception.enum.ts rename to src/shared/exception/enums/unexpected-exception.enums.ts diff --git a/src/shared/exception/helpers/unexpected-exception.factory.ts b/src/shared/exception/helpers/unexpected-exception.factory.ts index ec7978199..6263842f3 100644 --- a/src/shared/exception/helpers/unexpected-exception.factory.ts +++ b/src/shared/exception/helpers/unexpected-exception.factory.ts @@ -3,7 +3,7 @@ import type { Types } from "mongoose"; import type { RoleName } from "@/modules/role/types/role.types"; import type { GamePlay } from "@/modules/game/schemas/game-play/game-play.schema"; -import { UnexpectedExceptionReasons } from "@/shared/exception/enums/unexpected-exception.enum"; +import { UnexpectedExceptionReasons } from "@/shared/exception/enums/unexpected-exception.enums"; import { UnexpectedException } from "@/shared/exception/types/unexpected-exception.types"; function createCantFindPlayerWithIdUnexpectedException(scope: string, interpolations: { gameId: Types.ObjectId; playerId: Types.ObjectId }): UnexpectedException { diff --git a/src/shared/exception/types/bad-game-play-payload-exception.types.ts b/src/shared/exception/types/bad-game-play-payload-exception.types.ts index fdcd1fdb8..008b51d0e 100644 --- a/src/shared/exception/types/bad-game-play-payload-exception.types.ts +++ b/src/shared/exception/types/bad-game-play-payload-exception.types.ts @@ -1,6 +1,6 @@ import { BadRequestException } from "@nestjs/common"; -import type { BadGamePlayPayloadReasons } from "@/shared/exception/enums/bad-game-play-payload-error.enum"; +import type { BadGamePlayPayloadReasons } from "@/shared/exception/enums/bad-game-play-payload-error.enums"; class BadGamePlayPayloadException extends BadRequestException { public constructor(reason: BadGamePlayPayloadReasons) { diff --git a/src/shared/exception/types/bad-resource-mutation-exception.types.ts b/src/shared/exception/types/bad-resource-mutation-exception.types.ts index cd6843055..fef4e88b5 100644 --- a/src/shared/exception/types/bad-resource-mutation-exception.types.ts +++ b/src/shared/exception/types/bad-resource-mutation-exception.types.ts @@ -2,7 +2,7 @@ import { BadRequestException } from "@nestjs/common"; import { upperFirst } from "lodash"; import type { ApiResources } from "@/shared/api/enums/api.enums"; -import type { BadResourceMutationReasons } from "@/shared/exception/enums/bad-resource-mutation-error.enum"; +import type { BadResourceMutationReasons } from "@/shared/exception/enums/bad-resource-mutation-error.enums"; import { getResourceSingularForm } from "@/shared/api/helpers/api.helpers"; class BadResourceMutationException extends BadRequestException { diff --git a/src/shared/exception/types/resource-not-found-exception.types.ts b/src/shared/exception/types/resource-not-found-exception.types.ts index 70a4ce7a6..780f10aec 100644 --- a/src/shared/exception/types/resource-not-found-exception.types.ts +++ b/src/shared/exception/types/resource-not-found-exception.types.ts @@ -2,7 +2,7 @@ import { NotFoundException } from "@nestjs/common"; import { upperFirst } from "lodash"; import type { ApiResources } from "@/shared/api/enums/api.enums"; -import type { ResourceNotFoundReasons } from "@/shared/exception/enums/resource-not-found-error.enum"; +import type { ResourceNotFoundReasons } from "@/shared/exception/enums/resource-not-found-error.enums"; import { getResourceSingularForm } from "@/shared/api/helpers/api.helpers"; class ResourceNotFoundException extends NotFoundException { diff --git a/src/shared/exception/types/unexpected-exception.types.ts b/src/shared/exception/types/unexpected-exception.types.ts index 5f909120e..63c350e00 100644 --- a/src/shared/exception/types/unexpected-exception.types.ts +++ b/src/shared/exception/types/unexpected-exception.types.ts @@ -1,7 +1,7 @@ import { InternalServerErrorException } from "@nestjs/common"; import { template } from "radash"; -import type { UnexpectedExceptionReasons } from "@/shared/exception/enums/unexpected-exception.enum"; +import type { UnexpectedExceptionReasons } from "@/shared/exception/enums/unexpected-exception.enums"; import type { ExceptionInterpolations } from "@/shared/exception/types/exception.types"; class UnexpectedException extends InternalServerErrorException { diff --git a/tests/acceptance/features/game/helpers/game-datatable.helpers.ts b/tests/acceptance/features/game/helpers/game-datatable.helpers.ts index 368e95e79..017dfdc84 100644 --- a/tests/acceptance/features/game/helpers/game-datatable.helpers.ts +++ b/tests/acceptance/features/game/helpers/game-datatable.helpers.ts @@ -1,3 +1,5 @@ +import { plainToInstance } from "class-transformer"; + import { CreateGamePlayerDto } from "@/modules/game/dto/create-game/create-game-player/create-game-player.dto"; import type { MakeGamePlayTargetDto } from "@/modules/game/dto/make-game-play/make-game-play-target/make-game-play-target.dto"; import type { MakeGamePlayVoteDto } from "@/modules/game/dto/make-game-play/make-game-play-vote/make-game-play-vote.dto"; @@ -5,7 +7,6 @@ import { getPlayerWithNameOrThrow } from "@/modules/game/helpers/game.helpers"; import type { GameEvent } from "@/modules/game/schemas/game-event/game-event.schema"; import type { GameHistoryRecordPlayVote } from "@/modules/game/schemas/game-history-record/game-history-record-play/game-history-record-play-vote/game-history-record-play-vote.schema"; import type { GameHistoryRecordPlayerAttributeAlteration } from "@/modules/game/schemas/game-history-record/game-history-record-player-attribute-alteration/game-history-record-player-attribute-alteration.schema"; - import type { GamePlaySourceInteraction } from "@/modules/game/schemas/game-play/game-play-source/game-play-source-interaction/game-play-source-interaction.schema"; import type { Game } from "@/modules/game/schemas/game.schema"; import type { Player } from "@/modules/game/schemas/player/player.schema"; @@ -18,7 +19,6 @@ import type { PlayerInteractionType } from "@/modules/game/types/player/player-i import { DEFAULT_PLAIN_TO_INSTANCE_OPTIONS } from "@/shared/validation/constants/validation.constants"; import { createFakeObjectId } from "@tests/factories/shared/mongoose/mongoose.factory"; -import { plainToInstance } from "class-transformer"; const INTENTIONAL_UNKNOWN_PLAYER_NAME = ""; diff --git a/tests/acceptance/features/game/helpers/game-request.helpers.ts b/tests/acceptance/features/game/helpers/game-request.helpers.ts index 6dbdbb4ac..c383db3bc 100644 --- a/tests/acceptance/features/game/helpers/game-request.helpers.ts +++ b/tests/acceptance/features/game/helpers/game-request.helpers.ts @@ -1,8 +1,8 @@ -import type { CreateGameFeedbackDto } from "@/modules/game/dto/create-game-feedback/create-game-feedback.dto"; import type { Response } from "light-my-request"; import type { NestFastifyApplication } from "@nestjs/platform-fastify"; import { stringify } from "qs"; +import type { CreateGameFeedbackDto } from "@/modules/game/dto/create-game-feedback/create-game-feedback.dto"; import type { GetGameHistoryDto } from "@/modules/game/dto/get-game-history/get-game-history.dto"; import type { CreateGameDto } from "@/modules/game/dto/create-game/create-game.dto"; import type { MakeGamePlayDto } from "@/modules/game/dto/make-game-play/make-game-play.dto"; diff --git a/tests/acceptance/features/game/step-definitions/game-event/game-event.then-steps.ts b/tests/acceptance/features/game/step-definitions/game-event/game-event.then-steps.ts index f8cf0b905..7895c1520 100644 --- a/tests/acceptance/features/game/step-definitions/game-event/game-event.then-steps.ts +++ b/tests/acceptance/features/game/step-definitions/game-event/game-event.then-steps.ts @@ -1,8 +1,9 @@ import type { DataTable } from "@cucumber/cucumber"; import { Then } from "@cucumber/cucumber"; +import { expect } from "expect"; + import { convertDatatableToGameEvents, convertDatatableToPlayers } from "@tests/acceptance/features/game/helpers/game-datatable.helpers"; import type { CustomWorld } from "@tests/acceptance/shared/types/world.types"; -import { expect } from "expect"; Then(/^the game should have the following events$/u, function(this: CustomWorld, events: DataTable): void { const gameEvents = convertDatatableToGameEvents(events.rows()); diff --git a/tests/acceptance/features/game/step-definitions/game-feedback/game-feedback.when-steps.ts b/tests/acceptance/features/game/step-definitions/game-feedback/game-feedback.when-steps.ts index b773c6bcc..d28ba0da1 100644 --- a/tests/acceptance/features/game/step-definitions/game-feedback/game-feedback.when-steps.ts +++ b/tests/acceptance/features/game/step-definitions/game-feedback/game-feedback.when-steps.ts @@ -1,4 +1,5 @@ import { When } from "@cucumber/cucumber"; + import { createGameFeedback } from "@tests/acceptance/features/game/helpers/game-request.helpers"; import { setGameInContext } from "@tests/acceptance/shared/helpers/context.helpers"; import type { CustomWorld } from "@tests/acceptance/shared/types/world.types"; diff --git a/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts b/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts index fa118ae72..e128a4f89 100644 --- a/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts +++ b/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts @@ -1,3 +1,12 @@ +import { faker } from "@faker-js/faker"; +import type { BadRequestException, NotFoundException } from "@nestjs/common"; +import { HttpStatus } from "@nestjs/common"; +import { getModelToken } from "@nestjs/mongoose"; +import type { NestFastifyApplication } from "@nestjs/platform-fastify"; +import type { TestingModule } from "@nestjs/testing"; +import type { Model, Types } from "mongoose"; +import { stringify } from "qs"; + import { DEFAULT_GAME_OPTIONS } from "@/modules/game/constants/game-options/game-options.constants"; import type { CreateGameFeedbackDto } from "@/modules/game/dto/create-game-feedback/create-game-feedback.dto"; import type { CreateGamePlayerDto } from "@/modules/game/dto/create-game/create-game-player/create-game-player.dto"; @@ -9,7 +18,6 @@ import type { GameEvent } from "@/modules/game/schemas/game-event/game-event.sch import type { GameFeedback } from "@/modules/game/schemas/game-feedback/game-feedback.schema"; import { GameHistoryRecord } from "@/modules/game/schemas/game-history-record/game-history-record.schema"; import type { GameOptions } from "@/modules/game/schemas/game-options/game-options.schema"; - import type { GamePhase } from "@/modules/game/schemas/game-phase/game-phase.schema"; import type { GamePlay } from "@/modules/game/schemas/game-play/game-play.schema"; import { Game } from "@/modules/game/schemas/game.schema"; @@ -18,12 +26,7 @@ import { ELIGIBLE_ACTOR_ADDITIONAL_CARDS_ROLE_NAMES, ELIGIBLE_THIEF_ADDITIONAL_C import { ApiSortOrder } from "@/shared/api/enums/api.enums"; import { toJSON } from "@/shared/misc/helpers/object.helpers"; -import { faker } from "@faker-js/faker"; -import type { BadRequestException, NotFoundException } from "@nestjs/common"; -import { HttpStatus } from "@nestjs/common"; -import { getModelToken } from "@nestjs/mongoose"; -import type { NestFastifyApplication } from "@nestjs/platform-fastify"; -import type { TestingModule } from "@nestjs/testing"; + import { truncateAllCollections } from "@tests/e2e/helpers/mongoose.helpers"; import { initNestApp } from "@tests/e2e/helpers/nest-app.helpers"; import { createFakeCreateGameFeedbackDto } from "@tests/factories/game/dto/create-game-feedback/create-game-feedback.dto.factory"; @@ -39,7 +42,6 @@ import { createFakeGameHistoryRecord, createFakeGameHistoryRecordPlay, createFak import { createFakeCompositionGameOptions } from "@tests/factories/game/schemas/game-options/composition-game-options.schema.factory"; import { createFakeGameOptions } from "@tests/factories/game/schemas/game-options/game-options.schema.factory"; import { createFakeVotesGameOptions } from "@tests/factories/game/schemas/game-options/votes-game-options.schema.factory"; - import { createFakeGamePhase } from "@tests/factories/game/schemas/game-phase/game-phase.schema.factory"; import { createFakeGamePlaySourceInteraction } from "@tests/factories/game/schemas/game-play/game-play-source/game-play-source-interaction/game-play-source-interaction.schema.factory"; import { createFakeGamePlaySource } from "@tests/factories/game/schemas/game-play/game-play-source/game-play-source.schema.factory"; @@ -51,8 +53,6 @@ import { createFakePlayer } from "@tests/factories/game/schemas/player/player.sc import { createFakeObjectId } from "@tests/factories/shared/mongoose/mongoose.factory"; import { createObjectIdFromString } from "@tests/helpers/mongoose/mongoose.helpers"; import type { ExceptionResponse } from "@tests/types/exception/exception.types"; -import type { Model, Types } from "mongoose"; -import { stringify } from "qs"; describe("Game Controller", () => { let app: NestFastifyApplication; diff --git a/tests/e2e/specs/modules/game/providers/repositories/game-history-record.repository.e2e-spec.ts b/tests/e2e/specs/modules/game/providers/repositories/game-history-record.repository.e2e-spec.ts index 0f52be6d5..790a6e1f6 100644 --- a/tests/e2e/specs/modules/game/providers/repositories/game-history-record.repository.e2e-spec.ts +++ b/tests/e2e/specs/modules/game/providers/repositories/game-history-record.repository.e2e-spec.ts @@ -1,9 +1,9 @@ -import { GameHistoryRecordRepository } from "@/modules/game/providers/repositories/game-history-record/game-history-record.repository"; import { getModelToken } from "@nestjs/mongoose"; import type { NestFastifyApplication } from "@nestjs/platform-fastify"; import type { TestingModule } from "@nestjs/testing"; import type { Model, Types } from "mongoose"; +import { GameHistoryRecordRepository } from "@/modules/game/providers/repositories/game-history-record/game-history-record.repository"; import type { GamePhaseName } from "@/modules/game/types/game-phase/game-phase.types"; import type { RoleSide } from "@/modules/role/types/role.types"; import { GameHistoryRecord } from "@/modules/game/schemas/game-history-record/game-history-record.schema"; diff --git a/tests/factories/game/dto/create-game-feedback/create-game-feedback.dto.factory.ts b/tests/factories/game/dto/create-game-feedback/create-game-feedback.dto.factory.ts index 410e8c7ac..2beea5d18 100644 --- a/tests/factories/game/dto/create-game-feedback/create-game-feedback.dto.factory.ts +++ b/tests/factories/game/dto/create-game-feedback/create-game-feedback.dto.factory.ts @@ -1,8 +1,10 @@ -import { CreateGameFeedbackDto } from "@/modules/game/dto/create-game-feedback/create-game-feedback.dto"; -import { DEFAULT_PLAIN_TO_INSTANCE_OPTIONS } from "@/shared/validation/constants/validation.constants"; import { faker } from "@faker-js/faker"; import { plainToInstance } from "class-transformer"; +import { CreateGameFeedbackDto } from "@/modules/game/dto/create-game-feedback/create-game-feedback.dto"; + +import { DEFAULT_PLAIN_TO_INSTANCE_OPTIONS } from "@/shared/validation/constants/validation.constants"; + function createFakeCreateGameFeedbackDto(createGameFeedbackDto: Partial = {}, override: object = {}): CreateGameFeedbackDto { return plainToInstance(CreateGameFeedbackDto, { score: createGameFeedbackDto.score ?? faker.number.int({ min: 1, max: 5 }), diff --git a/tests/factories/game/dto/create-game/create-game-options/create-roles-game-options/create-roles-game-options.dto.factory.ts b/tests/factories/game/dto/create-game/create-game-options/create-roles-game-options/create-roles-game-options.dto.factory.ts index 670201dce..8b7e10c0e 100644 --- a/tests/factories/game/dto/create-game/create-game-options/create-roles-game-options/create-roles-game-options.dto.factory.ts +++ b/tests/factories/game/dto/create-game/create-game-options/create-roles-game-options/create-roles-game-options.dto.factory.ts @@ -1,7 +1,7 @@ -import { CreateWerewolfGameOptionsDto } from "@/modules/game/dto/create-game/create-game-options/create-roles-game-options/create-werewolf-game-options.dto"; import { faker } from "@faker-js/faker"; import { plainToInstance } from "class-transformer"; +import { CreateWerewolfGameOptionsDto } from "@/modules/game/dto/create-game/create-game-options/create-roles-game-options/create-werewolf-game-options.dto"; import { GAME_PHASE_NAMES } from "@/modules/game/constants/game-phase/game-phase.constants"; import { CreateActorGameOptionsDto } from "@/modules/game/dto/create-game/create-game-options/create-roles-game-options/create-actor-game-options.dto"; import { CreatePrejudicedManipulatorGameOptionsDto } from "@/modules/game/dto/create-game/create-game-options/create-roles-game-options/create-prejudiced-manipulator-game-options.dto"; diff --git a/tests/factories/game/schemas/game-event/game-event.schema.factory.ts b/tests/factories/game/schemas/game-event/game-event.schema.factory.ts index 9c9c99a01..9d4680e37 100644 --- a/tests/factories/game/schemas/game-event/game-event.schema.factory.ts +++ b/tests/factories/game/schemas/game-event/game-event.schema.factory.ts @@ -1,8 +1,10 @@ +import { faker } from "@faker-js/faker"; +import { plainToInstance } from "class-transformer"; + import { GAME_EVENT_TYPES } from "@/modules/game/constants/game-event/game-event.constants"; import { GameEvent } from "@/modules/game/schemas/game-event/game-event.schema"; + import { DEFAULT_PLAIN_TO_INSTANCE_OPTIONS } from "@/shared/validation/constants/validation.constants"; -import { faker } from "@faker-js/faker"; -import { plainToInstance } from "class-transformer"; function createFakeGameEvent(gameEvent: Partial = {}): GameEvent { return plainToInstance(GameEvent, { diff --git a/tests/factories/game/schemas/game-feedback/game-feedback.factory.ts b/tests/factories/game/schemas/game-feedback/game-feedback.factory.ts index 57d30b4fc..48ecd0954 100644 --- a/tests/factories/game/schemas/game-feedback/game-feedback.factory.ts +++ b/tests/factories/game/schemas/game-feedback/game-feedback.factory.ts @@ -1,9 +1,12 @@ +import { faker } from "@faker-js/faker"; +import { plainToInstance } from "class-transformer"; + import { GameFeedback } from "@/modules/game/schemas/game-feedback/game-feedback.schema"; import { GameFeedbackToInsert } from "@/modules/game/types/game-feedback/game-feedback.types"; + import { DEFAULT_PLAIN_TO_INSTANCE_OPTIONS } from "@/shared/validation/constants/validation.constants"; -import { faker } from "@faker-js/faker"; + import { createFakeObjectId } from "@tests/factories/shared/mongoose/mongoose.factory"; -import { plainToInstance } from "class-transformer"; function createFakeGameFeedbackToInsert(gameFeedbackToInsert: Partial = {}): GameFeedbackToInsert { return plainToInstance(GameFeedbackToInsert, { diff --git a/tests/factories/game/schemas/game-history-record/game-history-record.schema.factory.ts b/tests/factories/game/schemas/game-history-record/game-history-record.schema.factory.ts index c190e7289..5df406860 100644 --- a/tests/factories/game/schemas/game-history-record/game-history-record.schema.factory.ts +++ b/tests/factories/game/schemas/game-history-record/game-history-record.schema.factory.ts @@ -1,9 +1,9 @@ -import { GAME_SOURCES } from "@/modules/game/constants/game.constants"; -import { PLAYER_ATTRIBUTE_NAMES } from "@/modules/game/constants/player/player-attribute/player-attribute.constants"; -import { GameHistoryRecordPlayerAttributeAlteration } from "@/modules/game/schemas/game-history-record/game-history-record-player-attribute-alteration/game-history-record-player-attribute-alteration.schema"; import { faker } from "@faker-js/faker"; import { plainToInstance } from "class-transformer"; +import { GAME_SOURCES } from "@/modules/game/constants/game.constants"; +import { PLAYER_ATTRIBUTE_NAMES } from "@/modules/game/constants/player/player-attribute/player-attribute.constants"; +import { GameHistoryRecordPlayerAttributeAlteration } from "@/modules/game/schemas/game-history-record/game-history-record-player-attribute-alteration/game-history-record-player-attribute-alteration.schema"; import { GAME_HISTORY_RECORD_PLAYER_ATTRIBUTE_ALTERATION_STATUSES, GAME_HISTORY_RECORD_VOTING_RESULTS } from "@/modules/game/constants/game-history-record/game-history-record.constants"; import { GAME_PLAY_ACTIONS, GAME_PLAY_SOURCE_NAMES, GAME_PLAY_TYPES } from "@/modules/game/constants/game-play/game-play.constants"; import { GameHistoryRecordPlaySource } from "@/modules/game/schemas/game-history-record/game-history-record-play/game-history-record-play-source/game-history-record-play-source.schema"; diff --git a/tests/factories/game/schemas/game-options/game-roles-options/game-roles-options.schema.factory.ts b/tests/factories/game/schemas/game-options/game-roles-options/game-roles-options.schema.factory.ts index 6fbffe212..b75e424a7 100644 --- a/tests/factories/game/schemas/game-options/game-roles-options/game-roles-options.schema.factory.ts +++ b/tests/factories/game/schemas/game-options/game-roles-options/game-roles-options.schema.factory.ts @@ -1,7 +1,7 @@ -import { WerewolfGameOptions } from "@/modules/game/schemas/game-options/roles-game-options/werewolf-game-options/werewolf-game-options.schema"; import { faker } from "@faker-js/faker"; import { plainToInstance } from "class-transformer"; +import { WerewolfGameOptions } from "@/modules/game/schemas/game-options/roles-game-options/werewolf-game-options/werewolf-game-options.schema"; import { GAME_PHASE_NAMES } from "@/modules/game/constants/game-phase/game-phase.constants"; import { ActorGameOptions } from "@/modules/game/schemas/game-options/roles-game-options/actor-game-options/actor-game-options.schema"; import { PrejudicedManipulatorGameOptions } from "@/modules/game/schemas/game-options/roles-game-options/prejudiced-manipulator-game-options/prejudiced-manipulator-game-options.schema"; diff --git a/tests/global-setup.ts b/tests/global-setup.ts index 2cf81c4a6..ffcf25a95 100644 --- a/tests/global-setup.ts +++ b/tests/global-setup.ts @@ -1,2 +1,2 @@ -// eslint-disable-next-line @typescript-eslint/no-restricted-imports +// eslint-disable-next-line @typescript-eslint/no-restricted-imports, import/no-unassigned-import import "./unit/unit-setup"; \ No newline at end of file diff --git a/tests/stryker/incremental.json b/tests/stryker/incremental.json index 66f4522a9..55b8cc281 100644 --- a/tests/stryker/incremental.json +++ b/tests/stryker/incremental.json @@ -1907,7 +1907,7 @@ } } ], - "source": "import { CreateGameFeedbackDto } from \"@/modules/game/dto/create-game-feedback/create-game-feedback.dto\";\nimport { Body, Controller, Delete, Get, HttpCode, HttpStatus, Param, Post, Query } from \"@nestjs/common\";\nimport { ApiOperation, ApiResponse, ApiTags } from \"@nestjs/swagger\";\n\nimport { GetGameHistoryDto } from \"@/modules/game/dto/get-game-history/get-game-history.dto\";\nimport { ApiGameIdParam } from \"@/modules/game/controllers/decorators/api-game-id-param.decorator\";\nimport { ApiGameNotFoundResponse } from \"@/modules/game/controllers/decorators/api-game-not-found-response.decorator\";\nimport { GetGameByIdPipe } from \"@/modules/game/controllers/pipes/get-game-by-id.pipe\";\nimport { CreateGameDto } from \"@/modules/game/dto/create-game/create-game.dto\";\nimport { GetGameRandomCompositionPlayerResponseDto } from \"@/modules/game/dto/get-game-random-composition/get-game-random-composition-player-response/get-game-random-composition-player-response.dto\";\nimport { GetGameRandomCompositionDto } from \"@/modules/game/dto/get-game-random-composition/get-game-random-composition.dto\";\nimport { MakeGamePlayDto } from \"@/modules/game/dto/make-game-play/make-game-play.dto\";\nimport { GameHistoryRecordService } from \"@/modules/game/providers/services/game-history/game-history-record.service\";\nimport { GameRandomCompositionService } from \"@/modules/game/providers/services/game-random-composition.service\";\nimport { GameService } from \"@/modules/game/providers/services/game.service\";\nimport { GameHistoryRecord } from \"@/modules/game/schemas/game-history-record/game-history-record.schema\";\nimport { Game } from \"@/modules/game/schemas/game.schema\";\n\nimport { ApiResources } from \"@/shared/api/enums/api.enums\";\n\n@ApiTags(\"🎲 Games\")\n@Controller(ApiResources.GAMES)\nexport class GameController {\n public constructor(\n private readonly gameService: GameService,\n private readonly gameRandomCompositionService: GameRandomCompositionService,\n private readonly gameHistoryRecordService: GameHistoryRecordService,\n ) {}\n\n @Get()\n @ApiOperation({ summary: \"Get games\" })\n @ApiResponse({ status: HttpStatus.OK, type: Game, isArray: true })\n private async getGames(): Promise {\n return this.gameService.getGames();\n }\n\n @Get(\"random-composition\")\n @ApiOperation({ summary: \"Get game random composition for given players\" })\n @ApiResponse({ status: HttpStatus.OK, type: GetGameRandomCompositionPlayerResponseDto, isArray: true })\n private getGameRandomComposition(@Query() getGameRandomCompositionDto: GetGameRandomCompositionDto): GetGameRandomCompositionPlayerResponseDto[] {\n return this.gameRandomCompositionService.getGameRandomComposition(getGameRandomCompositionDto);\n }\n\n @Get(\":id\")\n @ApiOperation({ summary: \"Get a game by id\" })\n @ApiGameIdParam()\n @ApiResponse({ status: HttpStatus.OK, type: Game })\n @ApiGameNotFoundResponse()\n private getGame(@Param(\"id\", GetGameByIdPipe) game: Game): Game {\n return game;\n }\n\n @Post()\n @ApiOperation({ summary: \"Create a new game\" })\n private async createGame(@Body() createGameDto: CreateGameDto): Promise {\n return this.gameService.createGame(createGameDto);\n }\n\n @Delete(\":id\")\n @ApiOperation({ summary: \"Cancel a playing game\", description: `This endpoint won't delete the game, but set its status to canceled. In this status, the game can't be mutated anymore.` })\n @ApiGameIdParam()\n @ApiResponse({ status: HttpStatus.OK, type: Game, description: `Game's status will be set to canceled` })\n @ApiGameNotFoundResponse()\n private async cancelGame(@Param(\"id\", GetGameByIdPipe) game: Game): Promise {\n return this.gameService.cancelGame(game);\n }\n\n @Post(\":id/play\")\n @HttpCode(HttpStatus.OK)\n @ApiOperation({ summary: \"Make a game play\", description: `Make a play for a game with the \"playing\" status. Body parameters fields are required or optional based on the upcoming game play.` })\n @ApiResponse({ status: HttpStatus.OK, type: Game })\n private async makeGamePlay(\n @Param(\"id\", GetGameByIdPipe) game: Game,\n @Body() makeGamePlayDto: MakeGamePlayDto,\n ): Promise {\n return this.gameService.makeGamePlay(game, makeGamePlayDto);\n }\n\n @Get(\":id/history\")\n @ApiOperation({ summary: \"Get a game full history by id\" })\n @ApiGameIdParam()\n @ApiResponse({ status: HttpStatus.OK, type: [GameHistoryRecord] })\n @ApiGameNotFoundResponse()\n private async getGameHistory(\n @Param(\"id\", GetGameByIdPipe) game: Game,\n @Query() getGameHistoryDto: GetGameHistoryDto,\n ): Promise {\n return this.gameHistoryRecordService.getGameHistory(game._id, getGameHistoryDto);\n }\n\n @Post(\":id/feedback\")\n @ApiGameIdParam()\n @ApiOperation({ summary: \"Create a game feedback\" })\n @ApiResponse({ status: HttpStatus.OK, type: Game })\n @ApiGameNotFoundResponse()\n private async createGameFeedback(\n @Param(\"id\", GetGameByIdPipe) game: Game,\n @Body() createGameFeedbackDto: CreateGameFeedbackDto,\n ): Promise {\n return this.gameService.createGameFeedback(game, createGameFeedbackDto);\n }\n}" + "source": "import { Body, Controller, Delete, Get, HttpCode, HttpStatus, Param, Post, Query } from \"@nestjs/common\";\nimport { ApiOperation, ApiResponse, ApiTags } from \"@nestjs/swagger\";\n\nimport { CreateGameFeedbackDto } from \"@/modules/game/dto/create-game-feedback/create-game-feedback.dto\";\nimport { GetGameHistoryDto } from \"@/modules/game/dto/get-game-history/get-game-history.dto\";\nimport { ApiGameIdParam } from \"@/modules/game/controllers/decorators/api-game-id-param.decorator\";\nimport { ApiGameNotFoundResponse } from \"@/modules/game/controllers/decorators/api-game-not-found-response.decorator\";\nimport { GetGameByIdPipe } from \"@/modules/game/controllers/pipes/get-game-by-id.pipe\";\nimport { CreateGameDto } from \"@/modules/game/dto/create-game/create-game.dto\";\nimport { GetGameRandomCompositionPlayerResponseDto } from \"@/modules/game/dto/get-game-random-composition/get-game-random-composition-player-response/get-game-random-composition-player-response.dto\";\nimport { GetGameRandomCompositionDto } from \"@/modules/game/dto/get-game-random-composition/get-game-random-composition.dto\";\nimport { MakeGamePlayDto } from \"@/modules/game/dto/make-game-play/make-game-play.dto\";\nimport { GameHistoryRecordService } from \"@/modules/game/providers/services/game-history/game-history-record.service\";\nimport { GameRandomCompositionService } from \"@/modules/game/providers/services/game-random-composition.service\";\nimport { GameService } from \"@/modules/game/providers/services/game.service\";\nimport { GameHistoryRecord } from \"@/modules/game/schemas/game-history-record/game-history-record.schema\";\nimport { Game } from \"@/modules/game/schemas/game.schema\";\n\nimport { ApiResources } from \"@/shared/api/enums/api.enums\";\n\n@ApiTags(\"🎲 Games\")\n@Controller(ApiResources.GAMES)\nexport class GameController {\n public constructor(\n private readonly gameService: GameService,\n private readonly gameRandomCompositionService: GameRandomCompositionService,\n private readonly gameHistoryRecordService: GameHistoryRecordService,\n ) {}\n\n @Get()\n @ApiOperation({ summary: \"Get games\" })\n @ApiResponse({ status: HttpStatus.OK, type: Game, isArray: true })\n private async getGames(): Promise {\n return this.gameService.getGames();\n }\n\n @Get(\"random-composition\")\n @ApiOperation({ summary: \"Get game random composition for given players\" })\n @ApiResponse({ status: HttpStatus.OK, type: GetGameRandomCompositionPlayerResponseDto, isArray: true })\n private getGameRandomComposition(@Query() getGameRandomCompositionDto: GetGameRandomCompositionDto): GetGameRandomCompositionPlayerResponseDto[] {\n return this.gameRandomCompositionService.getGameRandomComposition(getGameRandomCompositionDto);\n }\n\n @Get(\":id\")\n @ApiOperation({ summary: \"Get a game by id\" })\n @ApiGameIdParam()\n @ApiResponse({ status: HttpStatus.OK, type: Game })\n @ApiGameNotFoundResponse()\n private getGame(@Param(\"id\", GetGameByIdPipe) game: Game): Game {\n return game;\n }\n\n @Post()\n @ApiOperation({ summary: \"Create a new game\" })\n private async createGame(@Body() createGameDto: CreateGameDto): Promise {\n return this.gameService.createGame(createGameDto);\n }\n\n @Delete(\":id\")\n @ApiOperation({ summary: \"Cancel a playing game\", description: `This endpoint won't delete the game, but set its status to canceled. In this status, the game can't be mutated anymore.` })\n @ApiGameIdParam()\n @ApiResponse({ status: HttpStatus.OK, type: Game, description: `Game's status will be set to canceled` })\n @ApiGameNotFoundResponse()\n private async cancelGame(@Param(\"id\", GetGameByIdPipe) game: Game): Promise {\n return this.gameService.cancelGame(game);\n }\n\n @Post(\":id/play\")\n @HttpCode(HttpStatus.OK)\n @ApiOperation({ summary: \"Make a game play\", description: `Make a play for a game with the \"playing\" status. Body parameters fields are required or optional based on the upcoming game play.` })\n @ApiResponse({ status: HttpStatus.OK, type: Game })\n private async makeGamePlay(\n @Param(\"id\", GetGameByIdPipe) game: Game,\n @Body() makeGamePlayDto: MakeGamePlayDto,\n ): Promise {\n return this.gameService.makeGamePlay(game, makeGamePlayDto);\n }\n\n @Get(\":id/history\")\n @ApiOperation({ summary: \"Get a game full history by id\" })\n @ApiGameIdParam()\n @ApiResponse({ status: HttpStatus.OK, type: [GameHistoryRecord] })\n @ApiGameNotFoundResponse()\n private async getGameHistory(\n @Param(\"id\", GetGameByIdPipe) game: Game,\n @Query() getGameHistoryDto: GetGameHistoryDto,\n ): Promise {\n return this.gameHistoryRecordService.getGameHistory(game._id, getGameHistoryDto);\n }\n\n @Post(\":id/feedback\")\n @ApiGameIdParam()\n @ApiOperation({ summary: \"Create a game feedback\" })\n @ApiResponse({ status: HttpStatus.OK, type: Game })\n @ApiGameNotFoundResponse()\n private async createGameFeedback(\n @Param(\"id\", GetGameByIdPipe) game: Game,\n @Body() createGameFeedbackDto: CreateGameFeedbackDto,\n ): Promise {\n return this.gameService.createGameFeedback(game, createGameFeedbackDto);\n }\n}" }, "src/modules/game/controllers/pipes/get-game-by-id.pipe.ts": { "language": "typescript", @@ -4874,7 +4874,7 @@ } } ], - "source": "import { MAX_ADDITIONAL_CARDS_COUNT_FOR_RECIPIENT } from \"@/modules/game/constants/game-additional-card/game-additional-card.constants\";\nimport type { ValidationArguments, ValidationOptions } from \"class-validator\";\nimport { registerDecorator } from \"class-validator\";\nimport { has } from \"lodash\";\n\nimport type { CreateGameDto } from \"@/modules/game/dto/create-game/create-game.dto\";\n\nfunction isAdditionalCardsForActorSizeRespected(value: unknown, validationArguments: ValidationArguments): boolean {\n const { players } = validationArguments.object as CreateGameDto;\n if (value === undefined || !players.some(player => player.role.name === \"actor\")) {\n return true;\n }\n if (!Array.isArray(value) || value.some(card => !has(card, \"recipient\"))) {\n return false;\n }\n const cards = value as { recipient: string }[];\n const actorAdditionalCards = cards.filter(card => card.recipient === \"actor\");\n\n return actorAdditionalCards.length !== 0 && actorAdditionalCards.length <= MAX_ADDITIONAL_CARDS_COUNT_FOR_RECIPIENT;\n}\n\nfunction getAdditionalCardsForActorSizeDefaultMessage(): string {\n return `additionalCards length for actor must be between 1 and ${MAX_ADDITIONAL_CARDS_COUNT_FOR_RECIPIENT}`;\n}\n\nfunction AdditionalCardsForActorSize(validationOptions?: ValidationOptions) {\n return (object: object, propertyName: string): void => {\n registerDecorator({\n name: \"AdditionalCardsForActorSize\",\n target: object.constructor,\n propertyName,\n options: validationOptions,\n validator: {\n validate: isAdditionalCardsForActorSizeRespected,\n defaultMessage: getAdditionalCardsForActorSizeDefaultMessage,\n },\n });\n };\n}\n\nexport {\n AdditionalCardsForActorSize,\n getAdditionalCardsForActorSizeDefaultMessage,\n isAdditionalCardsForActorSizeRespected,\n};" + "source": "import type { ValidationArguments, ValidationOptions } from \"class-validator\";\nimport { registerDecorator } from \"class-validator\";\nimport { has } from \"lodash\";\n\nimport { MAX_ADDITIONAL_CARDS_COUNT_FOR_RECIPIENT } from \"@/modules/game/constants/game-additional-card/game-additional-card.constants\";\nimport type { CreateGameDto } from \"@/modules/game/dto/create-game/create-game.dto\";\n\nfunction isAdditionalCardsForActorSizeRespected(value: unknown, validationArguments: ValidationArguments): boolean {\n const { players } = validationArguments.object as CreateGameDto;\n if (value === undefined || !players.some(player => player.role.name === \"actor\")) {\n return true;\n }\n if (!Array.isArray(value) || value.some(card => !has(card, \"recipient\"))) {\n return false;\n }\n const cards = value as { recipient: string }[];\n const actorAdditionalCards = cards.filter(card => card.recipient === \"actor\");\n\n return actorAdditionalCards.length !== 0 && actorAdditionalCards.length <= MAX_ADDITIONAL_CARDS_COUNT_FOR_RECIPIENT;\n}\n\nfunction getAdditionalCardsForActorSizeDefaultMessage(): string {\n return `additionalCards length for actor must be between 1 and ${MAX_ADDITIONAL_CARDS_COUNT_FOR_RECIPIENT}`;\n}\n\nfunction AdditionalCardsForActorSize(validationOptions?: ValidationOptions) {\n return (object: object, propertyName: string): void => {\n registerDecorator({\n name: \"AdditionalCardsForActorSize\",\n target: object.constructor,\n propertyName,\n options: validationOptions,\n validator: {\n validate: isAdditionalCardsForActorSizeRespected,\n defaultMessage: getAdditionalCardsForActorSizeDefaultMessage,\n },\n });\n };\n}\n\nexport {\n AdditionalCardsForActorSize,\n getAdditionalCardsForActorSizeDefaultMessage,\n isAdditionalCardsForActorSizeRespected,\n};" }, "src/modules/game/dto/base/decorators/additional-cards/additional-cards-for-thief-roles.decorator.ts": { "language": "typescript", @@ -7577,7 +7577,7 @@ } } ], - "source": "import { MAX_ADDITIONAL_CARDS_COUNT_FOR_RECIPIENT } from \"@/modules/game/constants/game-additional-card/game-additional-card.constants\";\nimport type { ValidationArguments, ValidationOptions } from \"class-validator\";\nimport { registerDecorator } from \"class-validator\";\nimport { has } from \"lodash\";\n\nimport type { CreateGameDto } from \"@/modules/game/dto/create-game/create-game.dto\";\n\nfunction isAdditionalCardsForThiefSizeRespected(value: unknown, validationArguments: ValidationArguments): boolean {\n const { players } = validationArguments.object as CreateGameDto;\n if (value === undefined || !players.some(player => player.role.name === \"thief\")) {\n return true;\n }\n if (!Array.isArray(value) || value.some(card => !has(card, \"recipient\"))) {\n return false;\n }\n const cards = value as { recipient: string }[];\n const thiefAdditionalCards = cards.filter(card => card.recipient === \"thief\");\n\n return thiefAdditionalCards.length !== 0 && thiefAdditionalCards.length <= MAX_ADDITIONAL_CARDS_COUNT_FOR_RECIPIENT;\n}\n\nfunction getAdditionalCardsForThiefSizeDefaultMessage(): string {\n return `additionalCards length for thief must be between 1 and ${MAX_ADDITIONAL_CARDS_COUNT_FOR_RECIPIENT}`;\n}\n\nfunction AdditionalCardsForThiefSize(validationOptions?: ValidationOptions) {\n return (object: object, propertyName: string): void => {\n registerDecorator({\n name: \"AdditionalCardsForThiefSize\",\n target: object.constructor,\n propertyName,\n options: validationOptions,\n validator: {\n validate: isAdditionalCardsForThiefSizeRespected,\n defaultMessage: getAdditionalCardsForThiefSizeDefaultMessage,\n },\n });\n };\n}\n\nexport {\n AdditionalCardsForThiefSize,\n getAdditionalCardsForThiefSizeDefaultMessage,\n isAdditionalCardsForThiefSizeRespected,\n};" + "source": "import type { ValidationArguments, ValidationOptions } from \"class-validator\";\nimport { registerDecorator } from \"class-validator\";\nimport { has } from \"lodash\";\n\nimport { MAX_ADDITIONAL_CARDS_COUNT_FOR_RECIPIENT } from \"@/modules/game/constants/game-additional-card/game-additional-card.constants\";\nimport type { CreateGameDto } from \"@/modules/game/dto/create-game/create-game.dto\";\n\nfunction isAdditionalCardsForThiefSizeRespected(value: unknown, validationArguments: ValidationArguments): boolean {\n const { players } = validationArguments.object as CreateGameDto;\n if (value === undefined || !players.some(player => player.role.name === \"thief\")) {\n return true;\n }\n if (!Array.isArray(value) || value.some(card => !has(card, \"recipient\"))) {\n return false;\n }\n const cards = value as { recipient: string }[];\n const thiefAdditionalCards = cards.filter(card => card.recipient === \"thief\");\n\n return thiefAdditionalCards.length !== 0 && thiefAdditionalCards.length <= MAX_ADDITIONAL_CARDS_COUNT_FOR_RECIPIENT;\n}\n\nfunction getAdditionalCardsForThiefSizeDefaultMessage(): string {\n return `additionalCards length for thief must be between 1 and ${MAX_ADDITIONAL_CARDS_COUNT_FOR_RECIPIENT}`;\n}\n\nfunction AdditionalCardsForThiefSize(validationOptions?: ValidationOptions) {\n return (object: object, propertyName: string): void => {\n registerDecorator({\n name: \"AdditionalCardsForThiefSize\",\n target: object.constructor,\n propertyName,\n options: validationOptions,\n validator: {\n validate: isAdditionalCardsForThiefSizeRespected,\n defaultMessage: getAdditionalCardsForThiefSizeDefaultMessage,\n },\n });\n };\n}\n\nexport {\n AdditionalCardsForThiefSize,\n getAdditionalCardsForThiefSizeDefaultMessage,\n isAdditionalCardsForThiefSizeRespected,\n};" }, "src/modules/game/dto/base/decorators/additional-cards/additional-cards-presence.decorator.ts": { "language": "typescript", @@ -8142,7 +8142,6 @@ "700", "701", "703", - "704", "705", "706", "707", @@ -8191,7 +8190,6 @@ "700", "701", "703", - "704", "705", "706", "707", @@ -8240,7 +8238,6 @@ "700", "701", "703", - "704", "705", "706", "707", @@ -8274,36 +8271,6 @@ } } }, - { - "id": "223", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/modules/game/dto/base/decorators/additional-cards/additional-cards-presence.decorator.ts(16,94): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", - "status": "CompileError", - "static": false, - "killedBy": [], - "coveredBy": [ - "702", - "712", - "713", - "717", - "718", - "727", - "728", - "1404", - "1405" - ], - "location": { - "end": { - "column": 2, - "line": 21 - }, - "start": { - "column": 101, - "line": 16 - } - } - }, { "id": "224", "mutatorName": "BooleanLiteral", @@ -8317,6 +8284,7 @@ ], "coveredBy": [ "702", + "704", "712", "713", "717", @@ -8350,6 +8318,7 @@ ], "coveredBy": [ "702", + "704", "712", "713", "717", @@ -8383,6 +8352,7 @@ ], "coveredBy": [ "702", + "704", "712", "713", "717", @@ -8416,6 +8386,7 @@ ], "coveredBy": [ "702", + "704", "712", "727", "1404" @@ -8444,6 +8415,7 @@ ], "coveredBy": [ "702", + "704", "712", "727", "1404" @@ -8582,6 +8554,36 @@ "line": 30 } } + }, + { + "id": "223", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/modules/game/dto/base/decorators/additional-cards/additional-cards-presence.decorator.ts(16,94): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", + "status": "CompileError", + "static": false, + "coveredBy": [ + "702", + "704", + "712", + "713", + "717", + "718", + "727", + "728", + "1404", + "1405" + ], + "location": { + "end": { + "column": 2, + "line": 21 + }, + "start": { + "column": 101, + "line": 16 + } + } } ], "source": "import type { ValidationArguments, ValidationOptions } from \"class-validator\";\nimport { registerDecorator } from \"class-validator\";\n\nimport { GAME_ADDITIONAL_CARDS_RECIPIENTS } from \"@/modules/game/constants/game-additional-card/game-additional-card.constants\";\nimport type { CreateGameDto } from \"@/modules/game/dto/create-game/create-game.dto\";\nimport type { RoleName } from \"@/modules/role/types/role.types\";\n\nfunction isAdditionalCardsPresenceRespected(value: unknown, validationArguments: ValidationArguments): boolean {\n const { players } = validationArguments.object as Partial;\n const gameAdditionalCardsRecipients = GAME_ADDITIONAL_CARDS_RECIPIENTS as readonly RoleName[];\n const doSomePlayersNeedAdditionalCards = players?.some(player => gameAdditionalCardsRecipients.includes(player.role.name)) === true;\n\n return doSomePlayersNeedAdditionalCards ? Array.isArray(value) : value === undefined;\n}\n\nfunction getAdditionalCardsPresenceDefaultMessage(validationArguments: ValidationArguments): string {\n if (!Array.isArray(validationArguments.value)) {\n return `additionalCards must be set if there is a player with one of the following roles : ${GAME_ADDITIONAL_CARDS_RECIPIENTS.toString()}`;\n }\n return `additionalCards can't be set if there is no player with one of the following roles : ${GAME_ADDITIONAL_CARDS_RECIPIENTS.toString()}`;\n}\n\nfunction AdditionalCardsPresence(validationOptions?: ValidationOptions) {\n return (object: object, propertyName: string): void => {\n registerDecorator({\n name: \"AdditionalCardsPresence\",\n target: object.constructor,\n propertyName,\n options: validationOptions,\n validator: {\n validate: isAdditionalCardsPresenceRespected,\n defaultMessage: getAdditionalCardsPresenceDefaultMessage,\n },\n });\n };\n}\n\nexport {\n isAdditionalCardsPresenceRespected,\n getAdditionalCardsPresenceDefaultMessage,\n AdditionalCardsPresence,\n};" @@ -12801,7 +12803,6 @@ "726" ], "coveredBy": [ - "701", "702", "703", "704", @@ -12848,32 +12849,6 @@ } } }, - { - "id": "318", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/modules/game/dto/base/decorators/composition/composition-groups-presence.decorator.ts(20,96): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", - "status": "CompileError", - "static": false, - "killedBy": [], - "coveredBy": [ - "700", - "721", - "726", - "1503", - "1504" - ], - "location": { - "end": { - "column": 2, - "line": 27 - }, - "start": { - "column": 103, - "line": 20 - } - } - }, { "id": "319", "mutatorName": "ConditionalExpression", @@ -12887,6 +12862,7 @@ ], "coveredBy": [ "700", + "701", "721", "726", "1503", @@ -12916,6 +12892,7 @@ ], "coveredBy": [ "700", + "701", "721", "726", "1503", @@ -12945,6 +12922,7 @@ ], "coveredBy": [ "700", + "701", "721", "726", "1503", @@ -12974,6 +12952,7 @@ ], "coveredBy": [ "700", + "701", "721", "726", "1503", @@ -12990,32 +12969,6 @@ } } }, - { - "id": "323", - "mutatorName": "OptionalChaining", - "replacement": "players.some", - "statusReason": "src/modules/game/dto/base/decorators/composition/composition-groups-presence.decorator.ts(22,51): error TS18048: 'players' is possibly 'undefined'.\n", - "status": "CompileError", - "static": false, - "killedBy": [], - "coveredBy": [ - "700", - "721", - "726", - "1503", - "1504" - ], - "location": { - "end": { - "column": 64, - "line": 22 - }, - "start": { - "column": 51, - "line": 22 - } - } - }, { "id": "324", "mutatorName": "ArrowFunction", @@ -13028,6 +12981,7 @@ "721" ], "coveredBy": [ + "701", "721", "726", "1503", @@ -13056,6 +13010,7 @@ "726" ], "coveredBy": [ + "701", "721", "726", "1503", @@ -13084,6 +13039,7 @@ "721" ], "coveredBy": [ + "701", "721", "726", "1503", @@ -13112,6 +13068,7 @@ "726" ], "coveredBy": [ + "701", "721", "726", "1503", @@ -13128,31 +13085,6 @@ } } }, - { - "id": "328", - "mutatorName": "StringLiteral", - "replacement": "\"\"", - "statusReason": "src/modules/game/dto/base/decorators/composition/composition-groups-presence.decorator.ts(22,79): error TS2367: This comparison appears to be unintentional because the types '\"werewolf\" | \"big-bad-wolf\" | \"accursed-wolf-father\" | \"white-werewolf\" | \"villager\" | \"villager-villager\" | \"seer\" | \"cupid\" | \"witch\" | \"hunter\" | \"little-girl\" | \"defender\" | ... 17 more ... | \"devoted-servant\"' and '\"\"' have no overlap.\n", - "status": "CompileError", - "static": false, - "killedBy": [], - "coveredBy": [ - "721", - "726", - "1503", - "1504" - ], - "location": { - "end": { - "column": 117, - "line": 22 - }, - "start": { - "column": 93, - "line": 22 - } - } - }, { "id": "329", "mutatorName": "BooleanLiteral", @@ -13166,6 +13098,7 @@ ], "coveredBy": [ "700", + "701", "721", "726", "1503", @@ -13195,6 +13128,7 @@ ], "coveredBy": [ "700", + "701", "721", "726", "1503", @@ -13224,6 +13158,7 @@ ], "coveredBy": [ "700", + "701", "721", "726", "1503", @@ -13252,6 +13187,7 @@ "721" ], "coveredBy": [ + "701", "721", "1503" ], @@ -13278,6 +13214,7 @@ "721" ], "coveredBy": [ + "701", "721", "1503" ], @@ -13413,6 +13350,83 @@ "line": 36 } } + }, + { + "id": "328", + "mutatorName": "StringLiteral", + "replacement": "\"\"", + "statusReason": "src/modules/game/dto/base/decorators/composition/composition-groups-presence.decorator.ts(22,79): error TS2367: This comparison appears to be unintentional because the types '\"werewolf\" | \"big-bad-wolf\" | \"accursed-wolf-father\" | \"white-werewolf\" | \"villager\" | \"villager-villager\" | \"seer\" | \"cupid\" | \"witch\" | \"hunter\" | \"little-girl\" | \"defender\" | ... 17 more ... | \"devoted-servant\"' and '\"\"' have no overlap.\n", + "status": "CompileError", + "static": false, + "coveredBy": [ + "701", + "721", + "726", + "1503", + "1504" + ], + "location": { + "end": { + "column": 117, + "line": 22 + }, + "start": { + "column": 93, + "line": 22 + } + } + }, + { + "id": "323", + "mutatorName": "OptionalChaining", + "replacement": "players.some", + "statusReason": "src/modules/game/dto/base/decorators/composition/composition-groups-presence.decorator.ts(22,51): error TS18048: 'players' is possibly 'undefined'.\n", + "status": "CompileError", + "static": false, + "coveredBy": [ + "700", + "701", + "721", + "726", + "1503", + "1504" + ], + "location": { + "end": { + "column": 64, + "line": 22 + }, + "start": { + "column": 51, + "line": 22 + } + } + }, + { + "id": "318", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/modules/game/dto/base/decorators/composition/composition-groups-presence.decorator.ts(20,96): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", + "status": "CompileError", + "static": false, + "coveredBy": [ + "700", + "701", + "721", + "726", + "1503", + "1504" + ], + "location": { + "end": { + "column": 2, + "line": 27 + }, + "start": { + "column": 103, + "line": 20 + } + } } ], "source": "import type { ValidationArguments, ValidationOptions } from \"class-validator\";\nimport { registerDecorator } from \"class-validator\";\nimport { has } from \"lodash\";\n\nimport type { RoleName } from \"@/modules/role/types/role.types\";\nimport type { CreateGameDto } from \"@/modules/game/dto/create-game/create-game.dto\";\n\nfunction isCompositionGroupsExistenceRespected(value: unknown): boolean {\n if (!Array.isArray(value) || value.some(player => !has(player, [\"role\", \"name\"]))) {\n return false;\n }\n const players = value as { role: { name: RoleName }; group?: string }[];\n const doesCompositionHasPrejudicedManipulator = players.some(({ role }) => role.name === \"prejudiced-manipulator\");\n const doesSomePlayerHaveAGroup = players.some(({ group }) => group !== undefined);\n const doesEveryPlayerHaveAGroup = players.every(({ group }) => group !== undefined);\n\n return doesCompositionHasPrejudicedManipulator && doesEveryPlayerHaveAGroup || !doesCompositionHasPrejudicedManipulator && !doesSomePlayerHaveAGroup;\n}\n\nfunction getCompositionGroupsPresenceDefaultMessage(validationArguments: ValidationArguments): string {\n const { players } = validationArguments.object as Partial;\n const doesCompositionHasPrejudicedManipulator = players?.some(({ role }) => role.name === \"prejudiced-manipulator\") === true;\n if (doesCompositionHasPrejudicedManipulator) {\n return `each player must have a group if there is a player with role \\`prejudiced-manipulator\\``;\n }\n return `any player can't have a group if there is no player with role \\`prejudiced-manipulator\\``;\n}\n\nfunction CompositionGroupsPresence(validationOptions?: ValidationOptions) {\n return (object: object, propertyName: string): void => {\n registerDecorator({\n name: \"CompositionGroupsConsistency\",\n target: object.constructor,\n propertyName,\n options: validationOptions,\n validator: {\n validate: isCompositionGroupsExistenceRespected,\n defaultMessage: getCompositionGroupsPresenceDefaultMessage,\n },\n });\n };\n}\n\nexport {\n CompositionGroupsPresence,\n isCompositionGroupsExistenceRespected,\n getCompositionGroupsPresenceDefaultMessage,\n};" @@ -16461,6 +16475,7 @@ "1546" ], "coveredBy": [ + "701", "721", "722", "723", @@ -16493,6 +16508,7 @@ "722" ], "coveredBy": [ + "701", "721", "722", "723", @@ -16513,32 +16529,6 @@ } } }, - { - "id": "400", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/modules/game/dto/base/decorators/composition/composition-has-two-groups-with-prejudiced-manipulator.decorator.ts(19,79): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", - "status": "CompileError", - "static": false, - "killedBy": [], - "coveredBy": [ - "700", - "721", - "722", - "723", - "1547" - ], - "location": { - "end": { - "column": 2, - "line": 21 - }, - "start": { - "column": 86, - "line": 19 - } - } - }, { "id": "401", "mutatorName": "StringLiteral", @@ -16552,6 +16542,7 @@ ], "coveredBy": [ "700", + "701", "721", "722", "723", @@ -16662,6 +16653,32 @@ "line": 30 } } + }, + { + "id": "400", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/modules/game/dto/base/decorators/composition/composition-has-two-groups-with-prejudiced-manipulator.decorator.ts(19,79): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", + "status": "CompileError", + "static": false, + "coveredBy": [ + "700", + "701", + "721", + "722", + "723", + "1547" + ], + "location": { + "end": { + "column": 2, + "line": 21 + }, + "start": { + "column": 86, + "line": 19 + } + } } ], "source": "import type { ValidationOptions } from \"class-validator\";\nimport { registerDecorator } from \"class-validator\";\nimport { has } from \"lodash\";\n\nimport type { RoleName } from \"@/modules/role/types/role.types\";\n\nfunction doesCompositionHasTwoGroupsWithPrejudicedManipulator(value: unknown): boolean {\n if (!Array.isArray(value) || value.some(player => !has(player, [\"role\", \"name\"]))) {\n return false;\n }\n const players = value as { role: { name: RoleName }; group?: string }[];\n const doesCompositionHasPrejudicedManipulator = players.some(({ role }) => role.name === \"prejudiced-manipulator\");\n const distinctGroups = [...new Set(players.map(({ group }) => group))];\n const expectedDistinctGroupsCount = 2;\n\n return !doesCompositionHasPrejudicedManipulator || distinctGroups.length === expectedDistinctGroupsCount;\n}\n\nfunction getCompositionHasTwoGroupsWithPrejudicedManipulatorDefaultMessage(): string {\n return `there must be exactly two groups among players when \\`prejudiced-manipulator\\` in the game`;\n}\n\nfunction CompositionHasTwoGroupsWithPrejudicedManipulator(validationOptions?: ValidationOptions) {\n return (object: object, propertyName: string): void => {\n registerDecorator({\n name: \"CompositionHasTwoGroupsWithPrejudicedManipulator\",\n target: object.constructor,\n propertyName,\n options: validationOptions,\n validator: {\n validate: doesCompositionHasTwoGroupsWithPrejudicedManipulator,\n defaultMessage: getCompositionHasTwoGroupsWithPrejudicedManipulatorDefaultMessage,\n },\n });\n };\n}\n\nexport {\n CompositionHasTwoGroupsWithPrejudicedManipulator,\n doesCompositionHasTwoGroupsWithPrejudicedManipulator,\n getCompositionHasTwoGroupsWithPrejudicedManipulatorDefaultMessage,\n};" @@ -20158,8 +20175,7 @@ ], "coveredBy": [ "700", - "701", - "704", + "703", "705", "707", "709", @@ -20282,8 +20298,7 @@ "static": false, "coveredBy": [ "700", - "701", - "704", + "703", "705", "707", "709", @@ -26230,6 +26245,7 @@ "1558" ], "coveredBy": [ + "702", "705", "706", "717", @@ -26263,6 +26279,7 @@ "1558" ], "coveredBy": [ + "702", "705", "706", "717", @@ -26296,6 +26313,7 @@ "706" ], "coveredBy": [ + "702", "705", "706", "717", @@ -26317,33 +26335,6 @@ } } }, - { - "id": "573", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/modules/game/dto/base/decorators/composition/composition-roles-min-in-game.decorator.ts(24,56): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", - "status": "CompileError", - "static": false, - "killedBy": [], - "coveredBy": [ - "700", - "705", - "706", - "717", - "718", - "1559" - ], - "location": { - "end": { - "column": 2, - "line": 26 - }, - "start": { - "column": 63, - "line": 24 - } - } - }, { "id": "574", "mutatorName": "StringLiteral", @@ -26357,6 +26348,7 @@ ], "coveredBy": [ "700", + "702", "705", "706", "717", @@ -26468,6 +26460,33 @@ "line": 35 } } + }, + { + "id": "573", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/modules/game/dto/base/decorators/composition/composition-roles-min-in-game.decorator.ts(24,56): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", + "status": "CompileError", + "static": false, + "coveredBy": [ + "700", + "702", + "705", + "706", + "717", + "718", + "1559" + ], + "location": { + "end": { + "column": 2, + "line": 26 + }, + "start": { + "column": 63, + "line": 24 + } + } } ], "source": "import { registerDecorator } from \"class-validator\";\nimport { has } from \"lodash\";\nimport type { ValidationOptions } from \"class-validator\";\n\nimport type { Role } from \"@/modules/role/types/role.class\";\nimport { ROLES } from \"@/modules/role/constants/role-set.constants\";\nimport type { RoleName } from \"@/modules/role/types/role.types\";\n\nfunction areCompositionRolesMinInGameRespected(value?: unknown): boolean {\n if (!Array.isArray(value) || value.some(player => !has(player, [\"role\", \"name\"]))) {\n return false;\n }\n const players = value as { role: { name: RoleName } }[];\n\n return ROLES\n .filter((role): role is Role & { minInGame: number } => role.minInGame !== undefined)\n .every(role => {\n const roleCount = players.filter(player => player.role.name === role.name).length;\n\n return roleCount === 0 || roleCount >= role.minInGame;\n });\n}\n\nfunction getCompositionRolesMinInGameDefaultMessage(): string {\n return \"players.role minimum occurrences in game must be reached. Please check `minInGame` property of roles\";\n}\n\nfunction CompositionRolesMinInGame(validationOptions?: ValidationOptions) {\n return (object: object, propertyName: string): void => {\n registerDecorator({\n name: \"CompositionRolesMinInGame\",\n target: object.constructor,\n propertyName,\n options: validationOptions,\n validator: {\n validate: areCompositionRolesMinInGameRespected,\n defaultMessage: getCompositionRolesMinInGameDefaultMessage,\n },\n });\n };\n}\n\nexport { CompositionRolesMinInGame, areCompositionRolesMinInGameRespected, getCompositionRolesMinInGameDefaultMessage };" @@ -26938,158 +26957,13 @@ "language": "typescript", "mutants": [ { - "id": "590", - "mutatorName": "BooleanLiteral", - "replacement": "has(params.value as object, \"name\")", - "statusReason": "Error: expect(received).toSatisfyAll(expected)\n\nExpected array to satisfy predicate for all values:\n [Function anonymous]\nReceived:\n [{\"name\": \"1\", \"role\": {\"name\": \"fox\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}, {\"name\": \"2\", \"role\": {\"name\": \"scandalmonger\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}, {\"name\": \"3\", \"role\": {\"name\": \"stuttering-judge\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}, {\"name\": \"4\", \"role\": {\"name\": \"villager\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}, {\"name\": \"5\", \"role\": {\"name\": \"pied-piper\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}, {\"name\": \"6\", \"role\": {\"name\": \"werewolf\"}, \"side\": {\"current\": \"werewolves\", \"original\": \"werewolves\"}}, {\"name\": \"7\", \"role\": {\"name\": \"seer\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}, {\"name\": \"8\", \"role\": {\"name\": \"little-girl\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}, {\"name\": \"9\", \"role\": {\"name\": \"three-brothers\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}, {\"name\": \"10\", \"role\": {\"name\": \"werewolf\"}, \"side\": {\"current\": \"werewolves\", \"original\": \"werewolves\"}}, …]\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox458659/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:259:23)\n at processTicksAndRejections (node:internal/process/task_queues:105:5)", - "status": "Killed", - "testsCompleted": 117, - "static": true, - "killedBy": [ - "696" - ], - "coveredBy": [ - "256", - "257", - "258", - "272", - "273", - "696", - "701", - "702", - "703", - "704", - "705", - "706", - "707", - "708", - "709", - "710", - "711", - "712", - "713", - "714", - "715", - "716", - "717", - "718", - "719", - "720", - "721", - "722", - "723", - "724", - "725", - "726", - "727", - "728", - "729", - "730", - "731", - "732", - "733", - "734", - "735", - "736", - "737", - "738", - "954", - "955", - "1082", - "1232", - "1233", - "1234", - "1235", - "1254", - "1255", - "1404", - "1405", - "1431", - "1432", - "1433", - "1434", - "1435", - "1436", - "1437", - "1438", - "1440", - "1441", - "1442", - "1443", - "1444", - "1445", - "1446", - "1447", - "1499", - "1500", - "1501", - "1502", - "1503", - "1504", - "1525", - "1526", - "1527", - "1528", - "1529", - "1530", - "1531", - "1543", - "1544", - "1545", - "1546", - "1554", - "1555", - "1556", - "1558", - "1565", - "1566", - "1567", - "1569", - "1582", - "1583", - "1584", - "1586", - "1590", - "1591", - "1592", - "1594", - "1616", - "1617", - "1618", - "1632", - "1633", - "1634", - "1635", - "1649", - "1650", - "1651", - "1652", - "1653", - "1654", - "1655" - ], - "location": { - "end": { - "column": 43, - "line": 10 - }, - "start": { - "column": 7, - "line": 10 - } - } - }, - { - "id": "592", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "statusReason": "TypeError: Cannot read properties of null (reading 'name')\n at playerRoleTransformer (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/src/modules/game/dto/base/game-player/transformers/player-role.transformer.ts:73:59)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/dto/base/game-player/transformers/player-role.transformer.spec.ts:64:35\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-each@29.7.0/node_modules/jest-each/build/bind.js:81:13)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", - "status": "Killed", - "testsCompleted": 115, + "id": "589", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/modules/game/dto/base/game-player/transformers/player-role.transformer.ts(9,60): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", + "status": "CompileError", "static": true, - "killedBy": [ - "1649" - ], + "killedBy": [], "coveredBy": [ "256", "257", @@ -27212,22 +27086,22 @@ ], "location": { "end": { - "column": 43, - "line": 10 + "column": 2, + "line": 28 }, "start": { - "column": 7, - "line": 10 + "column": 68, + "line": 9 } } }, { - "id": "593", - "mutatorName": "StringLiteral", - "replacement": "\"\"", - "statusReason": "Error: expect(received).toSatisfyAll(expected)\n\nExpected array to satisfy predicate for all values:\n [Function anonymous]\nReceived:\n [{\"name\": \"1\", \"role\": {\"name\": \"three-brothers\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}, {\"name\": \"2\", \"role\": {\"name\": \"villager\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}, {\"name\": \"3\", \"role\": {\"name\": \"werewolf\"}, \"side\": {\"current\": \"werewolves\", \"original\": \"werewolves\"}}, {\"name\": \"4\", \"role\": {\"name\": \"hunter\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}, {\"name\": \"5\", \"role\": {\"name\": \"three-brothers\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}, {\"name\": \"6\", \"role\": {\"name\": \"cupid\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}, {\"name\": \"7\", \"role\": {\"name\": \"villager\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}, {\"name\": \"8\", \"role\": {\"name\": \"actor\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}, {\"name\": \"9\", \"role\": {\"name\": \"stuttering-judge\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}, {\"name\": \"10\", \"role\": {\"name\": \"idiot\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}, …]\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox1121937/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:259:23)\n at processTicksAndRejections (node:internal/process/task_queues:95:5)", + "id": "590", + "mutatorName": "BooleanLiteral", + "replacement": "has(params.value as object, \"name\")", + "statusReason": "Error: expect(received).toSatisfyAll(expected)\n\nExpected array to satisfy predicate for all values:\n [Function anonymous]\nReceived:\n [{\"name\": \"1\", \"role\": {\"name\": \"fox\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}, {\"name\": \"2\", \"role\": {\"name\": \"scandalmonger\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}, {\"name\": \"3\", \"role\": {\"name\": \"stuttering-judge\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}, {\"name\": \"4\", \"role\": {\"name\": \"villager\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}, {\"name\": \"5\", \"role\": {\"name\": \"pied-piper\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}, {\"name\": \"6\", \"role\": {\"name\": \"werewolf\"}, \"side\": {\"current\": \"werewolves\", \"original\": \"werewolves\"}}, {\"name\": \"7\", \"role\": {\"name\": \"seer\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}, {\"name\": \"8\", \"role\": {\"name\": \"little-girl\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}, {\"name\": \"9\", \"role\": {\"name\": \"three-brothers\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}, {\"name\": \"10\", \"role\": {\"name\": \"werewolf\"}, \"side\": {\"current\": \"werewolves\", \"original\": \"werewolves\"}}, …]\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox458659/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:259:23)\n at processTicksAndRejections (node:internal/process/task_queues:105:5)", "status": "Killed", - "testsCompleted": 115, + "testsCompleted": 117, "static": true, "killedBy": [ "696" @@ -27354,75 +27228,23 @@ ], "location": { "end": { - "column": 42, + "column": 43, "line": 10 }, "start": { - "column": 36, - "line": 10 - } - } - }, - { - "id": "594", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "TypeError: Cannot read properties of null (reading 'name')\n at playerRoleTransformer (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/src/modules/game/dto/base/game-player/transformers/player-role.transformer.ts:73:59)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/dto/base/game-player/transformers/player-role.transformer.spec.ts:64:35\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-each@29.7.0/node_modules/jest-each/build/bind.js:81:13)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", - "status": "Killed", - "testsCompleted": 3, - "static": false, - "killedBy": [ - "1649" - ], - "coveredBy": [ - "1649", - "1650", - "1651" - ], - "location": { - "end": { - "column": 4, - "line": 12 - }, - "start": { - "column": 45, + "column": 7, "line": 10 } } }, { - "id": "598", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/modules/game/dto/base/game-player/transformers/player-role.transformer.ts(21,19): error TS18048: 'role' is possibly 'undefined'.\nsrc/modules/game/dto/base/game-player/transformers/player-role.transformer.ts(22,20): error TS18048: 'role' is possibly 'undefined'.\nsrc/modules/game/dto/base/game-player/transformers/player-role.transformer.ts(23,22): error TS18048: 'role' is possibly 'undefined'.\n", - "status": "CompileError", - "static": false, - "killedBy": [], - "coveredBy": [ - "1652" - ], - "location": { - "end": { - "column": 4, - "line": 22 - }, - "start": { - "column": 27, - "line": 20 - } - } - }, - { - "id": "599", + "id": "591", "mutatorName": "ConditionalExpression", "replacement": "true", - "statusReason": "Error: expect(received).toStrictEqual(expected) // deep equality\n\n- Expected - 1\n+ Received + 1\n\n Object {\n \"current\": \"seer\",\n- \"isRevealed\": false,\n+ \"isRevealed\": true,\n \"name\": \"seer\",\n \"original\": \"seer\",\n }\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/dto/base/game-player/transformers/player-role.transformer.spec.ts:64:69\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-each@29.7.0/node_modules/jest-each/build/bind.js:81:13)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", - "status": "Killed", - "testsCompleted": 111, + "statusReason": "src/modules/game/dto/base/game-player/transformers/player-role.transformer.ts(23,19): error TS18048: 'role' is possibly 'undefined'.\nsrc/modules/game/dto/base/game-player/transformers/player-role.transformer.ts(24,20): error TS18048: 'role' is possibly 'undefined'.\nsrc/modules/game/dto/base/game-player/transformers/player-role.transformer.ts(25,22): error TS18048: 'role' is possibly 'undefined'.\n", + "status": "CompileError", "static": true, - "killedBy": [ - "1653" - ], + "killedBy": [], "coveredBy": [ "256", "257", @@ -27535,31 +27357,35 @@ "1633", "1634", "1635", + "1649", + "1650", + "1651", + "1652", "1653", "1654", "1655" ], "location": { "end": { - "column": 55, - "line": 25 + "column": 43, + "line": 10 }, "start": { - "column": 22, - "line": 25 + "column": 7, + "line": 10 } } }, { - "id": "600", + "id": "592", "mutatorName": "ConditionalExpression", "replacement": "false", - "statusReason": "Error: expect(received).toStrictEqual(expected) // deep equality\n\n- Expected - 1\n+ Received + 1\n\n Object {\n \"current\": \"villager-villager\",\n- \"isRevealed\": true,\n+ \"isRevealed\": false,\n \"name\": \"villager-villager\",\n \"original\": \"villager-villager\",\n }\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox4853956/tests/unit/specs/modules/game/dto/base/game-player/transformers/player-role.transformer.spec.ts:64:69\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-each@29.7.0/node_modules/jest-each/build/bind.js:81:13)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "statusReason": "TypeError: Cannot read properties of null (reading 'name')\n at playerRoleTransformer (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/src/modules/game/dto/base/game-player/transformers/player-role.transformer.ts:73:59)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/dto/base/game-player/transformers/player-role.transformer.spec.ts:64:35\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-each@29.7.0/node_modules/jest-each/build/bind.js:81:13)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", "status": "Killed", - "testsCompleted": 111, + "testsCompleted": 115, "static": true, "killedBy": [ - "1655" + "1649" ], "coveredBy": [ "256", @@ -27673,31 +27499,35 @@ "1633", "1634", "1635", + "1649", + "1650", + "1651", + "1652", "1653", "1654", "1655" ], "location": { "end": { - "column": 55, - "line": 25 + "column": 43, + "line": 10 }, "start": { - "column": 22, - "line": 25 + "column": 7, + "line": 10 } } }, { - "id": "601", - "mutatorName": "EqualityOperator", - "replacement": "role.name !== \"villager-villager\"", - "statusReason": "Error: expect(received).toStrictEqual(expected) // deep equality\n\n- Expected - 30\n+ Received + 30\n\n@@ -12,98 +12,98 @@\n \"max\": 6,\n \"min\": 1,\n },\n \"eligibleTargets\": Array [\n Object {\n- \"_id\": Any,\n+ \"_id\": \"67014a10e1faf8fa9ae357de\",\n \"attributes\": Array [],\n \"isAlive\": true,\n \"name\": \"Antoine\",\n \"position\": 0,\n \"role\": Object {\n \"current\": \"villager\",\n- \"isRevealed\": false,\n+ \"isRevealed\": true,\n \"original\": \"villager\",\n },\n \"side\": Object {\n \"current\": \"villagers\",\n \"original\": \"villagers\",\n },\n },\n Object {\n- \"_id\": Any,\n+ \"_id\": \"67014a10e1faf8fa9ae357df\",\n \"attributes\": Array [],\n \"isAlive\": true,\n \"name\": \"Mathis\",\n \"position\": 1,\n \"role\": Object {\n \"current\": \"werewolf\",\n- \"isRevealed\": false,\n+ \"isRevealed\": true,\n \"original\": \"werewolf\",\n },\n \"side\": Object {\n \"current\": \"werewolves\",\n \"original\": \"werewolves\",\n },\n },\n Object {\n- \"_id\": Any,\n+ \"_id\": \"67014a10e1faf8fa9ae357e0\",\n \"attributes\": Array [],\n \"isAlive\": true,\n \"name\": \"Virgil\",\n \"position\": 2,\n \"role\": Object {\n \"current\": \"villager-villager\",\n- \"isRevealed\": true,\n+ \"isRevealed\": false,\n \"original\": \"villager-villager\",\n },\n \"side\": Object {\n \"current\": \"villagers\",\n \"original\": \"villagers\",\n },\n },\n Object {\n- \"_id\": Any,\n+ \"_id\": \"67014a10e1faf8fa9ae357e1\",\n \"attributes\": Array [],\n \"isAlive\": true,\n \"name\": \"JB\",\n \"position\": 3,\n \"role\": Object {\n \"current\": \"white-werewolf\",\n- \"isRevealed\": false,\n+ \"isRevealed\": true,\n \"original\": \"white-werewolf\",\n },\n \"side\": Object {\n \"current\": \"werewolves\",\n \"original\": \"werewolves\",\n },\n },\n Object {\n- \"_id\": Any,\n+ \"_id\": \"67014a10e1faf8fa9ae357e2\",\n \"attributes\": Array [],\n \"isAlive\": true,\n \"name\": \"Doudou\",\n \"position\": 4,\n \"role\": Object {\n \"current\": \"cupid\",\n- \"isRevealed\": false,\n+ \"isRevealed\": true,\n \"original\": \"cupid\",\n },\n \"side\": Object {\n \"current\": \"villagers\",\n \"original\": \"villagers\",\n },\n },\n Object {\n- \"_id\": Any,\n+ \"_id\": \"67014a10e1faf8fa9ae357e3\",\n \"attributes\": Array [],\n \"isAlive\": true,\n \"name\": \"Juju\",\n \"position\": 5,\n \"role\": Object {\n \"current\": \"seer\",\n- \"isRevealed\": false,\n+ \"isRevealed\": true,\n \"original\": \"seer\",\n },\n \"side\": Object {\n \"current\": \"villagers\",\n \"original\": \"villagers\",\n@@ -115,98 +115,98 @@\n },\n ],\n \"name\": \"survivors\",\n \"players\": Array [\n Object {\n- \"_id\": Any,\n+ \"_id\": \"67014a10e1faf8fa9ae357de\",\n \"attributes\": Array [],\n \"isAlive\": true,\n \"name\": \"Antoine\",\n \"position\": 0,\n \"role\": Object {\n \"current\": \"villager\",\n- \"isRevealed\": false,\n+ \"isRevealed\": true,\n \"original\": \"villager\",\n },\n \"side\": Object {\n \"current\": \"villagers\",\n \"original\": \"villagers\",\n },\n },\n Object {\n- \"_id\": Any,\n+ \"_id\": \"67014a10e1faf8fa9ae357df\",\n \"attributes\": Array [],\n \"isAlive\": true,\n \"name\": \"Mathis\",\n \"position\": 1,\n \"role\": Object {\n \"current\": \"werewolf\",\n- \"isRevealed\": false,\n+ \"isRevealed\": true,\n \"original\": \"werewolf\",\n },\n \"side\": Object {\n \"current\": \"werewolves\",\n \"original\": \"werewolves\",\n },\n },\n Object {\n- \"_id\": Any,\n+ \"_id\": \"67014a10e1faf8fa9ae357e0\",\n \"attributes\": Array [],\n \"isAlive\": true,\n \"name\": \"Virgil\",\n \"position\": 2,\n \"role\": Object {\n \"current\": \"villager-villager\",\n- \"isRevealed\": true,\n+ \"isRevealed\": false,\n \"original\": \"villager-villager\",\n },\n \"side\": Object {\n \"current\": \"villagers\",\n \"original\": \"villagers\",\n },\n },\n Object {\n- \"_id\": Any,\n+ \"_id\": \"67014a10e1faf8fa9ae357e1\",\n \"attributes\": Array [],\n \"isAlive\": true,\n \"name\": \"JB\",\n \"position\": 3,\n \"role\": Object {\n \"current\": \"white-werewolf\",\n- \"isRevealed\": false,\n+ \"isRevealed\": true,\n \"original\": \"white-werewolf\",\n },\n \"side\": Object {\n \"current\": \"werewolves\",\n \"original\": \"werewolves\",\n },\n },\n Object {\n- \"_id\": Any,\n+ \"_id\": \"67014a10e1faf8fa9ae357e2\",\n \"attributes\": Array [],\n \"isAlive\": true,\n \"name\": \"Doudou\",\n \"position\": 4,\n \"role\": Object {\n \"current\": \"cupid\",\n- \"isRevealed\": false,\n+ \"isRevealed\": true,\n \"original\": \"cupid\",\n },\n \"side\": Object {\n \"current\": \"villagers\",\n \"original\": \"villagers\",\n },\n },\n Object {\n- \"_id\": Any,\n+ \"_id\": \"67014a10e1faf8fa9ae357e3\",\n \"attributes\": Array [],\n \"isAlive\": true,\n \"name\": \"Juju\",\n \"position\": 5,\n \"role\": Object {\n \"current\": \"seer\",\n- \"isRevealed\": false,\n+ \"isRevealed\": true,\n \"original\": \"seer\",\n },\n \"side\": Object {\n \"current\": \"villagers\",\n \"original\": \"villagers\",\n@@ -327,11 +327,11 @@\n \"isAlive\": true,\n \"name\": \"Antoine\",\n \"position\": 0,\n \"role\": Object {\n \"current\": \"villager\",\n- \"isRevealed\": false,\n+ \"isRevealed\": true,\n \"original\": \"villager\",\n },\n \"side\": Object {\n \"current\": \"villagers\",\n \"original\": \"villagers\",\n@@ -343,11 +343,11 @@\n \"isAlive\": true,\n \"name\": \"Mathis\",\n \"position\": 1,\n \"role\": Object {\n \"current\": \"werewolf\",\n- \"isRevealed\": false,\n+ \"isRevealed\": true,\n \"original\": \"werewolf\",\n },\n \"side\": Object {\n \"current\": \"werewolves\",\n \"original\": \"werewolves\",\n@@ -359,11 +359,11 @@\n \"isAlive\": true,\n \"name\": \"Virgil\",\n \"position\": 2,\n \"role\": Object {\n \"current\": \"villager-villager\",\n- \"isRevealed\": true,\n+ \"isRevealed\": false,\n \"original\": \"villager-villager\",\n },\n \"side\": Object {\n \"current\": \"villagers\",\n \"original\": \"villagers\",\n@@ -375,11 +375,11 @@\n \"isAlive\": true,\n \"name\": \"JB\",\n \"position\": 3,\n \"role\": Object {\n \"current\": \"white-werewolf\",\n- \"isRevealed\": false,\n+ \"isRevealed\": true,\n \"original\": \"white-werewolf\",\n },\n \"side\": Object {\n \"current\": \"werewolves\",\n \"original\": \"werewolves\",\n@@ -391,11 +391,11 @@\n \"isAlive\": true,\n \"name\": \"Doudou\",\n \"position\": 4,\n \"role\": Object {\n \"current\": \"cupid\",\n- \"isRevealed\": false,\n+ \"isRevealed\": true,\n \"original\": \"cupid\",\n },\n \"side\": Object {\n \"current\": \"villagers\",\n \"original\": \"villagers\",\n@@ -407,11 +407,11 @@\n \"isAlive\": true,\n \"name\": \"Juju\",\n \"position\": 5,\n \"role\": Object {\n \"current\": \"seer\",\n- \"isRevealed\": false,\n+ \"isRevealed\": true,\n \"original\": \"seer\",\n },\n \"side\": Object {\n \"current\": \"villagers\",\n \"original\": \"villagers\",\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox6871045/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:888:37)\n at processTicksAndRejections (node:internal/process/task_queues:105:5)", + "id": "593", + "mutatorName": "StringLiteral", + "replacement": "\"\"", + "statusReason": "Error: expect(received).toSatisfyAll(expected)\n\nExpected array to satisfy predicate for all values:\n [Function anonymous]\nReceived:\n [{\"name\": \"1\", \"role\": {\"name\": \"three-brothers\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}, {\"name\": \"2\", \"role\": {\"name\": \"villager\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}, {\"name\": \"3\", \"role\": {\"name\": \"werewolf\"}, \"side\": {\"current\": \"werewolves\", \"original\": \"werewolves\"}}, {\"name\": \"4\", \"role\": {\"name\": \"hunter\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}, {\"name\": \"5\", \"role\": {\"name\": \"three-brothers\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}, {\"name\": \"6\", \"role\": {\"name\": \"cupid\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}, {\"name\": \"7\", \"role\": {\"name\": \"villager\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}, {\"name\": \"8\", \"role\": {\"name\": \"actor\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}, {\"name\": \"9\", \"role\": {\"name\": \"stuttering-judge\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}, {\"name\": \"10\", \"role\": {\"name\": \"idiot\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}, …]\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox1121937/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:259:23)\n at processTicksAndRejections (node:internal/process/task_queues:95:5)", "status": "Killed", - "testsCompleted": 111, + "testsCompleted": 115, "static": true, "killedBy": [ - "736" + "696" ], "coveredBy": [ "256", @@ -27811,166 +27641,60 @@ "1633", "1634", "1635", + "1649", + "1650", + "1651", + "1652", "1653", "1654", "1655" ], "location": { "end": { - "column": 55, - "line": 25 + "column": 42, + "line": 10 }, "start": { - "column": 22, - "line": 25 + "column": 36, + "line": 10 } } }, { - "id": "589", + "id": "594", "mutatorName": "BlockStatement", "replacement": "{}", - "statusReason": "src/modules/game/dto/base/game-player/transformers/player-role.transformer.ts(9,60): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", - "status": "CompileError", - "static": true, + "statusReason": "TypeError: Cannot read properties of null (reading 'name')\n at playerRoleTransformer (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/src/modules/game/dto/base/game-player/transformers/player-role.transformer.ts:73:59)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/dto/base/game-player/transformers/player-role.transformer.spec.ts:64:35\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-each@29.7.0/node_modules/jest-each/build/bind.js:81:13)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "status": "Killed", + "testsCompleted": 3, + "static": false, + "killedBy": [ + "1649" + ], "coveredBy": [ - "256", - "257", - "258", - "272", - "273", - "696", - "701", - "702", - "703", - "704", - "705", - "706", - "707", - "708", - "709", - "710", - "711", - "712", - "713", - "714", - "715", - "716", - "717", - "718", - "719", - "720", - "721", - "722", - "723", - "724", - "725", - "726", - "727", - "728", - "729", - "730", - "731", - "732", - "733", - "734", - "735", - "736", - "737", - "738", - "954", - "955", - "1082", - "1232", - "1233", - "1234", - "1235", - "1254", - "1255", - "1404", - "1405", - "1431", - "1432", - "1433", - "1434", - "1435", - "1436", - "1437", - "1438", - "1440", - "1441", - "1442", - "1443", - "1444", - "1445", - "1446", - "1447", - "1499", - "1500", - "1501", - "1502", - "1503", - "1504", - "1525", - "1526", - "1527", - "1528", - "1529", - "1530", - "1531", - "1543", - "1544", - "1545", - "1546", - "1554", - "1555", - "1556", - "1558", - "1565", - "1566", - "1567", - "1569", - "1582", - "1583", - "1584", - "1586", - "1590", - "1591", - "1592", - "1594", - "1616", - "1617", - "1618", - "1632", - "1633", - "1634", - "1635", "1649", "1650", - "1651", - "1652", - "1653", - "1654", - "1655" + "1651" ], "location": { "end": { - "column": 2, - "line": 28 + "column": 4, + "line": 12 }, "start": { - "column": 68, - "line": 9 + "column": 45, + "line": 10 } } }, { - "id": "596", + "id": "595", "mutatorName": "ConditionalExpression", - "replacement": "false", + "replacement": "true", "statusReason": "src/modules/game/dto/base/game-player/transformers/player-role.transformer.ts(23,19): error TS18048: 'role' is possibly 'undefined'.\nsrc/modules/game/dto/base/game-player/transformers/player-role.transformer.ts(24,20): error TS18048: 'role' is possibly 'undefined'.\nsrc/modules/game/dto/base/game-player/transformers/player-role.transformer.ts(25,22): error TS18048: 'role' is possibly 'undefined'.\n", "status": "CompileError", "static": true, + "killedBy": [], "coveredBy": [ "256", "257", @@ -28100,12 +27824,13 @@ } }, { - "id": "591", + "id": "596", "mutatorName": "ConditionalExpression", - "replacement": "true", + "replacement": "false", "statusReason": "src/modules/game/dto/base/game-player/transformers/player-role.transformer.ts(23,19): error TS18048: 'role' is possibly 'undefined'.\nsrc/modules/game/dto/base/game-player/transformers/player-role.transformer.ts(24,20): error TS18048: 'role' is possibly 'undefined'.\nsrc/modules/game/dto/base/game-player/transformers/player-role.transformer.ts(25,22): error TS18048: 'role' is possibly 'undefined'.\n", "status": "CompileError", "static": true, + "killedBy": [], "coveredBy": [ "256", "257", @@ -28218,9 +27943,6 @@ "1633", "1634", "1635", - "1649", - "1650", - "1651", "1652", "1653", "1654", @@ -28228,22 +27950,23 @@ ], "location": { "end": { - "column": 43, - "line": 10 + "column": 25, + "line": 20 }, "start": { "column": 7, - "line": 10 + "line": 20 } } }, { - "id": "595", - "mutatorName": "ConditionalExpression", - "replacement": "true", + "id": "597", + "mutatorName": "EqualityOperator", + "replacement": "role !== undefined", "statusReason": "src/modules/game/dto/base/game-player/transformers/player-role.transformer.ts(23,19): error TS18048: 'role' is possibly 'undefined'.\nsrc/modules/game/dto/base/game-player/transformers/player-role.transformer.ts(24,20): error TS18048: 'role' is possibly 'undefined'.\nsrc/modules/game/dto/base/game-player/transformers/player-role.transformer.ts(25,22): error TS18048: 'role' is possibly 'undefined'.\n", "status": "CompileError", "static": true, + "killedBy": [], "coveredBy": [ "256", "257", @@ -28373,12 +28096,38 @@ } }, { - "id": "602", - "mutatorName": "StringLiteral", - "replacement": "\"\"", - "statusReason": "src/modules/game/dto/base/game-player/transformers/player-role.transformer.ts(25,22): error TS2367: This comparison appears to be unintentional because the types '\"werewolf\" | \"big-bad-wolf\" | \"accursed-wolf-father\" | \"white-werewolf\" | \"villager\" | \"villager-villager\" | \"seer\" | \"cupid\" | \"witch\" | \"hunter\" | \"little-girl\" | \"defender\" | ... 17 more ... | \"devoted-servant\"' and '\"\"' have no overlap.\n", + "id": "598", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/modules/game/dto/base/game-player/transformers/player-role.transformer.ts(21,19): error TS18048: 'role' is possibly 'undefined'.\nsrc/modules/game/dto/base/game-player/transformers/player-role.transformer.ts(22,20): error TS18048: 'role' is possibly 'undefined'.\nsrc/modules/game/dto/base/game-player/transformers/player-role.transformer.ts(23,22): error TS18048: 'role' is possibly 'undefined'.\n", "status": "CompileError", + "static": false, + "killedBy": [], + "coveredBy": [ + "1652" + ], + "location": { + "end": { + "column": 4, + "line": 22 + }, + "start": { + "column": 27, + "line": 20 + } + } + }, + { + "id": "599", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "statusReason": "Error: expect(received).toStrictEqual(expected) // deep equality\n\n- Expected - 1\n+ Received + 1\n\n Object {\n \"current\": \"seer\",\n- \"isRevealed\": false,\n+ \"isRevealed\": true,\n \"name\": \"seer\",\n \"original\": \"seer\",\n }\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/dto/base/game-player/transformers/player-role.transformer.spec.ts:64:69\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-each@29.7.0/node_modules/jest-each/build/bind.js:81:13)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "status": "Killed", + "testsCompleted": 111, "static": true, + "killedBy": [ + "1653" + ], "coveredBy": [ "256", "257", @@ -28501,18 +28250,22 @@ "line": 25 }, "start": { - "column": 36, + "column": 22, "line": 25 } } }, { - "id": "597", - "mutatorName": "EqualityOperator", - "replacement": "role !== undefined", - "statusReason": "src/modules/game/dto/base/game-player/transformers/player-role.transformer.ts(23,19): error TS18048: 'role' is possibly 'undefined'.\nsrc/modules/game/dto/base/game-player/transformers/player-role.transformer.ts(24,20): error TS18048: 'role' is possibly 'undefined'.\nsrc/modules/game/dto/base/game-player/transformers/player-role.transformer.ts(25,22): error TS18048: 'role' is possibly 'undefined'.\n", - "status": "CompileError", + "id": "600", + "mutatorName": "ConditionalExpression", + "replacement": "false", + "statusReason": "Error: expect(received).toStrictEqual(expected) // deep equality\n\n- Expected - 1\n+ Received + 1\n\n Object {\n \"current\": \"villager-villager\",\n- \"isRevealed\": true,\n+ \"isRevealed\": false,\n \"name\": \"villager-villager\",\n \"original\": \"villager-villager\",\n }\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox4853956/tests/unit/specs/modules/game/dto/base/game-player/transformers/player-role.transformer.spec.ts:64:69\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-each@29.7.0/node_modules/jest-each/build/bind.js:81:13)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "status": "Killed", + "testsCompleted": 111, "static": true, + "killedBy": [ + "1655" + ], "coveredBy": [ "256", "257", @@ -28625,140 +28378,31 @@ "1633", "1634", "1635", - "1652", "1653", "1654", "1655" ], "location": { "end": { - "column": 25, - "line": 20 - }, - "start": { - "column": 7, - "line": 20 - } - } - } - ], - "source": "import { has } from \"lodash\";\nimport type { TransformFnParams } from \"class-transformer/types/interfaces\";\n\nimport { ROLES } from \"@/modules/role/constants/role-set.constants\";\nimport type { Role } from \"@/modules/role/types/role.class\";\nimport { getRoleWithName } from \"@/modules/role/helpers/role.helpers\";\nimport type { RoleName } from \"@/modules/role/types/role.types\";\n\nfunction playerRoleTransformer(params: TransformFnParams): unknown {\n if (!has(params.value as object, \"name\")) {\n return params.value;\n }\n const value = params.value as {\n name: RoleName;\n current: RoleName;\n original: RoleName;\n isRevealed: boolean;\n };\n const role = getRoleWithName(ROLES as Role[], value.name);\n if (role === undefined) {\n return value;\n }\n value.current = role.name;\n value.original = role.name;\n value.isRevealed = role.name === \"villager-villager\";\n\n return value;\n}\n\nexport { playerRoleTransformer };" - }, - "src/modules/game/dto/base/game-player/transformers/player-side.transformer.ts": { - "language": "typescript", - "mutants": [ - { - "id": "605", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "statusReason": "TypeError: Cannot set properties of null (setting 'current')\n at playerSideTransformer (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/src/modules/game/dto/base/game-player/transformers/player-side.transformer.ts:86:18)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/dto/base/game-player/transformers/player-side.transformer.spec.ts:65:35\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-each@29.7.0/node_modules/jest-each/build/bind.js:81:13)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", - "status": "Killed", - "testsCompleted": 75, - "static": true, - "killedBy": [ - "1636" - ], - "coveredBy": [ - "256", - "257", - "258", - "272", - "273", - "696", - "701", - "702", - "703", - "704", - "705", - "706", - "707", - "708", - "709", - "710", - "711", - "712", - "713", - "714", - "715", - "716", - "717", - "718", - "719", - "720", - "721", - "722", - "723", - "724", - "725", - "726", - "727", - "728", - "729", - "730", - "731", - "732", - "733", - "734", - "735", - "736", - "737", - "738", - "954", - "955", - "1082", - "1232", - "1233", - "1234", - "1235", - "1404", - "1405", - "1431", - "1432", - "1433", - "1434", - "1435", - "1436", - "1437", - "1438", - "1440", - "1441", - "1442", - "1443", - "1444", - "1445", - "1446", - "1447", - "1503", - "1504", - "1636", - "1637", - "1638", - "1639", - "1640", - "1641", - "1642" - ], - "location": { - "end": { - "column": 78, - "line": 11 + "column": 55, + "line": 25 }, "start": { - "column": 7, - "line": 11 + "column": 22, + "line": 25 } } }, { - "id": "606", - "mutatorName": "LogicalOperator", - "replacement": "!isObject(params.value) && !has(params.obj as object, [\"role\", \"name\"])", - "statusReason": "TypeError: Cannot set properties of null (setting 'current')\n at playerSideTransformer (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox458659/src/modules/game/dto/base/game-player/transformers/player-side.transformer.ts:86:18)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox458659/tests/unit/specs/modules/game/dto/base/game-player/transformers/player-side.transformer.spec.ts:65:35\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-each@29.7.0/node_modules/jest-each/build/bind.js:81:13)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "id": "601", + "mutatorName": "EqualityOperator", + "replacement": "role.name !== \"villager-villager\"", + "statusReason": "Error: expect(received).toStrictEqual(expected) // deep equality\n\n- Expected - 30\n+ Received + 30\n\n@@ -12,98 +12,98 @@\n \"max\": 6,\n \"min\": 1,\n },\n \"eligibleTargets\": Array [\n Object {\n- \"_id\": Any,\n+ \"_id\": \"67014a10e1faf8fa9ae357de\",\n \"attributes\": Array [],\n \"isAlive\": true,\n \"name\": \"Antoine\",\n \"position\": 0,\n \"role\": Object {\n \"current\": \"villager\",\n- \"isRevealed\": false,\n+ \"isRevealed\": true,\n \"original\": \"villager\",\n },\n \"side\": Object {\n \"current\": \"villagers\",\n \"original\": \"villagers\",\n },\n },\n Object {\n- \"_id\": Any,\n+ \"_id\": \"67014a10e1faf8fa9ae357df\",\n \"attributes\": Array [],\n \"isAlive\": true,\n \"name\": \"Mathis\",\n \"position\": 1,\n \"role\": Object {\n \"current\": \"werewolf\",\n- \"isRevealed\": false,\n+ \"isRevealed\": true,\n \"original\": \"werewolf\",\n },\n \"side\": Object {\n \"current\": \"werewolves\",\n \"original\": \"werewolves\",\n },\n },\n Object {\n- \"_id\": Any,\n+ \"_id\": \"67014a10e1faf8fa9ae357e0\",\n \"attributes\": Array [],\n \"isAlive\": true,\n \"name\": \"Virgil\",\n \"position\": 2,\n \"role\": Object {\n \"current\": \"villager-villager\",\n- \"isRevealed\": true,\n+ \"isRevealed\": false,\n \"original\": \"villager-villager\",\n },\n \"side\": Object {\n \"current\": \"villagers\",\n \"original\": \"villagers\",\n },\n },\n Object {\n- \"_id\": Any,\n+ \"_id\": \"67014a10e1faf8fa9ae357e1\",\n \"attributes\": Array [],\n \"isAlive\": true,\n \"name\": \"JB\",\n \"position\": 3,\n \"role\": Object {\n \"current\": \"white-werewolf\",\n- \"isRevealed\": false,\n+ \"isRevealed\": true,\n \"original\": \"white-werewolf\",\n },\n \"side\": Object {\n \"current\": \"werewolves\",\n \"original\": \"werewolves\",\n },\n },\n Object {\n- \"_id\": Any,\n+ \"_id\": \"67014a10e1faf8fa9ae357e2\",\n \"attributes\": Array [],\n \"isAlive\": true,\n \"name\": \"Doudou\",\n \"position\": 4,\n \"role\": Object {\n \"current\": \"cupid\",\n- \"isRevealed\": false,\n+ \"isRevealed\": true,\n \"original\": \"cupid\",\n },\n \"side\": Object {\n \"current\": \"villagers\",\n \"original\": \"villagers\",\n },\n },\n Object {\n- \"_id\": Any,\n+ \"_id\": \"67014a10e1faf8fa9ae357e3\",\n \"attributes\": Array [],\n \"isAlive\": true,\n \"name\": \"Juju\",\n \"position\": 5,\n \"role\": Object {\n \"current\": \"seer\",\n- \"isRevealed\": false,\n+ \"isRevealed\": true,\n \"original\": \"seer\",\n },\n \"side\": Object {\n \"current\": \"villagers\",\n \"original\": \"villagers\",\n@@ -115,98 +115,98 @@\n },\n ],\n \"name\": \"survivors\",\n \"players\": Array [\n Object {\n- \"_id\": Any,\n+ \"_id\": \"67014a10e1faf8fa9ae357de\",\n \"attributes\": Array [],\n \"isAlive\": true,\n \"name\": \"Antoine\",\n \"position\": 0,\n \"role\": Object {\n \"current\": \"villager\",\n- \"isRevealed\": false,\n+ \"isRevealed\": true,\n \"original\": \"villager\",\n },\n \"side\": Object {\n \"current\": \"villagers\",\n \"original\": \"villagers\",\n },\n },\n Object {\n- \"_id\": Any,\n+ \"_id\": \"67014a10e1faf8fa9ae357df\",\n \"attributes\": Array [],\n \"isAlive\": true,\n \"name\": \"Mathis\",\n \"position\": 1,\n \"role\": Object {\n \"current\": \"werewolf\",\n- \"isRevealed\": false,\n+ \"isRevealed\": true,\n \"original\": \"werewolf\",\n },\n \"side\": Object {\n \"current\": \"werewolves\",\n \"original\": \"werewolves\",\n },\n },\n Object {\n- \"_id\": Any,\n+ \"_id\": \"67014a10e1faf8fa9ae357e0\",\n \"attributes\": Array [],\n \"isAlive\": true,\n \"name\": \"Virgil\",\n \"position\": 2,\n \"role\": Object {\n \"current\": \"villager-villager\",\n- \"isRevealed\": true,\n+ \"isRevealed\": false,\n \"original\": \"villager-villager\",\n },\n \"side\": Object {\n \"current\": \"villagers\",\n \"original\": \"villagers\",\n },\n },\n Object {\n- \"_id\": Any,\n+ \"_id\": \"67014a10e1faf8fa9ae357e1\",\n \"attributes\": Array [],\n \"isAlive\": true,\n \"name\": \"JB\",\n \"position\": 3,\n \"role\": Object {\n \"current\": \"white-werewolf\",\n- \"isRevealed\": false,\n+ \"isRevealed\": true,\n \"original\": \"white-werewolf\",\n },\n \"side\": Object {\n \"current\": \"werewolves\",\n \"original\": \"werewolves\",\n },\n },\n Object {\n- \"_id\": Any,\n+ \"_id\": \"67014a10e1faf8fa9ae357e2\",\n \"attributes\": Array [],\n \"isAlive\": true,\n \"name\": \"Doudou\",\n \"position\": 4,\n \"role\": Object {\n \"current\": \"cupid\",\n- \"isRevealed\": false,\n+ \"isRevealed\": true,\n \"original\": \"cupid\",\n },\n \"side\": Object {\n \"current\": \"villagers\",\n \"original\": \"villagers\",\n },\n },\n Object {\n- \"_id\": Any,\n+ \"_id\": \"67014a10e1faf8fa9ae357e3\",\n \"attributes\": Array [],\n \"isAlive\": true,\n \"name\": \"Juju\",\n \"position\": 5,\n \"role\": Object {\n \"current\": \"seer\",\n- \"isRevealed\": false,\n+ \"isRevealed\": true,\n \"original\": \"seer\",\n },\n \"side\": Object {\n \"current\": \"villagers\",\n \"original\": \"villagers\",\n@@ -327,11 +327,11 @@\n \"isAlive\": true,\n \"name\": \"Antoine\",\n \"position\": 0,\n \"role\": Object {\n \"current\": \"villager\",\n- \"isRevealed\": false,\n+ \"isRevealed\": true,\n \"original\": \"villager\",\n },\n \"side\": Object {\n \"current\": \"villagers\",\n \"original\": \"villagers\",\n@@ -343,11 +343,11 @@\n \"isAlive\": true,\n \"name\": \"Mathis\",\n \"position\": 1,\n \"role\": Object {\n \"current\": \"werewolf\",\n- \"isRevealed\": false,\n+ \"isRevealed\": true,\n \"original\": \"werewolf\",\n },\n \"side\": Object {\n \"current\": \"werewolves\",\n \"original\": \"werewolves\",\n@@ -359,11 +359,11 @@\n \"isAlive\": true,\n \"name\": \"Virgil\",\n \"position\": 2,\n \"role\": Object {\n \"current\": \"villager-villager\",\n- \"isRevealed\": true,\n+ \"isRevealed\": false,\n \"original\": \"villager-villager\",\n },\n \"side\": Object {\n \"current\": \"villagers\",\n \"original\": \"villagers\",\n@@ -375,11 +375,11 @@\n \"isAlive\": true,\n \"name\": \"JB\",\n \"position\": 3,\n \"role\": Object {\n \"current\": \"white-werewolf\",\n- \"isRevealed\": false,\n+ \"isRevealed\": true,\n \"original\": \"white-werewolf\",\n },\n \"side\": Object {\n \"current\": \"werewolves\",\n \"original\": \"werewolves\",\n@@ -391,11 +391,11 @@\n \"isAlive\": true,\n \"name\": \"Doudou\",\n \"position\": 4,\n \"role\": Object {\n \"current\": \"cupid\",\n- \"isRevealed\": false,\n+ \"isRevealed\": true,\n \"original\": \"cupid\",\n },\n \"side\": Object {\n \"current\": \"villagers\",\n \"original\": \"villagers\",\n@@ -407,11 +407,11 @@\n \"isAlive\": true,\n \"name\": \"Juju\",\n \"position\": 5,\n \"role\": Object {\n \"current\": \"seer\",\n- \"isRevealed\": false,\n+ \"isRevealed\": true,\n \"original\": \"seer\",\n },\n \"side\": Object {\n \"current\": \"villagers\",\n \"original\": \"villagers\",\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox6871045/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:888:37)\n at processTicksAndRejections (node:internal/process/task_queues:105:5)", "status": "Killed", - "testsCompleted": 77, + "testsCompleted": 111, "static": true, "killedBy": [ - "1636" + "736" ], "coveredBy": [ "256", @@ -28812,6 +28456,8 @@ "1233", "1234", "1235", + "1254", + "1255", "1404", "1405", "1431", @@ -28830,38 +28476,69 @@ "1445", "1446", "1447", + "1499", + "1500", + "1501", + "1502", "1503", "1504", - "1636", - "1637", - "1638", - "1639", - "1640", - "1641", - "1642" + "1525", + "1526", + "1527", + "1528", + "1529", + "1530", + "1531", + "1543", + "1544", + "1545", + "1546", + "1554", + "1555", + "1556", + "1558", + "1565", + "1566", + "1567", + "1569", + "1582", + "1583", + "1584", + "1586", + "1590", + "1591", + "1592", + "1594", + "1616", + "1617", + "1618", + "1632", + "1633", + "1634", + "1635", + "1653", + "1654", + "1655" ], "location": { "end": { - "column": 78, - "line": 11 + "column": 55, + "line": 25 }, "start": { - "column": 7, - "line": 11 + "column": 22, + "line": 25 } } }, { - "id": "607", - "mutatorName": "BooleanLiteral", - "replacement": "isObject(params.value)", - "statusReason": "Error: expect(received).toSatisfyAll(expected)\n\nExpected array to satisfy predicate for all values:\n [Function anonymous]\nReceived:\n [{\"name\": \"1\", \"role\": {\"current\": \"white-werewolf\", \"isRevealed\": false, \"name\": \"white-werewolf\", \"original\": \"white-werewolf\"}, \"side\": {}}, {\"name\": \"2\", \"role\": {\"current\": \"three-brothers\", \"isRevealed\": false, \"name\": \"three-brothers\", \"original\": \"three-brothers\"}, \"side\": {}}, {\"name\": \"3\", \"role\": {\"current\": \"werewolf\", \"isRevealed\": false, \"name\": \"werewolf\", \"original\": \"werewolf\"}, \"side\": {}}, {\"name\": \"4\", \"role\": {\"current\": \"devoted-servant\", \"isRevealed\": false, \"name\": \"devoted-servant\", \"original\": \"devoted-servant\"}, \"side\": {}}, {\"name\": \"5\", \"role\": {\"current\": \"two-sisters\", \"isRevealed\": false, \"name\": \"two-sisters\", \"original\": \"two-sisters\"}, \"side\": {}}, {\"name\": \"6\", \"role\": {\"current\": \"villager\", \"isRevealed\": false, \"name\": \"villager\", \"original\": \"villager\"}, \"side\": {}}, {\"name\": \"7\", \"role\": {\"current\": \"villager\", \"isRevealed\": false, \"name\": \"villager\", \"original\": \"villager\"}, \"side\": {}}, {\"name\": \"8\", \"role\": {\"current\": \"three-brothers\", \"isRevealed\": false, \"name\": \"three-brothers\", \"original\": \"three-brothers\"}, \"side\": {}}, {\"name\": \"9\", \"role\": {\"current\": \"angel\", \"isRevealed\": false, \"name\": \"angel\", \"original\": \"angel\"}, \"side\": {}}, {\"name\": \"10\", \"role\": {\"current\": \"rusty-sword-knight\", \"isRevealed\": false, \"name\": \"rusty-sword-knight\", \"original\": \"rusty-sword-knight\"}, \"side\": {}}, …]\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox1121937/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:259:23)\n at processTicksAndRejections (node:internal/process/task_queues:95:5)", - "status": "Killed", - "testsCompleted": 75, + "id": "602", + "mutatorName": "StringLiteral", + "replacement": "\"\"", + "statusReason": "src/modules/game/dto/base/game-player/transformers/player-role.transformer.ts(25,22): error TS2367: This comparison appears to be unintentional because the types '\"werewolf\" | \"big-bad-wolf\" | \"accursed-wolf-father\" | \"white-werewolf\" | \"villager\" | \"villager-villager\" | \"seer\" | \"cupid\" | \"witch\" | \"hunter\" | \"little-girl\" | \"defender\" | ... 17 more ... | \"devoted-servant\"' and '\"\"' have no overlap.\n", + "status": "CompileError", "static": true, - "killedBy": [ - "696" - ], + "killedBy": [], "coveredBy": [ "256", "257", @@ -28914,6 +28591,8 @@ "1233", "1234", "1235", + "1254", + "1255", "1404", "1405", "1431", @@ -28932,38 +28611,75 @@ "1445", "1446", "1447", + "1499", + "1500", + "1501", + "1502", "1503", "1504", - "1636", - "1637", - "1638", - "1639", - "1640", - "1641", - "1642" + "1525", + "1526", + "1527", + "1528", + "1529", + "1530", + "1531", + "1543", + "1544", + "1545", + "1546", + "1554", + "1555", + "1556", + "1558", + "1565", + "1566", + "1567", + "1569", + "1582", + "1583", + "1584", + "1586", + "1590", + "1591", + "1592", + "1594", + "1616", + "1617", + "1618", + "1632", + "1633", + "1634", + "1635", + "1653", + "1654", + "1655" ], "location": { "end": { - "column": 30, - "line": 11 + "column": 55, + "line": 25 }, "start": { - "column": 7, - "line": 11 + "column": 36, + "line": 25 } } - }, + } + ], + "source": "import { has } from \"lodash\";\nimport type { TransformFnParams } from \"class-transformer/types/interfaces\";\n\nimport { ROLES } from \"@/modules/role/constants/role-set.constants\";\nimport type { Role } from \"@/modules/role/types/role.class\";\nimport { getRoleWithName } from \"@/modules/role/helpers/role.helpers\";\nimport type { RoleName } from \"@/modules/role/types/role.types\";\n\nfunction playerRoleTransformer(params: TransformFnParams): unknown {\n if (!has(params.value as object, \"name\")) {\n return params.value;\n }\n const value = params.value as {\n name: RoleName;\n current: RoleName;\n original: RoleName;\n isRevealed: boolean;\n };\n const role = getRoleWithName(ROLES as Role[], value.name);\n if (role === undefined) {\n return value;\n }\n value.current = role.name;\n value.original = role.name;\n value.isRevealed = role.name === \"villager-villager\";\n\n return value;\n}\n\nexport { playerRoleTransformer };" + }, + "src/modules/game/dto/base/game-player/transformers/player-side.transformer.ts": { + "language": "typescript", + "mutants": [ { - "id": "608", - "mutatorName": "BooleanLiteral", - "replacement": "has(params.obj as object, [\"role\", \"name\"])", - "statusReason": "Error: expect(received).toSatisfyAll(expected)\n\nExpected array to satisfy predicate for all values:\n [Function anonymous]\nReceived:\n [{\"name\": \"1\", \"role\": {\"current\": \"werewolf\", \"isRevealed\": false, \"name\": \"werewolf\", \"original\": \"werewolf\"}, \"side\": {}}, {\"name\": \"2\", \"role\": {\"current\": \"seer\", \"isRevealed\": false, \"name\": \"seer\", \"original\": \"seer\"}, \"side\": {}}, {\"name\": \"3\", \"role\": {\"current\": \"scandalmonger\", \"isRevealed\": false, \"name\": \"scandalmonger\", \"original\": \"scandalmonger\"}, \"side\": {}}, {\"name\": \"4\", \"role\": {\"current\": \"white-werewolf\", \"isRevealed\": false, \"name\": \"white-werewolf\", \"original\": \"white-werewolf\"}, \"side\": {}}, {\"name\": \"5\", \"role\": {\"current\": \"pied-piper\", \"isRevealed\": false, \"name\": \"pied-piper\", \"original\": \"pied-piper\"}, \"side\": {}}, {\"name\": \"6\", \"role\": {\"current\": \"villager\", \"isRevealed\": false, \"name\": \"villager\", \"original\": \"villager\"}, \"side\": {}}, {\"name\": \"7\", \"role\": {\"current\": \"stuttering-judge\", \"isRevealed\": false, \"name\": \"stuttering-judge\", \"original\": \"stuttering-judge\"}, \"side\": {}}, {\"name\": \"8\", \"role\": {\"current\": \"wolf-hound\", \"isRevealed\": false, \"name\": \"wolf-hound\", \"original\": \"wolf-hound\"}, \"side\": {}}, {\"name\": \"9\", \"role\": {\"current\": \"villager\", \"isRevealed\": false, \"name\": \"villager\", \"original\": \"villager\"}, \"side\": {}}, {\"name\": \"10\", \"role\": {\"current\": \"bear-tamer\", \"isRevealed\": false, \"name\": \"bear-tamer\", \"original\": \"bear-tamer\"}, \"side\": {}}, …]\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox6871045/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:263:23)\n at processTicksAndRejections (node:internal/process/task_queues:105:5)", - "status": "Killed", - "testsCompleted": 73, + "id": "603", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/modules/game/dto/base/game-player/transformers/player-side.transformer.ts(10,60): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", + "status": "CompileError", "static": true, - "killedBy": [ - "696" - ], + "killedBy": [], "coveredBy": [ "256", "257", @@ -29036,6 +28752,8 @@ "1447", "1503", "1504", + "1636", + "1637", "1638", "1639", "1640", @@ -29044,26 +28762,23 @@ ], "location": { "end": { - "column": 78, - "line": 11 + "column": 2, + "line": 27 }, "start": { - "column": 34, - "line": 11 + "column": 68, + "line": 10 } } }, { - "id": "609", - "mutatorName": "ArrayDeclaration", - "replacement": "[]", - "statusReason": "Error: expect(received).toStrictEqual(expected) // deep equality\n\n- Expected - 4\n+ Received + 1\n\n- Object {\n- \"current\": \"werewolves\",\n- \"original\": \"werewolves\",\n- }\n+ Object {}\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/dto/base/game-player/transformers/player-side.transformer.spec.ts:65:74\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-each@29.7.0/node_modules/jest-each/build/bind.js:81:13)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", - "status": "Killed", - "testsCompleted": 73, + "id": "604", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "statusReason": "src/modules/game/dto/base/game-player/transformers/player-side.transformer.ts(23,19): error TS18048: 'role' is possibly 'undefined'.\nsrc/modules/game/dto/base/game-player/transformers/player-side.transformer.ts(24,20): error TS18048: 'role' is possibly 'undefined'.\n", + "status": "CompileError", "static": true, - "killedBy": [ - "1641" - ], + "killedBy": [], "coveredBy": [ "256", "257", @@ -29136,6 +28851,8 @@ "1447", "1503", "1504", + "1636", + "1637", "1638", "1639", "1640", @@ -29144,25 +28861,25 @@ ], "location": { "end": { - "column": 77, + "column": 78, "line": 11 }, "start": { - "column": 61, + "column": 7, "line": 11 } } }, { - "id": "610", - "mutatorName": "StringLiteral", - "replacement": "\"\"", - "statusReason": "Error: expect(received).toSatisfyAll(expected)\n\nExpected array to satisfy predicate for all values:\n [Function anonymous]\nReceived:\n [{\"name\": \"1\", \"role\": {\"current\": \"scapegoat\", \"isRevealed\": false, \"name\": \"scapegoat\", \"original\": \"scapegoat\"}, \"side\": {}}, {\"name\": \"2\", \"role\": {\"current\": \"stuttering-judge\", \"isRevealed\": false, \"name\": \"stuttering-judge\", \"original\": \"stuttering-judge\"}, \"side\": {}}, {\"name\": \"3\", \"role\": {\"current\": \"white-werewolf\", \"isRevealed\": false, \"name\": \"white-werewolf\", \"original\": \"white-werewolf\"}, \"side\": {}}, {\"name\": \"4\", \"role\": {\"current\": \"idiot\", \"isRevealed\": false, \"name\": \"idiot\", \"original\": \"idiot\"}, \"side\": {}}, {\"name\": \"5\", \"role\": {\"current\": \"werewolf\", \"isRevealed\": false, \"name\": \"werewolf\", \"original\": \"werewolf\"}, \"side\": {}}, {\"name\": \"6\", \"role\": {\"current\": \"villager\", \"isRevealed\": false, \"name\": \"villager\", \"original\": \"villager\"}, \"side\": {}}, {\"name\": \"7\", \"role\": {\"current\": \"three-brothers\", \"isRevealed\": false, \"name\": \"three-brothers\", \"original\": \"three-brothers\"}, \"side\": {}}, {\"name\": \"8\", \"role\": {\"current\": \"werewolf\", \"isRevealed\": false, \"name\": \"werewolf\", \"original\": \"werewolf\"}, \"side\": {}}, {\"name\": \"9\", \"role\": {\"current\": \"rusty-sword-knight\", \"isRevealed\": false, \"name\": \"rusty-sword-knight\", \"original\": \"rusty-sword-knight\"}, \"side\": {}}, {\"name\": \"10\", \"role\": {\"current\": \"accursed-wolf-father\", \"isRevealed\": false, \"name\": \"accursed-wolf-father\", \"original\": \"accursed-wolf-father\"}, \"side\": {}}, …]\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox1121937/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:259:23)\n at processTicksAndRejections (node:internal/process/task_queues:95:5)", + "id": "605", + "mutatorName": "ConditionalExpression", + "replacement": "false", + "statusReason": "TypeError: Cannot set properties of null (setting 'current')\n at playerSideTransformer (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/src/modules/game/dto/base/game-player/transformers/player-side.transformer.ts:86:18)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/dto/base/game-player/transformers/player-side.transformer.spec.ts:65:35\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-each@29.7.0/node_modules/jest-each/build/bind.js:81:13)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", "status": "Killed", - "testsCompleted": 73, + "testsCompleted": 75, "static": true, "killedBy": [ - "696" + "1636" ], "coveredBy": [ "256", @@ -29236,6 +28953,8 @@ "1447", "1503", "1504", + "1636", + "1637", "1638", "1639", "1640", @@ -29244,25 +28963,25 @@ ], "location": { "end": { - "column": 68, + "column": 78, "line": 11 }, "start": { - "column": 62, + "column": 7, "line": 11 } } }, { - "id": "611", - "mutatorName": "StringLiteral", - "replacement": "\"\"", - "statusReason": "Error: expect(received).toSatisfyAll(expected)\n\nExpected array to satisfy predicate for all values:\n [Function anonymous]\nReceived:\n [{\"name\": \"1\", \"role\": {\"current\": \"defender\", \"isRevealed\": false, \"name\": \"defender\", \"original\": \"defender\"}, \"side\": {}}, {\"name\": \"2\", \"role\": {\"current\": \"devoted-servant\", \"isRevealed\": false, \"name\": \"devoted-servant\", \"original\": \"devoted-servant\"}, \"side\": {}}, {\"name\": \"3\", \"role\": {\"current\": \"fox\", \"isRevealed\": false, \"name\": \"fox\", \"original\": \"fox\"}, \"side\": {}}, {\"name\": \"4\", \"role\": {\"current\": \"villager\", \"isRevealed\": false, \"name\": \"villager\", \"original\": \"villager\"}, \"side\": {}}, {\"name\": \"5\", \"role\": {\"current\": \"villager\", \"isRevealed\": false, \"name\": \"villager\", \"original\": \"villager\"}, \"side\": {}}, {\"name\": \"6\", \"role\": {\"current\": \"pied-piper\", \"isRevealed\": false, \"name\": \"pied-piper\", \"original\": \"pied-piper\"}, \"side\": {}}, {\"name\": \"7\", \"role\": {\"current\": \"villager\", \"isRevealed\": false, \"name\": \"villager\", \"original\": \"villager\"}, \"side\": {}}, {\"name\": \"8\", \"role\": {\"current\": \"villager\", \"isRevealed\": false, \"name\": \"villager\", \"original\": \"villager\"}, \"side\": {}}, {\"name\": \"9\", \"role\": {\"current\": \"two-sisters\", \"isRevealed\": false, \"name\": \"two-sisters\", \"original\": \"two-sisters\"}, \"side\": {}}, {\"name\": \"10\", \"role\": {\"current\": \"prejudiced-manipulator\", \"isRevealed\": false, \"name\": \"prejudiced-manipulator\", \"original\": \"prejudiced-manipulator\"}, \"side\": {}}, …]\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox1121937/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:259:23)\n at processTicksAndRejections (node:internal/process/task_queues:95:5)", + "id": "606", + "mutatorName": "LogicalOperator", + "replacement": "!isObject(params.value) && !has(params.obj as object, [\"role\", \"name\"])", + "statusReason": "TypeError: Cannot set properties of null (setting 'current')\n at playerSideTransformer (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox458659/src/modules/game/dto/base/game-player/transformers/player-side.transformer.ts:86:18)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox458659/tests/unit/specs/modules/game/dto/base/game-player/transformers/player-side.transformer.spec.ts:65:35\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-each@29.7.0/node_modules/jest-each/build/bind.js:81:13)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", "status": "Killed", - "testsCompleted": 73, + "testsCompleted": 77, "static": true, "killedBy": [ - "696" + "1636" ], "coveredBy": [ "256", @@ -29336,6 +29055,8 @@ "1447", "1503", "1504", + "1636", + "1637", "1638", "1639", "1640", @@ -29344,72 +29065,26 @@ ], "location": { "end": { - "column": 76, + "column": 78, "line": 11 }, "start": { - "column": 70, + "column": 7, "line": 11 } } }, { - "id": "612", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "TypeError: Cannot set properties of null (setting 'current')\n at playerSideTransformer (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/src/modules/game/dto/base/game-player/transformers/player-side.transformer.ts:86:18)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/dto/base/game-player/transformers/player-side.transformer.spec.ts:65:35\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-each@29.7.0/node_modules/jest-each/build/bind.js:81:13)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "id": "607", + "mutatorName": "BooleanLiteral", + "replacement": "isObject(params.value)", + "statusReason": "Error: expect(received).toSatisfyAll(expected)\n\nExpected array to satisfy predicate for all values:\n [Function anonymous]\nReceived:\n [{\"name\": \"1\", \"role\": {\"current\": \"white-werewolf\", \"isRevealed\": false, \"name\": \"white-werewolf\", \"original\": \"white-werewolf\"}, \"side\": {}}, {\"name\": \"2\", \"role\": {\"current\": \"three-brothers\", \"isRevealed\": false, \"name\": \"three-brothers\", \"original\": \"three-brothers\"}, \"side\": {}}, {\"name\": \"3\", \"role\": {\"current\": \"werewolf\", \"isRevealed\": false, \"name\": \"werewolf\", \"original\": \"werewolf\"}, \"side\": {}}, {\"name\": \"4\", \"role\": {\"current\": \"devoted-servant\", \"isRevealed\": false, \"name\": \"devoted-servant\", \"original\": \"devoted-servant\"}, \"side\": {}}, {\"name\": \"5\", \"role\": {\"current\": \"two-sisters\", \"isRevealed\": false, \"name\": \"two-sisters\", \"original\": \"two-sisters\"}, \"side\": {}}, {\"name\": \"6\", \"role\": {\"current\": \"villager\", \"isRevealed\": false, \"name\": \"villager\", \"original\": \"villager\"}, \"side\": {}}, {\"name\": \"7\", \"role\": {\"current\": \"villager\", \"isRevealed\": false, \"name\": \"villager\", \"original\": \"villager\"}, \"side\": {}}, {\"name\": \"8\", \"role\": {\"current\": \"three-brothers\", \"isRevealed\": false, \"name\": \"three-brothers\", \"original\": \"three-brothers\"}, \"side\": {}}, {\"name\": \"9\", \"role\": {\"current\": \"angel\", \"isRevealed\": false, \"name\": \"angel\", \"original\": \"angel\"}, \"side\": {}}, {\"name\": \"10\", \"role\": {\"current\": \"rusty-sword-knight\", \"isRevealed\": false, \"name\": \"rusty-sword-knight\", \"original\": \"rusty-sword-knight\"}, \"side\": {}}, …]\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox1121937/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:259:23)\n at processTicksAndRejections (node:internal/process/task_queues:95:5)", "status": "Killed", - "testsCompleted": 4, - "static": false, + "testsCompleted": 75, + "static": true, "killedBy": [ - "1636" + "696" ], - "coveredBy": [ - "1636", - "1637", - "1638", - "1639" - ], - "location": { - "end": { - "column": 4, - "line": 13 - }, - "start": { - "column": 80, - "line": 11 - } - } - }, - { - "id": "616", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/modules/game/dto/base/game-player/transformers/player-side.transformer.ts(21,19): error TS18048: 'role' is possibly 'undefined'.\nsrc/modules/game/dto/base/game-player/transformers/player-side.transformer.ts(22,20): error TS18048: 'role' is possibly 'undefined'.\n", - "status": "CompileError", - "static": false, - "killedBy": [], - "coveredBy": [ - "1640" - ], - "location": { - "end": { - "column": 4, - "line": 22 - }, - "start": { - "column": 27, - "line": 20 - } - } - }, - { - "id": "603", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/modules/game/dto/base/game-player/transformers/player-side.transformer.ts(10,60): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", - "status": "CompileError", - "static": true, "coveredBy": [ "256", "257", @@ -29492,22 +29167,26 @@ ], "location": { "end": { - "column": 2, - "line": 27 + "column": 30, + "line": 11 }, "start": { - "column": 68, - "line": 10 + "column": 7, + "line": 11 } } }, { - "id": "614", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "statusReason": "src/modules/game/dto/base/game-player/transformers/player-side.transformer.ts(23,19): error TS18048: 'role' is possibly 'undefined'.\nsrc/modules/game/dto/base/game-player/transformers/player-side.transformer.ts(24,20): error TS18048: 'role' is possibly 'undefined'.\n", - "status": "CompileError", + "id": "608", + "mutatorName": "BooleanLiteral", + "replacement": "has(params.obj as object, [\"role\", \"name\"])", + "statusReason": "Error: expect(received).toSatisfyAll(expected)\n\nExpected array to satisfy predicate for all values:\n [Function anonymous]\nReceived:\n [{\"name\": \"1\", \"role\": {\"current\": \"werewolf\", \"isRevealed\": false, \"name\": \"werewolf\", \"original\": \"werewolf\"}, \"side\": {}}, {\"name\": \"2\", \"role\": {\"current\": \"seer\", \"isRevealed\": false, \"name\": \"seer\", \"original\": \"seer\"}, \"side\": {}}, {\"name\": \"3\", \"role\": {\"current\": \"scandalmonger\", \"isRevealed\": false, \"name\": \"scandalmonger\", \"original\": \"scandalmonger\"}, \"side\": {}}, {\"name\": \"4\", \"role\": {\"current\": \"white-werewolf\", \"isRevealed\": false, \"name\": \"white-werewolf\", \"original\": \"white-werewolf\"}, \"side\": {}}, {\"name\": \"5\", \"role\": {\"current\": \"pied-piper\", \"isRevealed\": false, \"name\": \"pied-piper\", \"original\": \"pied-piper\"}, \"side\": {}}, {\"name\": \"6\", \"role\": {\"current\": \"villager\", \"isRevealed\": false, \"name\": \"villager\", \"original\": \"villager\"}, \"side\": {}}, {\"name\": \"7\", \"role\": {\"current\": \"stuttering-judge\", \"isRevealed\": false, \"name\": \"stuttering-judge\", \"original\": \"stuttering-judge\"}, \"side\": {}}, {\"name\": \"8\", \"role\": {\"current\": \"wolf-hound\", \"isRevealed\": false, \"name\": \"wolf-hound\", \"original\": \"wolf-hound\"}, \"side\": {}}, {\"name\": \"9\", \"role\": {\"current\": \"villager\", \"isRevealed\": false, \"name\": \"villager\", \"original\": \"villager\"}, \"side\": {}}, {\"name\": \"10\", \"role\": {\"current\": \"bear-tamer\", \"isRevealed\": false, \"name\": \"bear-tamer\", \"original\": \"bear-tamer\"}, \"side\": {}}, …]\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox6871045/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:263:23)\n at processTicksAndRejections (node:internal/process/task_queues:105:5)", + "status": "Killed", + "testsCompleted": 73, "static": true, + "killedBy": [ + "696" + ], "coveredBy": [ "256", "257", @@ -29580,28 +29259,34 @@ "1447", "1503", "1504", + "1638", + "1639", "1640", "1641", "1642" ], "location": { "end": { - "column": 25, - "line": 20 + "column": 78, + "line": 11 }, "start": { - "column": 7, - "line": 20 + "column": 34, + "line": 11 } } }, { - "id": "604", - "mutatorName": "ConditionalExpression", - "replacement": "true", - "statusReason": "src/modules/game/dto/base/game-player/transformers/player-side.transformer.ts(23,19): error TS18048: 'role' is possibly 'undefined'.\nsrc/modules/game/dto/base/game-player/transformers/player-side.transformer.ts(24,20): error TS18048: 'role' is possibly 'undefined'.\n", - "status": "CompileError", + "id": "609", + "mutatorName": "ArrayDeclaration", + "replacement": "[]", + "statusReason": "Error: expect(received).toStrictEqual(expected) // deep equality\n\n- Expected - 4\n+ Received + 1\n\n- Object {\n- \"current\": \"werewolves\",\n- \"original\": \"werewolves\",\n- }\n+ Object {}\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/dto/base/game-player/transformers/player-side.transformer.spec.ts:65:74\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-each@29.7.0/node_modules/jest-each/build/bind.js:81:13)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "status": "Killed", + "testsCompleted": 73, "static": true, + "killedBy": [ + "1641" + ], "coveredBy": [ "256", "257", @@ -29674,8 +29359,6 @@ "1447", "1503", "1504", - "1636", - "1637", "1638", "1639", "1640", @@ -29684,22 +29367,26 @@ ], "location": { "end": { - "column": 78, + "column": 77, "line": 11 }, "start": { - "column": 7, + "column": 61, "line": 11 } } }, { - "id": "613", - "mutatorName": "ConditionalExpression", - "replacement": "true", - "statusReason": "src/modules/game/dto/base/game-player/transformers/player-side.transformer.ts(23,19): error TS18048: 'role' is possibly 'undefined'.\nsrc/modules/game/dto/base/game-player/transformers/player-side.transformer.ts(24,20): error TS18048: 'role' is possibly 'undefined'.\n", - "status": "CompileError", + "id": "610", + "mutatorName": "StringLiteral", + "replacement": "\"\"", + "statusReason": "Error: expect(received).toSatisfyAll(expected)\n\nExpected array to satisfy predicate for all values:\n [Function anonymous]\nReceived:\n [{\"name\": \"1\", \"role\": {\"current\": \"scapegoat\", \"isRevealed\": false, \"name\": \"scapegoat\", \"original\": \"scapegoat\"}, \"side\": {}}, {\"name\": \"2\", \"role\": {\"current\": \"stuttering-judge\", \"isRevealed\": false, \"name\": \"stuttering-judge\", \"original\": \"stuttering-judge\"}, \"side\": {}}, {\"name\": \"3\", \"role\": {\"current\": \"white-werewolf\", \"isRevealed\": false, \"name\": \"white-werewolf\", \"original\": \"white-werewolf\"}, \"side\": {}}, {\"name\": \"4\", \"role\": {\"current\": \"idiot\", \"isRevealed\": false, \"name\": \"idiot\", \"original\": \"idiot\"}, \"side\": {}}, {\"name\": \"5\", \"role\": {\"current\": \"werewolf\", \"isRevealed\": false, \"name\": \"werewolf\", \"original\": \"werewolf\"}, \"side\": {}}, {\"name\": \"6\", \"role\": {\"current\": \"villager\", \"isRevealed\": false, \"name\": \"villager\", \"original\": \"villager\"}, \"side\": {}}, {\"name\": \"7\", \"role\": {\"current\": \"three-brothers\", \"isRevealed\": false, \"name\": \"three-brothers\", \"original\": \"three-brothers\"}, \"side\": {}}, {\"name\": \"8\", \"role\": {\"current\": \"werewolf\", \"isRevealed\": false, \"name\": \"werewolf\", \"original\": \"werewolf\"}, \"side\": {}}, {\"name\": \"9\", \"role\": {\"current\": \"rusty-sword-knight\", \"isRevealed\": false, \"name\": \"rusty-sword-knight\", \"original\": \"rusty-sword-knight\"}, \"side\": {}}, {\"name\": \"10\", \"role\": {\"current\": \"accursed-wolf-father\", \"isRevealed\": false, \"name\": \"accursed-wolf-father\", \"original\": \"accursed-wolf-father\"}, \"side\": {}}, …]\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox1121937/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:259:23)\n at processTicksAndRejections (node:internal/process/task_queues:95:5)", + "status": "Killed", + "testsCompleted": 73, "static": true, + "killedBy": [ + "696" + ], "coveredBy": [ "256", "257", @@ -29772,28 +29459,34 @@ "1447", "1503", "1504", + "1638", + "1639", "1640", "1641", "1642" ], "location": { "end": { - "column": 25, - "line": 20 + "column": 68, + "line": 11 }, "start": { - "column": 7, - "line": 20 + "column": 62, + "line": 11 } } }, { - "id": "615", - "mutatorName": "EqualityOperator", - "replacement": "role !== undefined", - "statusReason": "src/modules/game/dto/base/game-player/transformers/player-side.transformer.ts(23,19): error TS18048: 'role' is possibly 'undefined'.\nsrc/modules/game/dto/base/game-player/transformers/player-side.transformer.ts(24,20): error TS18048: 'role' is possibly 'undefined'.\n", - "status": "CompileError", + "id": "611", + "mutatorName": "StringLiteral", + "replacement": "\"\"", + "statusReason": "Error: expect(received).toSatisfyAll(expected)\n\nExpected array to satisfy predicate for all values:\n [Function anonymous]\nReceived:\n [{\"name\": \"1\", \"role\": {\"current\": \"defender\", \"isRevealed\": false, \"name\": \"defender\", \"original\": \"defender\"}, \"side\": {}}, {\"name\": \"2\", \"role\": {\"current\": \"devoted-servant\", \"isRevealed\": false, \"name\": \"devoted-servant\", \"original\": \"devoted-servant\"}, \"side\": {}}, {\"name\": \"3\", \"role\": {\"current\": \"fox\", \"isRevealed\": false, \"name\": \"fox\", \"original\": \"fox\"}, \"side\": {}}, {\"name\": \"4\", \"role\": {\"current\": \"villager\", \"isRevealed\": false, \"name\": \"villager\", \"original\": \"villager\"}, \"side\": {}}, {\"name\": \"5\", \"role\": {\"current\": \"villager\", \"isRevealed\": false, \"name\": \"villager\", \"original\": \"villager\"}, \"side\": {}}, {\"name\": \"6\", \"role\": {\"current\": \"pied-piper\", \"isRevealed\": false, \"name\": \"pied-piper\", \"original\": \"pied-piper\"}, \"side\": {}}, {\"name\": \"7\", \"role\": {\"current\": \"villager\", \"isRevealed\": false, \"name\": \"villager\", \"original\": \"villager\"}, \"side\": {}}, {\"name\": \"8\", \"role\": {\"current\": \"villager\", \"isRevealed\": false, \"name\": \"villager\", \"original\": \"villager\"}, \"side\": {}}, {\"name\": \"9\", \"role\": {\"current\": \"two-sisters\", \"isRevealed\": false, \"name\": \"two-sisters\", \"original\": \"two-sisters\"}, \"side\": {}}, {\"name\": \"10\", \"role\": {\"current\": \"prejudiced-manipulator\", \"isRevealed\": false, \"name\": \"prejudiced-manipulator\", \"original\": \"prejudiced-manipulator\"}, \"side\": {}}, …]\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox1121937/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:259:23)\n at processTicksAndRejections (node:internal/process/task_queues:95:5)", + "status": "Killed", + "testsCompleted": 73, "static": true, + "killedBy": [ + "696" + ], "coveredBy": [ "256", "257", @@ -29866,44 +29559,66 @@ "1447", "1503", "1504", + "1638", + "1639", "1640", "1641", "1642" ], "location": { "end": { - "column": 25, - "line": 20 + "column": 76, + "line": 11 }, "start": { - "column": 7, - "line": 20 + "column": 70, + "line": 11 } } - } - ], - "source": "import isObject from \"isobject\";\nimport { has } from \"lodash\";\nimport type { TransformFnParams } from \"class-transformer/types/interfaces\";\n\nimport type { Role } from \"@/modules/role/types/role.class\";\nimport { ROLES } from \"@/modules/role/constants/role-set.constants\";\nimport type { RoleName, RoleSide } from \"@/modules/role/types/role.types\";\nimport { getRoleWithName } from \"@/modules/role/helpers/role.helpers\";\n\nfunction playerSideTransformer(params: TransformFnParams): unknown {\n if (!isObject(params.value) || !has(params.obj as object, [\"role\", \"name\"])) {\n return params.value;\n }\n const obj = params.obj as { role: { name: RoleName } };\n const value = params.value as {\n current: RoleSide;\n original: RoleSide;\n };\n const role = getRoleWithName(ROLES as Role[], obj.role.name);\n if (role === undefined) {\n return value;\n }\n value.current = role.side;\n value.original = role.side;\n\n return params.value;\n}\n\nexport { playerSideTransformer };" - }, - "src/modules/game/dto/base/transformers/game-players-position.transformer.ts": { - "language": "typescript", - "mutants": [ + }, { - "id": "618", - "mutatorName": "BooleanLiteral", - "replacement": "Array.isArray(params.value)", - "statusReason": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: 201\nReceived: 500\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox6871045/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:887:35)\n at processTicksAndRejections (node:internal/process/task_queues:105:5)", + "id": "612", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "TypeError: Cannot set properties of null (setting 'current')\n at playerSideTransformer (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/src/modules/game/dto/base/game-player/transformers/player-side.transformer.ts:86:18)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/dto/base/game-player/transformers/player-side.transformer.spec.ts:65:35\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-each@29.7.0/node_modules/jest-each/build/bind.js:81:13)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", "status": "Killed", - "testsCompleted": 75, - "static": true, + "testsCompleted": 4, + "static": false, "killedBy": [ - "736" + "1636" ], + "coveredBy": [ + "1636", + "1637", + "1638", + "1639" + ], + "location": { + "end": { + "column": 4, + "line": 13 + }, + "start": { + "column": 80, + "line": 11 + } + } + }, + { + "id": "613", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "statusReason": "src/modules/game/dto/base/game-player/transformers/player-side.transformer.ts(23,19): error TS18048: 'role' is possibly 'undefined'.\nsrc/modules/game/dto/base/game-player/transformers/player-side.transformer.ts(24,20): error TS18048: 'role' is possibly 'undefined'.\n", + "status": "CompileError", + "static": true, + "killedBy": [], "coveredBy": [ "256", "257", "258", "272", "273", + "696", "701", "702", "703", @@ -29944,14 +29659,11 @@ "738", "954", "955", - "1080", - "1081", "1082", - "1083", - "1084", - "1085", - "1086", - "1087", + "1232", + "1233", + "1234", + "1235", "1404", "1405", "1431", @@ -29972,40 +29684,36 @@ "1447", "1503", "1504", - "1631", - "1632", - "1633", - "1634", - "1635" + "1640", + "1641", + "1642" ], "location": { "end": { - "column": 35, - "line": 5 + "column": 25, + "line": 20 }, "start": { "column": 7, - "line": 5 + "line": 20 } } }, { - "id": "619", + "id": "614", "mutatorName": "ConditionalExpression", - "replacement": "true", - "statusReason": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: 0\nReceived: undefined\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox4853956/tests/unit/specs/modules/game/dto/base/transformers/game-players-position.transformer.spec.ts:57:64)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", - "status": "Killed", - "testsCompleted": 72, + "replacement": "false", + "statusReason": "src/modules/game/dto/base/game-player/transformers/player-side.transformer.ts(23,19): error TS18048: 'role' is possibly 'undefined'.\nsrc/modules/game/dto/base/game-player/transformers/player-side.transformer.ts(24,20): error TS18048: 'role' is possibly 'undefined'.\n", + "status": "CompileError", "static": true, - "killedBy": [ - "1635" - ], + "killedBy": [], "coveredBy": [ "256", "257", "258", "272", "273", + "696", "701", "702", "703", @@ -30046,14 +29754,11 @@ "738", "954", "955", - "1080", - "1081", "1082", - "1083", - "1084", - "1085", - "1086", - "1087", + "1232", + "1233", + "1234", + "1235", "1404", "1405", "1431", @@ -30074,40 +29779,36 @@ "1447", "1503", "1504", - "1631", - "1632", - "1633", - "1634", - "1635" + "1640", + "1641", + "1642" ], "location": { "end": { - "column": 35, - "line": 5 + "column": 25, + "line": 20 }, "start": { "column": 7, - "line": 5 + "line": 20 } } }, { - "id": "620", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "statusReason": "TypeError: Cannot read properties of null (reading 'some')\n at gamePlayersPositionTransformer (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/src/modules/game/dto/base/transformers/game-players-position.transformer.ts:66:144)\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/dto/base/transformers/game-players-position.transformer.spec.ts:11:44)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", - "status": "Killed", - "testsCompleted": 72, + "id": "615", + "mutatorName": "EqualityOperator", + "replacement": "role !== undefined", + "statusReason": "src/modules/game/dto/base/game-player/transformers/player-side.transformer.ts(23,19): error TS18048: 'role' is possibly 'undefined'.\nsrc/modules/game/dto/base/game-player/transformers/player-side.transformer.ts(24,20): error TS18048: 'role' is possibly 'undefined'.\n", + "status": "CompileError", "static": true, - "killedBy": [ - "1631" - ], + "killedBy": [], "coveredBy": [ "256", "257", "258", "272", "273", + "696", "701", "702", "703", @@ -30148,14 +29849,11 @@ "738", "954", "955", - "1080", - "1081", "1082", - "1083", - "1084", - "1085", - "1086", - "1087", + "1232", + "1233", + "1234", + "1235", "1404", "1405", "1431", @@ -30176,59 +29874,57 @@ "1447", "1503", "1504", - "1631", - "1632", - "1633", - "1634", - "1635" + "1640", + "1641", + "1642" ], "location": { "end": { - "column": 35, - "line": 5 + "column": 25, + "line": 20 }, "start": { "column": 7, - "line": 5 + "line": 20 } } }, { - "id": "621", + "id": "616", "mutatorName": "BlockStatement", "replacement": "{}", - "statusReason": "TypeError: Cannot read properties of null (reading 'some')\n at gamePlayersPositionTransformer (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/src/modules/game/dto/base/transformers/game-players-position.transformer.ts:66:144)\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/dto/base/transformers/game-players-position.transformer.spec.ts:11:44)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", - "status": "Killed", - "testsCompleted": 1, + "statusReason": "src/modules/game/dto/base/game-player/transformers/player-side.transformer.ts(21,19): error TS18048: 'role' is possibly 'undefined'.\nsrc/modules/game/dto/base/game-player/transformers/player-side.transformer.ts(22,20): error TS18048: 'role' is possibly 'undefined'.\n", + "status": "CompileError", "static": false, - "killedBy": [ - "1631" - ], + "killedBy": [], "coveredBy": [ - "1631" + "1640" ], "location": { "end": { "column": 4, - "line": 7 + "line": 22 }, "start": { - "column": 37, - "line": 5 + "column": 27, + "line": 20 } } - }, + } + ], + "source": "import isObject from \"isobject\";\nimport { has } from \"lodash\";\nimport type { TransformFnParams } from \"class-transformer/types/interfaces\";\n\nimport type { Role } from \"@/modules/role/types/role.class\";\nimport { ROLES } from \"@/modules/role/constants/role-set.constants\";\nimport type { RoleName, RoleSide } from \"@/modules/role/types/role.types\";\nimport { getRoleWithName } from \"@/modules/role/helpers/role.helpers\";\n\nfunction playerSideTransformer(params: TransformFnParams): unknown {\n if (!isObject(params.value) || !has(params.obj as object, [\"role\", \"name\"])) {\n return params.value;\n }\n const obj = params.obj as { role: { name: RoleName } };\n const value = params.value as {\n current: RoleSide;\n original: RoleSide;\n };\n const role = getRoleWithName(ROLES as Role[], obj.role.name);\n if (role === undefined) {\n return value;\n }\n value.current = role.side;\n value.original = role.side;\n\n return params.value;\n}\n\nexport { playerSideTransformer };" + }, + "src/modules/game/dto/base/transformers/game-players-position.transformer.ts": { + "language": "typescript", + "mutants": [ { - "id": "622", - "mutatorName": "ConditionalExpression", - "replacement": "true", - "statusReason": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: 0\nReceived: undefined\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/dto/base/transformers/game-players-position.transformer.spec.ts:57:64)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", - "status": "Killed", - "testsCompleted": 71, + "id": "617", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/modules/game/dto/base/transformers/game-players-position.transformer.ts(4,69): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", + "status": "CompileError", "static": true, - "killedBy": [ - "1635" - ], + "killedBy": [], "coveredBy": [ "256", "257", @@ -30303,6 +29999,7 @@ "1447", "1503", "1504", + "1631", "1632", "1633", "1634", @@ -30310,25 +30007,25 @@ ], "location": { "end": { - "column": 100, - "line": 10 + "column": 2, + "line": 18 }, "start": { - "column": 7, - "line": 9 + "column": 77, + "line": 4 } } }, { - "id": "623", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "statusReason": "TypeError: Cannot create property 'position' on string 'toto'\n at gamePlayersPositionTransformer (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/src/modules/game/dto/base/transformers/game-players-position.transformer.ts:90:28)\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/dto/base/transformers/game-players-position.transformer.spec.ts:22:44)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "id": "618", + "mutatorName": "BooleanLiteral", + "replacement": "Array.isArray(params.value)", + "statusReason": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: 201\nReceived: 500\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox6871045/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:887:35)\n at processTicksAndRejections (node:internal/process/task_queues:105:5)", "status": "Killed", - "testsCompleted": 71, + "testsCompleted": 75, "static": true, "killedBy": [ - "1632" + "736" ], "coveredBy": [ "256", @@ -30404,6 +30101,7 @@ "1447", "1503", "1504", + "1631", "1632", "1633", "1634", @@ -30411,25 +30109,25 @@ ], "location": { "end": { - "column": 100, - "line": 10 + "column": 35, + "line": 5 }, "start": { "column": 7, - "line": 9 + "line": 5 } } }, { - "id": "624", - "mutatorName": "MethodExpression", - "replacement": "value.every(player => typeof player !== \"object\" || has(player, \"position\") && (player as {\n position: number | undefined;\n}).position !== undefined)", - "statusReason": "Error: expect(received).toContainEqual(expected) // deep equality\n\nExpected value: \"players.0.position must not be less than 0\"\nReceived array: [\"one of the players.role must have at least one role from `werewolves` side\"]\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:817:60\n at processTicksAndRejections (node:internal/process/task_queues:95:5)", + "id": "619", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "statusReason": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: 0\nReceived: undefined\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox4853956/tests/unit/specs/modules/game/dto/base/transformers/game-players-position.transformer.spec.ts:57:64)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", "status": "Killed", - "testsCompleted": 71, + "testsCompleted": 72, "static": true, "killedBy": [ - "710" + "1635" ], "coveredBy": [ "256", @@ -30505,6 +30203,7 @@ "1447", "1503", "1504", + "1631", "1632", "1633", "1634", @@ -30512,25 +30211,25 @@ ], "location": { "end": { - "column": 100, - "line": 10 + "column": 35, + "line": 5 }, "start": { "column": 7, - "line": 9 + "line": 5 } } }, { - "id": "625", - "mutatorName": "ArrowFunction", - "replacement": "() => undefined", - "statusReason": "Error: expect(received).toContainEqual(expected) // deep equality\n\nExpected value: \"players.0.position must not be less than 0\"\nReceived array: [\"one of the players.role must have at least one role from `werewolves` side\"]\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:817:60\n at processTicksAndRejections (node:internal/process/task_queues:95:5)", + "id": "620", + "mutatorName": "ConditionalExpression", + "replacement": "false", + "statusReason": "TypeError: Cannot read properties of null (reading 'some')\n at gamePlayersPositionTransformer (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/src/modules/game/dto/base/transformers/game-players-position.transformer.ts:66:144)\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/dto/base/transformers/game-players-position.transformer.spec.ts:11:44)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", "status": "Killed", - "testsCompleted": 71, + "testsCompleted": 72, "static": true, "killedBy": [ - "710" + "1631" ], "coveredBy": [ "256", @@ -30606,6 +30305,7 @@ "1447", "1503", "1504", + "1631", "1632", "1633", "1634", @@ -30613,119 +30313,50 @@ ], "location": { "end": { - "column": 99, - "line": 10 + "column": 35, + "line": 5 }, "start": { - "column": 18, - "line": 9 + "column": 7, + "line": 5 } } }, { - "id": "626", - "mutatorName": "ConditionalExpression", - "replacement": "true", - "statusReason": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: 201\nReceived: 500\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox6871045/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:887:35)\n at processTicksAndRejections (node:internal/process/task_queues:105:5)", + "id": "621", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "TypeError: Cannot read properties of null (reading 'some')\n at gamePlayersPositionTransformer (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/src/modules/game/dto/base/transformers/game-players-position.transformer.ts:66:144)\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/dto/base/transformers/game-players-position.transformer.spec.ts:11:44)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", "status": "Killed", - "testsCompleted": 67, - "static": true, + "testsCompleted": 1, + "static": false, "killedBy": [ - "736" + "1631" ], "coveredBy": [ - "256", - "257", - "258", - "272", - "273", - "701", - "702", - "703", - "704", - "705", - "706", - "707", - "708", - "709", - "710", - "711", - "712", - "713", - "714", - "715", - "716", - "717", - "718", - "719", - "720", - "721", - "722", - "723", - "724", - "725", - "726", - "727", - "728", - "729", - "730", - "731", - "732", - "733", - "734", - "735", - "736", - "737", - "738", - "954", - "955", - "1082", - "1404", - "1405", - "1431", - "1432", - "1433", - "1434", - "1435", - "1436", - "1437", - "1438", - "1440", - "1441", - "1442", - "1443", - "1444", - "1445", - "1446", - "1447", - "1503", - "1504", - "1632", - "1633", - "1634", - "1635" + "1631" ], "location": { "end": { - "column": 99, - "line": 10 + "column": 4, + "line": 7 }, "start": { - "column": 28, - "line": 9 + "column": 37, + "line": 5 } } }, { - "id": "627", + "id": "622", "mutatorName": "ConditionalExpression", - "replacement": "false", - "statusReason": "TypeError: Cannot create property 'position' on string 'toto'\n at gamePlayersPositionTransformer (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/src/modules/game/dto/base/transformers/game-players-position.transformer.ts:90:28)\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/dto/base/transformers/game-players-position.transformer.spec.ts:22:44)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "replacement": "true", + "statusReason": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: 0\nReceived: undefined\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/dto/base/transformers/game-players-position.transformer.spec.ts:57:64)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", "status": "Killed", - "testsCompleted": 67, + "testsCompleted": 71, "static": true, "killedBy": [ - "1632" + "1635" ], "coveredBy": [ "256", @@ -30773,7 +30404,14 @@ "738", "954", "955", + "1080", + "1081", "1082", + "1083", + "1084", + "1085", + "1086", + "1087", "1404", "1405", "1431", @@ -30801,25 +30439,25 @@ ], "location": { "end": { - "column": 99, + "column": 100, "line": 10 }, "start": { - "column": 28, + "column": 7, "line": 9 } } }, { - "id": "628", - "mutatorName": "LogicalOperator", - "replacement": "typeof player !== \"object\" && has(player, \"position\") && (player as {\n position: number | undefined;\n}).position !== undefined", - "statusReason": "Error: expect(received).toContainEqual(expected) // deep equality\n\nExpected value: \"players.0.position must not be less than 0\"\nReceived array: [\"one of the players.role must have at least one role from `werewolves` side\"]\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:817:60\n at processTicksAndRejections (node:internal/process/task_queues:95:5)", + "id": "623", + "mutatorName": "ConditionalExpression", + "replacement": "false", + "statusReason": "TypeError: Cannot create property 'position' on string 'toto'\n at gamePlayersPositionTransformer (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/src/modules/game/dto/base/transformers/game-players-position.transformer.ts:90:28)\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/dto/base/transformers/game-players-position.transformer.spec.ts:22:44)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", "status": "Killed", - "testsCompleted": 67, + "testsCompleted": 71, "static": true, "killedBy": [ - "710" + "1632" ], "coveredBy": [ "256", @@ -30867,7 +30505,14 @@ "738", "954", "955", + "1080", + "1081", "1082", + "1083", + "1084", + "1085", + "1086", + "1087", "1404", "1405", "1431", @@ -30895,25 +30540,25 @@ ], "location": { "end": { - "column": 99, + "column": 100, "line": 10 }, "start": { - "column": 28, + "column": 7, "line": 9 } } }, { - "id": "629", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "statusReason": "TypeError: Cannot create property 'position' on string 'toto'\n at gamePlayersPositionTransformer (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/src/modules/game/dto/base/transformers/game-players-position.transformer.ts:90:28)\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/dto/base/transformers/game-players-position.transformer.spec.ts:22:44)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "id": "624", + "mutatorName": "MethodExpression", + "replacement": "value.every(player => typeof player !== \"object\" || has(player, \"position\") && (player as {\n position: number | undefined;\n}).position !== undefined)", + "statusReason": "Error: expect(received).toContainEqual(expected) // deep equality\n\nExpected value: \"players.0.position must not be less than 0\"\nReceived array: [\"one of the players.role must have at least one role from `werewolves` side\"]\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:817:60\n at processTicksAndRejections (node:internal/process/task_queues:95:5)", "status": "Killed", - "testsCompleted": 67, + "testsCompleted": 71, "static": true, "killedBy": [ - "1632" + "710" ], "coveredBy": [ "256", @@ -30961,7 +30606,14 @@ "738", "954", "955", + "1080", + "1081", "1082", + "1083", + "1084", + "1085", + "1086", + "1087", "1404", "1405", "1431", @@ -30989,25 +30641,25 @@ ], "location": { "end": { - "column": 54, - "line": 9 + "column": 100, + "line": 10 }, "start": { - "column": 28, + "column": 7, "line": 9 } } }, { - "id": "630", - "mutatorName": "EqualityOperator", - "replacement": "typeof player === \"object\"", - "statusReason": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: 201\nReceived: 500\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox6871045/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:887:35)\n at processTicksAndRejections (node:internal/process/task_queues:105:5)", + "id": "625", + "mutatorName": "ArrowFunction", + "replacement": "() => undefined", + "statusReason": "Error: expect(received).toContainEqual(expected) // deep equality\n\nExpected value: \"players.0.position must not be less than 0\"\nReceived array: [\"one of the players.role must have at least one role from `werewolves` side\"]\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:817:60\n at processTicksAndRejections (node:internal/process/task_queues:95:5)", "status": "Killed", - "testsCompleted": 67, + "testsCompleted": 71, "static": true, "killedBy": [ - "736" + "710" ], "coveredBy": [ "256", @@ -31055,7 +30707,14 @@ "738", "954", "955", + "1080", + "1081", "1082", + "1083", + "1084", + "1085", + "1086", + "1087", "1404", "1405", "1431", @@ -31083,25 +30742,25 @@ ], "location": { "end": { - "column": 54, - "line": 9 + "column": 99, + "line": 10 }, "start": { - "column": 28, + "column": 18, "line": 9 } } }, { - "id": "632", + "id": "626", "mutatorName": "ConditionalExpression", - "replacement": "false", - "statusReason": "Error: expect(received).toContainEqual(expected) // deep equality\n\nExpected value: \"players.0.position must not be less than 0\"\nReceived array: [\"one of the players.role must have at least one role from `werewolves` side\"]\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:817:60\n at processTicksAndRejections (node:internal/process/task_queues:95:5)", + "replacement": "true", + "statusReason": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: 201\nReceived: 500\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox6871045/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:887:35)\n at processTicksAndRejections (node:internal/process/task_queues:105:5)", "status": "Killed", "testsCompleted": 67, "static": true, "killedBy": [ - "710" + "736" ], "coveredBy": [ "256", @@ -31181,21 +30840,21 @@ "line": 10 }, "start": { - "column": 5, - "line": 10 + "column": 28, + "line": 9 } } }, { - "id": "633", - "mutatorName": "LogicalOperator", - "replacement": "has(player, \"position\") || (player as {\n position: number | undefined;\n}).position !== undefined", - "statusReason": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: 0\nReceived: undefined\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/dto/base/transformers/game-players-position.transformer.spec.ts:57:64)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "id": "627", + "mutatorName": "ConditionalExpression", + "replacement": "false", + "statusReason": "TypeError: Cannot create property 'position' on string 'toto'\n at gamePlayersPositionTransformer (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/src/modules/game/dto/base/transformers/game-players-position.transformer.ts:90:28)\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/dto/base/transformers/game-players-position.transformer.spec.ts:22:44)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", "status": "Killed", "testsCompleted": 67, "static": true, "killedBy": [ - "1635" + "1632" ], "coveredBy": [ "256", @@ -31275,15 +30934,15 @@ "line": 10 }, "start": { - "column": 5, - "line": 10 + "column": 28, + "line": 9 } } }, { - "id": "634", - "mutatorName": "StringLiteral", - "replacement": "\"\"", + "id": "628", + "mutatorName": "LogicalOperator", + "replacement": "typeof player !== \"object\" && has(player, \"position\") && (player as {\n position: number | undefined;\n}).position !== undefined", "statusReason": "Error: expect(received).toContainEqual(expected) // deep equality\n\nExpected value: \"players.0.position must not be less than 0\"\nReceived array: [\"one of the players.role must have at least one role from `werewolves` side\"]\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:817:60\n at processTicksAndRejections (node:internal/process/task_queues:95:5)", "status": "Killed", "testsCompleted": 67, @@ -31365,25 +31024,25 @@ ], "location": { "end": { - "column": 27, + "column": 99, "line": 10 }, "start": { - "column": 17, - "line": 10 + "column": 28, + "line": 9 } } }, { - "id": "635", + "id": "629", "mutatorName": "ConditionalExpression", - "replacement": "true", - "statusReason": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: 0\nReceived: undefined\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/dto/base/transformers/game-players-position.transformer.spec.ts:57:64)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "replacement": "false", + "statusReason": "TypeError: Cannot create property 'position' on string 'toto'\n at gamePlayersPositionTransformer (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/src/modules/game/dto/base/transformers/game-players-position.transformer.ts:90:28)\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/dto/base/transformers/game-players-position.transformer.spec.ts:22:44)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", "status": "Killed", "testsCompleted": 67, "static": true, "killedBy": [ - "1635" + "1632" ], "coveredBy": [ "256", @@ -31459,26 +31118,117 @@ ], "location": { "end": { - "column": 99, - "line": 10 + "column": 54, + "line": 9 }, "start": { - "column": 32, - "line": 10 + "column": 28, + "line": 9 } } }, { - "id": "636", + "id": "630", "mutatorName": "EqualityOperator", - "replacement": "(player as {\n position: number | undefined;\n}).position === undefined", - "statusReason": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: 0\nReceived: undefined\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/dto/base/transformers/game-players-position.transformer.spec.ts:57:64)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "replacement": "typeof player === \"object\"", + "statusReason": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: 201\nReceived: 500\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox6871045/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:887:35)\n at processTicksAndRejections (node:internal/process/task_queues:105:5)", "status": "Killed", "testsCompleted": 67, "static": true, "killedBy": [ + "736" + ], + "coveredBy": [ + "256", + "257", + "258", + "272", + "273", + "701", + "702", + "703", + "704", + "705", + "706", + "707", + "708", + "709", + "710", + "711", + "712", + "713", + "714", + "715", + "716", + "717", + "718", + "719", + "720", + "721", + "722", + "723", + "724", + "725", + "726", + "727", + "728", + "729", + "730", + "731", + "732", + "733", + "734", + "735", + "736", + "737", + "738", + "954", + "955", + "1082", + "1404", + "1405", + "1431", + "1432", + "1433", + "1434", + "1435", + "1436", + "1437", + "1438", + "1440", + "1441", + "1442", + "1443", + "1444", + "1445", + "1446", + "1447", + "1503", + "1504", + "1632", + "1633", + "1634", "1635" ], + "location": { + "end": { + "column": 54, + "line": 9 + }, + "start": { + "column": 28, + "line": 9 + } + } + }, + { + "id": "631", + "mutatorName": "StringLiteral", + "replacement": "\"\"", + "statusReason": "src/modules/game/dto/base/transformers/game-players-position.transformer.ts(9,28): error TS2367: This comparison appears to be unintentional because the types '\"string\" | \"number\" | \"bigint\" | \"boolean\" | \"symbol\" | \"undefined\" | \"object\" | \"function\"' and '\"\"' have no overlap.\n", + "status": "CompileError", + "static": true, + "killedBy": [], "coveredBy": [ "256", "257", @@ -31553,27 +31303,32 @@ ], "location": { "end": { - "column": 99, - "line": 10 + "column": 54, + "line": 9 }, "start": { - "column": 32, - "line": 10 + "column": 46, + "line": 9 } } }, { - "id": "637", - "mutatorName": "BlockStatement", - "replacement": "{}", + "id": "632", + "mutatorName": "ConditionalExpression", + "replacement": "false", "statusReason": "Error: expect(received).toContainEqual(expected) // deep equality\n\nExpected value: \"players.0.position must not be less than 0\"\nReceived array: [\"one of the players.role must have at least one role from `werewolves` side\"]\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:817:60\n at processTicksAndRejections (node:internal/process/task_queues:95:5)", "status": "Killed", - "testsCompleted": 57, + "testsCompleted": 67, "static": true, "killedBy": [ "710" ], "coveredBy": [ + "256", + "257", + "258", + "272", + "273", "701", "702", "703", @@ -31612,7 +31367,11 @@ "736", "737", "738", + "954", + "955", "1082", + "1404", + "1405", "1431", "1432", "1433", @@ -31629,31 +31388,34 @@ "1445", "1446", "1447", + "1503", + "1504", "1632", "1633", - "1634" + "1634", + "1635" ], "location": { "end": { - "column": 4, - "line": 12 + "column": 99, + "line": 10 }, "start": { - "column": 102, + "column": 5, "line": 10 } } }, { - "id": "638", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "statusReason": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: 201\nReceived: 500\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox6871045/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:887:35)\n at processTicksAndRejections (node:internal/process/task_queues:105:5)", + "id": "633", + "mutatorName": "LogicalOperator", + "replacement": "has(player, \"position\") || (player as {\n position: number | undefined;\n}).position !== undefined", + "statusReason": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: 0\nReceived: undefined\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/dto/base/transformers/game-players-position.transformer.spec.ts:57:64)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", "status": "Killed", - "testsCompleted": 20, + "testsCompleted": 67, "static": true, "killedBy": [ - "736" + "1635" ], "coveredBy": [ "256", @@ -31661,43 +31423,94 @@ "258", "272", "273", + "701", + "702", + "703", + "704", + "705", + "706", + "707", + "708", + "709", + "710", + "711", + "712", + "713", + "714", + "715", + "716", + "717", + "718", + "719", + "720", + "721", + "722", + "723", + "724", + "725", + "726", + "727", + "728", + "729", + "730", + "731", + "732", + "733", + "734", + "735", "736", "737", "738", "954", "955", - "1080", - "1081", "1082", - "1083", - "1084", - "1085", - "1086", - "1087", "1404", "1405", + "1431", + "1432", + "1433", + "1434", + "1435", + "1436", + "1437", + "1438", + "1440", + "1441", + "1442", + "1443", + "1444", + "1445", + "1446", + "1447", "1503", "1504", + "1632", + "1633", + "1634", "1635" ], "location": { "end": { - "column": 35, - "line": 14 + "column": 99, + "line": 10 }, "start": { - "column": 19, - "line": 14 + "column": 5, + "line": 10 } } }, { - "id": "617", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/modules/game/dto/base/transformers/game-players-position.transformer.ts(4,69): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", - "status": "CompileError", + "id": "634", + "mutatorName": "StringLiteral", + "replacement": "\"\"", + "statusReason": "Error: expect(received).toContainEqual(expected) // deep equality\n\nExpected value: \"players.0.position must not be less than 0\"\nReceived array: [\"one of the players.role must have at least one role from `werewolves` side\"]\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:817:60\n at processTicksAndRejections (node:internal/process/task_queues:95:5)", + "status": "Killed", + "testsCompleted": 67, "static": true, + "killedBy": [ + "710" + ], "coveredBy": [ "256", "257", @@ -31744,14 +31557,7 @@ "738", "954", "955", - "1080", - "1081", "1082", - "1083", - "1084", - "1085", - "1086", - "1087", "1404", "1405", "1431", @@ -31772,7 +31578,6 @@ "1447", "1503", "1504", - "1631", "1632", "1633", "1634", @@ -31780,22 +31585,26 @@ ], "location": { "end": { - "column": 2, - "line": 18 + "column": 27, + "line": 10 }, "start": { - "column": 77, - "line": 4 + "column": 17, + "line": 10 } } }, { - "id": "631", - "mutatorName": "StringLiteral", - "replacement": "\"\"", - "statusReason": "src/modules/game/dto/base/transformers/game-players-position.transformer.ts(9,28): error TS2367: This comparison appears to be unintentional because the types '\"string\" | \"number\" | \"bigint\" | \"boolean\" | \"symbol\" | \"undefined\" | \"object\" | \"function\"' and '\"\"' have no overlap.\n", - "status": "CompileError", + "id": "635", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "statusReason": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: 0\nReceived: undefined\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/dto/base/transformers/game-players-position.transformer.spec.ts:57:64)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "status": "Killed", + "testsCompleted": 67, "static": true, + "killedBy": [ + "1635" + ], "coveredBy": [ "256", "257", @@ -31870,22 +31679,202 @@ ], "location": { "end": { - "column": 54, - "line": 9 + "column": 99, + "line": 10 }, "start": { - "column": 46, - "line": 9 + "column": 32, + "line": 10 } } }, { - "id": "640", + "id": "636", "mutatorName": "EqualityOperator", - "replacement": "i >= value.length", - "statusReason": "Cannot set properties of undefined (setting 'position') TypeError: Cannot set properties of undefined (setting 'position')\n at Object.gamePlayersPositionTransformer [as transformFn] (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/src/modules/game/dto/base/transformers/game-players-position.transformer.ts:90:28)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:412:24\n at Array.forEach ()\n at TransformOperationExecutor.applyCustomTransformations (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:411:15)\n at TransformOperationExecutor.transform (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:334:33)\n at ClassTransformer.plainToInstance (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/ClassTransformer.ts:77:21)\n at plainToInstance (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/index.ts:84:27)\n at createFakeCreateGameDto (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/factories/game/dto/create-game/create-game.dto.factory.ts:13:25)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/unit/specs/modules/game/providers/services/game-play/game-play.service.spec.ts:1279:38\n at _dispatchDescribe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:91:26)\n at describe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:55:5)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/unit/specs/modules/game/providers/services/game-play/game-play.service.spec.ts:1240:3\n at _dispatchDescribe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:91:26)\n at describe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:55:5)\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/unit/specs/modules/game/providers/services/game-play/game-play.service.spec.ts:36:1)\n at Runtime._execModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:1439:24)\n at Runtime._loadModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:1022:12)\n at Runtime.requireModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:882:12)\n at jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:77:13)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", - "status": "RuntimeError", + "replacement": "(player as {\n position: number | undefined;\n}).position === undefined", + "statusReason": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: 0\nReceived: undefined\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/dto/base/transformers/game-players-position.transformer.spec.ts:57:64)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "status": "Killed", + "testsCompleted": 67, "static": true, + "killedBy": [ + "1635" + ], + "coveredBy": [ + "256", + "257", + "258", + "272", + "273", + "701", + "702", + "703", + "704", + "705", + "706", + "707", + "708", + "709", + "710", + "711", + "712", + "713", + "714", + "715", + "716", + "717", + "718", + "719", + "720", + "721", + "722", + "723", + "724", + "725", + "726", + "727", + "728", + "729", + "730", + "731", + "732", + "733", + "734", + "735", + "736", + "737", + "738", + "954", + "955", + "1082", + "1404", + "1405", + "1431", + "1432", + "1433", + "1434", + "1435", + "1436", + "1437", + "1438", + "1440", + "1441", + "1442", + "1443", + "1444", + "1445", + "1446", + "1447", + "1503", + "1504", + "1632", + "1633", + "1634", + "1635" + ], + "location": { + "end": { + "column": 99, + "line": 10 + }, + "start": { + "column": 32, + "line": 10 + } + } + }, + { + "id": "637", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "Error: expect(received).toContainEqual(expected) // deep equality\n\nExpected value: \"players.0.position must not be less than 0\"\nReceived array: [\"one of the players.role must have at least one role from `werewolves` side\"]\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:817:60\n at processTicksAndRejections (node:internal/process/task_queues:95:5)", + "status": "Killed", + "testsCompleted": 57, + "static": true, + "killedBy": [ + "710" + ], + "coveredBy": [ + "701", + "702", + "703", + "704", + "705", + "706", + "707", + "708", + "709", + "710", + "711", + "712", + "713", + "714", + "715", + "716", + "717", + "718", + "719", + "720", + "721", + "722", + "723", + "724", + "725", + "726", + "727", + "728", + "729", + "730", + "731", + "732", + "733", + "734", + "735", + "736", + "737", + "738", + "1082", + "1431", + "1432", + "1433", + "1434", + "1435", + "1436", + "1437", + "1438", + "1440", + "1441", + "1442", + "1443", + "1444", + "1445", + "1446", + "1447", + "1632", + "1633", + "1634" + ], + "location": { + "end": { + "column": 4, + "line": 12 + }, + "start": { + "column": 102, + "line": 10 + } + } + }, + { + "id": "638", + "mutatorName": "ConditionalExpression", + "replacement": "false", + "statusReason": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: 201\nReceived: 500\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox6871045/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:887:35)\n at processTicksAndRejections (node:internal/process/task_queues:105:5)", + "status": "Killed", + "testsCompleted": 20, + "static": true, + "killedBy": [ + "736" + ], "coveredBy": [ "256", "257", @@ -31929,6 +31918,51 @@ "statusReason": "Cannot set properties of undefined (setting 'position') TypeError: Cannot set properties of undefined (setting 'position')\n at Object.gamePlayersPositionTransformer [as transformFn] (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/src/modules/game/dto/base/transformers/game-players-position.transformer.ts:90:28)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:412:24\n at Array.forEach ()\n at TransformOperationExecutor.applyCustomTransformations (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:411:15)\n at TransformOperationExecutor.transform (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:334:33)\n at ClassTransformer.plainToInstance (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/ClassTransformer.ts:77:21)\n at plainToInstance (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/index.ts:84:27)\n at createFakeCreateGameDto (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/factories/game/dto/create-game/create-game.dto.factory.ts:13:25)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:321:41\n at _dispatchDescribe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:91:26)\n at describe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:55:5)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:308:3\n at _dispatchDescribe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:91:26)\n at describe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:55:5)\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:58:1)\n at Runtime._execModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:1439:24)\n at Runtime._loadModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:1022:12)\n at Runtime.requireModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:882:12)\n at jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:77:13)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34), Cannot set properties of undefined (setting 'position') TypeError: Cannot set properties of undefined (setting 'position')\n at Object.gamePlayersPositionTransformer [as transformFn] (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/src/modules/game/dto/base/transformers/game-players-position.transformer.ts:90:28)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:412:24\n at Array.forEach ()\n at TransformOperationExecutor.applyCustomTransformations (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:411:15)\n at TransformOperationExecutor.transform (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:334:33)\n at ClassTransformer.plainToInstance (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/ClassTransformer.ts:77:21)\n at plainToInstance (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/index.ts:84:27)\n at createFakeCreateGameDto (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/factories/game/dto/create-game/create-game.dto.factory.ts:13:25)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/unit/specs/modules/game/providers/services/game-play/game-play.service.spec.ts:677:38\n at _dispatchDescribe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:91:26)\n at describe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:55:5)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/unit/specs/modules/game/providers/services/game-play/game-play.service.spec.ts:664:3\n at _dispatchDescribe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:91:26)\n at describe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:55:5)\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/unit/specs/modules/game/providers/services/game-play/game-play.service.spec.ts:36:1)\n at Runtime._execModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:1439:24)\n at Runtime._loadModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:1022:12)\n at Runtime.requireModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:882:12)\n at jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:77:13)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34), Cannot set properties of undefined (setting 'position') TypeError: Cannot set properties of undefined (setting 'position')\n at Object.gamePlayersPositionTransformer [as transformFn] (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/src/modules/game/dto/base/transformers/game-players-position.transformer.ts:90:28)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:412:24\n at Array.forEach ()\n at TransformOperationExecutor.applyCustomTransformations (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:411:15)\n at TransformOperationExecutor.transform (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:334:33)\n at ClassTransformer.plainToInstance (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/ClassTransformer.ts:77:21)\n at plainToInstance (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/index.ts:84:27)\n at createFakeCreateGameDto (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/factories/game/dto/create-game/create-game.dto.factory.ts:13:25)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/unit/specs/modules/game/helpers/game.helpers.spec.ts:41:41\n at _dispatchDescribe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:91:26)\n at describe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:55:5)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/unit/specs/modules/game/helpers/game.helpers.spec.ts:32:3\n at _dispatchDescribe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:91:26)\n at describe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:55:5)\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/unit/specs/modules/game/helpers/game.helpers.spec.ts:31:1)\n at Runtime._execModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:1439:24)\n at Runtime._loadModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:1022:12)\n at Runtime.requireModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:882:12)\n at jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:77:13)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34), Cannot set properties of undefined (setting 'position') TypeError: Cannot set properties of undefined (setting 'position')\n at Object.gamePlayersPositionTransformer [as transformFn] (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/src/modules/game/dto/base/transformers/game-players-position.transformer.ts:90:28)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:412:24\n at Array.forEach ()\n at TransformOperationExecutor.applyCustomTransformations (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:411:15)\n at TransformOperationExecutor.transform (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:334:33)\n at ClassTransformer.plainToInstance (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/ClassTransformer.ts:77:21)\n at plainToInstance (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/index.ts:84:27)\n at createFakeCreateGameDto (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/factories/game/dto/create-game/create-game.dto.factory.ts:13:25)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/unit/specs/modules/game/dto/base/decorators/additional-cards/additional-cards-for-thief-size.decorator.spec.ts:21:47\n at _dispatchDescribe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:91:26)\n at describe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:55:5)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/unit/specs/modules/game/dto/base/decorators/additional-cards/additional-cards-for-thief-size.decorator.spec.ts:12:3\n at _dispatchDescribe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:91:26)\n at describe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:55:5)\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/unit/specs/modules/game/dto/base/decorators/additional-cards/additional-cards-for-thief-size.decorator.spec.ts:11:1)\n at Runtime._execModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:1439:24)\n at Runtime._loadModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:1022:12)\n at Runtime.requireModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:882:12)\n at jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:77:13)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34), Cannot set properties of undefined (setting 'position') TypeError: Cannot set properties of undefined (setting 'position')\n at Object.gamePlayersPositionTransformer [as transformFn] (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/src/modules/game/dto/base/transformers/game-players-position.transformer.ts:90:28)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:412:24\n at Array.forEach ()\n at TransformOperationExecutor.applyCustomTransformations (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:411:15)\n at TransformOperationExecutor.transform (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:334:33)\n at ClassTransformer.plainToInstance (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/ClassTransformer.ts:77:21)\n at plainToInstance (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/index.ts:84:27)\n at createFakeCreateGameDto (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/factories/game/dto/create-game/create-game.dto.factory.ts:13:25)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/unit/specs/modules/game/dto/base/decorators/additional-cards/additional-cards-for-actor-size.decorator.spec.ts:21:47\n at _dispatchDescribe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:91:26)\n at describe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:55:5)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/unit/specs/modules/game/dto/base/decorators/additional-cards/additional-cards-for-actor-size.decorator.spec.ts:12:3\n at _dispatchDescribe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:91:26)\n at describe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:55:5)\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/unit/specs/modules/game/dto/base/decorators/additional-cards/additional-cards-for-actor-size.decorator.spec.ts:11:1)\n at Runtime._execModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:1439:24)\n at Runtime._loadModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:1022:12)\n at Runtime.requireModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:882:12)\n at jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:77:13)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34), Cannot set properties of undefined (setting 'position') TypeError: Cannot set properties of undefined (setting 'position')\n at Object.gamePlayersPositionTransformer [as transformFn] (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/src/modules/game/dto/base/transformers/game-players-position.transformer.ts:90:28)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:412:24\n at Array.forEach ()\n at TransformOperationExecutor.applyCustomTransformations (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:411:15)\n at TransformOperationExecutor.transform (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:334:33)\n at ClassTransformer.plainToInstance (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/ClassTransformer.ts:77:21)\n at plainToInstance (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/index.ts:84:27)\n at createFakeCreateGameDto (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/factories/game/dto/create-game/create-game.dto.factory.ts:13:25)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/unit/specs/modules/game/dto/base/decorators/additional-cards/additional-cards-roles-max-in-game.decorator.spec.ts:24:42\n at _dispatchDescribe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:91:26)\n at describe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:55:5)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/unit/specs/modules/game/dto/base/decorators/additional-cards/additional-cards-roles-max-in-game.decorator.spec.ts:12:3\n at _dispatchDescribe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:91:26)\n at describe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:55:5)\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/unit/specs/modules/game/dto/base/decorators/additional-cards/additional-cards-roles-max-in-game.decorator.spec.ts:11:1)\n at Runtime._execModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:1439:24)\n at Runtime._loadModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:1022:12)\n at Runtime.requireModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:882:12)\n at jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:77:13)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34), Cannot set properties of undefined (setting 'position') TypeError: Cannot set properties of undefined (setting 'position')\n at Object.gamePlayersPositionTransformer [as transformFn] (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/src/modules/game/dto/base/transformers/game-players-position.transformer.ts:90:28)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:412:24\n at Array.forEach ()\n at TransformOperationExecutor.applyCustomTransformations (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:411:15)\n at TransformOperationExecutor.transform (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:334:33)\n at ClassTransformer.plainToInstance (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/ClassTransformer.ts:77:21)\n at plainToInstance (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/index.ts:84:27)\n at createFakeCreateGameDto (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/factories/game/dto/create-game/create-game.dto.factory.ts:13:25)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/unit/specs/modules/game/dto/base/decorators/additional-cards/additional-cards-presence.decorator.spec.ts:29:42\n at _dispatchDescribe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:91:26)\n at describe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:55:5)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/unit/specs/modules/game/dto/base/decorators/additional-cards/additional-cards-presence.decorator.spec.ts:11:3\n at _dispatchDescribe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:91:26)\n at describe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:55:5)\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/unit/specs/modules/game/dto/base/decorators/additional-cards/additional-cards-presence.decorator.spec.ts:10:1)\n at Runtime._execModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:1439:24)\n at Runtime._loadModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:1022:12)\n at Runtime.requireModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:882:12)\n at jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:77:13)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", "status": "RuntimeError", "static": true, + "killedBy": [], + "coveredBy": [ + "256", + "257", + "258", + "272", + "273", + "736", + "737", + "738", + "954", + "955", + "1080", + "1081", + "1082", + "1083", + "1084", + "1085", + "1086", + "1087", + "1404", + "1405", + "1503", + "1504", + "1635" + ], + "location": { + "end": { + "column": 35, + "line": 14 + }, + "start": { + "column": 19, + "line": 14 + } + } + }, + { + "id": "640", + "mutatorName": "EqualityOperator", + "replacement": "i >= value.length", + "statusReason": "Cannot set properties of undefined (setting 'position') TypeError: Cannot set properties of undefined (setting 'position')\n at Object.gamePlayersPositionTransformer [as transformFn] (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/src/modules/game/dto/base/transformers/game-players-position.transformer.ts:90:28)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:412:24\n at Array.forEach ()\n at TransformOperationExecutor.applyCustomTransformations (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:411:15)\n at TransformOperationExecutor.transform (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:334:33)\n at ClassTransformer.plainToInstance (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/ClassTransformer.ts:77:21)\n at plainToInstance (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/index.ts:84:27)\n at createFakeCreateGameDto (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/factories/game/dto/create-game/create-game.dto.factory.ts:13:25)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/unit/specs/modules/game/providers/services/game-play/game-play.service.spec.ts:1279:38\n at _dispatchDescribe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:91:26)\n at describe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:55:5)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/unit/specs/modules/game/providers/services/game-play/game-play.service.spec.ts:1240:3\n at _dispatchDescribe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:91:26)\n at describe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:55:5)\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/unit/specs/modules/game/providers/services/game-play/game-play.service.spec.ts:36:1)\n at Runtime._execModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:1439:24)\n at Runtime._loadModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:1022:12)\n at Runtime.requireModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:882:12)\n at jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:77:13)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "status": "RuntimeError", + "static": true, + "killedBy": [], "coveredBy": [ "256", "257", @@ -31972,6 +32006,7 @@ "statusReason": "Cannot set properties of undefined (setting 'position') TypeError: Cannot set properties of undefined (setting 'position')\n at Object.gamePlayersPositionTransformer [as transformFn] (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/src/modules/game/dto/base/transformers/game-players-position.transformer.ts:90:28)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:412:24\n at Array.forEach ()\n at TransformOperationExecutor.applyCustomTransformations (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:411:15)\n at TransformOperationExecutor.transform (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:334:33)\n at ClassTransformer.plainToInstance (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/ClassTransformer.ts:77:21)\n at plainToInstance (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/index.ts:84:27)\n at createFakeCreateGameDto (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/factories/game/dto/create-game/create-game.dto.factory.ts:13:25)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:321:41\n at _dispatchDescribe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:91:26)\n at describe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:55:5)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:308:3\n at _dispatchDescribe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:91:26)\n at describe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:55:5)\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:58:1)\n at Runtime._execModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:1439:24)\n at Runtime._loadModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:1022:12)\n at Runtime.requireModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:882:12)\n at jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:77:13)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34), Cannot set properties of undefined (setting 'position') TypeError: Cannot set properties of undefined (setting 'position')\n at Object.gamePlayersPositionTransformer [as transformFn] (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/src/modules/game/dto/base/transformers/game-players-position.transformer.ts:90:28)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:412:24\n at Array.forEach ()\n at TransformOperationExecutor.applyCustomTransformations (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:411:15)\n at TransformOperationExecutor.transform (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:334:33)\n at ClassTransformer.plainToInstance (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/ClassTransformer.ts:77:21)\n at plainToInstance (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/index.ts:84:27)\n at createFakeCreateGameDto (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/factories/game/dto/create-game/create-game.dto.factory.ts:13:25)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/unit/specs/modules/game/helpers/game.helpers.spec.ts:41:41\n at _dispatchDescribe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:91:26)\n at describe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:55:5)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/unit/specs/modules/game/helpers/game.helpers.spec.ts:32:3\n at _dispatchDescribe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:91:26)\n at describe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:55:5)\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/unit/specs/modules/game/helpers/game.helpers.spec.ts:31:1)\n at Runtime._execModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:1439:24)\n at Runtime._loadModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:1022:12)\n at Runtime.requireModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:882:12)\n at jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:77:13)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34), Cannot set properties of undefined (setting 'position') TypeError: Cannot set properties of undefined (setting 'position')\n at Object.gamePlayersPositionTransformer [as transformFn] (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/src/modules/game/dto/base/transformers/game-players-position.transformer.ts:90:28)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:412:24\n at Array.forEach ()\n at TransformOperationExecutor.applyCustomTransformations (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:411:15)\n at TransformOperationExecutor.transform (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:334:33)\n at ClassTransformer.plainToInstance (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/ClassTransformer.ts:77:21)\n at plainToInstance (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/index.ts:84:27)\n at createFakeCreateGameDto (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/factories/game/dto/create-game/create-game.dto.factory.ts:13:25)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/unit/specs/modules/game/dto/base/decorators/additional-cards/additional-cards-presence.decorator.spec.ts:29:42\n at _dispatchDescribe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:91:26)\n at describe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:55:5)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/unit/specs/modules/game/dto/base/decorators/additional-cards/additional-cards-presence.decorator.spec.ts:11:3\n at _dispatchDescribe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:91:26)\n at describe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:55:5)\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/unit/specs/modules/game/dto/base/decorators/additional-cards/additional-cards-presence.decorator.spec.ts:10:1)\n at Runtime._execModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:1439:24)\n at Runtime._loadModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:1022:12)\n at Runtime.requireModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:882:12)\n at jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:77:13)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34), Cannot set properties of undefined (setting 'position') TypeError: Cannot set properties of undefined (setting 'position')\n at Object.gamePlayersPositionTransformer [as transformFn] (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/src/modules/game/dto/base/transformers/game-players-position.transformer.ts:90:28)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:412:24\n at Array.forEach ()\n at TransformOperationExecutor.applyCustomTransformations (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:411:15)\n at TransformOperationExecutor.transform (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:334:33)\n at ClassTransformer.plainToInstance (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/ClassTransformer.ts:77:21)\n at plainToInstance (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/index.ts:84:27)\n at createFakeCreateGameDto (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/factories/game/dto/create-game/create-game.dto.factory.ts:13:25)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/unit/specs/modules/game/dto/base/decorators/additional-cards/additional-cards-for-thief-size.decorator.spec.ts:21:47\n at _dispatchDescribe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:91:26)\n at describe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:55:5)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/unit/specs/modules/game/dto/base/decorators/additional-cards/additional-cards-for-thief-size.decorator.spec.ts:12:3\n at _dispatchDescribe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:91:26)\n at describe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:55:5)\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/unit/specs/modules/game/dto/base/decorators/additional-cards/additional-cards-for-thief-size.decorator.spec.ts:11:1)\n at Runtime._execModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:1439:24)\n at Runtime._loadModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:1022:12)\n at Runtime.requireModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:882:12)\n at jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:77:13)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34), Cannot set properties of undefined (setting 'position') TypeError: Cannot set properties of undefined (setting 'position')\n at Object.gamePlayersPositionTransformer [as transformFn] (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/src/modules/game/dto/base/transformers/game-players-position.transformer.ts:90:28)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:412:24\n at Array.forEach ()\n at TransformOperationExecutor.applyCustomTransformations (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:411:15)\n at TransformOperationExecutor.transform (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:334:33)\n at ClassTransformer.plainToInstance (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/ClassTransformer.ts:77:21)\n at plainToInstance (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/index.ts:84:27)\n at createFakeCreateGameDto (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/factories/game/dto/create-game/create-game.dto.factory.ts:13:25)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/unit/specs/modules/game/dto/base/decorators/additional-cards/additional-cards-for-actor-size.decorator.spec.ts:21:47\n at _dispatchDescribe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:91:26)\n at describe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:55:5)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/unit/specs/modules/game/dto/base/decorators/additional-cards/additional-cards-for-actor-size.decorator.spec.ts:12:3\n at _dispatchDescribe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:91:26)\n at describe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:55:5)\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/unit/specs/modules/game/dto/base/decorators/additional-cards/additional-cards-for-actor-size.decorator.spec.ts:11:1)\n at Runtime._execModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:1439:24)\n at Runtime._loadModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:1022:12)\n at Runtime.requireModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:882:12)\n at jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:77:13)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34), Cannot set properties of undefined (setting 'position') TypeError: Cannot set properties of undefined (setting 'position')\n at Object.gamePlayersPositionTransformer [as transformFn] (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/src/modules/game/dto/base/transformers/game-players-position.transformer.ts:90:28)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:412:24\n at Array.forEach ()\n at TransformOperationExecutor.applyCustomTransformations (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:411:15)\n at TransformOperationExecutor.transform (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:334:33)\n at ClassTransformer.plainToInstance (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/ClassTransformer.ts:77:21)\n at plainToInstance (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/index.ts:84:27)\n at createFakeCreateGameDto (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/factories/game/dto/create-game/create-game.dto.factory.ts:13:25)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/unit/specs/modules/game/dto/base/decorators/additional-cards/additional-cards-roles-max-in-game.decorator.spec.ts:24:42\n at _dispatchDescribe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:91:26)\n at describe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:55:5)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/unit/specs/modules/game/dto/base/decorators/additional-cards/additional-cards-roles-max-in-game.decorator.spec.ts:12:3\n at _dispatchDescribe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:91:26)\n at describe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:55:5)\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/unit/specs/modules/game/dto/base/decorators/additional-cards/additional-cards-roles-max-in-game.decorator.spec.ts:11:1)\n at Runtime._execModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:1439:24)\n at Runtime._loadModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:1022:12)\n at Runtime.requireModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:882:12)\n at jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:77:13)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34), Cannot set properties of undefined (setting 'position') TypeError: Cannot set properties of undefined (setting 'position')\n at Object.gamePlayersPositionTransformer [as transformFn] (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/src/modules/game/dto/base/transformers/game-players-position.transformer.ts:90:28)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:412:24\n at Array.forEach ()\n at TransformOperationExecutor.applyCustomTransformations (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:411:15)\n at TransformOperationExecutor.transform (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/TransformOperationExecutor.ts:334:33)\n at ClassTransformer.plainToInstance (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/ClassTransformer.ts:77:21)\n at plainToInstance (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/class-transformer@0.5.1/node_modules/src/index.ts:84:27)\n at createFakeCreateGameDto (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/factories/game/dto/create-game/create-game.dto.factory.ts:13:25)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/unit/specs/modules/game/providers/services/game-play/game-play.service.spec.ts:677:38\n at _dispatchDescribe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:91:26)\n at describe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:55:5)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/unit/specs/modules/game/providers/services/game-play/game-play.service.spec.ts:664:3\n at _dispatchDescribe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:91:26)\n at describe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:55:5)\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/unit/specs/modules/game/providers/services/game-play/game-play.service.spec.ts:36:1)\n at Runtime._execModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:1439:24)\n at Runtime._loadModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:1022:12)\n at Runtime.requireModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:882:12)\n at jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:77:13)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", "status": "RuntimeError", "static": true, + "killedBy": [], "coveredBy": [ "256", "257", @@ -32007,8 +32042,8 @@ "replacement": "{}", "statusReason": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: 201\nReceived: 500\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:887:35)\n at processTicksAndRejections (node:internal/process/task_queues:105:5)", "status": "Killed", - "static": true, "testsCompleted": 16, + "static": true, "killedBy": [ "736" ], @@ -32584,16 +32619,16 @@ "934", "935", "936", - "1698" + "1695" ], "location": { "end": { "column": 2, - "line": 9 + "line": 10 }, "start": { "column": 59, - "line": 7 + "line": 8 } } }, @@ -32653,16 +32688,16 @@ "934", "935", "936", - "1698" + "1695" ], "location": { "end": { "column": 127, - "line": 8 + "line": 9 }, "start": { "column": 56, - "line": 8 + "line": 9 } } }, @@ -32675,7 +32710,7 @@ "testsCompleted": 44, "static": false, "killedBy": [ - "1698" + "1695" ], "coveredBy": [ "736", @@ -32722,21 +32757,21 @@ "934", "935", "936", - "1698" + "1695" ], "location": { "end": { "column": 125, - "line": 8 + "line": 9 }, "start": { "column": 121, - "line": 8 + "line": 9 } } } ], - "source": "import { GameEvent } from \"@/modules/game/schemas/game-event/game-event.schema\";\n\nimport { toJSON } from \"@/shared/misc/helpers/object.helpers\";\nimport { DEFAULT_PLAIN_TO_INSTANCE_OPTIONS } from \"@/shared/validation/constants/validation.constants\";\nimport { plainToInstance } from \"class-transformer\";\n\nfunction createGameEvent(gameEvent: GameEvent): GameEvent {\n return plainToInstance(GameEvent, toJSON(gameEvent), { ...DEFAULT_PLAIN_TO_INSTANCE_OPTIONS, excludeExtraneousValues: true });\n}\n\nexport {\n createGameEvent,\n};" + "source": "import { plainToInstance } from \"class-transformer\";\n\nimport { GameEvent } from \"@/modules/game/schemas/game-event/game-event.schema\";\n\nimport { toJSON } from \"@/shared/misc/helpers/object.helpers\";\nimport { DEFAULT_PLAIN_TO_INSTANCE_OPTIONS } from \"@/shared/validation/constants/validation.constants\";\n\nfunction createGameEvent(gameEvent: GameEvent): GameEvent {\n return plainToInstance(GameEvent, toJSON(gameEvent), { ...DEFAULT_PLAIN_TO_INSTANCE_OPTIONS, excludeExtraneousValues: true });\n}\n\nexport {\n createGameEvent,\n};" }, "src/modules/game/helpers/game-feedback/game-feedback.factory.ts": { "language": "typescript", @@ -32758,11 +32793,11 @@ "location": { "end": { "column": 2, - "line": 9 + "line": 11 }, "start": { "column": 103, - "line": 7 + "line": 9 } } }, @@ -32780,16 +32815,16 @@ "location": { "end": { "column": 2, - "line": 13 + "line": 15 }, "start": { "column": 71, - "line": 11 + "line": 13 } } } ], - "source": "import { GameFeedback } from \"@/modules/game/schemas/game-feedback/game-feedback.schema\";\nimport { GameFeedbackToInsert } from \"@/modules/game/types/game-feedback/game-feedback.types\";\nimport { toJSON } from \"@/shared/misc/helpers/object.helpers\";\nimport { DEFAULT_PLAIN_TO_INSTANCE_OPTIONS } from \"@/shared/validation/constants/validation.constants\";\nimport { plainToInstance } from \"class-transformer\";\n\nfunction createGameFeedbackToInsert(gameFeedbackToInsert: GameFeedbackToInsert): GameFeedbackToInsert {\n return plainToInstance(GameFeedbackToInsert, toJSON(gameFeedbackToInsert), DEFAULT_PLAIN_TO_INSTANCE_OPTIONS);\n}\n\nfunction createGameFeedback(gameFeedback: GameFeedback): GameFeedback {\n return plainToInstance(GameFeedback, toJSON(gameFeedback), DEFAULT_PLAIN_TO_INSTANCE_OPTIONS);\n}\n\nexport {\n createGameFeedbackToInsert,\n createGameFeedback,\n};" + "source": "import { plainToInstance } from \"class-transformer\";\n\nimport { GameFeedback } from \"@/modules/game/schemas/game-feedback/game-feedback.schema\";\nimport { GameFeedbackToInsert } from \"@/modules/game/types/game-feedback/game-feedback.types\";\n\nimport { toJSON } from \"@/shared/misc/helpers/object.helpers\";\nimport { DEFAULT_PLAIN_TO_INSTANCE_OPTIONS } from \"@/shared/validation/constants/validation.constants\";\n\nfunction createGameFeedbackToInsert(gameFeedbackToInsert: GameFeedbackToInsert): GameFeedbackToInsert {\n return plainToInstance(GameFeedbackToInsert, toJSON(gameFeedbackToInsert), DEFAULT_PLAIN_TO_INSTANCE_OPTIONS);\n}\n\nfunction createGameFeedback(gameFeedback: GameFeedback): GameFeedback {\n return plainToInstance(GameFeedback, toJSON(gameFeedback), DEFAULT_PLAIN_TO_INSTANCE_OPTIONS);\n}\n\nexport {\n createGameFeedbackToInsert,\n createGameFeedback,\n};" }, "src/modules/game/helpers/game-history-record/game-history-record-play/game-history-record-play-source/game-history-record-play-source.factory.ts": { "language": "typescript", @@ -32811,16 +32846,16 @@ "location": { "end": { "column": 2, - "line": 8 + "line": 10 }, "start": { "column": 131, - "line": 6 + "line": 8 } } } ], - "source": "import { GameHistoryRecordPlaySource } from \"@/modules/game/schemas/game-history-record/game-history-record-play/game-history-record-play-source/game-history-record-play-source.schema\";\nimport { toJSON } from \"@/shared/misc/helpers/object.helpers\";\nimport { DEFAULT_PLAIN_TO_INSTANCE_OPTIONS } from \"@/shared/validation/constants/validation.constants\";\nimport { plainToInstance } from \"class-transformer\";\n\nfunction createGameHistoryRecordPlaySource(gameHistoryRecordPlaySource: GameHistoryRecordPlaySource): GameHistoryRecordPlaySource {\n return plainToInstance(GameHistoryRecordPlaySource, toJSON(gameHistoryRecordPlaySource), DEFAULT_PLAIN_TO_INSTANCE_OPTIONS);\n}\n\nexport {\n createGameHistoryRecordPlaySource,\n};" + "source": "import { plainToInstance } from \"class-transformer\";\n\nimport { GameHistoryRecordPlaySource } from \"@/modules/game/schemas/game-history-record/game-history-record-play/game-history-record-play-source/game-history-record-play-source.schema\";\n\nimport { toJSON } from \"@/shared/misc/helpers/object.helpers\";\nimport { DEFAULT_PLAIN_TO_INSTANCE_OPTIONS } from \"@/shared/validation/constants/validation.constants\";\n\nfunction createGameHistoryRecordPlaySource(gameHistoryRecordPlaySource: GameHistoryRecordPlaySource): GameHistoryRecordPlaySource {\n return plainToInstance(GameHistoryRecordPlaySource, toJSON(gameHistoryRecordPlaySource), DEFAULT_PLAIN_TO_INSTANCE_OPTIONS);\n}\n\nexport {\n createGameHistoryRecordPlaySource,\n};" }, "src/modules/game/helpers/game-history-record/game-history-record-play/game-history-record-play-voting/game-history-record-play-voting.factory.ts": { "language": "typescript", @@ -32845,16 +32880,16 @@ "location": { "end": { "column": 2, - "line": 8 + "line": 10 }, "start": { "column": 131, - "line": 6 + "line": 8 } } } ], - "source": "import { GameHistoryRecordPlayVoting } from \"@/modules/game/schemas/game-history-record/game-history-record-play/game-history-record-play-voting/game-history-record-play-voting.schema\";\nimport { toJSON } from \"@/shared/misc/helpers/object.helpers\";\nimport { DEFAULT_PLAIN_TO_INSTANCE_OPTIONS } from \"@/shared/validation/constants/validation.constants\";\nimport { plainToInstance } from \"class-transformer\";\n\nfunction createGameHistoryRecordPlayVoting(gameHistoryRecordPlayVoting: GameHistoryRecordPlayVoting): GameHistoryRecordPlayVoting {\n return plainToInstance(GameHistoryRecordPlayVoting, toJSON(gameHistoryRecordPlayVoting), DEFAULT_PLAIN_TO_INSTANCE_OPTIONS);\n}\n\nexport {\n createGameHistoryRecordPlayVoting,\n};" + "source": "import { plainToInstance } from \"class-transformer\";\n\nimport { GameHistoryRecordPlayVoting } from \"@/modules/game/schemas/game-history-record/game-history-record-play/game-history-record-play-voting/game-history-record-play-voting.schema\";\n\nimport { toJSON } from \"@/shared/misc/helpers/object.helpers\";\nimport { DEFAULT_PLAIN_TO_INSTANCE_OPTIONS } from \"@/shared/validation/constants/validation.constants\";\n\nfunction createGameHistoryRecordPlayVoting(gameHistoryRecordPlayVoting: GameHistoryRecordPlayVoting): GameHistoryRecordPlayVoting {\n return plainToInstance(GameHistoryRecordPlayVoting, toJSON(gameHistoryRecordPlayVoting), DEFAULT_PLAIN_TO_INSTANCE_OPTIONS);\n}\n\nexport {\n createGameHistoryRecordPlayVoting,\n};" }, "src/modules/game/helpers/game-history-record/game-history-record-play/game-history-record-play.factory.ts": { "language": "typescript", @@ -32876,16 +32911,16 @@ "location": { "end": { "column": 2, - "line": 8 + "line": 10 }, "start": { "column": 107, - "line": 6 + "line": 8 } } } ], - "source": "import { GameHistoryRecordPlay } from \"@/modules/game/schemas/game-history-record/game-history-record-play/game-history-record-play.schema\";\nimport { toJSON } from \"@/shared/misc/helpers/object.helpers\";\nimport { DEFAULT_PLAIN_TO_INSTANCE_OPTIONS } from \"@/shared/validation/constants/validation.constants\";\nimport { plainToInstance } from \"class-transformer\";\n\nfunction createGameHistoryRecordPlay(gameHistoryRecordPlay: GameHistoryRecordPlay): GameHistoryRecordPlay {\n return plainToInstance(GameHistoryRecordPlay, toJSON(gameHistoryRecordPlay), DEFAULT_PLAIN_TO_INSTANCE_OPTIONS);\n}\n\nexport {\n createGameHistoryRecordPlay,\n};" + "source": "import { plainToInstance } from \"class-transformer\";\n\nimport { GameHistoryRecordPlay } from \"@/modules/game/schemas/game-history-record/game-history-record-play/game-history-record-play.schema\";\n\nimport { toJSON } from \"@/shared/misc/helpers/object.helpers\";\nimport { DEFAULT_PLAIN_TO_INSTANCE_OPTIONS } from \"@/shared/validation/constants/validation.constants\";\n\nfunction createGameHistoryRecordPlay(gameHistoryRecordPlay: GameHistoryRecordPlay): GameHistoryRecordPlay {\n return plainToInstance(GameHistoryRecordPlay, toJSON(gameHistoryRecordPlay), DEFAULT_PLAIN_TO_INSTANCE_OPTIONS);\n}\n\nexport {\n createGameHistoryRecordPlay,\n};" }, "src/modules/game/helpers/game-history-record/game-history-record-player-attribute-alteration/game-history-record-player-attribute-alteration.factory.ts": { "language": "typescript", @@ -32908,16 +32943,16 @@ "location": { "end": { "column": 2, - "line": 8 + "line": 10 }, "start": { "column": 174, - "line": 6 + "line": 8 } } } ], - "source": "import { GameHistoryRecordPlayerAttributeAlteration } from \"@/modules/game/schemas/game-history-record/game-history-record-player-attribute-alteration/game-history-record-player-attribute-alteration.schema\";\nimport { toJSON } from \"@/shared/misc/helpers/object.helpers\";\nimport { DEFAULT_PLAIN_TO_INSTANCE_OPTIONS } from \"@/shared/validation/constants/validation.constants\";\nimport { plainToInstance } from \"class-transformer\";\n\nfunction createGameHistoryRecordPlayerAttributeAlteration(playerAttributeAlteration: GameHistoryRecordPlayerAttributeAlteration): GameHistoryRecordPlayerAttributeAlteration {\n return plainToInstance(GameHistoryRecordPlayerAttributeAlteration, toJSON(playerAttributeAlteration), DEFAULT_PLAIN_TO_INSTANCE_OPTIONS);\n}\n\nexport {\n createGameHistoryRecordPlayerAttributeAlteration,\n};" + "source": "import { plainToInstance } from \"class-transformer\";\n\nimport { GameHistoryRecordPlayerAttributeAlteration } from \"@/modules/game/schemas/game-history-record/game-history-record-player-attribute-alteration/game-history-record-player-attribute-alteration.schema\";\n\nimport { toJSON } from \"@/shared/misc/helpers/object.helpers\";\nimport { DEFAULT_PLAIN_TO_INSTANCE_OPTIONS } from \"@/shared/validation/constants/validation.constants\";\n\nfunction createGameHistoryRecordPlayerAttributeAlteration(playerAttributeAlteration: GameHistoryRecordPlayerAttributeAlteration): GameHistoryRecordPlayerAttributeAlteration {\n return plainToInstance(GameHistoryRecordPlayerAttributeAlteration, toJSON(playerAttributeAlteration), DEFAULT_PLAIN_TO_INSTANCE_OPTIONS);\n}\n\nexport {\n createGameHistoryRecordPlayerAttributeAlteration,\n};" }, "src/modules/game/helpers/game-history-record/game-history-record.factory.ts": { "language": "typescript", @@ -32946,16 +32981,16 @@ "location": { "end": { "column": 2, - "line": 8 + "line": 10 }, "start": { "column": 123, - "line": 6 + "line": 8 } } } ], - "source": "import { GameHistoryRecordToInsert } from \"@/modules/game/types/game-history-record/game-history-record.types\";\nimport { toJSON } from \"@/shared/misc/helpers/object.helpers\";\nimport { DEFAULT_PLAIN_TO_INSTANCE_OPTIONS } from \"@/shared/validation/constants/validation.constants\";\nimport { plainToInstance } from \"class-transformer\";\n\nfunction createGameHistoryRecordToInsert(gameHistoryRecordToInsert: GameHistoryRecordToInsert): GameHistoryRecordToInsert {\n return plainToInstance(GameHistoryRecordToInsert, toJSON(gameHistoryRecordToInsert), DEFAULT_PLAIN_TO_INSTANCE_OPTIONS);\n}\n\nexport {\n createGameHistoryRecordToInsert,\n};" + "source": "import { plainToInstance } from \"class-transformer\";\n\nimport { GameHistoryRecordToInsert } from \"@/modules/game/types/game-history-record/game-history-record.types\";\n\nimport { toJSON } from \"@/shared/misc/helpers/object.helpers\";\nimport { DEFAULT_PLAIN_TO_INSTANCE_OPTIONS } from \"@/shared/validation/constants/validation.constants\";\n\nfunction createGameHistoryRecordToInsert(gameHistoryRecordToInsert: GameHistoryRecordToInsert): GameHistoryRecordToInsert {\n return plainToInstance(GameHistoryRecordToInsert, toJSON(gameHistoryRecordToInsert), DEFAULT_PLAIN_TO_INSTANCE_OPTIONS);\n}\n\nexport {\n createGameHistoryRecordToInsert,\n};" }, "src/modules/game/helpers/game-history-record/game-history-record.helpers.ts": { "language": "typescript", @@ -34592,95 +34627,6 @@ "src/modules/game/helpers/game-play/game-play.factory.ts": { "language": "typescript", "mutants": [ - { - "id": "721", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/modules/game/helpers/game-play/game-play.factory.ts(9,64): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", - "status": "CompileError", - "static": false, - "killedBy": [], - "coveredBy": [ - "160", - "161", - "162", - "164", - "302", - "303", - "304", - "305", - "306", - "307", - "308", - "383", - "384", - "385", - "387", - "388", - "389", - "390", - "391", - "392", - "393", - "400", - "401", - "404", - "464", - "588", - "648", - "649", - "666", - "676", - "682", - "736", - "737", - "748", - "857", - "1231", - "1256", - "1257", - "1258", - "1259", - "1260", - "1261", - "1262", - "1263", - "1264", - "1265", - "1266", - "1267", - "1268", - "1269", - "1270", - "1271", - "1272", - "1273", - "1274", - "1275", - "1276", - "1277", - "1278", - "1279", - "1280", - "1281", - "1282", - "1283", - "1284", - "1285", - "1286", - "1287" - ], - "location": { - "end": { - "column": 2, - "line": 11 - }, - "start": { - "column": 79, - "line": 9 - } - } - }, { "id": "722", "mutatorName": "ObjectLiteral", @@ -34865,101 +34811,6 @@ } } }, - { - "id": "724", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/modules/game/helpers/game-play/game-play.factory.ts(13,46): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", - "status": "CompileError", - "static": false, - "killedBy": [], - "coveredBy": [ - "160", - "161", - "162", - "163", - "164", - "178", - "302", - "303", - "304", - "305", - "306", - "307", - "308", - "383", - "384", - "385", - "387", - "388", - "389", - "390", - "391", - "392", - "393", - "400", - "401", - "404", - "464", - "465", - "466", - "467", - "588", - "648", - "649", - "666", - "676", - "682", - "736", - "737", - "738", - "748", - "749", - "857", - "1231", - "1256", - "1257", - "1258", - "1259", - "1260", - "1261", - "1262", - "1263", - "1264", - "1265", - "1266", - "1267", - "1268", - "1269", - "1270", - "1271", - "1272", - "1273", - "1274", - "1275", - "1276", - "1277", - "1278", - "1279", - "1280", - "1281", - "1282", - "1283", - "1284", - "1285", - "1287" - ], - "location": { - "end": { - "column": 2, - "line": 15 - }, - "start": { - "column": 55, - "line": 13 - } - } - }, { "id": "725", "mutatorName": "ObjectLiteral", @@ -35331,174 +35182,6 @@ } } }, - { - "id": "734", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/modules/game/helpers/game-play/game-play.factory.ts(19,83): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", - "status": "CompileError", - "static": false, - "killedBy": [], - "coveredBy": [ - "588", - "682", - "1257" - ], - "location": { - "end": { - "column": 2, - "line": 35 - }, - "start": { - "column": 92, - "line": 27 - } - } - }, - { - "id": "735", - "mutatorName": "ObjectLiteral", - "replacement": "{}", - "statusReason": "src/modules/game/helpers/game-play/game-play.factory.ts(20,25): error TS2345: Argument of type '{}' is not assignable to parameter of type 'GamePlay'.\n Type '{}' is missing the following properties from type 'GamePlay': type, source, action, occurrence\n", - "status": "CompileError", - "static": false, - "killedBy": [], - "coveredBy": [ - "588", - "682", - "1257" - ], - "location": { - "end": { - "column": 4, - "line": 34 - }, - "start": { - "column": 25, - "line": 28 - } - } - }, - { - "id": "736", - "mutatorName": "StringLiteral", - "replacement": "\"\"", - "statusReason": "src/modules/game/helpers/game-play/game-play.factory.ts(21,5): error TS2322: Type '\"\"' is not assignable to type '\"request-another-vote\" | \"no-action\" | \"vote\" | \"target\" | \"choose-card\" | \"choose-side\" | \"bury-dead-bodies\"'.\n", - "status": "CompileError", - "static": false, - "killedBy": [], - "coveredBy": [ - "588", - "682", - "1257" - ], - "location": { - "end": { - "column": 29, - "line": 29 - }, - "start": { - "column": 11, - "line": 29 - } - } - }, - { - "id": "737", - "mutatorName": "ObjectLiteral", - "replacement": "{}", - "statusReason": "src/modules/game/helpers/game-play/game-play.factory.ts(22,34): error TS2345: Argument of type '{}' is not assignable to parameter of type 'GamePlaySource'.\n Property 'name' is missing in type '{}' but required in type 'GamePlaySource'.\n", - "status": "CompileError", - "static": false, - "killedBy": [], - "coveredBy": [ - "588", - "682", - "1257" - ], - "location": { - "end": { - "column": 55, - "line": 30 - }, - "start": { - "column": 34, - "line": 30 - } - } - }, - { - "id": "738", - "mutatorName": "StringLiteral", - "replacement": "\"\"", - "statusReason": "src/modules/game/helpers/game-play/game-play.factory.ts(22,36): error TS2322: Type '\"\"' is not assignable to type '\"stuttering-judge\" | \"sheriff\" | \"charmed\" | \"survivors\" | \"werewolves\" | \"lovers\" | \"big-bad-wolf\" | \"accursed-wolf-father\" | \"white-werewolf\" | \"seer\" | \"cupid\" | \"witch\" | ... 12 more ... | \"actor\"'.\n", - "status": "CompileError", - "static": false, - "killedBy": [], - "coveredBy": [ - "588", - "682", - "1257" - ], - "location": { - "end": { - "column": 53, - "line": 30 - }, - "start": { - "column": 42, - "line": 30 - } - } - }, - { - "id": "739", - "mutatorName": "StringLiteral", - "replacement": "\"\"", - "statusReason": "src/modules/game/helpers/game-play/game-play.factory.ts(23,5): error TS2322: Type '\"\"' is not assignable to type '\"request-another-vote\" | \"vote\" | \"choose-card\" | \"choose-side\" | \"bury-dead-bodies\" | \"eat\" | \"look\" | \"charm\" | \"use-potions\" | \"shoot\" | \"protect\" | \"mark\" | \"meet-each-other\" | ... 7 more ... | \"infect\"'.\n", - "status": "CompileError", - "static": false, - "killedBy": [], - "coveredBy": [ - "588", - "682", - "1257" - ], - "location": { - "end": { - "column": 31, - "line": 31 - }, - "start": { - "column": 13, - "line": 31 - } - } - }, - { - "id": "740", - "mutatorName": "StringLiteral", - "replacement": "\"\"", - "statusReason": "src/modules/game/helpers/game-play/game-play.factory.ts(24,5): error TS2322: Type '\"\"' is not assignable to type '\"consequential\" | \"one-night-only\" | \"on-nights\" | \"on-days\" | \"anytime\"'.\n", - "status": "CompileError", - "static": false, - "killedBy": [], - "coveredBy": [ - "588", - "682", - "1257" - ], - "location": { - "end": { - "column": 32, - "line": 32 - }, - "start": { - "column": 17, - "line": 32 - } - } - }, { "id": "741", "mutatorName": "BlockStatement", @@ -39781,6 +39464,349 @@ "line": 268 } } + }, + { + "id": "735", + "mutatorName": "ObjectLiteral", + "replacement": "{}", + "statusReason": "src/modules/game/helpers/game-play/game-play.factory.ts(28,25): error TS2345: Argument of type '{}' is not assignable to parameter of type 'GamePlay'.\n Type '{}' is missing the following properties from type 'GamePlay': type, source, action, occurrence\n", + "status": "CompileError", + "static": false, + "coveredBy": [ + "588", + "682", + "1257" + ], + "location": { + "end": { + "column": 4, + "line": 34 + }, + "start": { + "column": 25, + "line": 28 + } + } + }, + { + "id": "734", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/modules/game/helpers/game-play/game-play.factory.ts(27,83): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", + "status": "CompileError", + "static": false, + "coveredBy": [ + "588", + "682", + "1257" + ], + "location": { + "end": { + "column": 2, + "line": 35 + }, + "start": { + "column": 92, + "line": 27 + } + } + }, + { + "id": "721", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/modules/game/helpers/game-play/game-play.factory.ts(9,64): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", + "status": "CompileError", + "static": false, + "coveredBy": [ + "160", + "161", + "162", + "164", + "302", + "303", + "304", + "305", + "306", + "307", + "308", + "383", + "384", + "385", + "387", + "388", + "389", + "390", + "391", + "392", + "393", + "400", + "401", + "404", + "464", + "588", + "648", + "649", + "666", + "676", + "682", + "736", + "737", + "748", + "857", + "1231", + "1256", + "1257", + "1258", + "1259", + "1260", + "1261", + "1262", + "1263", + "1264", + "1265", + "1266", + "1267", + "1268", + "1269", + "1270", + "1271", + "1272", + "1273", + "1274", + "1275", + "1276", + "1277", + "1278", + "1279", + "1280", + "1281", + "1282", + "1283", + "1284", + "1285", + "1286", + "1287" + ], + "location": { + "end": { + "column": 2, + "line": 11 + }, + "start": { + "column": 79, + "line": 9 + } + } + }, + { + "id": "724", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/modules/game/helpers/game-play/game-play.factory.ts(13,46): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", + "status": "CompileError", + "static": false, + "coveredBy": [ + "160", + "161", + "162", + "163", + "164", + "178", + "302", + "303", + "304", + "305", + "306", + "307", + "308", + "383", + "384", + "385", + "387", + "388", + "389", + "390", + "391", + "392", + "393", + "400", + "401", + "404", + "464", + "465", + "466", + "467", + "588", + "648", + "649", + "666", + "676", + "682", + "736", + "737", + "738", + "748", + "749", + "857", + "1231", + "1256", + "1257", + "1258", + "1259", + "1260", + "1261", + "1262", + "1263", + "1264", + "1265", + "1266", + "1267", + "1268", + "1269", + "1270", + "1271", + "1272", + "1273", + "1274", + "1275", + "1276", + "1277", + "1278", + "1279", + "1280", + "1281", + "1282", + "1283", + "1284", + "1285", + "1287" + ], + "location": { + "end": { + "column": 2, + "line": 15 + }, + "start": { + "column": 55, + "line": 13 + } + } + }, + { + "id": "737", + "mutatorName": "ObjectLiteral", + "replacement": "{}", + "statusReason": "src/modules/game/helpers/game-play/game-play.factory.ts(30,34): error TS2345: Argument of type '{}' is not assignable to parameter of type 'GamePlaySource'.\n Property 'name' is missing in type '{}' but required in type 'GamePlaySource'.\n", + "status": "CompileError", + "static": false, + "coveredBy": [ + "588", + "682", + "1257" + ], + "location": { + "end": { + "column": 55, + "line": 30 + }, + "start": { + "column": 34, + "line": 30 + } + } + }, + { + "id": "739", + "mutatorName": "StringLiteral", + "replacement": "\"\"", + "statusReason": "src/modules/game/helpers/game-play/game-play.factory.ts(31,5): error TS2322: Type '\"\"' is not assignable to type '\"request-another-vote\" | \"vote\" | \"choose-card\" | \"choose-side\" | \"bury-dead-bodies\" | \"eat\" | \"look\" | \"charm\" | \"use-potions\" | \"shoot\" | \"protect\" | \"mark\" | \"meet-each-other\" | ... 6 more ... | \"infect\"'.\n", + "status": "CompileError", + "static": false, + "coveredBy": [ + "588", + "682", + "1257" + ], + "location": { + "end": { + "column": 31, + "line": 31 + }, + "start": { + "column": 13, + "line": 31 + } + } + }, + { + "id": "738", + "mutatorName": "StringLiteral", + "replacement": "\"\"", + "statusReason": "src/modules/game/helpers/game-play/game-play.factory.ts(30,36): error TS2322: Type '\"\"' is not assignable to type '\"big-bad-wolf\" | \"accursed-wolf-father\" | \"white-werewolf\" | \"seer\" | \"cupid\" | \"witch\" | \"hunter\" | \"defender\" | \"scapegoat\" | \"two-sisters\" | \"three-brothers\" | \"fox\" | \"stuttering-judge\" | ... 10 more ... | \"lovers\"'.\n", + "status": "CompileError", + "static": false, + "coveredBy": [ + "588", + "682", + "1257" + ], + "location": { + "end": { + "column": 53, + "line": 30 + }, + "start": { + "column": 42, + "line": 30 + } + } + }, + { + "id": "736", + "mutatorName": "StringLiteral", + "replacement": "\"\"", + "statusReason": "src/modules/game/helpers/game-play/game-play.factory.ts(29,5): error TS2322: Type '\"\"' is not assignable to type '\"choose-side\" | \"choose-card\" | \"vote\" | \"bury-dead-bodies\" | \"request-another-vote\" | \"target\" | \"no-action\"'.\n", + "status": "CompileError", + "static": false, + "coveredBy": [ + "588", + "682", + "1257" + ], + "location": { + "end": { + "column": 29, + "line": 29 + }, + "start": { + "column": 11, + "line": 29 + } + } + }, + { + "id": "740", + "mutatorName": "StringLiteral", + "replacement": "\"\"", + "statusReason": "src/modules/game/helpers/game-play/game-play.factory.ts(32,5): error TS2322: Type '\"\"' is not assignable to type '\"consequential\" | \"one-night-only\" | \"on-nights\" | \"on-days\" | \"anytime\"'.\n", + "status": "CompileError", + "static": false, + "coveredBy": [ + "588", + "682", + "1257" + ], + "location": { + "end": { + "column": 32, + "line": 32 + }, + "start": { + "column": 17, + "line": 32 + } + } } ], "source": "import { plainToInstance } from \"class-transformer\";\n\nimport { GamePlaySource } from \"@/modules/game/schemas/game-play/game-play-source/game-play-source.schema\";\nimport { GamePlay } from \"@/modules/game/schemas/game-play/game-play.schema\";\nimport type { GamePlayOccurrence } from \"@/modules/game/types/game-play/game-play.types\";\n\nimport { DEFAULT_PLAIN_TO_INSTANCE_OPTIONS } from \"@/shared/validation/constants/validation.constants\";\n\nfunction createGamePlaySource(gamePlaySource: GamePlaySource): GamePlaySource {\n return plainToInstance(GamePlaySource, gamePlaySource, { ...DEFAULT_PLAIN_TO_INSTANCE_OPTIONS, excludeExtraneousValues: true });\n}\n\nfunction createGamePlay(gamePlay: GamePlay): GamePlay {\n return plainToInstance(GamePlay, gamePlay, { ...DEFAULT_PLAIN_TO_INSTANCE_OPTIONS, excludeExtraneousValues: true });\n}\n\nfunction createGamePlayStutteringJudgeRequestsAnotherVote(gamePlay: Partial = {}): GamePlay {\n return createGamePlay({\n type: \"request-another-vote\",\n source: createGamePlaySource({ name: \"stuttering-judge\" }),\n action: \"request-another-vote\",\n occurrence: \"consequential\",\n ...gamePlay,\n });\n}\n\nfunction createGamePlaySurvivorsBuryDeadBodies(gamePlay: Partial = {}): GamePlay {\n return createGamePlay({\n type: \"bury-dead-bodies\",\n source: createGamePlaySource({ name: \"survivors\" }),\n action: \"bury-dead-bodies\",\n occurrence: \"consequential\",\n ...gamePlay,\n });\n}\n\nfunction createGamePlaySheriffSettlesVotes(gamePlay: Partial = {}): GamePlay {\n return createGamePlay({\n type: \"target\",\n source: createGamePlaySource({ name: \"sheriff\" }),\n action: \"settle-votes\",\n occurrence: \"consequential\",\n ...gamePlay,\n });\n}\n\nfunction createGamePlaySheriffDelegates(gamePlay: Partial = {}): GamePlay {\n return createGamePlay({\n type: \"target\",\n source: createGamePlaySource({ name: \"sheriff\" }),\n action: \"delegate\",\n occurrence: \"consequential\",\n ...gamePlay,\n });\n}\n\nfunction createGamePlaySurvivorsVote(gamePlay: Partial = {}): GamePlay {\n let occurrence: GamePlayOccurrence = \"on-days\";\n if (gamePlay.causes?.includes(\"angel-presence\") === true) {\n occurrence = \"one-night-only\";\n } else if (gamePlay.causes !== undefined) {\n occurrence = \"consequential\";\n }\n return createGamePlay({\n type: \"vote\",\n source: createGamePlaySource({ name: \"survivors\" }),\n action: \"vote\",\n occurrence,\n ...gamePlay,\n });\n}\n\nfunction createGamePlaySurvivorsElectSheriff(gamePlay: Partial = {}): GamePlay {\n return createGamePlay({\n type: \"vote\",\n source: createGamePlaySource({ name: \"survivors\" }),\n action: \"elect-sheriff\",\n occurrence: \"anytime\",\n ...gamePlay,\n });\n}\n\nfunction createGamePlayThiefChoosesCard(gamePlay: Partial = {}): GamePlay {\n return createGamePlay({\n type: \"choose-card\",\n source: createGamePlaySource({ name: \"thief\" }),\n action: \"choose-card\",\n occurrence: \"one-night-only\",\n ...gamePlay,\n });\n}\n\nfunction createGamePlayScapegoatBansVoting(gamePlay: Partial = {}): GamePlay {\n return createGamePlay({\n type: \"target\",\n source: createGamePlaySource({ name: \"scapegoat\" }),\n action: \"ban-voting\",\n occurrence: \"consequential\",\n ...gamePlay,\n });\n}\n\nfunction createGamePlayWolfHoundChoosesSide(gamePlay: Partial = {}): GamePlay {\n return createGamePlay({\n type: \"choose-side\",\n source: createGamePlaySource({ name: \"wolf-hound\" }),\n action: \"choose-side\",\n occurrence: \"one-night-only\",\n ...gamePlay,\n });\n}\n\nfunction createGamePlayWildChildChoosesModel(gamePlay: Partial = {}): GamePlay {\n return createGamePlay({\n type: \"target\",\n source: createGamePlaySource({ name: \"wild-child\" }),\n action: \"choose-model\",\n occurrence: \"one-night-only\",\n ...gamePlay,\n });\n}\n\nfunction createGamePlayFoxSniffs(gamePlay: Partial = {}): GamePlay {\n return createGamePlay({\n type: \"target\",\n source: createGamePlaySource({ name: \"fox\" }),\n action: \"sniff\",\n occurrence: \"on-nights\",\n ...gamePlay,\n });\n}\n\nfunction createGamePlayCharmedMeetEachOther(gamePlay: Partial = {}): GamePlay {\n return createGamePlay({\n type: \"no-action\",\n source: createGamePlaySource({ name: \"charmed\" }),\n action: \"meet-each-other\",\n occurrence: \"on-nights\",\n ...gamePlay,\n });\n}\n\nfunction createGamePlayLoversMeetEachOther(gamePlay: Partial = {}): GamePlay {\n return createGamePlay({\n type: \"no-action\",\n source: createGamePlaySource({ name: \"lovers\" }),\n action: \"meet-each-other\",\n occurrence: \"one-night-only\",\n ...gamePlay,\n });\n}\n\nfunction createGamePlayThreeBrothersMeetEachOther(gamePlay: Partial = {}): GamePlay {\n return createGamePlay({\n type: \"no-action\",\n source: createGamePlaySource({ name: \"three-brothers\" }),\n action: \"meet-each-other\",\n occurrence: \"on-nights\",\n ...gamePlay,\n });\n}\n\nfunction createGamePlayTwoSistersMeetEachOther(gamePlay: Partial = {}): GamePlay {\n return createGamePlay({\n type: \"no-action\",\n source: createGamePlaySource({ name: \"two-sisters\" }),\n action: \"meet-each-other\",\n occurrence: \"on-nights\",\n ...gamePlay,\n });\n}\n\nfunction createGamePlayScandalmongerMarks(gamePlay: Partial = {}): GamePlay {\n return createGamePlay({\n type: \"target\",\n source: createGamePlaySource({ name: \"scandalmonger\" }),\n action: \"mark\",\n occurrence: \"on-nights\",\n ...gamePlay,\n });\n}\n\nfunction createGamePlayDefenderProtects(gamePlay: Partial = {}): GamePlay {\n return createGamePlay({\n type: \"target\",\n source: createGamePlaySource({ name: \"defender\" }),\n action: \"protect\",\n occurrence: \"on-nights\",\n ...gamePlay,\n });\n}\n\nfunction createGamePlayHunterShoots(gamePlay: Partial = {}): GamePlay {\n return createGamePlay({\n type: \"target\",\n source: createGamePlaySource({ name: \"hunter\" }),\n action: \"shoot\",\n occurrence: \"consequential\",\n ...gamePlay,\n });\n}\n\nfunction createGamePlayWitchUsesPotions(gamePlay: Partial = {}): GamePlay {\n return createGamePlay({\n type: \"target\",\n source: createGamePlaySource({ name: \"witch\" }),\n action: \"use-potions\",\n occurrence: \"on-nights\",\n ...gamePlay,\n });\n}\n\nfunction createGamePlayPiedPiperCharms(gamePlay: Partial = {}): GamePlay {\n return createGamePlay({\n type: \"target\",\n source: createGamePlaySource({ name: \"pied-piper\" }),\n action: \"charm\",\n occurrence: \"on-nights\",\n ...gamePlay,\n });\n}\n\nfunction createGamePlayCupidCharms(gamePlay: Partial = {}): GamePlay {\n return createGamePlay({\n type: \"target\",\n source: createGamePlaySource({ name: \"cupid\" }),\n action: \"charm\",\n occurrence: \"one-night-only\",\n ...gamePlay,\n });\n}\n\nfunction createGamePlaySeerLooks(gamePlay: Partial = {}): GamePlay {\n return createGamePlay({\n type: \"target\",\n source: createGamePlaySource({ name: \"seer\" }),\n action: \"look\",\n occurrence: \"on-nights\",\n ...gamePlay,\n });\n}\n\nfunction createGamePlayWhiteWerewolfEats(gamePlay: Partial = {}): GamePlay {\n return createGamePlay({\n type: \"target\",\n source: createGamePlaySource({ name: \"white-werewolf\" }),\n action: \"eat\",\n occurrence: \"on-nights\",\n ...gamePlay,\n });\n}\n\nfunction createGamePlayBigBadWolfEats(gamePlay: Partial = {}): GamePlay {\n return createGamePlay({\n type: \"target\",\n source: createGamePlaySource({ name: \"big-bad-wolf\" }),\n action: \"eat\",\n occurrence: \"on-nights\",\n ...gamePlay,\n });\n}\n\nfunction createGamePlayWerewolvesEat(gamePlay: Partial = {}): GamePlay {\n return createGamePlay({\n type: \"target\",\n source: createGamePlaySource({ name: \"werewolves\" }),\n action: \"eat\",\n occurrence: \"on-nights\",\n ...gamePlay,\n });\n}\n\nexport {\n createGamePlayStutteringJudgeRequestsAnotherVote,\n createGamePlaySurvivorsBuryDeadBodies,\n createGamePlaySheriffSettlesVotes,\n createGamePlaySheriffDelegates,\n createGamePlaySurvivorsVote,\n createGamePlaySurvivorsElectSheriff,\n createGamePlayThiefChoosesCard,\n createGamePlayScapegoatBansVoting,\n createGamePlayWolfHoundChoosesSide,\n createGamePlayWildChildChoosesModel,\n createGamePlayFoxSniffs,\n createGamePlayCharmedMeetEachOther,\n createGamePlayLoversMeetEachOther,\n createGamePlayThreeBrothersMeetEachOther,\n createGamePlayTwoSistersMeetEachOther,\n createGamePlayScandalmongerMarks,\n createGamePlayDefenderProtects,\n createGamePlayHunterShoots,\n createGamePlayWitchUsesPotions,\n createGamePlayPiedPiperCharms,\n createGamePlayCupidCharms,\n createGamePlaySeerLooks,\n createGamePlayWhiteWerewolfEats,\n createGamePlayBigBadWolfEats,\n createGamePlayWerewolvesEat,\n createGamePlaySource,\n createGamePlay,\n};" @@ -43002,7 +43028,7 @@ } } ], - "source": "import { plainToInstance } from \"class-transformer\";\nimport type { Types } from \"mongoose\";\nimport { isEqual } from \"radash\";\n\nimport type { GamePlayCause } from \"@/modules/game/types/game-play/game-play.types\";\nimport type { PlayerInteractionType } from \"@/modules/game/types/player/player-interaction/player-interaction.types\";\nimport { GAME_PLAYS_PRIORITY_LIST } from \"@/modules/game/constants/game.constants\";\nimport { MakeGamePlayTargetWithRelationsDto } from \"@/modules/game/dto/make-game-play/make-game-play-target/make-game-play-target-with-relations.dto\";\nimport { MakeGamePlayVoteWithRelationsDto } from \"@/modules/game/dto/make-game-play/make-game-play-vote/make-game-play-vote-with-relations.dto\";\nimport { MakeGamePlayWithRelationsDto } from \"@/modules/game/dto/make-game-play/make-game-play-with-relations.dto\";\nimport type { MakeGamePlayDto } from \"@/modules/game/dto/make-game-play/make-game-play.dto\";\nimport { getAdditionalCardWithId, getGroupOfPlayers, getPlayerWithId } from \"@/modules/game/helpers/game.helpers\";\nimport { doesPlayerHaveActiveAttributeWithName } from \"@/modules/game/helpers/player/player-attribute/player-attribute.helpers\";\nimport type { GameAdditionalCard } from \"@/modules/game/schemas/game-additional-card/game-additional-card.schema\";\nimport type { GamePlay } from \"@/modules/game/schemas/game-play/game-play.schema\";\nimport type { Game } from \"@/modules/game/schemas/game.schema\";\nimport type { GameWithCurrentPlay } from \"@/modules/game/types/game-with-current-play.types\";\n\nimport { ApiResources } from \"@/shared/api/enums/api.enums\";\nimport { ResourceNotFoundReasons } from \"@/shared/exception/enums/resource-not-found-error.enum\";\nimport { ResourceNotFoundException } from \"@/shared/exception/types/resource-not-found-exception.types\";\nimport { DEFAULT_PLAIN_TO_INSTANCE_OPTIONS } from \"@/shared/validation/constants/validation.constants\";\n\nfunction getVotesWithRelationsFromMakeGamePlayDto(makeGamePlayDto: MakeGamePlayDto, game: Game): MakeGamePlayVoteWithRelationsDto[] | undefined {\n if (makeGamePlayDto.votes === undefined) {\n return;\n }\n return makeGamePlayDto.votes.reduce((acc, vote) => {\n const source = getPlayerWithId(game, vote.sourceId);\n const target = getPlayerWithId(game, vote.targetId);\n if (source === undefined) {\n throw new ResourceNotFoundException(ApiResources.PLAYERS, vote.sourceId.toString(), ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_PLAYER_VOTE_SOURCE);\n }\n if (target === undefined) {\n throw new ResourceNotFoundException(ApiResources.PLAYERS, vote.targetId.toString(), ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_PLAYER_VOTE_TARGET);\n }\n const plainToInstanceOptions = { ...DEFAULT_PLAIN_TO_INSTANCE_OPTIONS, excludeExtraneousValues: true };\n const voteWithRelations = plainToInstance(MakeGamePlayVoteWithRelationsDto, vote, plainToInstanceOptions);\n voteWithRelations.source = source;\n voteWithRelations.target = target;\n\n return [...acc, voteWithRelations];\n }, []);\n}\n\nfunction getTargetsWithRelationsFromMakeGamePlayDto(makeGamePlayDto: MakeGamePlayDto, game: Game): MakeGamePlayTargetWithRelationsDto[] | undefined {\n if (makeGamePlayDto.targets === undefined) {\n return;\n }\n return makeGamePlayDto.targets.reduce((acc, target) => {\n const player = getPlayerWithId(game, target.playerId);\n if (player === undefined) {\n throw new ResourceNotFoundException(ApiResources.PLAYERS, target.playerId.toString(), ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_PLAYER_TARGET);\n }\n const plainToInstanceOptions = { ...DEFAULT_PLAIN_TO_INSTANCE_OPTIONS, excludeExtraneousValues: true };\n const targetWithRelations = plainToInstance(MakeGamePlayTargetWithRelationsDto, target, plainToInstanceOptions);\n targetWithRelations.player = player;\n\n return [...acc, targetWithRelations];\n }, []);\n}\n\nfunction getChosenCardFromMakeGamePlayDto(makeGamePlayDto: MakeGamePlayDto, game: Game): GameAdditionalCard | undefined {\n if (makeGamePlayDto.chosenCardId === undefined) {\n return;\n }\n const chosenCard = getAdditionalCardWithId(game.additionalCards, makeGamePlayDto.chosenCardId);\n if (chosenCard === undefined) {\n throw new ResourceNotFoundException(ApiResources.GAME_ADDITIONAL_CARDS, makeGamePlayDto.chosenCardId.toString(), ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_CHOSEN_CARD);\n }\n return chosenCard;\n}\n\nfunction createMakeGamePlayDtoWithRelations(makeGamePlayDto: MakeGamePlayDto, game: Game): MakeGamePlayWithRelationsDto {\n const chosenCard = getChosenCardFromMakeGamePlayDto(makeGamePlayDto, game);\n const targets = getTargetsWithRelationsFromMakeGamePlayDto(makeGamePlayDto, game);\n const votes = getVotesWithRelationsFromMakeGamePlayDto(makeGamePlayDto, game);\n const makeGamePlayWithRelationsDto = plainToInstance(MakeGamePlayWithRelationsDto, makeGamePlayDto, { ...DEFAULT_PLAIN_TO_INSTANCE_OPTIONS, excludeExtraneousValues: true });\n makeGamePlayWithRelationsDto.chosenCard = chosenCard;\n makeGamePlayWithRelationsDto.targets = targets;\n makeGamePlayWithRelationsDto.votes = votes;\n\n return makeGamePlayWithRelationsDto;\n}\n\nfunction doesGamePlayHaveCause(gamePlay: GamePlay, cause: GamePlayCause): boolean {\n return gamePlay.causes?.includes(cause) ?? false;\n}\n\nfunction doesGamePlayHaveAnyCause(gamePlay: GamePlay, causes: GamePlayCause[]): boolean {\n return causes.some(cause => doesGamePlayHaveCause(gamePlay, cause));\n}\n\nfunction findPlayPriorityIndex(play: GamePlay): number {\n return GAME_PLAYS_PRIORITY_LIST.findIndex(playInPriorityList => {\n const { source, action, causes } = playInPriorityList;\n const areBothCausesUndefined = causes === undefined && play.causes === undefined;\n\n return source.name === play.source.name && action === play.action && (areBothCausesUndefined || causes && doesGamePlayHaveAnyCause(play, [...causes]));\n });\n}\n\nfunction areGamePlaysEqual(playA: GamePlay, playB: GamePlay): boolean {\n return playA.action === playB.action && isEqual(playA.causes, playB.causes) && playA.source.name === playB.source.name;\n}\n\nfunction canSurvivorsVote(game: Game): boolean {\n const survivors = getGroupOfPlayers(game, \"survivors\");\n\n return survivors.some(player => !doesPlayerHaveActiveAttributeWithName(player, \"cant-vote\", game));\n}\n\nfunction isPlayerInteractableInCurrentGamePlay(playerId: Types.ObjectId, game: GameWithCurrentPlay): boolean {\n const { interactions } = game.currentPlay.source;\n\n return !!interactions?.find(({ eligibleTargets }) => eligibleTargets.find(({ _id }) => _id.equals(playerId)));\n}\n\nfunction isPlayerInteractableWithInteractionTypeInCurrentGamePlay(playerId: Types.ObjectId, interactionType: PlayerInteractionType, game: GameWithCurrentPlay): boolean {\n const { interactions } = game.currentPlay.source;\n const interaction = interactions?.find(({ type }) => type === interactionType);\n\n return !!interaction?.eligibleTargets.find(({ _id }) => _id.equals(playerId));\n}\n\nexport {\n getVotesWithRelationsFromMakeGamePlayDto,\n getTargetsWithRelationsFromMakeGamePlayDto,\n getChosenCardFromMakeGamePlayDto,\n createMakeGamePlayDtoWithRelations,\n findPlayPriorityIndex,\n areGamePlaysEqual,\n canSurvivorsVote,\n isPlayerInteractableInCurrentGamePlay,\n isPlayerInteractableWithInteractionTypeInCurrentGamePlay,\n doesGamePlayHaveCause,\n doesGamePlayHaveAnyCause,\n};" + "source": "import { plainToInstance } from \"class-transformer\";\nimport type { Types } from \"mongoose\";\nimport { isEqual } from \"radash\";\n\nimport type { GamePlayCause } from \"@/modules/game/types/game-play/game-play.types\";\nimport type { PlayerInteractionType } from \"@/modules/game/types/player/player-interaction/player-interaction.types\";\nimport { GAME_PLAYS_PRIORITY_LIST } from \"@/modules/game/constants/game.constants\";\nimport { MakeGamePlayTargetWithRelationsDto } from \"@/modules/game/dto/make-game-play/make-game-play-target/make-game-play-target-with-relations.dto\";\nimport { MakeGamePlayVoteWithRelationsDto } from \"@/modules/game/dto/make-game-play/make-game-play-vote/make-game-play-vote-with-relations.dto\";\nimport { MakeGamePlayWithRelationsDto } from \"@/modules/game/dto/make-game-play/make-game-play-with-relations.dto\";\nimport type { MakeGamePlayDto } from \"@/modules/game/dto/make-game-play/make-game-play.dto\";\nimport { getAdditionalCardWithId, getGroupOfPlayers, getPlayerWithId } from \"@/modules/game/helpers/game.helpers\";\nimport { doesPlayerHaveActiveAttributeWithName } from \"@/modules/game/helpers/player/player-attribute/player-attribute.helpers\";\nimport type { GameAdditionalCard } from \"@/modules/game/schemas/game-additional-card/game-additional-card.schema\";\nimport type { GamePlay } from \"@/modules/game/schemas/game-play/game-play.schema\";\nimport type { Game } from \"@/modules/game/schemas/game.schema\";\nimport type { GameWithCurrentPlay } from \"@/modules/game/types/game-with-current-play.types\";\n\nimport { ApiResources } from \"@/shared/api/enums/api.enums\";\nimport { ResourceNotFoundReasons } from \"@/shared/exception/enums/resource-not-found-error.enums\";\nimport { ResourceNotFoundException } from \"@/shared/exception/types/resource-not-found-exception.types\";\nimport { DEFAULT_PLAIN_TO_INSTANCE_OPTIONS } from \"@/shared/validation/constants/validation.constants\";\n\nfunction getVotesWithRelationsFromMakeGamePlayDto(makeGamePlayDto: MakeGamePlayDto, game: Game): MakeGamePlayVoteWithRelationsDto[] | undefined {\n if (makeGamePlayDto.votes === undefined) {\n return;\n }\n return makeGamePlayDto.votes.reduce((acc, vote) => {\n const source = getPlayerWithId(game, vote.sourceId);\n const target = getPlayerWithId(game, vote.targetId);\n if (source === undefined) {\n throw new ResourceNotFoundException(ApiResources.PLAYERS, vote.sourceId.toString(), ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_PLAYER_VOTE_SOURCE);\n }\n if (target === undefined) {\n throw new ResourceNotFoundException(ApiResources.PLAYERS, vote.targetId.toString(), ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_PLAYER_VOTE_TARGET);\n }\n const plainToInstanceOptions = { ...DEFAULT_PLAIN_TO_INSTANCE_OPTIONS, excludeExtraneousValues: true };\n const voteWithRelations = plainToInstance(MakeGamePlayVoteWithRelationsDto, vote, plainToInstanceOptions);\n voteWithRelations.source = source;\n voteWithRelations.target = target;\n\n return [...acc, voteWithRelations];\n }, []);\n}\n\nfunction getTargetsWithRelationsFromMakeGamePlayDto(makeGamePlayDto: MakeGamePlayDto, game: Game): MakeGamePlayTargetWithRelationsDto[] | undefined {\n if (makeGamePlayDto.targets === undefined) {\n return;\n }\n return makeGamePlayDto.targets.reduce((acc, target) => {\n const player = getPlayerWithId(game, target.playerId);\n if (player === undefined) {\n throw new ResourceNotFoundException(ApiResources.PLAYERS, target.playerId.toString(), ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_PLAYER_TARGET);\n }\n const plainToInstanceOptions = { ...DEFAULT_PLAIN_TO_INSTANCE_OPTIONS, excludeExtraneousValues: true };\n const targetWithRelations = plainToInstance(MakeGamePlayTargetWithRelationsDto, target, plainToInstanceOptions);\n targetWithRelations.player = player;\n\n return [...acc, targetWithRelations];\n }, []);\n}\n\nfunction getChosenCardFromMakeGamePlayDto(makeGamePlayDto: MakeGamePlayDto, game: Game): GameAdditionalCard | undefined {\n if (makeGamePlayDto.chosenCardId === undefined) {\n return;\n }\n const chosenCard = getAdditionalCardWithId(game.additionalCards, makeGamePlayDto.chosenCardId);\n if (chosenCard === undefined) {\n throw new ResourceNotFoundException(ApiResources.GAME_ADDITIONAL_CARDS, makeGamePlayDto.chosenCardId.toString(), ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_CHOSEN_CARD);\n }\n return chosenCard;\n}\n\nfunction createMakeGamePlayDtoWithRelations(makeGamePlayDto: MakeGamePlayDto, game: Game): MakeGamePlayWithRelationsDto {\n const chosenCard = getChosenCardFromMakeGamePlayDto(makeGamePlayDto, game);\n const targets = getTargetsWithRelationsFromMakeGamePlayDto(makeGamePlayDto, game);\n const votes = getVotesWithRelationsFromMakeGamePlayDto(makeGamePlayDto, game);\n const makeGamePlayWithRelationsDto = plainToInstance(MakeGamePlayWithRelationsDto, makeGamePlayDto, { ...DEFAULT_PLAIN_TO_INSTANCE_OPTIONS, excludeExtraneousValues: true });\n makeGamePlayWithRelationsDto.chosenCard = chosenCard;\n makeGamePlayWithRelationsDto.targets = targets;\n makeGamePlayWithRelationsDto.votes = votes;\n\n return makeGamePlayWithRelationsDto;\n}\n\nfunction doesGamePlayHaveCause(gamePlay: GamePlay, cause: GamePlayCause): boolean {\n return gamePlay.causes?.includes(cause) ?? false;\n}\n\nfunction doesGamePlayHaveAnyCause(gamePlay: GamePlay, causes: GamePlayCause[]): boolean {\n return causes.some(cause => doesGamePlayHaveCause(gamePlay, cause));\n}\n\nfunction findPlayPriorityIndex(play: GamePlay): number {\n return GAME_PLAYS_PRIORITY_LIST.findIndex(playInPriorityList => {\n const { source, action, causes } = playInPriorityList;\n const areBothCausesUndefined = causes === undefined && play.causes === undefined;\n\n return source.name === play.source.name && action === play.action && (areBothCausesUndefined || causes && doesGamePlayHaveAnyCause(play, [...causes]));\n });\n}\n\nfunction areGamePlaysEqual(playA: GamePlay, playB: GamePlay): boolean {\n return playA.action === playB.action && isEqual(playA.causes, playB.causes) && playA.source.name === playB.source.name;\n}\n\nfunction canSurvivorsVote(game: Game): boolean {\n const survivors = getGroupOfPlayers(game, \"survivors\");\n\n return survivors.some(player => !doesPlayerHaveActiveAttributeWithName(player, \"cant-vote\", game));\n}\n\nfunction isPlayerInteractableInCurrentGamePlay(playerId: Types.ObjectId, game: GameWithCurrentPlay): boolean {\n const { interactions } = game.currentPlay.source;\n\n return !!interactions?.find(({ eligibleTargets }) => eligibleTargets.find(({ _id }) => _id.equals(playerId)));\n}\n\nfunction isPlayerInteractableWithInteractionTypeInCurrentGamePlay(playerId: Types.ObjectId, interactionType: PlayerInteractionType, game: GameWithCurrentPlay): boolean {\n const { interactions } = game.currentPlay.source;\n const interaction = interactions?.find(({ type }) => type === interactionType);\n\n return !!interaction?.eligibleTargets.find(({ _id }) => _id.equals(playerId));\n}\n\nexport {\n getVotesWithRelationsFromMakeGamePlayDto,\n getTargetsWithRelationsFromMakeGamePlayDto,\n getChosenCardFromMakeGamePlayDto,\n createMakeGamePlayDtoWithRelations,\n findPlayPriorityIndex,\n areGamePlaysEqual,\n canSurvivorsVote,\n isPlayerInteractableInCurrentGamePlay,\n isPlayerInteractableWithInteractionTypeInCurrentGamePlay,\n doesGamePlayHaveCause,\n doesGamePlayHaveAnyCause,\n};" }, "src/modules/game/helpers/game-victory/game-victory.factory.ts": { "language": "typescript", @@ -46465,73 +46491,6 @@ } } }, - { - "id": "1085", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/modules/game/helpers/game.helpers.ts(31,65): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", - "status": "CompileError", - "static": false, - "killedBy": [], - "coveredBy": [ - "160", - "161", - "162", - "165", - "166", - "224", - "225", - "580", - "748", - "749", - "943", - "944", - "959", - "960", - "961", - "962", - "963", - "964", - "986", - "987", - "1019", - "1020", - "1021", - "1022", - "1023", - "1024", - "1025", - "1026", - "1028", - "1029", - "1030", - "1031", - "1032", - "1033", - "1034", - "1035", - "1036", - "1037", - "1038", - "1039", - "1040", - "1041", - "1042", - "1043", - "1395", - "1396" - ], - "location": { - "end": { - "column": 2, - "line": 33 - }, - "start": { - "column": 74, - "line": 31 - } - } - }, { "id": "1086", "mutatorName": "MethodExpression", @@ -47568,6 +47527,31 @@ } } }, + { + "id": "1103", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/modules/game/helpers/game.helpers.ts(51,61): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", + "status": "CompileError", + "static": false, + "killedBy": [], + "coveredBy": [ + "950", + "951", + "952", + "953" + ], + "location": { + "end": { + "column": 2, + "line": 53 + }, + "start": { + "column": 80, + "line": 51 + } + } + }, { "id": "1104", "mutatorName": "ArrowFunction", @@ -47680,6 +47664,182 @@ } } }, + { + "id": "1108", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/modules/game/helpers/game.helpers.ts(55,86): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", + "status": "CompileError", + "static": false, + "killedBy": [], + "coveredBy": [ + "952", + "953" + ], + "location": { + "end": { + "column": 2, + "line": 61 + }, + "start": { + "column": 93, + "line": 55 + } + } + }, + { + "id": "1109", + "mutatorName": "BooleanLiteral", + "replacement": "player", + "statusReason": "src/modules/game/helpers/game.helpers.ts(60,3): error TS2322: Type 'undefined' is not assignable to type 'Player'.\n", + "status": "CompileError", + "static": false, + "killedBy": [], + "coveredBy": [ + "952", + "953" + ], + "location": { + "end": { + "column": 14, + "line": 57 + }, + "start": { + "column": 7, + "line": 57 + } + } + }, + { + "id": "1110", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "statusReason": "src/modules/game/helpers/game.helpers.ts(60,3): error TS2322: Type 'Player | undefined' is not assignable to type 'Player'.\n Type 'undefined' is not assignable to type 'Player'.\n", + "status": "CompileError", + "static": false, + "killedBy": [], + "coveredBy": [ + "952", + "953" + ], + "location": { + "end": { + "column": 14, + "line": 57 + }, + "start": { + "column": 7, + "line": 57 + } + } + }, + { + "id": "1111", + "mutatorName": "ConditionalExpression", + "replacement": "false", + "statusReason": "src/modules/game/helpers/game.helpers.ts(60,3): error TS2322: Type 'Player | undefined' is not assignable to type 'Player'.\n Type 'undefined' is not assignable to type 'Player'.\n", + "status": "CompileError", + "static": false, + "killedBy": [], + "coveredBy": [ + "952", + "953" + ], + "location": { + "end": { + "column": 14, + "line": 57 + }, + "start": { + "column": 7, + "line": 57 + } + } + }, + { + "id": "1112", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/modules/game/helpers/game.helpers.ts(58,3): error TS2322: Type 'Player | undefined' is not assignable to type 'Player'.\n Type 'undefined' is not assignable to type 'Player'.\n", + "status": "CompileError", + "static": false, + "killedBy": [], + "coveredBy": [ + "953" + ], + "location": { + "end": { + "column": 4, + "line": 59 + }, + "start": { + "column": 16, + "line": 57 + } + } + }, + { + "id": "1113", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/modules/game/helpers/game.helpers.ts(63,56): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", + "status": "CompileError", + "static": false, + "killedBy": [], + "coveredBy": [ + "736", + "737", + "738", + "954", + "955", + "1081", + "1082", + "1083", + "1084", + "1085", + "1086", + "1087" + ], + "location": { + "end": { + "column": 2, + "line": 65 + }, + "start": { + "column": 65, + "line": 63 + } + } + }, + { + "id": "1114", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/modules/game/helpers/game.helpers.ts(67,96): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", + "status": "CompileError", + "static": false, + "killedBy": [], + "coveredBy": [ + "956", + "957", + "958", + "1163", + "1164", + "1165", + "1210", + "1211" + ], + "location": { + "end": { + "column": 2, + "line": 69 + }, + "start": { + "column": 127, + "line": 67 + } + } + }, { "id": "1115", "mutatorName": "OptionalChaining", @@ -51889,6 +52049,37 @@ } } }, + { + "id": "1235", + "mutatorName": "StringLiteral", + "replacement": "\"\"", + "statusReason": "src/modules/game/helpers/game.helpers.ts(139,65): error TS2367: This comparison appears to be unintentional because the types '\"werewolf\" | \"big-bad-wolf\" | \"accursed-wolf-father\" | \"white-werewolf\" | \"villager\" | \"villager-villager\" | \"seer\" | \"cupid\" | \"witch\" | \"hunter\" | \"little-girl\" | \"defender\" | ... 17 more ... | \"devoted-servant\"' and '\"\"' have no overlap.\n", + "status": "CompileError", + "static": false, + "killedBy": [], + "coveredBy": [ + "303", + "305", + "306", + "307", + "308", + "500", + "501", + "553", + "554", + "982" + ], + "location": { + "end": { + "column": 96, + "line": 139 + }, + "start": { + "column": 89, + "line": 139 + } + } + }, { "id": "1236", "mutatorName": "BlockStatement", @@ -54048,8 +54239,7 @@ "999" ], "coveredBy": [ - "659", - "660", + "658", "661", "662", "999", @@ -54083,8 +54273,7 @@ "999" ], "coveredBy": [ - "659", - "660", + "658", "661", "662", "999", @@ -54121,7 +54310,7 @@ "433", "434", "435", - "658", + "659", "660", "661", "662", @@ -54168,245 +54357,244 @@ "killedBy": [ "996" ], + "coveredBy": [ + "433", + "434", + "435", + "659", + "660", + "661", + "662", + "841", + "913", + "914", + "915", + "916", + "917", + "918", + "919", + "996", + "997", + "998", + "999", + "1002", + "1003", + "1004", + "1005", + "1006", + "1007", + "1008", + "1009" + ], + "location": { + "end": { + "column": 52, + "line": 182 + }, + "start": { + "column": 16, + "line": 182 + } + } + }, + { + "id": "1294", + "mutatorName": "EqualityOperator", + "replacement": "currentIndex > sortedPlayers.length", + "statusReason": "TypeError: Cannot read properties of undefined (reading 'isAlive')\n at getNearestAliveNeighborInSortedPlayers (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/src/modules/game/helpers/game.helpers.ts:420:285)\n at getNearestAliveNeighbor (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/src/modules/game/helpers/game.helpers.ts:445:12)\n at getFoxSniffedPlayers (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/src/modules/game/helpers/game.helpers.ts:366:32)\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/helpers/game.helpers.spec.ts:687:34)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "status": "Killed", + "testsCompleted": 29, + "static": false, + "killedBy": [ + "996" + ], + "coveredBy": [ + "433", + "434", + "435", + "659", + "660", + "661", + "662", + "841", + "913", + "914", + "915", + "916", + "917", + "918", + "919", + "996", + "997", + "998", + "999", + "1002", + "1003", + "1004", + "1005", + "1006", + "1007", + "1008", + "1009" + ], + "location": { + "end": { + "column": 52, + "line": 182 + }, + "start": { + "column": 16, + "line": 182 + } + } + }, + { + "id": "1295", + "mutatorName": "EqualityOperator", + "replacement": "currentIndex < sortedPlayers.length", + "statusReason": "Error: expect(received).toStrictEqual(expected) // deep equality\n\n- Expected - 1\n+ Received + 9\n\n@@ -110,11 +110,19 @@\n },\n \"phase\": \"day\",\n \"players\": Array [\n Player {\n \"_id\": \"545653bfddb02fbb4db4292d\",\n- \"attributes\": Array [],\n+ \"attributes\": Array [\n+ PlayerAttribute {\n+ \"activeAt\": undefined,\n+ \"doesRemainAfterDeath\": true,\n+ \"name\": \"powerless\",\n+ \"remainingPhases\": undefined,\n+ \"source\": \"fox\",\n+ },\n+ ],\n \"death\": undefined,\n \"group\": undefined,\n \"isAlive\": true,\n \"name\": \"Dejah\",\n \"position\": 0,\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/providers/services/game-play/game-play-maker/game-play-maker.service.spec.ts:1616:63)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "status": "Killed", + "testsCompleted": 29, + "static": false, + "killedBy": [ + "434" + ], + "coveredBy": [ + "433", + "434", + "435", + "659", + "660", + "661", + "662", + "841", + "913", + "914", + "915", + "916", + "917", + "918", + "919", + "996", + "997", + "998", + "999", + "1002", + "1003", + "1004", + "1005", + "1006", + "1007", + "1008", + "1009" + ], + "location": { + "end": { + "column": 52, + "line": 182 + }, + "start": { + "column": 16, + "line": 182 + } + } + }, + { + "id": "1296", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "TypeError: Cannot read properties of undefined (reading 'isAlive')\n at getNearestAliveNeighborInSortedPlayers (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/src/modules/game/helpers/game.helpers.ts:420:285)\n at getNearestAliveNeighbor (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/src/modules/game/helpers/game.helpers.ts:445:12)\n at getFoxSniffedPlayers (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/src/modules/game/helpers/game.helpers.ts:366:32)\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/helpers/game.helpers.spec.ts:687:34)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "status": "Killed", + "testsCompleted": 5, + "static": false, + "killedBy": [ + "996" + ], + "coveredBy": [ + "919", + "996", + "997", + "998", + "999", + "1002" + ], + "location": { + "end": { + "column": 6, + "line": 184 + }, + "start": { + "column": 54, + "line": 182 + } + } + }, + { + "id": "1297", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "statusReason": "Error: expect(received).toStrictEqual(expected) // deep equality\n\n- Expected - 8\n+ Received + 8\n\n@@ -34,23 +34,23 @@\n \"current\": \"villagers\",\n \"original\": \"villagers\",\n },\n },\n Player {\n- \"_id\": \"9f6e15d73d426d81acbbcde1\",\n+ \"_id\": \"f0afefdb9c6deba72e7bc7bd\",\n \"attributes\": Array [],\n \"death\": undefined,\n \"group\": undefined,\n- \"isAlive\": true,\n- \"name\": \"Asa\",\n- \"position\": 1,\n+ \"isAlive\": false,\n+ \"name\": \"Adolphus\",\n+ \"position\": 0,\n \"role\": PlayerRole {\n- \"current\": \"villager\",\n+ \"current\": \"werewolf\",\n \"isRevealed\": false,\n- \"original\": \"villager\",\n+ \"original\": \"werewolf\",\n },\n \"side\": PlayerSide {\n- \"current\": \"villagers\",\n- \"original\": \"villagers\",\n+ \"current\": \"werewolves\",\n+ \"original\": \"werewolves\",\n },\n },\n ]\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/helpers/game.helpers.spec.ts:704:58)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "status": "Killed", + "testsCompleted": 29, + "static": false, + "killedBy": [ + "997" + ], + "coveredBy": [ + "433", + "434", + "435", + "658", + "659", + "660", + "661", + "662", + "841", + "913", + "914", + "915", + "916", + "917", + "918", + "919", + "996", + "997", + "998", + "999", + "1002", + "1003", + "1004", + "1005", + "1006", + "1007", + "1008", + "1009" + ], + "location": { + "end": { + "column": 127, + "line": 186 + }, + "start": { + "column": 9, + "line": 186 + } + } + }, + { + "id": "1298", + "mutatorName": "ConditionalExpression", + "replacement": "false", + "statusReason": "src/modules/game/helpers/game.helpers.ts(170,140): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", + "status": "CompileError", + "static": false, + "killedBy": [], "coveredBy": [ "433", "434", "435", "658", - "660", - "661", - "662", - "841", - "913", - "914", - "915", - "916", - "917", - "918", - "919", - "996", - "997", - "998", - "999", - "1002", - "1003", - "1004", - "1005", - "1006", - "1007", - "1008", - "1009" - ], - "location": { - "end": { - "column": 52, - "line": 182 - }, - "start": { - "column": 16, - "line": 182 - } - } - }, - { - "id": "1294", - "mutatorName": "EqualityOperator", - "replacement": "currentIndex > sortedPlayers.length", - "statusReason": "TypeError: Cannot read properties of undefined (reading 'isAlive')\n at getNearestAliveNeighborInSortedPlayers (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/src/modules/game/helpers/game.helpers.ts:420:285)\n at getNearestAliveNeighbor (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/src/modules/game/helpers/game.helpers.ts:445:12)\n at getFoxSniffedPlayers (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/src/modules/game/helpers/game.helpers.ts:366:32)\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/helpers/game.helpers.spec.ts:687:34)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", - "status": "Killed", - "testsCompleted": 29, - "static": false, - "killedBy": [ - "996" - ], - "coveredBy": [ - "433", - "434", - "435", - "658", - "660", - "661", - "662", - "841", - "913", - "914", - "915", - "916", - "917", - "918", - "919", - "996", - "997", - "998", - "999", - "1002", - "1003", - "1004", - "1005", - "1006", - "1007", - "1008", - "1009" - ], - "location": { - "end": { - "column": 52, - "line": 182 - }, - "start": { - "column": 16, - "line": 182 - } - } - }, - { - "id": "1295", - "mutatorName": "EqualityOperator", - "replacement": "currentIndex < sortedPlayers.length", - "statusReason": "Error: expect(received).toStrictEqual(expected) // deep equality\n\n- Expected - 1\n+ Received + 9\n\n@@ -110,11 +110,19 @@\n },\n \"phase\": \"day\",\n \"players\": Array [\n Player {\n \"_id\": \"545653bfddb02fbb4db4292d\",\n- \"attributes\": Array [],\n+ \"attributes\": Array [\n+ PlayerAttribute {\n+ \"activeAt\": undefined,\n+ \"doesRemainAfterDeath\": true,\n+ \"name\": \"powerless\",\n+ \"remainingPhases\": undefined,\n+ \"source\": \"fox\",\n+ },\n+ ],\n \"death\": undefined,\n \"group\": undefined,\n \"isAlive\": true,\n \"name\": \"Dejah\",\n \"position\": 0,\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/providers/services/game-play/game-play-maker/game-play-maker.service.spec.ts:1616:63)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", - "status": "Killed", - "testsCompleted": 29, - "static": false, - "killedBy": [ - "434" - ], - "coveredBy": [ - "433", - "434", - "435", - "658", - "660", - "661", - "662", - "841", - "913", - "914", - "915", - "916", - "917", - "918", - "919", - "996", - "997", - "998", - "999", - "1002", - "1003", - "1004", - "1005", - "1006", - "1007", - "1008", - "1009" - ], - "location": { - "end": { - "column": 52, - "line": 182 - }, - "start": { - "column": 16, - "line": 182 - } - } - }, - { - "id": "1296", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "TypeError: Cannot read properties of undefined (reading 'isAlive')\n at getNearestAliveNeighborInSortedPlayers (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/src/modules/game/helpers/game.helpers.ts:420:285)\n at getNearestAliveNeighbor (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/src/modules/game/helpers/game.helpers.ts:445:12)\n at getFoxSniffedPlayers (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/src/modules/game/helpers/game.helpers.ts:366:32)\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/helpers/game.helpers.spec.ts:687:34)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", - "status": "Killed", - "testsCompleted": 5, - "static": false, - "killedBy": [ - "996" - ], - "coveredBy": [ - "918", - "919", - "996", - "997", - "998", - "999", - "1002" - ], - "location": { - "end": { - "column": 6, - "line": 184 - }, - "start": { - "column": 54, - "line": 182 - } - } - }, - { - "id": "1297", - "mutatorName": "ConditionalExpression", - "replacement": "true", - "statusReason": "Error: expect(received).toStrictEqual(expected) // deep equality\n\n- Expected - 8\n+ Received + 8\n\n@@ -34,23 +34,23 @@\n \"current\": \"villagers\",\n \"original\": \"villagers\",\n },\n },\n Player {\n- \"_id\": \"9f6e15d73d426d81acbbcde1\",\n+ \"_id\": \"f0afefdb9c6deba72e7bc7bd\",\n \"attributes\": Array [],\n \"death\": undefined,\n \"group\": undefined,\n- \"isAlive\": true,\n- \"name\": \"Asa\",\n- \"position\": 1,\n+ \"isAlive\": false,\n+ \"name\": \"Adolphus\",\n+ \"position\": 0,\n \"role\": PlayerRole {\n- \"current\": \"villager\",\n+ \"current\": \"werewolf\",\n \"isRevealed\": false,\n- \"original\": \"villager\",\n+ \"original\": \"werewolf\",\n },\n \"side\": PlayerSide {\n- \"current\": \"villagers\",\n- \"original\": \"villagers\",\n+ \"current\": \"werewolves\",\n+ \"original\": \"werewolves\",\n },\n },\n ]\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/helpers/game.helpers.spec.ts:704:58)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", - "status": "Killed", - "testsCompleted": 29, - "static": false, - "killedBy": [ - "997" - ], - "coveredBy": [ - "433", - "434", - "435", - "658", - "659", - "660", - "661", - "662", - "841", - "913", - "914", - "915", - "916", - "917", - "918", - "919", - "996", - "997", - "998", - "999", - "1002", - "1003", - "1004", - "1005", - "1006", - "1007", - "1008", - "1009" - ], - "location": { - "end": { - "column": 127, - "line": 186 - }, - "start": { - "column": 9, - "line": 186 - } - } - }, - { - "id": "1298", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "statusReason": "src/modules/game/helpers/game.helpers.ts(170,140): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", - "status": "CompileError", - "static": false, - "killedBy": [], - "coveredBy": [ - "433", - "434", - "435", - "658", - "659", + "659", "660", "661", "662", @@ -54816,7 +55004,6 @@ "662" ], "coveredBy": [ - "660", "661", "662", "997", @@ -54849,7 +55036,6 @@ "static": false, "killedBy": [], "coveredBy": [ - "660", "661", "662", "997", @@ -55984,32 +56170,6 @@ } } }, - { - "id": "1343", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/modules/game/helpers/game.helpers.ts(203,107): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", - "status": "CompileError", - "static": false, - "killedBy": [], - "coveredBy": [ - "588", - "682", - "683", - "1012", - "1013" - ], - "location": { - "end": { - "column": 2, - "line": 225 - }, - "start": { - "column": 115, - "line": 221 - } - } - }, { "id": "1344", "mutatorName": "MethodExpression", @@ -56801,225 +56961,93 @@ } }, { - "id": "1108", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/modules/game/helpers/game.helpers.ts(55,86): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", - "status": "CompileError", - "static": false, - "coveredBy": [ - "952", - "953" - ], - "location": { - "end": { - "column": 2, - "line": 61 - }, - "start": { - "column": 93, - "line": 55 - } - } - }, - { - "id": "1103", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/modules/game/helpers/game.helpers.ts(51,61): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", - "status": "CompileError", - "static": false, - "coveredBy": [ - "950", - "951", - "952", - "953" - ], - "location": { - "end": { - "column": 2, - "line": 53 - }, - "start": { - "column": 80, - "line": 51 - } - } - }, - { - "id": "1109", - "mutatorName": "BooleanLiteral", - "replacement": "player", - "statusReason": "src/modules/game/helpers/game.helpers.ts(60,3): error TS2322: Type 'undefined' is not assignable to type 'Player'.\n", - "status": "CompileError", - "static": false, - "coveredBy": [ - "952", - "953" - ], - "location": { - "end": { - "column": 14, - "line": 57 - }, - "start": { - "column": 7, - "line": 57 - } - } - }, - { - "id": "1111", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "statusReason": "src/modules/game/helpers/game.helpers.ts(60,3): error TS2322: Type 'Player | undefined' is not assignable to type 'Player'.\n Type 'undefined' is not assignable to type 'Player'.\n", - "status": "CompileError", - "static": false, - "coveredBy": [ - "952", - "953" - ], - "location": { - "end": { - "column": 14, - "line": 57 - }, - "start": { - "column": 7, - "line": 57 - } - } - }, - { - "id": "1110", - "mutatorName": "ConditionalExpression", - "replacement": "true", - "statusReason": "src/modules/game/helpers/game.helpers.ts(60,3): error TS2322: Type 'Player | undefined' is not assignable to type 'Player'.\n Type 'undefined' is not assignable to type 'Player'.\n", - "status": "CompileError", - "static": false, - "coveredBy": [ - "952", - "953" - ], - "location": { - "end": { - "column": 14, - "line": 57 - }, - "start": { - "column": 7, - "line": 57 - } - } - }, - { - "id": "1112", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/modules/game/helpers/game.helpers.ts(58,3): error TS2322: Type 'Player | undefined' is not assignable to type 'Player'.\n Type 'undefined' is not assignable to type 'Player'.\n", - "status": "CompileError", - "static": false, - "coveredBy": [ - "953" - ], - "location": { - "end": { - "column": 4, - "line": 59 - }, - "start": { - "column": 16, - "line": 57 - } - } - }, - { - "id": "1114", + "id": "1085", "mutatorName": "BlockStatement", "replacement": "{}", - "statusReason": "src/modules/game/helpers/game.helpers.ts(67,96): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", + "statusReason": "src/modules/game/helpers/game.helpers.ts(31,65): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", "status": "CompileError", "static": false, "coveredBy": [ - "956", - "957", - "958", - "1163", - "1164", - "1165", - "1210", - "1211" + "160", + "161", + "162", + "165", + "166", + "224", + "225", + "580", + "748", + "749", + "943", + "944", + "959", + "960", + "961", + "962", + "963", + "964", + "986", + "987", + "1019", + "1020", + "1021", + "1022", + "1023", + "1024", + "1025", + "1026", + "1028", + "1029", + "1030", + "1031", + "1032", + "1033", + "1034", + "1035", + "1036", + "1037", + "1038", + "1039", + "1040", + "1041", + "1042", + "1043", + "1395", + "1396" ], "location": { "end": { "column": 2, - "line": 69 + "line": 33 }, "start": { - "column": 127, - "line": 67 + "column": 74, + "line": 31 } } }, { - "id": "1113", + "id": "1343", "mutatorName": "BlockStatement", "replacement": "{}", - "statusReason": "src/modules/game/helpers/game.helpers.ts(63,56): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", + "statusReason": "src/modules/game/helpers/game.helpers.ts(221,107): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", "status": "CompileError", "static": false, "coveredBy": [ - "736", - "737", - "738", - "954", - "955", - "1081", - "1082", - "1083", - "1084", - "1085", - "1086", - "1087" + "588", + "682", + "683", + "1012", + "1013" ], "location": { "end": { "column": 2, - "line": 65 - }, - "start": { - "column": 65, - "line": 63 - } - } - }, - { - "id": "1235", - "mutatorName": "StringLiteral", - "replacement": "\"\"", - "statusReason": "src/modules/game/helpers/game.helpers.ts(139,65): error TS2367: This comparison appears to be unintentional because the types '\"werewolf\" | \"big-bad-wolf\" | \"accursed-wolf-father\" | \"white-werewolf\" | \"villager\" | \"villager-villager\" | \"seer\" | \"cupid\" | \"witch\" | \"hunter\" | \"little-girl\" | \"defender\" | ... 17 more ... | \"devoted-servant\"' and '\"\"' have no overlap.\n", - "status": "CompileError", - "static": false, - "coveredBy": [ - "303", - "305", - "306", - "307", - "308", - "500", - "501", - "553", - "554", - "982" - ], - "location": { - "end": { - "column": 96, - "line": 139 + "line": 225 }, "start": { - "column": 89, - "line": 139 + "column": 115, + "line": 221 } } } @@ -57029,95 +57057,6 @@ "src/modules/game/helpers/game.mutators.ts": { "language": "typescript", "mutants": [ - { - "id": "1364", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/modules/game/helpers/game.mutators.ts(16,105): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", - "status": "CompileError", - "static": false, - "killedBy": [], - "coveredBy": [ - "366", - "370", - "399", - "405", - "410", - "418", - "422", - "423", - "424", - "425", - "426", - "427", - "428", - "430", - "435", - "437", - "439", - "443", - "444", - "451", - "453", - "455", - "458", - "459", - "460", - "462", - "588", - "589", - "590", - "591", - "592", - "593", - "594", - "595", - "596", - "604", - "639", - "640", - "641", - "657", - "662", - "682", - "683", - "749", - "1148", - "1149", - "1150", - "1151", - "1152", - "1217", - "1218", - "1219", - "1220", - "1221", - "1222", - "1224", - "1227", - "1228", - "1229", - "1302", - "1303", - "1304", - "1306", - "1307", - "1312", - "1313", - "1315", - "1316" - ], - "location": { - "end": { - "column": 2, - "line": 24 - }, - "start": { - "column": 110, - "line": 16 - } - } - }, { "id": "1365", "mutatorName": "ArrowFunction", @@ -58690,37 +58629,6 @@ } } }, - { - "id": "1406", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/modules/game/helpers/game.mutators.ts(71,69): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", - "status": "CompileError", - "static": false, - "killedBy": [], - "coveredBy": [ - "588", - "648", - "649", - "666", - "676", - "682", - "748", - "1231", - "1317", - "1318" - ], - "location": { - "end": { - "column": 2, - "line": 76 - }, - "start": { - "column": 74, - "line": 71 - } - } - }, { "id": "1407", "mutatorName": "BlockStatement", @@ -59033,6 +58941,124 @@ "line": 91 } } + }, + { + "id": "1364", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/modules/game/helpers/game.mutators.ts(16,105): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", + "status": "CompileError", + "static": false, + "coveredBy": [ + "366", + "370", + "399", + "405", + "410", + "418", + "422", + "423", + "424", + "425", + "426", + "427", + "428", + "430", + "435", + "437", + "439", + "443", + "444", + "451", + "453", + "455", + "458", + "459", + "460", + "462", + "588", + "589", + "590", + "591", + "592", + "593", + "594", + "595", + "596", + "604", + "639", + "640", + "641", + "657", + "662", + "682", + "683", + "749", + "1148", + "1149", + "1150", + "1151", + "1152", + "1217", + "1218", + "1219", + "1220", + "1221", + "1222", + "1224", + "1227", + "1228", + "1229", + "1302", + "1303", + "1304", + "1306", + "1307", + "1312", + "1313", + "1315", + "1316" + ], + "location": { + "end": { + "column": 2, + "line": 24 + }, + "start": { + "column": 110, + "line": 16 + } + } + }, + { + "id": "1406", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/modules/game/helpers/game.mutators.ts(71,69): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", + "status": "CompileError", + "static": false, + "coveredBy": [ + "588", + "648", + "649", + "666", + "676", + "682", + "748", + "1231", + "1317", + "1318" + ], + "location": { + "end": { + "column": 2, + "line": 76 + }, + "start": { + "column": 74, + "line": 71 + } + } } ], "source": "import type { Types } from \"mongoose\";\n\nimport type { PlayerAttributeName } from \"@/modules/game/types/player/player-attribute/player-attribute.types\";\nimport type { GameSource } from \"@/modules/game/types/game.types\";\nimport { createGameAdditionalCard } from \"@/modules/game/helpers/game-additional-card/game-additional-card.factory\";\nimport type { GameAdditionalCard } from \"@/modules/game/schemas/game-additional-card/game-additional-card.schema\";\nimport { createGame } from \"@/modules/game/helpers/game.factory\";\nimport { getPlayerWithId } from \"@/modules/game/helpers/game.helpers\";\nimport { createPlayerAttribute } from \"@/modules/game/helpers/player/player-attribute/player-attribute.factory\";\nimport { createPlayer } from \"@/modules/game/helpers/player/player.factory\";\nimport type { GamePlay } from \"@/modules/game/schemas/game-play/game-play.schema\";\nimport type { Game } from \"@/modules/game/schemas/game.schema\";\nimport type { PlayerAttribute } from \"@/modules/game/schemas/player/player-attribute/player-attribute.schema\";\nimport type { Player } from \"@/modules/game/schemas/player/player.schema\";\n\nfunction updatePlayerInGame(playerId: Types.ObjectId, playerDataToUpdate: Partial, game: Game): Game {\n const clonedGame = createGame(game);\n const playerIdx = clonedGame.players.findIndex(player => player._id.equals(playerId));\n if (playerIdx !== -1) {\n const clonedPlayer = createPlayer(clonedGame.players[playerIdx]);\n clonedGame.players.splice(playerIdx, 1, createPlayer(Object.assign(clonedPlayer, playerDataToUpdate)));\n }\n return clonedGame;\n}\n\nfunction addPlayerAttributeInGame(playerId: Types.ObjectId, game: Game, attribute: PlayerAttribute): Game {\n const clonedGame = createGame(game);\n const player = getPlayerWithId(clonedGame, playerId);\n if (!player) {\n return clonedGame;\n }\n player.attributes.push(createPlayerAttribute(attribute));\n\n return updatePlayerInGame(playerId, player, clonedGame);\n}\n\nfunction addPlayersAttributeInGame(playerIds: Types.ObjectId[], game: Game, attribute: PlayerAttribute): Game {\n const clonedGame = createGame(game);\n clonedGame.players = clonedGame.players.map(player => {\n if (playerIds.find(playerId => playerId.equals(player._id))) {\n player.attributes.push(createPlayerAttribute(attribute));\n }\n return player;\n });\n\n return clonedGame;\n}\n\nfunction removePlayerAttributeByNameInGame(playerId: Types.ObjectId, game: Game, attributeName: PlayerAttributeName): Game {\n const clonedGame = createGame(game);\n const player = getPlayerWithId(clonedGame, playerId);\n if (!player) {\n return clonedGame;\n }\n player.attributes = player.attributes.filter(({ name }) => name !== attributeName);\n\n return updatePlayerInGame(playerId, player, clonedGame);\n}\n\nfunction removePlayerAttributeByNameAndSourceInGame(playerId: Types.ObjectId, game: Game, attributeName: PlayerAttributeName, attributeSource: GameSource): Game {\n const clonedGame = createGame(game);\n const player = getPlayerWithId(clonedGame, playerId);\n if (!player) {\n return clonedGame;\n }\n player.attributes = player.attributes.filter(({ name, source }) => name !== attributeName || source !== attributeSource);\n\n return updatePlayerInGame(playerId, player, clonedGame);\n}\n\nfunction prependUpcomingPlayInGame(gamePlay: GamePlay, game: Game): Game {\n const clonedGame = createGame(game);\n clonedGame.upcomingPlays.unshift(gamePlay);\n\n return clonedGame;\n}\n\nfunction appendUpcomingPlayInGame(gamePlay: GamePlay, game: Game): Game {\n const clonedGame = createGame(game);\n clonedGame.upcomingPlays.push(gamePlay);\n\n return clonedGame;\n}\n\nfunction updateAdditionalCardInGame(cardId: Types.ObjectId, cardDataToUpdate: Partial, game: Game): Game {\n const clonedGame = createGame(game);\n if (!clonedGame.additionalCards) {\n return clonedGame;\n }\n const cardIdx = clonedGame.additionalCards.findIndex(card => card._id.equals(cardId));\n if (cardIdx !== -1) {\n const clonedCard = createGameAdditionalCard(clonedGame.additionalCards[cardIdx]);\n clonedGame.additionalCards.splice(cardIdx, 1, createGameAdditionalCard(Object.assign(clonedCard, cardDataToUpdate)));\n }\n return clonedGame;\n}\n\nexport {\n updatePlayerInGame,\n addPlayerAttributeInGame,\n addPlayersAttributeInGame,\n removePlayerAttributeByNameInGame,\n removePlayerAttributeByNameAndSourceInGame,\n prependUpcomingPlayInGame,\n appendUpcomingPlayInGame,\n updateAdditionalCardInGame,\n};" @@ -59880,6 +59906,7 @@ "1363" ], "coveredBy": [ + "420", "1363" ], "location": { @@ -66935,55 +66962,6 @@ "src/modules/game/helpers/player/player-death/player-death.factory.ts": { "language": "typescript", "mutants": [ - { - "id": "1596", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/modules/game/helpers/player/player-death/player-death.factory.ts(7,55): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", - "status": "CompileError", - "static": false, - "killedBy": [], - "coveredBy": [ - "368", - "382", - "386", - "400", - "401", - "402", - "403", - "441", - "588", - "645", - "673", - "682", - "683", - "1422", - "1423", - "1424", - "1505", - "1506", - "1507", - "1508", - "1509", - "1510", - "1511", - "1512", - "1513", - "1514", - "1515", - "1516" - ], - "location": { - "end": { - "column": 2, - "line": 9 - }, - "start": { - "column": 67, - "line": 7 - } - } - }, { "id": "1597", "mutatorName": "BlockStatement", @@ -68003,6 +67981,54 @@ "line": 94 } } + }, + { + "id": "1596", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/modules/game/helpers/player/player-death/player-death.factory.ts(7,55): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", + "status": "CompileError", + "static": false, + "coveredBy": [ + "368", + "382", + "386", + "400", + "401", + "402", + "403", + "441", + "588", + "645", + "673", + "682", + "683", + "1422", + "1423", + "1424", + "1505", + "1506", + "1507", + "1508", + "1509", + "1510", + "1511", + "1512", + "1513", + "1514", + "1515", + "1516" + ], + "location": { + "end": { + "column": 2, + "line": 9 + }, + "start": { + "column": 67, + "line": 7 + } + } } ], "source": "import { plainToInstance } from \"class-transformer\";\n\nimport { PlayerDeath } from \"@/modules/game/schemas/player/player-death/player-death.schema\";\n\nimport { DEFAULT_PLAIN_TO_INSTANCE_OPTIONS } from \"@/shared/validation/constants/validation.constants\";\n\nfunction createPlayerDeath(playerDeath: PlayerDeath): PlayerDeath {\n return plainToInstance(PlayerDeath, playerDeath, DEFAULT_PLAIN_TO_INSTANCE_OPTIONS);\n}\n\nfunction createPlayerDiseaseByRustySwordKnightDeath(playerDeath: Partial = {}): PlayerDeath {\n return createPlayerDeath({\n cause: \"disease\",\n source: \"rusty-sword-knight\",\n ...playerDeath,\n });\n}\n\nfunction createPlayerBrokenHeartByCupidDeath(playerDeath: Partial = {}): PlayerDeath {\n return createPlayerDeath({\n cause: \"broken-heart\",\n source: \"cupid\",\n ...playerDeath,\n });\n}\n\nfunction createPlayerReconsiderPardonBySurvivorsDeath(playerDeath: Partial = {}): PlayerDeath {\n return createPlayerDeath({\n cause: \"reconsider-pardon\",\n source: \"survivors\",\n ...playerDeath,\n });\n}\n\nfunction createPlayerVoteScapegoatedBySurvivorsDeath(playerDeath: Partial = {}): PlayerDeath {\n return createPlayerDeath({\n cause: \"vote-scapegoated\",\n source: \"survivors\",\n ...playerDeath,\n });\n}\n\nfunction createPlayerVoteBySheriffDeath(playerDeath: Partial = {}): PlayerDeath {\n return createPlayerDeath({\n cause: \"vote\",\n source: \"sheriff\",\n ...playerDeath,\n });\n}\n\nfunction createPlayerVoteBySurvivorsDeath(playerDeath: Partial = {}): PlayerDeath {\n return createPlayerDeath({\n cause: \"vote\",\n source: \"survivors\",\n ...playerDeath,\n });\n}\n\nfunction createPlayerShotByHunterDeath(playerDeath: Partial = {}): PlayerDeath {\n return createPlayerDeath({\n cause: \"shot\",\n source: \"hunter\",\n ...playerDeath,\n });\n}\n\nfunction createPlayerEatenByWhiteWerewolfDeath(playerDeath: Partial = {}): PlayerDeath {\n return createPlayerDeath({\n cause: \"eaten\",\n source: \"white-werewolf\",\n ...playerDeath,\n });\n}\n\nfunction createPlayerEatenByBigBadWolfDeath(playerDeath: Partial = {}): PlayerDeath {\n return createPlayerDeath({\n cause: \"eaten\",\n source: \"big-bad-wolf\",\n ...playerDeath,\n });\n}\n\nfunction createPlayerEatenByWerewolvesDeath(playerDeath: Partial = {}): PlayerDeath {\n return createPlayerDeath({\n cause: \"eaten\",\n source: \"werewolves\",\n ...playerDeath,\n });\n}\n\nfunction createPlayerDeathPotionByWitchDeath(playerDeath: Partial = {}): PlayerDeath {\n return createPlayerDeath({\n cause: \"death-potion\",\n source: \"witch\",\n ...playerDeath,\n });\n}\n\nexport {\n createPlayerDiseaseByRustySwordKnightDeath,\n createPlayerBrokenHeartByCupidDeath,\n createPlayerReconsiderPardonBySurvivorsDeath,\n createPlayerVoteScapegoatedBySurvivorsDeath,\n createPlayerVoteBySheriffDeath,\n createPlayerVoteBySurvivorsDeath,\n createPlayerShotByHunterDeath,\n createPlayerEatenByWhiteWerewolfDeath,\n createPlayerEatenByBigBadWolfDeath,\n createPlayerEatenByWerewolvesDeath,\n createPlayerDeathPotionByWitchDeath,\n createPlayerDeath,\n};" @@ -68011,13 +68037,16 @@ "language": "typescript", "mutants": [ { - "id": "1641", - "mutatorName": "BlockStatement", + "id": "1642", + "mutatorName": "ObjectLiteral", "replacement": "{}", - "statusReason": "src/modules/game/helpers/player/player.factory.ts(9,40): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", - "status": "CompileError", + "statusReason": "Error: expect(received).toStrictEqual(expected) // deep equality\n\n- Expected - 0\n+ Received + 1\n\n@@ -8,10 +8,11 @@\n \"remainingPhases\": undefined,\n \"source\": \"fox\",\n },\n ],\n \"death\": undefined,\n+ \"extra\": \"extra\",\n \"group\": undefined,\n \"isAlive\": true,\n \"name\": \"Toto\",\n \"position\": 1,\n \"role\": PlayerRole {\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/helpers/player/player.factory.spec.ts:39:55)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "status": "Killed", + "testsCompleted": 92, "static": false, - "killedBy": [], + "killedBy": [ + "1597" + ], "coveredBy": [ "366", "370", @@ -68115,19 +68144,19 @@ ], "location": { "end": { - "column": 2, - "line": 11 + "column": 121, + "line": 10 }, "start": { - "column": 47, - "line": 9 + "column": 50, + "line": 10 } } }, { - "id": "1642", - "mutatorName": "ObjectLiteral", - "replacement": "{}", + "id": "1643", + "mutatorName": "BooleanLiteral", + "replacement": "false", "statusReason": "Error: expect(received).toStrictEqual(expected) // deep equality\n\n- Expected - 0\n+ Received + 1\n\n@@ -8,10 +8,11 @@\n \"remainingPhases\": undefined,\n \"source\": \"fox\",\n },\n ],\n \"death\": undefined,\n+ \"extra\": \"extra\",\n \"group\": undefined,\n \"isAlive\": true,\n \"name\": \"Toto\",\n \"position\": 1,\n \"role\": PlayerRole {\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/helpers/player/player.factory.spec.ts:39:55)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", "status": "Killed", "testsCompleted": 92, @@ -68232,26 +68261,112 @@ ], "location": { "end": { - "column": 121, + "column": 119, "line": 10 }, "start": { - "column": 50, + "column": 115, "line": 10 } } }, { - "id": "1643", + "id": "1644", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/modules/game/helpers/player/player.factory.ts(13,52): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", + "status": "CompileError", + "static": false, + "killedBy": [], + "coveredBy": [ + "590", + "591", + "592", + "593", + "594", + "1598", + "1599" + ], + "location": { + "end": { + "column": 2, + "line": 15 + }, + "start": { + "column": 63, + "line": 13 + } + } + }, + { + "id": "1645", + "mutatorName": "ObjectLiteral", + "replacement": "{}", + "statusReason": "Error: expect(received).toStrictEqual(expected) // deep equality\n\n- Expected - 0\n+ Received + 1\n\n@@ -11,10 +11,11 @@\n ],\n \"death\": PlayerDeath {\n \"cause\": \"eaten\",\n \"source\": \"rusty-sword-knight\",\n },\n+ \"extra\": \"extra\",\n \"group\": undefined,\n \"isAlive\": false,\n \"name\": \"Toto\",\n \"position\": 1,\n \"role\": PlayerRole {\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/helpers/player/player.factory.spec.ts:72:59)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "status": "Killed", + "testsCompleted": 7, + "static": false, + "killedBy": [ + "1599" + ], + "coveredBy": [ + "590", + "591", + "592", + "593", + "594", + "1598", + "1599" + ], + "location": { + "end": { + "column": 129, + "line": 14 + }, + "start": { + "column": 58, + "line": 14 + } + } + }, + { + "id": "1646", "mutatorName": "BooleanLiteral", "replacement": "false", - "statusReason": "Error: expect(received).toStrictEqual(expected) // deep equality\n\n- Expected - 0\n+ Received + 1\n\n@@ -8,10 +8,11 @@\n \"remainingPhases\": undefined,\n \"source\": \"fox\",\n },\n ],\n \"death\": undefined,\n+ \"extra\": \"extra\",\n \"group\": undefined,\n \"isAlive\": true,\n \"name\": \"Toto\",\n \"position\": 1,\n \"role\": PlayerRole {\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/helpers/player/player.factory.spec.ts:39:55)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "statusReason": "Error: expect(received).toStrictEqual(expected) // deep equality\n\n- Expected - 0\n+ Received + 1\n\n@@ -11,10 +11,11 @@\n ],\n \"death\": PlayerDeath {\n \"cause\": \"death-potion\",\n \"source\": \"survivors\",\n },\n+ \"extra\": \"extra\",\n \"group\": undefined,\n \"isAlive\": false,\n \"name\": \"Toto\",\n \"position\": 1,\n \"role\": PlayerRole {\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/helpers/player/player.factory.spec.ts:72:59)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", "status": "Killed", - "testsCompleted": 92, + "testsCompleted": 7, "static": false, "killedBy": [ - "1597" + "1599" ], + "coveredBy": [ + "590", + "591", + "592", + "593", + "594", + "1598", + "1599" + ], + "location": { + "end": { + "column": 127, + "line": 14 + }, + "start": { + "column": 123, + "line": 14 + } + } + }, + { + "id": "1641", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/modules/game/helpers/player/player.factory.ts(9,40): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", + "status": "CompileError", + "static": false, "coveredBy": [ "366", "370", @@ -68347,104 +68462,14 @@ "1596", "1597" ], - "location": { - "end": { - "column": 119, - "line": 10 - }, - "start": { - "column": 115, - "line": 10 - } - } - }, - { - "id": "1644", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/modules/game/helpers/player/player.factory.ts(13,52): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", - "status": "CompileError", - "static": false, - "killedBy": [], - "coveredBy": [ - "590", - "591", - "592", - "593", - "594", - "1598", - "1599" - ], "location": { "end": { "column": 2, - "line": 15 - }, - "start": { - "column": 63, - "line": 13 - } - } - }, - { - "id": "1645", - "mutatorName": "ObjectLiteral", - "replacement": "{}", - "statusReason": "Error: expect(received).toStrictEqual(expected) // deep equality\n\n- Expected - 0\n+ Received + 1\n\n@@ -11,10 +11,11 @@\n ],\n \"death\": PlayerDeath {\n \"cause\": \"eaten\",\n \"source\": \"rusty-sword-knight\",\n },\n+ \"extra\": \"extra\",\n \"group\": undefined,\n \"isAlive\": false,\n \"name\": \"Toto\",\n \"position\": 1,\n \"role\": PlayerRole {\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/helpers/player/player.factory.spec.ts:72:59)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", - "status": "Killed", - "testsCompleted": 7, - "static": false, - "killedBy": [ - "1599" - ], - "coveredBy": [ - "590", - "591", - "592", - "593", - "594", - "1598", - "1599" - ], - "location": { - "end": { - "column": 129, - "line": 14 - }, - "start": { - "column": 58, - "line": 14 - } - } - }, - { - "id": "1646", - "mutatorName": "BooleanLiteral", - "replacement": "false", - "statusReason": "Error: expect(received).toStrictEqual(expected) // deep equality\n\n- Expected - 0\n+ Received + 1\n\n@@ -11,10 +11,11 @@\n ],\n \"death\": PlayerDeath {\n \"cause\": \"death-potion\",\n \"source\": \"survivors\",\n },\n+ \"extra\": \"extra\",\n \"group\": undefined,\n \"isAlive\": false,\n \"name\": \"Toto\",\n \"position\": 1,\n \"role\": PlayerRole {\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/helpers/player/player.factory.spec.ts:72:59)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", - "status": "Killed", - "testsCompleted": 7, - "static": false, - "killedBy": [ - "1599" - ], - "coveredBy": [ - "590", - "591", - "592", - "593", - "594", - "1598", - "1599" - ], - "location": { - "end": { - "column": 127, - "line": 14 + "line": 11 }, "start": { - "column": 123, - "line": 14 + "column": 47, + "line": 9 } } } @@ -70268,16 +70293,16 @@ "location": { "end": { "column": 4, - "line": 13 + "line": 14 }, "start": { "column": 82, - "line": 11 + "line": 12 } } } ], - "source": "import { GameFeedback } from \"@/modules/game/schemas/game-feedback/game-feedback.schema\";\nimport { GameFeedbackDocument, GameFeedbackToInsert } from \"@/modules/game/types/game-feedback/game-feedback.types\";\nimport { Injectable } from \"@nestjs/common\";\nimport { InjectModel } from \"@nestjs/mongoose\";\nimport { Model } from \"mongoose\";\n\n@Injectable()\nexport class GameFeedbackRepository {\n public constructor(@InjectModel(GameFeedback.name) private readonly gameFeedbackModel: Model) {}\n\n public async create(gameFeedback: GameFeedbackToInsert): Promise {\n return this.gameFeedbackModel.create(gameFeedback);\n }\n}" + "source": "import { Injectable } from \"@nestjs/common\";\nimport { InjectModel } from \"@nestjs/mongoose\";\nimport { Model } from \"mongoose\";\n\nimport { GameFeedbackDocument, GameFeedbackToInsert } from \"@/modules/game/types/game-feedback/game-feedback.types\";\nimport { GameFeedback } from \"@/modules/game/schemas/game-feedback/game-feedback.schema\";\n\n@Injectable()\nexport class GameFeedbackRepository {\n public constructor(@InjectModel(GameFeedback.name) private readonly gameFeedbackModel: Model) {}\n\n public async create(gameFeedback: GameFeedbackToInsert): Promise {\n return this.gameFeedbackModel.create(gameFeedback);\n }\n}" }, "src/modules/game/providers/repositories/game-history-record/game-history-record.repository.ts": { "language": "typescript", @@ -72929,7 +72954,7 @@ } } ], - "source": "import { GAME_POPULATED_FIELDS } from \"@/modules/game/constants/game.constants\";\nimport { Injectable } from \"@nestjs/common\";\nimport { InjectModel } from \"@nestjs/mongoose\";\nimport { Model } from \"mongoose\";\nimport type { FilterQuery, QueryOptions } from \"mongoose\";\n\nimport type { GameDocument } from \"@/modules/game/types/game.types\";\nimport type { CreateGameDto } from \"@/modules/game/dto/create-game/create-game.dto\";\nimport { Game } from \"@/modules/game/schemas/game.schema\";\n\n@Injectable()\nexport class GameRepository {\n public constructor(@InjectModel(Game.name) private readonly gameModel: Model) {}\n\n public async find(filter: FilterQuery = {}): Promise {\n return this.gameModel.find(filter, null, { populate: GAME_POPULATED_FIELDS });\n }\n\n public async findOne(filter: FilterQuery): Promise {\n return this.gameModel.findOne(filter, null, { populate: GAME_POPULATED_FIELDS });\n }\n\n public async create(game: CreateGameDto): Promise {\n return this.gameModel.create(game);\n }\n\n public async updateOne(filter: FilterQuery, game: Partial, options: QueryOptions = {}): Promise {\n return this.gameModel.findOneAndUpdate(filter, game, {\n new: true,\n populate: GAME_POPULATED_FIELDS,\n ...options,\n });\n }\n}" + "source": "import { Injectable } from \"@nestjs/common\";\nimport { InjectModel } from \"@nestjs/mongoose\";\nimport { Model } from \"mongoose\";\nimport type { FilterQuery, QueryOptions } from \"mongoose\";\n\nimport { GAME_POPULATED_FIELDS } from \"@/modules/game/constants/game.constants\";\nimport type { GameDocument } from \"@/modules/game/types/game.types\";\nimport type { CreateGameDto } from \"@/modules/game/dto/create-game/create-game.dto\";\nimport { Game } from \"@/modules/game/schemas/game.schema\";\n\n@Injectable()\nexport class GameRepository {\n public constructor(@InjectModel(Game.name) private readonly gameModel: Model) {}\n\n public async find(filter: FilterQuery = {}): Promise {\n return this.gameModel.find(filter, null, { populate: GAME_POPULATED_FIELDS });\n }\n\n public async findOne(filter: FilterQuery): Promise {\n return this.gameModel.findOne(filter, null, { populate: GAME_POPULATED_FIELDS });\n }\n\n public async create(game: CreateGameDto): Promise {\n return this.gameModel.create(game);\n }\n\n public async updateOne(filter: FilterQuery, game: Partial, options: QueryOptions = {}): Promise {\n return this.gameModel.findOneAndUpdate(filter, game, {\n new: true,\n populate: GAME_POPULATED_FIELDS,\n ...options,\n });\n }\n}" }, "src/modules/game/providers/services/game-event/game-events-generator.service.ts": { "language": "typescript", @@ -72962,11 +72987,11 @@ "location": { "end": { "column": 4, - "line": 30 + "line": 31 }, "start": { "column": 118, - "line": 15 + "line": 16 } } }, @@ -72998,11 +73023,11 @@ "location": { "end": { "column": 39, - "line": 16 + "line": 17 }, "start": { "column": 37, - "line": 16 + "line": 17 } } }, @@ -73034,11 +73059,11 @@ "location": { "end": { "column": 36, - "line": 20 + "line": 21 }, "start": { "column": 9, - "line": 20 + "line": 21 } } }, @@ -73070,11 +73095,11 @@ "location": { "end": { "column": 36, - "line": 20 + "line": 21 }, "start": { "column": 9, - "line": 20 + "line": 21 } } }, @@ -73096,11 +73121,11 @@ "location": { "end": { "column": 6, - "line": 22 + "line": 23 }, "start": { "column": 38, - "line": 20 + "line": 21 } } }, @@ -73135,11 +73160,11 @@ "location": { "end": { "column": 4, - "line": 44 + "line": 45 }, "start": { "column": 87, - "line": 32 + "line": 33 } } }, @@ -73177,11 +73202,11 @@ "location": { "end": { "column": 51, - "line": 33 + "line": 34 }, "start": { "column": 26, - "line": 33 + "line": 34 } } }, @@ -73219,11 +73244,11 @@ "location": { "end": { "column": 51, - "line": 33 + "line": 34 }, "start": { "column": 26, - "line": 33 + "line": 34 } } }, @@ -73261,11 +73286,11 @@ "location": { "end": { "column": 51, - "line": 33 + "line": 34 }, "start": { "column": 26, - "line": 33 + "line": 34 } } }, @@ -73300,11 +73325,11 @@ "location": { "end": { "column": 51, - "line": 33 + "line": 34 }, "start": { "column": 46, - "line": 33 + "line": 34 } } }, @@ -73339,11 +73364,11 @@ "location": { "end": { "column": 82, - "line": 34 + "line": 35 }, "start": { "column": 50, - "line": 34 + "line": 35 } } }, @@ -73378,11 +73403,11 @@ "location": { "end": { "column": 82, - "line": 34 + "line": 35 }, "start": { "column": 68, - "line": 34 + "line": 35 } } }, @@ -73406,11 +73431,11 @@ "location": { "end": { "column": 6, - "line": 43 + "line": 44 }, "start": { "column": 60, - "line": 36 + "line": 37 } } }, @@ -73434,11 +73459,11 @@ "location": { "end": { "column": 61, - "line": 39 + "line": 40 }, "start": { "column": 11, - "line": 39 + "line": 40 } } }, @@ -73462,11 +73487,11 @@ "location": { "end": { "column": 61, - "line": 39 + "line": 40 }, "start": { "column": 11, - "line": 39 + "line": 40 } } }, @@ -73490,11 +73515,11 @@ "location": { "end": { "column": 61, - "line": 39 + "line": 40 }, "start": { "column": 11, - "line": 39 + "line": 40 } } }, @@ -73518,11 +73543,11 @@ "location": { "end": { "column": 34, - "line": 39 + "line": 40 }, "start": { "column": 11, - "line": 39 + "line": 40 } } }, @@ -73546,11 +73571,11 @@ "location": { "end": { "column": 34, - "line": 39 + "line": 40 }, "start": { "column": 11, - "line": 39 + "line": 40 } } }, @@ -73574,11 +73599,11 @@ "location": { "end": { "column": 61, - "line": 39 + "line": 40 }, "start": { "column": 38, - "line": 39 + "line": 40 } } }, @@ -73602,11 +73627,11 @@ "location": { "end": { "column": 61, - "line": 39 + "line": 40 }, "start": { "column": 38, - "line": 39 + "line": 40 } } }, @@ -73624,11 +73649,11 @@ "location": { "end": { "column": 8, - "line": 41 + "line": 42 }, "start": { "column": 63, - "line": 39 + "line": 40 } } }, @@ -73655,11 +73680,11 @@ "location": { "end": { "column": 35, - "line": 42 + "line": 43 }, "start": { "column": 14, - "line": 42 + "line": 43 } } }, @@ -73679,11 +73704,11 @@ "location": { "end": { "column": 4, - "line": 51 + "line": 52 }, "start": { "column": 79, - "line": 46 + "line": 47 } } }, @@ -73703,11 +73728,11 @@ "location": { "end": { "column": 6, - "line": 50 + "line": 51 }, "start": { "column": 28, - "line": 47 + "line": 48 } } }, @@ -73727,11 +73752,11 @@ "location": { "end": { "column": 28, - "line": 48 + "line": 49 }, "start": { "column": 13, - "line": 48 + "line": 49 } } }, @@ -73750,11 +73775,11 @@ "location": { "end": { "column": 4, - "line": 58 + "line": 59 }, "start": { "column": 94, - "line": 53 + "line": 54 } } }, @@ -73773,11 +73798,11 @@ "location": { "end": { "column": 6, - "line": 57 + "line": 58 }, "start": { "column": 28, - "line": 54 + "line": 55 } } }, @@ -73796,11 +73821,11 @@ "location": { "end": { "column": 44, - "line": 55 + "line": 56 }, "start": { "column": 13, - "line": 55 + "line": 56 } } }, @@ -73819,11 +73844,11 @@ "location": { "end": { "column": 4, - "line": 65 + "line": 66 }, "start": { "column": 101, - "line": 60 + "line": 61 } } }, @@ -73842,11 +73867,11 @@ "location": { "end": { "column": 6, - "line": 64 + "line": 65 }, "start": { "column": 28, - "line": 61 + "line": 62 } } }, @@ -73865,11 +73890,11 @@ "location": { "end": { "column": 53, - "line": 62 + "line": 63 }, "start": { "column": 13, - "line": 62 + "line": 63 } } }, @@ -73887,11 +73912,11 @@ "location": { "end": { "column": 4, - "line": 72 + "line": 73 }, "start": { "column": 74, - "line": 67 + "line": 68 } } }, @@ -73909,11 +73934,11 @@ "location": { "end": { "column": 6, - "line": 71 + "line": 72 }, "start": { "column": 28, - "line": 68 + "line": 69 } } }, @@ -73931,11 +73956,11 @@ "location": { "end": { "column": 41, - "line": 69 + "line": 70 }, "start": { "column": 13, - "line": 69 + "line": 70 } } }, @@ -73953,11 +73978,11 @@ "location": { "end": { "column": 60, - "line": 70 + "line": 71 }, "start": { "column": 48, - "line": 70 + "line": 71 } } }, @@ -73976,11 +74001,11 @@ "location": { "end": { "column": 4, - "line": 79 + "line": 80 }, "start": { "column": 87, - "line": 74 + "line": 75 } } }, @@ -73999,11 +74024,11 @@ "location": { "end": { "column": 6, - "line": 78 + "line": 79 }, "start": { "column": 28, - "line": 75 + "line": 76 } } }, @@ -74022,11 +74047,11 @@ "location": { "end": { "column": 37, - "line": 76 + "line": 77 }, "start": { "column": 13, - "line": 76 + "line": 77 } } }, @@ -74045,11 +74070,11 @@ "location": { "end": { "column": 4, - "line": 86 + "line": 87 }, "start": { "column": 83, - "line": 81 + "line": 82 } } }, @@ -74068,11 +74093,11 @@ "location": { "end": { "column": 6, - "line": 85 + "line": 86 }, "start": { "column": 28, - "line": 82 + "line": 83 } } }, @@ -74091,11 +74116,11 @@ "location": { "end": { "column": 32, - "line": 83 + "line": 84 }, "start": { "column": 13, - "line": 83 + "line": 84 } } }, @@ -74114,11 +74139,11 @@ "location": { "end": { "column": 4, - "line": 93 + "line": 94 }, "start": { "column": 85, - "line": 88 + "line": 89 } } }, @@ -74137,11 +74162,11 @@ "location": { "end": { "column": 6, - "line": 92 + "line": 93 }, "start": { "column": 28, - "line": 89 + "line": 90 } } }, @@ -74160,11 +74185,11 @@ "location": { "end": { "column": 35, - "line": 90 + "line": 91 }, "start": { "column": 13, - "line": 90 + "line": 91 } } }, @@ -74182,11 +74207,11 @@ "location": { "end": { "column": 4, - "line": 100 + "line": 101 }, "start": { "column": 88, - "line": 95 + "line": 96 } } }, @@ -74204,11 +74229,11 @@ "location": { "end": { "column": 6, - "line": 99 + "line": 100 }, "start": { "column": 28, - "line": 96 + "line": 97 } } }, @@ -74226,11 +74251,11 @@ "location": { "end": { "column": 41, - "line": 97 + "line": 98 }, "start": { "column": 13, - "line": 97 + "line": 98 } } }, @@ -74248,11 +74273,11 @@ "location": { "end": { "column": 4, - "line": 107 + "line": 108 }, "start": { "column": 88, - "line": 102 + "line": 103 } } }, @@ -74270,11 +74295,11 @@ "location": { "end": { "column": 6, - "line": 106 + "line": 107 }, "start": { "column": 28, - "line": 103 + "line": 104 } } }, @@ -74292,11 +74317,11 @@ "location": { "end": { "column": 41, - "line": 104 + "line": 105 }, "start": { "column": 13, - "line": 104 + "line": 105 } } }, @@ -74330,11 +74355,11 @@ "location": { "end": { "column": 4, - "line": 130 + "line": 131 }, "start": { "column": 121, - "line": 109 + "line": 110 } } }, @@ -74368,11 +74393,11 @@ "location": { "end": { "column": 27, - "line": 110 + "line": 111 }, "start": { "column": 9, - "line": 110 + "line": 111 } } }, @@ -74406,11 +74431,11 @@ "location": { "end": { "column": 27, - "line": 110 + "line": 111 }, "start": { "column": 9, - "line": 110 + "line": 111 } } }, @@ -74444,11 +74469,11 @@ "location": { "end": { "column": 27, - "line": 110 + "line": 111 }, "start": { "column": 9, - "line": 110 + "line": 111 } } }, @@ -74469,11 +74494,11 @@ "location": { "end": { "column": 6, - "line": 112 + "line": 113 }, "start": { "column": 29, - "line": 110 + "line": 111 } } }, @@ -74503,11 +74528,11 @@ "location": { "end": { "column": 83, - "line": 113 + "line": 114 }, "start": { "column": 41, - "line": 113 + "line": 114 } } }, @@ -74536,11 +74561,11 @@ "location": { "end": { "column": 104, - "line": 113 + "line": 114 }, "start": { "column": 84, - "line": 113 + "line": 114 } } }, @@ -74570,11 +74595,11 @@ "location": { "end": { "column": 77, - "line": 114 + "line": 115 }, "start": { "column": 42, - "line": 114 + "line": 115 } } }, @@ -74594,11 +74619,11 @@ "location": { "end": { "column": 105, - "line": 114 + "line": 115 }, "start": { "column": 78, - "line": 114 + "line": 115 } } }, @@ -74631,11 +74656,11 @@ "location": { "end": { "column": 6, - "line": 127 + "line": 128 }, "start": { "column": 92, - "line": 117 + "line": 118 } } }, @@ -74665,11 +74690,11 @@ "location": { "end": { "column": 88, - "line": 118 + "line": 119 }, "start": { "column": 15, - "line": 118 + "line": 119 } } }, @@ -74699,11 +74724,11 @@ "location": { "end": { "column": 112, - "line": 119 + "line": 120 }, "start": { "column": 24, - "line": 119 + "line": 120 } } }, @@ -74733,11 +74758,11 @@ "location": { "end": { "column": 126, - "line": 120 + "line": 121 }, "start": { "column": 31, - "line": 120 + "line": 121 } } }, @@ -74767,11 +74792,11 @@ "location": { "end": { "column": 77, - "line": 121 + "line": 122 }, "start": { "column": 21, - "line": 121 + "line": 122 } } }, @@ -74801,11 +74826,11 @@ "location": { "end": { "column": 102, - "line": 122 + "line": 123 }, "start": { "column": 21, - "line": 122 + "line": 123 } } }, @@ -74835,11 +74860,11 @@ "location": { "end": { "column": 93, - "line": 123 + "line": 124 }, "start": { "column": 16, - "line": 123 + "line": 124 } } }, @@ -74869,11 +74894,11 @@ "location": { "end": { "column": 93, - "line": 124 + "line": 125 }, "start": { "column": 14, - "line": 124 + "line": 125 } } }, @@ -74903,11 +74928,11 @@ "location": { "end": { "column": 98, - "line": 125 + "line": 126 }, "start": { "column": 16, - "line": 125 + "line": 126 } } }, @@ -74937,11 +74962,11 @@ "location": { "end": { "column": 98, - "line": 126 + "line": 127 }, "start": { "column": 16, - "line": 126 + "line": 127 } } }, @@ -74971,11 +74996,11 @@ "location": { "end": { "column": 76, - "line": 129 + "line": 130 }, "start": { "column": 12, - "line": 129 + "line": 130 } } }, @@ -75000,11 +75025,11 @@ "location": { "end": { "column": 4, - "line": 149 + "line": 150 }, "start": { "column": 64, - "line": 132 + "line": 133 } } }, @@ -75029,11 +75054,11 @@ "location": { "end": { "column": 39, - "line": 133 + "line": 134 }, "start": { "column": 37, - "line": 133 + "line": 134 } } }, @@ -75058,11 +75083,11 @@ "location": { "end": { "column": 24, - "line": 134 + "line": 135 }, "start": { "column": 9, - "line": 134 + "line": 135 } } }, @@ -75090,11 +75115,11 @@ "location": { "end": { "column": 24, - "line": 134 + "line": 135 }, "start": { "column": 9, - "line": 134 + "line": 135 } } }, @@ -75122,11 +75147,11 @@ "location": { "end": { "column": 24, - "line": 134 + "line": 135 }, "start": { "column": 9, - "line": 134 + "line": 135 } } }, @@ -75149,11 +75174,11 @@ "location": { "end": { "column": 6, - "line": 136 + "line": 137 }, "start": { "column": 26, - "line": 134 + "line": 135 } } }, @@ -75175,11 +75200,11 @@ "location": { "end": { "column": 6, - "line": 140 + "line": 141 }, "start": { "column": 37, - "line": 137 + "line": 138 } } }, @@ -75201,11 +75226,11 @@ "location": { "end": { "column": 26, - "line": 138 + "line": 139 }, "start": { "column": 13, - "line": 138 + "line": 139 } } }, @@ -75227,11 +75252,11 @@ "location": { "end": { "column": 86, - "line": 141 + "line": 142 }, "start": { "column": 67, - "line": 141 + "line": 142 } } }, @@ -75253,11 +75278,11 @@ "location": { "end": { "column": 31, - "line": 142 + "line": 143 }, "start": { "column": 9, - "line": 142 + "line": 143 } } }, @@ -75279,11 +75304,11 @@ "location": { "end": { "column": 31, - "line": 142 + "line": 143 }, "start": { "column": 9, - "line": 142 + "line": 143 } } }, @@ -75306,11 +75331,11 @@ "location": { "end": { "column": 6, - "line": 147 + "line": 148 }, "start": { "column": 33, - "line": 142 + "line": 143 } } }, @@ -75330,11 +75355,11 @@ "location": { "end": { "column": 8, - "line": 146 + "line": 147 }, "start": { "column": 39, - "line": 143 + "line": 144 } } }, @@ -75354,11 +75379,11 @@ "location": { "end": { "column": 47, - "line": 144 + "line": 145 }, "start": { "column": 15, - "line": 144 + "line": 145 } } }, @@ -75381,11 +75406,11 @@ "location": { "end": { "column": 42, - "line": 145 + "line": 146 }, "start": { "column": 18, - "line": 145 + "line": 146 } } }, @@ -75411,11 +75436,11 @@ "location": { "end": { "column": 4, - "line": 164 + "line": 165 }, "start": { "column": 97, - "line": 151 + "line": 152 } } }, @@ -75441,11 +75466,11 @@ "location": { "end": { "column": 39, - "line": 152 + "line": 153 }, "start": { "column": 37, - "line": 152 + "line": 153 } } }, @@ -75471,11 +75496,11 @@ "location": { "end": { "column": 44, - "line": 153 + "line": 154 }, "start": { "column": 9, - "line": 153 + "line": 154 } } }, @@ -75501,11 +75526,11 @@ "location": { "end": { "column": 44, - "line": 153 + "line": 154 }, "start": { "column": 9, - "line": 153 + "line": 154 } } }, @@ -75531,11 +75556,11 @@ "location": { "end": { "column": 44, - "line": 153 + "line": 154 }, "start": { "column": 9, - "line": 153 + "line": 154 } } }, @@ -75561,11 +75586,11 @@ "location": { "end": { "column": 44, - "line": 153 + "line": 154 }, "start": { "column": 10, - "line": 153 + "line": 154 } } }, @@ -75589,11 +75614,11 @@ "location": { "end": { "column": 6, - "line": 155 + "line": 156 }, "start": { "column": 46, - "line": 153 + "line": 154 } } }, @@ -75615,11 +75640,11 @@ "location": { "end": { "column": 113, - "line": 156 + "line": 157 }, "start": { "column": 72, - "line": 156 + "line": 157 } } }, @@ -75641,11 +75666,11 @@ "location": { "end": { "column": 113, - "line": 156 + "line": 157 }, "start": { "column": 82, - "line": 156 + "line": 157 } } }, @@ -75667,11 +75692,11 @@ "location": { "end": { "column": 113, - "line": 156 + "line": 157 }, "start": { "column": 82, - "line": 156 + "line": 157 } } }, @@ -75693,11 +75718,11 @@ "location": { "end": { "column": 113, - "line": 156 + "line": 157 }, "start": { "column": 82, - "line": 156 + "line": 157 } } }, @@ -75716,11 +75741,11 @@ "location": { "end": { "column": 113, - "line": 156 + "line": 157 }, "start": { "column": 106, - "line": 156 + "line": 157 } } }, @@ -75739,11 +75764,11 @@ "location": { "end": { "column": 28, - "line": 157 + "line": 158 }, "start": { "column": 9, - "line": 157 + "line": 158 } } }, @@ -75762,11 +75787,11 @@ "location": { "end": { "column": 28, - "line": 157 + "line": 158 }, "start": { "column": 9, - "line": 157 + "line": 158 } } }, @@ -75787,11 +75812,11 @@ "location": { "end": { "column": 6, - "line": 162 + "line": 163 }, "start": { "column": 30, - "line": 157 + "line": 158 } } }, @@ -75809,11 +75834,11 @@ "location": { "end": { "column": 8, - "line": 161 + "line": 162 }, "start": { "column": 39, - "line": 158 + "line": 159 } } }, @@ -75831,11 +75856,11 @@ "location": { "end": { "column": 32, - "line": 159 + "line": 160 }, "start": { "column": 15, - "line": 159 + "line": 160 } } }, @@ -75856,11 +75881,11 @@ "location": { "end": { "column": 39, - "line": 160 + "line": 161 }, "start": { "column": 18, - "line": 160 + "line": 161 } } }, @@ -75887,11 +75912,11 @@ "location": { "end": { "column": 4, - "line": 179 + "line": 180 }, "start": { "column": 101, - "line": 166 + "line": 167 } } }, @@ -75918,11 +75943,11 @@ "location": { "end": { "column": 39, - "line": 167 + "line": 168 }, "start": { "column": 37, - "line": 167 + "line": 168 } } }, @@ -75949,11 +75974,11 @@ "location": { "end": { "column": 48, - "line": 168 + "line": 169 }, "start": { "column": 9, - "line": 168 + "line": 169 } } }, @@ -75980,11 +76005,11 @@ "location": { "end": { "column": 48, - "line": 168 + "line": 169 }, "start": { "column": 9, - "line": 168 + "line": 169 } } }, @@ -76011,11 +76036,11 @@ "location": { "end": { "column": 48, - "line": 168 + "line": 169 }, "start": { "column": 9, - "line": 168 + "line": 169 } } }, @@ -76042,11 +76067,11 @@ "location": { "end": { "column": 48, - "line": 168 + "line": 169 }, "start": { "column": 10, - "line": 168 + "line": 169 } } }, @@ -76070,11 +76095,11 @@ "location": { "end": { "column": 6, - "line": 170 + "line": 171 }, "start": { "column": 50, - "line": 168 + "line": 169 } } }, @@ -76097,11 +76122,11 @@ "location": { "end": { "column": 126, - "line": 171 + "line": 172 }, "start": { "column": 80, - "line": 171 + "line": 172 } } }, @@ -76124,11 +76149,11 @@ "location": { "end": { "column": 126, - "line": 171 + "line": 172 }, "start": { "column": 90, - "line": 171 + "line": 172 } } }, @@ -76151,11 +76176,11 @@ "location": { "end": { "column": 126, - "line": 171 + "line": 172 }, "start": { "column": 90, - "line": 171 + "line": 172 } } }, @@ -76178,11 +76203,11 @@ "location": { "end": { "column": 126, - "line": 171 + "line": 172 }, "start": { "column": 90, - "line": 171 + "line": 172 } } }, @@ -76202,11 +76227,11 @@ "location": { "end": { "column": 126, - "line": 171 + "line": 172 }, "start": { "column": 114, - "line": 171 + "line": 172 } } }, @@ -76226,11 +76251,11 @@ "location": { "end": { "column": 88, - "line": 172 + "line": 173 }, "start": { "column": 9, - "line": 172 + "line": 173 } } }, @@ -76250,11 +76275,11 @@ "location": { "end": { "column": 88, - "line": 172 + "line": 173 }, "start": { "column": 9, - "line": 172 + "line": 173 } } }, @@ -76274,11 +76299,11 @@ "location": { "end": { "column": 88, - "line": 172 + "line": 173 }, "start": { "column": 9, - "line": 172 + "line": 173 } } }, @@ -76300,11 +76325,11 @@ "location": { "end": { "column": 88, - "line": 172 + "line": 173 }, "start": { "column": 36, - "line": 172 + "line": 173 } } }, @@ -76326,11 +76351,11 @@ "location": { "end": { "column": 88, - "line": 172 + "line": 173 }, "start": { "column": 36, - "line": 172 + "line": 173 } } }, @@ -76349,11 +76374,11 @@ "location": { "end": { "column": 88, - "line": 172 + "line": 173 }, "start": { "column": 70, - "line": 172 + "line": 173 } } }, @@ -76374,11 +76399,11 @@ "location": { "end": { "column": 6, - "line": 177 + "line": 178 }, "start": { "column": 90, - "line": 172 + "line": 173 } } }, @@ -76396,11 +76421,11 @@ "location": { "end": { "column": 8, - "line": 176 + "line": 177 }, "start": { "column": 39, - "line": 173 + "line": 174 } } }, @@ -76418,11 +76443,11 @@ "location": { "end": { "column": 43, - "line": 174 + "line": 175 }, "start": { "column": 15, - "line": 174 + "line": 175 } } }, @@ -76443,11 +76468,11 @@ "location": { "end": { "column": 43, - "line": 175 + "line": 176 }, "start": { "column": 18, - "line": 175 + "line": 176 } } }, @@ -76472,11 +76497,11 @@ "location": { "end": { "column": 4, - "line": 192 + "line": 193 }, "start": { "column": 93, - "line": 181 + "line": 182 } } }, @@ -76501,11 +76526,11 @@ "location": { "end": { "column": 39, - "line": 182 + "line": 183 }, "start": { "column": 37, - "line": 182 + "line": 183 } } }, @@ -76530,11 +76555,11 @@ "location": { "end": { "column": 40, - "line": 183 + "line": 184 }, "start": { "column": 9, - "line": 183 + "line": 184 } } }, @@ -76559,11 +76584,11 @@ "location": { "end": { "column": 40, - "line": 183 + "line": 184 }, "start": { "column": 9, - "line": 183 + "line": 184 } } }, @@ -76588,11 +76613,11 @@ "location": { "end": { "column": 40, - "line": 183 + "line": 184 }, "start": { "column": 9, - "line": 183 + "line": 184 } } }, @@ -76617,11 +76642,11 @@ "location": { "end": { "column": 40, - "line": 183 + "line": 184 }, "start": { "column": 10, - "line": 183 + "line": 184 } } }, @@ -76645,11 +76670,11 @@ "location": { "end": { "column": 6, - "line": 185 + "line": 186 }, "start": { "column": 42, - "line": 183 + "line": 184 } } }, @@ -76667,11 +76692,11 @@ "location": { "end": { "column": 6, - "line": 189 + "line": 190 }, "start": { "column": 37, - "line": 186 + "line": 187 } } }, @@ -76689,11 +76714,11 @@ "location": { "end": { "column": 20, - "line": 187 + "line": 188 }, "start": { "column": 13, - "line": 187 + "line": 188 } } }, @@ -76717,11 +76742,11 @@ "location": { "end": { "column": 4, - "line": 206 + "line": 207 }, "start": { "column": 95, - "line": 194 + "line": 195 } } }, @@ -76745,11 +76770,11 @@ "location": { "end": { "column": 103, - "line": 195 + "line": 196 }, "start": { "column": 82, - "line": 195 + "line": 196 } } }, @@ -76773,11 +76798,11 @@ "location": { "end": { "column": 101, - "line": 195 + "line": 196 }, "start": { "column": 95, - "line": 195 + "line": 196 } } }, @@ -76801,11 +76826,11 @@ "location": { "end": { "column": 105, - "line": 196 + "line": 197 }, "start": { "column": 83, - "line": 196 + "line": 197 } } }, @@ -76829,11 +76854,11 @@ "location": { "end": { "column": 103, - "line": 196 + "line": 197 }, "start": { "column": 96, - "line": 196 + "line": 197 } } }, @@ -76860,11 +76885,11 @@ "location": { "end": { "column": 153, - "line": 197 + "line": 198 }, "start": { "column": 52, - "line": 197 + "line": 198 } } }, @@ -76891,11 +76916,11 @@ "location": { "end": { "column": 153, - "line": 197 + "line": 198 }, "start": { "column": 52, - "line": 197 + "line": 198 } } }, @@ -76922,11 +76947,11 @@ "location": { "end": { "column": 153, - "line": 197 + "line": 198 }, "start": { "column": 52, - "line": 197 + "line": 198 } } }, @@ -76953,11 +76978,11 @@ "location": { "end": { "column": 100, - "line": 197 + "line": 198 }, "start": { "column": 52, - "line": 197 + "line": 198 } } }, @@ -76984,11 +77009,11 @@ "location": { "end": { "column": 100, - "line": 197 + "line": 198 }, "start": { "column": 52, - "line": 197 + "line": 198 } } }, @@ -77012,11 +77037,11 @@ "location": { "end": { "column": 75, - "line": 197 + "line": 198 }, "start": { "column": 52, - "line": 197 + "line": 198 } } }, @@ -77040,11 +77065,11 @@ "location": { "end": { "column": 100, - "line": 197 + "line": 198 }, "start": { "column": 88, - "line": 197 + "line": 198 } } }, @@ -77069,11 +77094,11 @@ "location": { "end": { "column": 153, - "line": 197 + "line": 198 }, "start": { "column": 104, - "line": 197 + "line": 198 } } }, @@ -77098,11 +77123,11 @@ "location": { "end": { "column": 153, - "line": 197 + "line": 198 }, "start": { "column": 104, - "line": 197 + "line": 198 } } }, @@ -77124,11 +77149,11 @@ "location": { "end": { "column": 128, - "line": 197 + "line": 198 }, "start": { "column": 104, - "line": 197 + "line": 198 } } }, @@ -77150,11 +77175,11 @@ "location": { "end": { "column": 153, - "line": 197 + "line": 198 }, "start": { "column": 141, - "line": 197 + "line": 198 } } }, @@ -77181,11 +77206,11 @@ "location": { "end": { "column": 78, - "line": 199 + "line": 200 }, "start": { "column": 33, - "line": 199 + "line": 200 } } }, @@ -77212,11 +77237,11 @@ "location": { "end": { "column": 78, - "line": 199 + "line": 200 }, "start": { "column": 33, - "line": 199 + "line": 200 } } }, @@ -77243,11 +77268,11 @@ "location": { "end": { "column": 78, - "line": 199 + "line": 200 }, "start": { "column": 33, - "line": 199 + "line": 200 } } }, @@ -77271,11 +77296,11 @@ "location": { "end": { "column": 78, - "line": 199 + "line": 200 }, "start": { "column": 66, - "line": 199 + "line": 200 } } }, @@ -77302,11 +77327,11 @@ "location": { "end": { "column": 117, - "line": 200 + "line": 201 }, "start": { "column": 27, - "line": 200 + "line": 201 } } }, @@ -77333,11 +77358,11 @@ "location": { "end": { "column": 117, - "line": 200 + "line": 201 }, "start": { "column": 27, - "line": 200 + "line": 201 } } }, @@ -77364,11 +77389,11 @@ "location": { "end": { "column": 117, - "line": 200 + "line": 201 }, "start": { "column": 27, - "line": 200 + "line": 201 } } }, @@ -77395,11 +77420,11 @@ "location": { "end": { "column": 75, - "line": 200 + "line": 201 }, "start": { "column": 27, - "line": 200 + "line": 201 } } }, @@ -77426,11 +77451,11 @@ "location": { "end": { "column": 75, - "line": 200 + "line": 201 }, "start": { "column": 27, - "line": 200 + "line": 201 } } }, @@ -77454,11 +77479,11 @@ "location": { "end": { "column": 6, - "line": 205 + "line": 206 }, "start": { "column": 28, - "line": 202 + "line": 203 } } }, @@ -77479,11 +77504,11 @@ "location": { "end": { "column": 42, - "line": 203 + "line": 204 }, "start": { "column": 29, - "line": 203 + "line": 204 } } }, @@ -77503,11 +77528,11 @@ "location": { "end": { "column": 58, - "line": 203 + "line": 204 }, "start": { "column": 45, - "line": 203 + "line": 204 } } }, @@ -77534,11 +77559,11 @@ "location": { "end": { "column": 33, - "line": 204 + "line": 205 }, "start": { "column": 16, - "line": 204 + "line": 205 } } }, @@ -77577,11 +77602,11 @@ "location": { "end": { "column": 4, - "line": 219 + "line": 220 }, "start": { "column": 70, - "line": 208 + "line": 209 } } }, @@ -77620,11 +77645,11 @@ "location": { "end": { "column": 39, - "line": 209 + "line": 210 }, "start": { "column": 37, - "line": 209 + "line": 210 } } }, @@ -77663,11 +77688,11 @@ "location": { "end": { "column": 64, - "line": 210 + "line": 211 }, "start": { "column": 9, - "line": 210 + "line": 211 } } }, @@ -77709,11 +77734,11 @@ "location": { "end": { "column": 64, - "line": 210 + "line": 211 }, "start": { "column": 9, - "line": 210 + "line": 211 } } }, @@ -77755,11 +77780,11 @@ "location": { "end": { "column": 64, - "line": 210 + "line": 211 }, "start": { "column": 9, - "line": 210 + "line": 211 } } }, @@ -77801,11 +77826,11 @@ "location": { "end": { "column": 30, - "line": 210 + "line": 211 }, "start": { "column": 9, - "line": 210 + "line": 211 } } }, @@ -77847,11 +77872,11 @@ "location": { "end": { "column": 30, - "line": 210 + "line": 211 }, "start": { "column": 9, - "line": 210 + "line": 211 } } }, @@ -77880,11 +77905,11 @@ "location": { "end": { "column": 64, - "line": 210 + "line": 211 }, "start": { "column": 34, - "line": 210 + "line": 211 } } }, @@ -77910,11 +77935,11 @@ "location": { "end": { "column": 64, - "line": 210 + "line": 211 }, "start": { "column": 34, - "line": 210 + "line": 211 } } }, @@ -77940,11 +77965,11 @@ "location": { "end": { "column": 64, - "line": 210 + "line": 211 }, "start": { "column": 54, - "line": 210 + "line": 211 } } }, @@ -77980,11 +78005,11 @@ "location": { "end": { "column": 6, - "line": 212 + "line": 213 }, "start": { "column": 66, - "line": 210 + "line": 211 } } }, @@ -78007,11 +78032,11 @@ "location": { "end": { "column": 66, - "line": 213 + "line": 214 }, "start": { "column": 37, - "line": 213 + "line": 214 } } }, @@ -78034,11 +78059,11 @@ "location": { "end": { "column": 64, - "line": 213 + "line": 214 }, "start": { "column": 45, - "line": 213 + "line": 214 } } }, @@ -78061,11 +78086,11 @@ "location": { "end": { "column": 72, - "line": 214 + "line": 215 }, "start": { "column": 60, - "line": 214 + "line": 215 } } }, @@ -78088,11 +78113,11 @@ "location": { "end": { "column": 104, - "line": 215 + "line": 216 }, "start": { "column": 9, - "line": 215 + "line": 216 } } }, @@ -78115,11 +78140,11 @@ "location": { "end": { "column": 104, - "line": 215 + "line": 216 }, "start": { "column": 9, - "line": 215 + "line": 216 } } }, @@ -78142,11 +78167,11 @@ "location": { "end": { "column": 104, - "line": 215 + "line": 216 }, "start": { "column": 9, - "line": 215 + "line": 216 } } }, @@ -78169,11 +78194,11 @@ "location": { "end": { "column": 53, - "line": 215 + "line": 216 }, "start": { "column": 9, - "line": 215 + "line": 216 } } }, @@ -78196,11 +78221,11 @@ "location": { "end": { "column": 53, - "line": 215 + "line": 216 }, "start": { "column": 9, - "line": 215 + "line": 216 } } }, @@ -78226,11 +78251,11 @@ "location": { "end": { "column": 34, - "line": 215 + "line": 216 }, "start": { "column": 9, - "line": 215 + "line": 216 } } }, @@ -78256,11 +78281,11 @@ "location": { "end": { "column": 34, - "line": 215 + "line": 216 }, "start": { "column": 9, - "line": 215 + "line": 216 } } }, @@ -78283,11 +78308,11 @@ "location": { "end": { "column": 34, - "line": 215 + "line": 216 }, "start": { "column": 29, - "line": 215 + "line": 216 } } }, @@ -78308,11 +78333,11 @@ "location": { "end": { "column": 6, - "line": 217 + "line": 218 }, "start": { "column": 106, - "line": 215 + "line": 216 } } }, @@ -78339,11 +78364,11 @@ "location": { "end": { "column": 4, - "line": 239 + "line": 240 }, "start": { "column": 116, - "line": 221 + "line": 222 } } }, @@ -78370,11 +78395,11 @@ "location": { "end": { "column": 39, - "line": 222 + "line": 223 }, "start": { "column": 37, - "line": 222 + "line": 223 } } }, @@ -78401,11 +78426,11 @@ "location": { "end": { "column": 55, - "line": 223 + "line": 224 }, "start": { "column": 9, - "line": 223 + "line": 224 } } }, @@ -78432,11 +78457,11 @@ "location": { "end": { "column": 55, - "line": 223 + "line": 224 }, "start": { "column": 9, - "line": 223 + "line": 224 } } }, @@ -78463,11 +78488,11 @@ "location": { "end": { "column": 55, - "line": 223 + "line": 224 }, "start": { "column": 9, - "line": 223 + "line": 224 } } }, @@ -78494,11 +78519,11 @@ "location": { "end": { "column": 55, - "line": 223 + "line": 224 }, "start": { "column": 10, - "line": 223 + "line": 224 } } }, @@ -78521,11 +78546,11 @@ "location": { "end": { "column": 6, - "line": 225 + "line": 226 }, "start": { "column": 57, - "line": 223 + "line": 224 } } }, @@ -78549,11 +78574,11 @@ "location": { "end": { "column": 118, - "line": 226 + "line": 227 }, "start": { "column": 9, - "line": 226 + "line": 227 } } }, @@ -78577,11 +78602,11 @@ "location": { "end": { "column": 118, - "line": 226 + "line": 227 }, "start": { "column": 9, - "line": 226 + "line": 227 } } }, @@ -78602,11 +78627,11 @@ "location": { "end": { "column": 96, - "line": 226 + "line": 227 }, "start": { "column": 85, - "line": 226 + "line": 227 } } }, @@ -78627,11 +78652,11 @@ "location": { "end": { "column": 105, - "line": 226 + "line": 227 }, "start": { "column": 98, - "line": 226 + "line": 227 } } }, @@ -78652,11 +78677,11 @@ "location": { "end": { "column": 117, - "line": 226 + "line": 227 }, "start": { "column": 107, - "line": 226 + "line": 227 } } }, @@ -78677,11 +78702,11 @@ "location": { "end": { "column": 6, - "line": 231 + "line": 232 }, "start": { "column": 120, - "line": 226 + "line": 227 } } }, @@ -78699,11 +78724,11 @@ "location": { "end": { "column": 8, - "line": 230 + "line": 231 }, "start": { "column": 39, - "line": 227 + "line": 228 } } }, @@ -78721,11 +78746,11 @@ "location": { "end": { "column": 40, - "line": 228 + "line": 229 }, "start": { "column": 15, - "line": 228 + "line": 229 } } }, @@ -78743,11 +78768,11 @@ "location": { "end": { "column": 57, - "line": 229 + "line": 230 }, "start": { "column": 50, - "line": 229 + "line": 230 } } }, @@ -78771,11 +78796,11 @@ "location": { "end": { "column": 101, - "line": 232 + "line": 233 }, "start": { "column": 9, - "line": 232 + "line": 233 } } }, @@ -78799,11 +78824,11 @@ "location": { "end": { "column": 101, - "line": 232 + "line": 233 }, "start": { "column": 9, - "line": 232 + "line": 233 } } }, @@ -78824,11 +78849,11 @@ "location": { "end": { "column": 88, - "line": 232 + "line": 233 }, "start": { "column": 79, - "line": 232 + "line": 233 } } }, @@ -78849,11 +78874,11 @@ "location": { "end": { "column": 100, - "line": 232 + "line": 233 }, "start": { "column": 90, - "line": 232 + "line": 233 } } }, @@ -78874,11 +78899,11 @@ "location": { "end": { "column": 6, - "line": 237 + "line": 238 }, "start": { "column": 103, - "line": 232 + "line": 233 } } }, @@ -78896,11 +78921,11 @@ "location": { "end": { "column": 8, - "line": 236 + "line": 237 }, "start": { "column": 39, - "line": 233 + "line": 234 } } }, @@ -78918,11 +78943,11 @@ "location": { "end": { "column": 34, - "line": 234 + "line": 235 }, "start": { "column": 15, - "line": 234 + "line": 235 } } }, @@ -78940,11 +78965,11 @@ "location": { "end": { "column": 67, - "line": 235 + "line": 236 }, "start": { "column": 58, - "line": 235 + "line": 236 } } }, @@ -78971,11 +78996,11 @@ "location": { "end": { "column": 4, - "line": 257 + "line": 258 }, "start": { "column": 65, - "line": 241 + "line": 242 } } }, @@ -79002,11 +79027,11 @@ "location": { "end": { "column": 39, - "line": 242 + "line": 243 }, "start": { "column": 37, - "line": 242 + "line": 243 } } }, @@ -79033,11 +79058,11 @@ "location": { "end": { "column": 100, - "line": 243 + "line": 244 }, "start": { "column": 78, - "line": 243 + "line": 244 } } }, @@ -79064,11 +79089,11 @@ "location": { "end": { "column": 73, - "line": 244 + "line": 245 }, "start": { "column": 9, - "line": 244 + "line": 245 } } }, @@ -79095,11 +79120,11 @@ "location": { "end": { "column": 73, - "line": 244 + "line": 245 }, "start": { "column": 9, - "line": 244 + "line": 245 } } }, @@ -79126,11 +79151,11 @@ "location": { "end": { "column": 73, - "line": 244 + "line": 245 }, "start": { "column": 9, - "line": 244 + "line": 245 } } }, @@ -79160,11 +79185,11 @@ "location": { "end": { "column": 44, - "line": 244 + "line": 245 }, "start": { "column": 9, - "line": 244 + "line": 245 } } }, @@ -79194,11 +79219,11 @@ "location": { "end": { "column": 44, - "line": 244 + "line": 245 }, "start": { "column": 9, - "line": 244 + "line": 245 } } }, @@ -79225,11 +79250,11 @@ "location": { "end": { "column": 33, - "line": 244 + "line": 245 }, "start": { "column": 9, - "line": 244 + "line": 245 } } }, @@ -79256,11 +79281,11 @@ "location": { "end": { "column": 44, - "line": 244 + "line": 245 }, "start": { "column": 38, - "line": 244 + "line": 245 } } }, @@ -79281,11 +79306,11 @@ "location": { "end": { "column": 6, - "line": 249 + "line": 250 }, "start": { "column": 75, - "line": 244 + "line": 245 } } }, @@ -79303,11 +79328,11 @@ "location": { "end": { "column": 8, - "line": 248 + "line": 249 }, "start": { "column": 39, - "line": 245 + "line": 246 } } }, @@ -79325,11 +79350,11 @@ "location": { "end": { "column": 45, - "line": 246 + "line": 247 }, "start": { "column": 15, - "line": 246 + "line": 247 } } }, @@ -79350,11 +79375,11 @@ "location": { "end": { "column": 45, - "line": 247 + "line": 248 }, "start": { "column": 18, - "line": 247 + "line": 248 } } }, @@ -79384,11 +79409,11 @@ "location": { "end": { "column": 6, - "line": 256 + "line": 257 }, "start": { "column": 12, - "line": 250 + "line": 251 } } }, @@ -79415,11 +79440,11 @@ "location": { "end": { "column": 8, - "line": 255 + "line": 256 }, "start": { "column": 23, - "line": 252 + "line": 253 } } }, @@ -79446,11 +79471,11 @@ "location": { "end": { "column": 33, - "line": 253 + "line": 254 }, "start": { "column": 15, - "line": 253 + "line": 254 } } }, @@ -79477,16 +79502,16 @@ "location": { "end": { "column": 42, - "line": 254 + "line": 255 }, "start": { "column": 18, - "line": 254 + "line": 255 } } } ], - "source": "import { GAME_EVENT_PRIORITY_LIST_ON_DAYS, GAME_EVENT_PRIORITY_LIST_ON_NIGHTS } from \"@/modules/game/constants/game-event/game-event.constants\";\nimport { createGameEvent } from \"@/modules/game/helpers/game-event/game-event.factory\";\nimport { doesHavePlayerAttributeAlterationWithNameAndStatus, doesHavePlayerAttributeAlterationWithNameSourceAndStatus } from \"@/modules/game/helpers/game-history-record/game-history-record.helpers\";\nimport { getNearestAliveNeighbor, getPlayersWithActiveAttributeName, getPlayersWithCurrentRole, getPlayersWithIds, getPlayerWithActiveAttributeName, getPlayerWithCurrentRole } from \"@/modules/game/helpers/game.helpers\";\nimport { isPlayerAliveAndPowerful } from \"@/modules/game/helpers/player/player.helpers\";\nimport { GameEvent } from \"@/modules/game/schemas/game-event/game-event.schema\";\nimport { GameHistoryRecord } from \"@/modules/game/schemas/game-history-record/game-history-record.schema\";\nimport { Game } from \"@/modules/game/schemas/game.schema\";\nimport { Player } from \"@/modules/game/schemas/player/player.schema\";\nimport { GamePlaySourceName } from \"@/modules/game/types/game-play/game-play.types\";\nimport { Injectable } from \"@nestjs/common\";\n\n@Injectable()\nexport class GameEventsGeneratorService {\n public generateGameEventsFromGameAndLastRecord(game: Game, lastGameHistoryRecord?: GameHistoryRecord): GameEvent[] {\n const gameEvents: GameEvent[] = [];\n const lastGamePlaySourceGameEvent = this.generateLastGamePlaySourceGameEvent(game, lastGameHistoryRecord);\n gameEvents.push(...this.generateFirstTickGameEvents(game));\n gameEvents.push(...this.generateRevealedPlayersGameEvents(lastGameHistoryRecord));\n if (lastGamePlaySourceGameEvent) {\n gameEvents.push(lastGamePlaySourceGameEvent);\n }\n gameEvents.push(...this.generateDeadPlayersGameEvents(lastGameHistoryRecord));\n gameEvents.push(...this.generateSwitchedSidePlayersGameEvents(lastGameHistoryRecord));\n gameEvents.push(...this.generatePlayerAttributeAlterationsEvents(game, lastGameHistoryRecord));\n gameEvents.push(...this.generateGamePhaseStartsGameEvents(game));\n gameEvents.push(...this.generateTurnStartsGameEvents(game));\n\n return this.sortGameEventsByGamePhase(gameEvents, game);\n }\n\n private sortGameEventsByGamePhase(gameEvents: GameEvent[], game: Game): GameEvent[] {\n const priorityList = game.phase.name === \"day\" ? GAME_EVENT_PRIORITY_LIST_ON_DAYS : GAME_EVENT_PRIORITY_LIST_ON_NIGHTS;\n const priorityMap = new Map(priorityList.map((event, index) => [event, index]));\n\n return gameEvents.toSorted((gameEventA, gameEventB) => {\n const priorityA = priorityMap.get(gameEventA.type);\n const priorityB = priorityMap.get(gameEventB.type);\n if (priorityA === undefined || priorityB === undefined) {\n return 0;\n }\n return priorityA - priorityB;\n });\n }\n\n private generateSeerHasSeenGameEvent(targetedPlayers?: Player[]): GameEvent {\n return createGameEvent({\n type: \"seer-has-seen\",\n players: targetedPlayers,\n });\n }\n\n private generateScandalmongerHayHaveMarkedGameEvent(targetedPlayers?: Player[]): GameEvent {\n return createGameEvent({\n type: \"scandalmonger-may-have-marked\",\n players: targetedPlayers,\n });\n }\n\n private generateAccursedWolfFatherMayHaveInfectedGameEvent(targetedPlayers?: Player[]): GameEvent {\n return createGameEvent({\n type: \"accursed-wolf-father-may-have-infected\",\n players: targetedPlayers,\n });\n }\n\n private generateWolfHoundHasChosenSideGameEvent(game: Game): GameEvent {\n return createGameEvent({\n type: \"wolf-hound-has-chosen-side\",\n players: getPlayersWithCurrentRole(game, \"wolf-hound\"),\n });\n }\n\n private generatePiedPiperHasCharmedGameEvent(targetedPlayers?: Player[]): GameEvent {\n return createGameEvent({\n type: \"pied-piper-has-charmed\",\n players: targetedPlayers,\n });\n }\n\n private generateCupidHasCharmedGameEvent(targetedPlayers?: Player[]): GameEvent {\n return createGameEvent({\n type: \"cupid-has-charmed\",\n players: targetedPlayers,\n });\n }\n\n private generateFoxMayHaveSniffedGameEvent(targetedPlayers?: Player[]): GameEvent {\n return createGameEvent({\n type: \"fox-may-have-sniffed\",\n players: targetedPlayers,\n });\n }\n\n private generateThiefMayHaveChosenCardGameEvent(sourcePlayers?: Player[]): GameEvent {\n return createGameEvent({\n type: \"thief-may-have-chosen-card\",\n players: sourcePlayers,\n });\n }\n\n private generateActorMayHaveChosenCardGameEvent(sourcePlayers?: Player[]): GameEvent {\n return createGameEvent({\n type: \"actor-may-have-chosen-card\",\n players: sourcePlayers,\n });\n }\n\n private generateLastGamePlaySourceGameEvent(game: Game, gameHistoryRecord?: GameHistoryRecord): GameEvent | undefined {\n if (!gameHistoryRecord) {\n return undefined;\n }\n const lastHistorySourcePlayersIds = gameHistoryRecord.play.source.players?.map(player => player._id);\n const lastHistoryTargetedPlayerIds = gameHistoryRecord.play.targets?.map(target => target.player._id);\n const lastHistorySourcePlayersInGame = lastHistorySourcePlayersIds ? getPlayersWithIds(lastHistorySourcePlayersIds, game) : undefined;\n const lastHistoryTargetedPlayersInGame = lastHistoryTargetedPlayerIds ? getPlayersWithIds(lastHistoryTargetedPlayerIds, game) : undefined;\n const gamePlaySourcesGameEvent: Partial GameEvent>> = {\n \"seer\": () => this.generateSeerHasSeenGameEvent(lastHistoryTargetedPlayersInGame),\n \"scandalmonger\": () => this.generateScandalmongerHayHaveMarkedGameEvent(lastHistoryTargetedPlayersInGame),\n \"accursed-wolf-father\": () => this.generateAccursedWolfFatherMayHaveInfectedGameEvent(lastHistoryTargetedPlayersInGame),\n \"wolf-hound\": () => this.generateWolfHoundHasChosenSideGameEvent(game),\n \"pied-piper\": () => this.generatePiedPiperHasCharmedGameEvent(lastHistoryTargetedPlayersInGame),\n \"cupid\": () => this.generateCupidHasCharmedGameEvent(lastHistoryTargetedPlayersInGame),\n \"fox\": () => this.generateFoxMayHaveSniffedGameEvent(lastHistoryTargetedPlayersInGame),\n \"thief\": () => this.generateThiefMayHaveChosenCardGameEvent(lastHistorySourcePlayersInGame),\n \"actor\": () => this.generateActorMayHaveChosenCardGameEvent(lastHistorySourcePlayersInGame),\n };\n\n return gamePlaySourcesGameEvent[gameHistoryRecord.play.source.name]?.();\n }\n\n private generateFirstTickGameEvents(game: Game): GameEvent[] {\n const gameEvents: GameEvent[] = [];\n if (game.tick !== 1) {\n return gameEvents;\n }\n gameEvents.push(createGameEvent({\n type: \"game-starts\",\n players: game.players,\n }));\n const villagerVillagerPlayer = getPlayerWithCurrentRole(game, \"villager-villager\");\n if (villagerVillagerPlayer) {\n gameEvents.push(createGameEvent({\n type: \"villager-villager-introduction\",\n players: [villagerVillagerPlayer],\n }));\n }\n return gameEvents;\n }\n\n private generateRevealedPlayersGameEvents(gameHistoryRecord?: GameHistoryRecord): GameEvent[] {\n const gameEvents: GameEvent[] = [];\n if (!gameHistoryRecord?.revealedPlayers) {\n return gameEvents;\n }\n const revealedIdiotPlayer = gameHistoryRecord.revealedPlayers.find(player => player.role.current === \"idiot\");\n if (revealedIdiotPlayer) {\n gameEvents.push(createGameEvent({\n type: \"idiot-is-spared\",\n players: [revealedIdiotPlayer],\n }));\n }\n return gameEvents;\n }\n\n private generateSwitchedSidePlayersGameEvents(gameHistoryRecord?: GameHistoryRecord): GameEvent[] {\n const gameEvents: GameEvent[] = [];\n if (!gameHistoryRecord?.switchedSidePlayers) {\n return gameEvents;\n }\n const switchedWildChildPlayer = gameHistoryRecord.switchedSidePlayers.find(player => player.role.current === \"wild-child\");\n if (switchedWildChildPlayer && gameHistoryRecord.play.action === \"bury-dead-bodies\") {\n gameEvents.push(createGameEvent({\n type: \"wild-child-has-transformed\",\n players: [switchedWildChildPlayer],\n }));\n }\n return gameEvents;\n }\n\n private generateDeadPlayersGameEvents(gameHistoryRecord?: GameHistoryRecord): GameEvent[] {\n const gameEvents: GameEvent[] = [];\n if (!gameHistoryRecord?.deadPlayers) {\n return gameEvents;\n }\n gameEvents.push(createGameEvent({\n type: \"death\",\n players: gameHistoryRecord.deadPlayers,\n }));\n\n return gameEvents;\n }\n\n private generateBearGrowlsOrSleepsGameEvent(game: Game, bearTamerPlayer: Player): GameEvent {\n const leftAliveNeighbor = getNearestAliveNeighbor(bearTamerPlayer._id, game, { direction: \"left\" });\n const rightAliveNeighbor = getNearestAliveNeighbor(bearTamerPlayer._id, game, { direction: \"right\" });\n const doesBearTamerHaveWerewolfSidedNeighbor = leftAliveNeighbor?.side.current === \"werewolves\" || rightAliveNeighbor?.side.current === \"werewolves\";\n const { doesGrowlOnWerewolvesSide } = game.options.roles.bearTamer;\n const isBearTamerInfected = bearTamerPlayer.side.current === \"werewolves\";\n const doesBearGrowl = doesGrowlOnWerewolvesSide && isBearTamerInfected || doesBearTamerHaveWerewolfSidedNeighbor;\n\n return createGameEvent({\n type: doesBearGrowl ? \"bear-growls\" : \"bear-sleeps\",\n players: [bearTamerPlayer],\n });\n }\n\n private generateGamePhaseStartsGameEvents(game: Game): GameEvent[] {\n const gameEvents: GameEvent[] = [];\n if (game.phase.tick !== 1 || game.phase.name === \"twilight\") {\n return gameEvents;\n }\n gameEvents.push(createGameEvent({ type: \"game-phase-starts\" }));\n const bearTamerPlayer = getPlayerWithCurrentRole(game, \"bear-tamer\");\n if (game.phase.name === \"day\" && bearTamerPlayer && isPlayerAliveAndPowerful(bearTamerPlayer, game)) {\n gameEvents.push(this.generateBearGrowlsOrSleepsGameEvent(game, bearTamerPlayer));\n }\n return gameEvents;\n }\n\n private generatePlayerAttributeAlterationsEvents(game: Game, gameHistoryRecord?: GameHistoryRecord): GameEvent[] {\n const gameEvents: GameEvent[] = [];\n if (!gameHistoryRecord?.playerAttributeAlterations) {\n return gameEvents;\n }\n if (doesHavePlayerAttributeAlterationWithNameSourceAndStatus(gameHistoryRecord, \"powerless\", \"elder\", \"attached\")) {\n gameEvents.push(createGameEvent({\n type: \"elder-has-taken-revenge\",\n players: getPlayersWithCurrentRole(game, \"elder\"),\n }));\n }\n if (doesHavePlayerAttributeAlterationWithNameAndStatus(gameHistoryRecord, \"sheriff\", \"attached\")) {\n gameEvents.push(createGameEvent({\n type: \"sheriff-promotion\",\n players: getPlayersWithActiveAttributeName(game, \"sheriff\"),\n }));\n }\n return gameEvents;\n }\n\n private generateTurnStartsGameEvents(game: Game): GameEvent[] {\n const gameEvents: GameEvent[] = [];\n const scandalmongerMarkedPlayer = getPlayerWithActiveAttributeName(game, \"scandalmonger-marked\");\n if (game.currentPlay?.action === \"vote\" && scandalmongerMarkedPlayer) {\n gameEvents.push(createGameEvent({\n type: \"scandalmonger-mark-is-active\",\n players: [scandalmongerMarkedPlayer],\n }));\n }\n return [\n ...gameEvents,\n createGameEvent({\n type: \"game-turn-starts\",\n players: game.currentPlay?.source.players,\n }),\n ];\n }\n}" + "source": "import { Injectable } from \"@nestjs/common\";\n\nimport { GAME_EVENT_PRIORITY_LIST_ON_DAYS, GAME_EVENT_PRIORITY_LIST_ON_NIGHTS } from \"@/modules/game/constants/game-event/game-event.constants\";\nimport { createGameEvent } from \"@/modules/game/helpers/game-event/game-event.factory\";\nimport { doesHavePlayerAttributeAlterationWithNameAndStatus, doesHavePlayerAttributeAlterationWithNameSourceAndStatus } from \"@/modules/game/helpers/game-history-record/game-history-record.helpers\";\nimport { getNearestAliveNeighbor, getPlayersWithActiveAttributeName, getPlayersWithCurrentRole, getPlayersWithIds, getPlayerWithActiveAttributeName, getPlayerWithCurrentRole } from \"@/modules/game/helpers/game.helpers\";\nimport { isPlayerAliveAndPowerful } from \"@/modules/game/helpers/player/player.helpers\";\nimport { GameEvent } from \"@/modules/game/schemas/game-event/game-event.schema\";\nimport { GameHistoryRecord } from \"@/modules/game/schemas/game-history-record/game-history-record.schema\";\nimport { Game } from \"@/modules/game/schemas/game.schema\";\nimport { Player } from \"@/modules/game/schemas/player/player.schema\";\nimport { GamePlaySourceName } from \"@/modules/game/types/game-play/game-play.types\";\n\n@Injectable()\nexport class GameEventsGeneratorService {\n public generateGameEventsFromGameAndLastRecord(game: Game, lastGameHistoryRecord?: GameHistoryRecord): GameEvent[] {\n const gameEvents: GameEvent[] = [];\n const lastGamePlaySourceGameEvent = this.generateLastGamePlaySourceGameEvent(game, lastGameHistoryRecord);\n gameEvents.push(...this.generateFirstTickGameEvents(game));\n gameEvents.push(...this.generateRevealedPlayersGameEvents(lastGameHistoryRecord));\n if (lastGamePlaySourceGameEvent) {\n gameEvents.push(lastGamePlaySourceGameEvent);\n }\n gameEvents.push(...this.generateDeadPlayersGameEvents(lastGameHistoryRecord));\n gameEvents.push(...this.generateSwitchedSidePlayersGameEvents(lastGameHistoryRecord));\n gameEvents.push(...this.generatePlayerAttributeAlterationsEvents(game, lastGameHistoryRecord));\n gameEvents.push(...this.generateGamePhaseStartsGameEvents(game));\n gameEvents.push(...this.generateTurnStartsGameEvents(game));\n\n return this.sortGameEventsByGamePhase(gameEvents, game);\n }\n\n private sortGameEventsByGamePhase(gameEvents: GameEvent[], game: Game): GameEvent[] {\n const priorityList = game.phase.name === \"day\" ? GAME_EVENT_PRIORITY_LIST_ON_DAYS : GAME_EVENT_PRIORITY_LIST_ON_NIGHTS;\n const priorityMap = new Map(priorityList.map((event, index) => [event, index]));\n\n return gameEvents.toSorted((gameEventA, gameEventB) => {\n const priorityA = priorityMap.get(gameEventA.type);\n const priorityB = priorityMap.get(gameEventB.type);\n if (priorityA === undefined || priorityB === undefined) {\n return 0;\n }\n return priorityA - priorityB;\n });\n }\n\n private generateSeerHasSeenGameEvent(targetedPlayers?: Player[]): GameEvent {\n return createGameEvent({\n type: \"seer-has-seen\",\n players: targetedPlayers,\n });\n }\n\n private generateScandalmongerHayHaveMarkedGameEvent(targetedPlayers?: Player[]): GameEvent {\n return createGameEvent({\n type: \"scandalmonger-may-have-marked\",\n players: targetedPlayers,\n });\n }\n\n private generateAccursedWolfFatherMayHaveInfectedGameEvent(targetedPlayers?: Player[]): GameEvent {\n return createGameEvent({\n type: \"accursed-wolf-father-may-have-infected\",\n players: targetedPlayers,\n });\n }\n\n private generateWolfHoundHasChosenSideGameEvent(game: Game): GameEvent {\n return createGameEvent({\n type: \"wolf-hound-has-chosen-side\",\n players: getPlayersWithCurrentRole(game, \"wolf-hound\"),\n });\n }\n\n private generatePiedPiperHasCharmedGameEvent(targetedPlayers?: Player[]): GameEvent {\n return createGameEvent({\n type: \"pied-piper-has-charmed\",\n players: targetedPlayers,\n });\n }\n\n private generateCupidHasCharmedGameEvent(targetedPlayers?: Player[]): GameEvent {\n return createGameEvent({\n type: \"cupid-has-charmed\",\n players: targetedPlayers,\n });\n }\n\n private generateFoxMayHaveSniffedGameEvent(targetedPlayers?: Player[]): GameEvent {\n return createGameEvent({\n type: \"fox-may-have-sniffed\",\n players: targetedPlayers,\n });\n }\n\n private generateThiefMayHaveChosenCardGameEvent(sourcePlayers?: Player[]): GameEvent {\n return createGameEvent({\n type: \"thief-may-have-chosen-card\",\n players: sourcePlayers,\n });\n }\n\n private generateActorMayHaveChosenCardGameEvent(sourcePlayers?: Player[]): GameEvent {\n return createGameEvent({\n type: \"actor-may-have-chosen-card\",\n players: sourcePlayers,\n });\n }\n\n private generateLastGamePlaySourceGameEvent(game: Game, gameHistoryRecord?: GameHistoryRecord): GameEvent | undefined {\n if (!gameHistoryRecord) {\n return undefined;\n }\n const lastHistorySourcePlayersIds = gameHistoryRecord.play.source.players?.map(player => player._id);\n const lastHistoryTargetedPlayerIds = gameHistoryRecord.play.targets?.map(target => target.player._id);\n const lastHistorySourcePlayersInGame = lastHistorySourcePlayersIds ? getPlayersWithIds(lastHistorySourcePlayersIds, game) : undefined;\n const lastHistoryTargetedPlayersInGame = lastHistoryTargetedPlayerIds ? getPlayersWithIds(lastHistoryTargetedPlayerIds, game) : undefined;\n const gamePlaySourcesGameEvent: Partial GameEvent>> = {\n \"seer\": () => this.generateSeerHasSeenGameEvent(lastHistoryTargetedPlayersInGame),\n \"scandalmonger\": () => this.generateScandalmongerHayHaveMarkedGameEvent(lastHistoryTargetedPlayersInGame),\n \"accursed-wolf-father\": () => this.generateAccursedWolfFatherMayHaveInfectedGameEvent(lastHistoryTargetedPlayersInGame),\n \"wolf-hound\": () => this.generateWolfHoundHasChosenSideGameEvent(game),\n \"pied-piper\": () => this.generatePiedPiperHasCharmedGameEvent(lastHistoryTargetedPlayersInGame),\n \"cupid\": () => this.generateCupidHasCharmedGameEvent(lastHistoryTargetedPlayersInGame),\n \"fox\": () => this.generateFoxMayHaveSniffedGameEvent(lastHistoryTargetedPlayersInGame),\n \"thief\": () => this.generateThiefMayHaveChosenCardGameEvent(lastHistorySourcePlayersInGame),\n \"actor\": () => this.generateActorMayHaveChosenCardGameEvent(lastHistorySourcePlayersInGame),\n };\n\n return gamePlaySourcesGameEvent[gameHistoryRecord.play.source.name]?.();\n }\n\n private generateFirstTickGameEvents(game: Game): GameEvent[] {\n const gameEvents: GameEvent[] = [];\n if (game.tick !== 1) {\n return gameEvents;\n }\n gameEvents.push(createGameEvent({\n type: \"game-starts\",\n players: game.players,\n }));\n const villagerVillagerPlayer = getPlayerWithCurrentRole(game, \"villager-villager\");\n if (villagerVillagerPlayer) {\n gameEvents.push(createGameEvent({\n type: \"villager-villager-introduction\",\n players: [villagerVillagerPlayer],\n }));\n }\n return gameEvents;\n }\n\n private generateRevealedPlayersGameEvents(gameHistoryRecord?: GameHistoryRecord): GameEvent[] {\n const gameEvents: GameEvent[] = [];\n if (!gameHistoryRecord?.revealedPlayers) {\n return gameEvents;\n }\n const revealedIdiotPlayer = gameHistoryRecord.revealedPlayers.find(player => player.role.current === \"idiot\");\n if (revealedIdiotPlayer) {\n gameEvents.push(createGameEvent({\n type: \"idiot-is-spared\",\n players: [revealedIdiotPlayer],\n }));\n }\n return gameEvents;\n }\n\n private generateSwitchedSidePlayersGameEvents(gameHistoryRecord?: GameHistoryRecord): GameEvent[] {\n const gameEvents: GameEvent[] = [];\n if (!gameHistoryRecord?.switchedSidePlayers) {\n return gameEvents;\n }\n const switchedWildChildPlayer = gameHistoryRecord.switchedSidePlayers.find(player => player.role.current === \"wild-child\");\n if (switchedWildChildPlayer && gameHistoryRecord.play.action === \"bury-dead-bodies\") {\n gameEvents.push(createGameEvent({\n type: \"wild-child-has-transformed\",\n players: [switchedWildChildPlayer],\n }));\n }\n return gameEvents;\n }\n\n private generateDeadPlayersGameEvents(gameHistoryRecord?: GameHistoryRecord): GameEvent[] {\n const gameEvents: GameEvent[] = [];\n if (!gameHistoryRecord?.deadPlayers) {\n return gameEvents;\n }\n gameEvents.push(createGameEvent({\n type: \"death\",\n players: gameHistoryRecord.deadPlayers,\n }));\n\n return gameEvents;\n }\n\n private generateBearGrowlsOrSleepsGameEvent(game: Game, bearTamerPlayer: Player): GameEvent {\n const leftAliveNeighbor = getNearestAliveNeighbor(bearTamerPlayer._id, game, { direction: \"left\" });\n const rightAliveNeighbor = getNearestAliveNeighbor(bearTamerPlayer._id, game, { direction: \"right\" });\n const doesBearTamerHaveWerewolfSidedNeighbor = leftAliveNeighbor?.side.current === \"werewolves\" || rightAliveNeighbor?.side.current === \"werewolves\";\n const { doesGrowlOnWerewolvesSide } = game.options.roles.bearTamer;\n const isBearTamerInfected = bearTamerPlayer.side.current === \"werewolves\";\n const doesBearGrowl = doesGrowlOnWerewolvesSide && isBearTamerInfected || doesBearTamerHaveWerewolfSidedNeighbor;\n\n return createGameEvent({\n type: doesBearGrowl ? \"bear-growls\" : \"bear-sleeps\",\n players: [bearTamerPlayer],\n });\n }\n\n private generateGamePhaseStartsGameEvents(game: Game): GameEvent[] {\n const gameEvents: GameEvent[] = [];\n if (game.phase.tick !== 1 || game.phase.name === \"twilight\") {\n return gameEvents;\n }\n gameEvents.push(createGameEvent({ type: \"game-phase-starts\" }));\n const bearTamerPlayer = getPlayerWithCurrentRole(game, \"bear-tamer\");\n if (game.phase.name === \"day\" && bearTamerPlayer && isPlayerAliveAndPowerful(bearTamerPlayer, game)) {\n gameEvents.push(this.generateBearGrowlsOrSleepsGameEvent(game, bearTamerPlayer));\n }\n return gameEvents;\n }\n\n private generatePlayerAttributeAlterationsEvents(game: Game, gameHistoryRecord?: GameHistoryRecord): GameEvent[] {\n const gameEvents: GameEvent[] = [];\n if (!gameHistoryRecord?.playerAttributeAlterations) {\n return gameEvents;\n }\n if (doesHavePlayerAttributeAlterationWithNameSourceAndStatus(gameHistoryRecord, \"powerless\", \"elder\", \"attached\")) {\n gameEvents.push(createGameEvent({\n type: \"elder-has-taken-revenge\",\n players: getPlayersWithCurrentRole(game, \"elder\"),\n }));\n }\n if (doesHavePlayerAttributeAlterationWithNameAndStatus(gameHistoryRecord, \"sheriff\", \"attached\")) {\n gameEvents.push(createGameEvent({\n type: \"sheriff-promotion\",\n players: getPlayersWithActiveAttributeName(game, \"sheriff\"),\n }));\n }\n return gameEvents;\n }\n\n private generateTurnStartsGameEvents(game: Game): GameEvent[] {\n const gameEvents: GameEvent[] = [];\n const scandalmongerMarkedPlayer = getPlayerWithActiveAttributeName(game, \"scandalmonger-marked\");\n if (game.currentPlay?.action === \"vote\" && scandalmongerMarkedPlayer) {\n gameEvents.push(createGameEvent({\n type: \"scandalmonger-mark-is-active\",\n players: [scandalmongerMarkedPlayer],\n }));\n }\n return [\n ...gameEvents,\n createGameEvent({\n type: \"game-turn-starts\",\n players: game.currentPlay?.source.players,\n }),\n ];\n }\n}" }, "src/modules/game/providers/services/game-feedback/game-feedback.service.ts": { "language": "typescript", @@ -79507,11 +79532,11 @@ "location": { "end": { "column": 4, - "line": 23 + "line": 25 }, "start": { "column": 116, - "line": 15 + "line": 17 } } }, @@ -79531,11 +79556,11 @@ "location": { "end": { "column": 6, - "line": 20 + "line": 22 }, "start": { "column": 61, - "line": 17 + "line": 19 } } }, @@ -79560,11 +79585,11 @@ "location": { "end": { "column": 4, - "line": 29 + "line": 31 }, "start": { "column": 56, - "line": 25 + "line": 27 } } }, @@ -79589,11 +79614,11 @@ "location": { "end": { "column": 22, - "line": 26 + "line": 28 }, "start": { "column": 9, - "line": 26 + "line": 28 } } }, @@ -79618,11 +79643,11 @@ "location": { "end": { "column": 22, - "line": 26 + "line": 28 }, "start": { "column": 9, - "line": 26 + "line": 28 } } }, @@ -79643,16 +79668,16 @@ "location": { "end": { "column": 6, - "line": 28 + "line": 30 }, "start": { "column": 24, - "line": 26 + "line": 28 } } } ], - "source": "import { CreateGameFeedbackDto } from \"@/modules/game/dto/create-game-feedback/create-game-feedback.dto\";\nimport { createGameFeedbackToInsert } from \"@/modules/game/helpers/game-feedback/game-feedback.factory\";\nimport { GameFeedbackRepository } from \"@/modules/game/providers/repositories/game-feedback/game-feedback.repository\";\nimport { GameFeedback } from \"@/modules/game/schemas/game-feedback/game-feedback.schema\";\nimport { Game } from \"@/modules/game/schemas/game.schema\";\nimport { ApiResources } from \"@/shared/api/enums/api.enums\";\nimport { BadResourceMutationReasons } from \"@/shared/exception/enums/bad-resource-mutation-error.enum\";\nimport { BadResourceMutationException } from \"@/shared/exception/types/bad-resource-mutation-exception.types\";\nimport { Injectable } from \"@nestjs/common\";\n\n@Injectable()\nexport class GameFeedbackService {\n public constructor(private readonly gameFeedbackRepository: GameFeedbackRepository) {}\n\n public async createGameFeedback(game: Game, createGameFeedbackDto: CreateGameFeedbackDto): Promise {\n this.validateCreateGameFeedback(game);\n const gameFeedbackToInsert = createGameFeedbackToInsert({\n ...createGameFeedbackDto,\n gameId: game._id,\n });\n\n return this.gameFeedbackRepository.create(gameFeedbackToInsert);\n }\n\n private validateCreateGameFeedback(game: Game): void {\n if (game.feedback) {\n throw new BadResourceMutationException(ApiResources.GAMES, game._id.toString(), BadResourceMutationReasons.FEEDBACK_ALREADY_EXISTS);\n }\n }\n}" + "source": "import { Injectable } from \"@nestjs/common\";\n\nimport { CreateGameFeedbackDto } from \"@/modules/game/dto/create-game-feedback/create-game-feedback.dto\";\nimport { createGameFeedbackToInsert } from \"@/modules/game/helpers/game-feedback/game-feedback.factory\";\nimport { GameFeedbackRepository } from \"@/modules/game/providers/repositories/game-feedback/game-feedback.repository\";\nimport { GameFeedback } from \"@/modules/game/schemas/game-feedback/game-feedback.schema\";\nimport { Game } from \"@/modules/game/schemas/game.schema\";\n\nimport { ApiResources } from \"@/shared/api/enums/api.enums\";\nimport { BadResourceMutationReasons } from \"@/shared/exception/enums/bad-resource-mutation-error.enums\";\nimport { BadResourceMutationException } from \"@/shared/exception/types/bad-resource-mutation-exception.types\";\n\n@Injectable()\nexport class GameFeedbackService {\n public constructor(private readonly gameFeedbackRepository: GameFeedbackRepository) {}\n\n public async createGameFeedback(game: Game, createGameFeedbackDto: CreateGameFeedbackDto): Promise {\n this.validateCreateGameFeedback(game);\n const gameFeedbackToInsert = createGameFeedbackToInsert({\n ...createGameFeedbackDto,\n gameId: game._id,\n });\n\n return this.gameFeedbackRepository.create(gameFeedbackToInsert);\n }\n\n private validateCreateGameFeedback(game: Game): void {\n if (game.feedback) {\n throw new BadResourceMutationException(ApiResources.GAMES, game._id.toString(), BadResourceMutationReasons.FEEDBACK_ALREADY_EXISTS);\n }\n }\n}" }, "src/modules/game/providers/services/game-history/game-history-record-to-insert-generator.service.ts": { "language": "typescript", @@ -79681,11 +79706,11 @@ "location": { "end": { "column": 4, - "line": 48 + "line": 50 }, "start": { "column": 145, - "line": 28 + "line": 30 } } }, @@ -79716,11 +79741,11 @@ "location": { "end": { "column": 38, - "line": 29 + "line": 31 }, "start": { "column": 9, - "line": 29 + "line": 31 } } }, @@ -79751,11 +79776,11 @@ "location": { "end": { "column": 38, - "line": 29 + "line": 31 }, "start": { "column": 9, - "line": 29 + "line": 31 } } }, @@ -79786,11 +79811,11 @@ "location": { "end": { "column": 38, - "line": 29 + "line": 31 }, "start": { "column": 9, - "line": 29 + "line": 31 } } }, @@ -79811,11 +79836,11 @@ "location": { "end": { "column": 6, - "line": 31 + "line": 33 }, "start": { "column": 40, - "line": 29 + "line": 31 } } }, @@ -79836,11 +79861,11 @@ "location": { "end": { "column": 98, - "line": 30 + "line": 32 }, "start": { "column": 56, - "line": 30 + "line": 32 } } }, @@ -79858,11 +79883,11 @@ "location": { "end": { "column": 124, - "line": 30 + "line": 32 }, "start": { "column": 100, - "line": 30 + "line": 32 } } }, @@ -79889,11 +79914,11 @@ "location": { "end": { "column": 6, - "line": 43 + "line": 45 }, "start": { "column": 66, - "line": 32 + "line": 34 } } }, @@ -79923,11 +79948,11 @@ "location": { "end": { "column": 55, - "line": 44 + "line": 46 }, "start": { "column": 9, - "line": 44 + "line": 46 } } }, @@ -79957,11 +79982,11 @@ "location": { "end": { "column": 55, - "line": 44 + "line": 46 }, "start": { "column": 9, - "line": 44 + "line": 46 } } }, @@ -79991,11 +80016,11 @@ "location": { "end": { "column": 55, - "line": 44 + "line": 46 }, "start": { "column": 9, - "line": 44 + "line": 46 } } }, @@ -80022,11 +80047,11 @@ "location": { "end": { "column": 55, - "line": 44 + "line": 46 }, "start": { "column": 49, - "line": 44 + "line": 46 } } }, @@ -80043,17 +80068,18 @@ ], "coveredBy": [ "748", - "822", + "817", + "821", "823" ], "location": { "end": { "column": 6, - "line": 46 + "line": 48 }, "start": { "column": 57, - "line": 44 + "line": 46 } } }, @@ -80074,11 +80100,11 @@ "location": { "end": { "column": 4, - "line": 59 + "line": 61 }, "start": { "column": 120, - "line": 50 + "line": 52 } } }, @@ -80099,11 +80125,11 @@ "location": { "end": { "column": 88, - "line": 51 + "line": 53 }, "start": { "column": 57, - "line": 51 + "line": 53 } } }, @@ -80124,11 +80150,11 @@ "location": { "end": { "column": 88, - "line": 51 + "line": 53 }, "start": { "column": 67, - "line": 51 + "line": 53 } } }, @@ -80149,11 +80175,11 @@ "location": { "end": { "column": 4, - "line": 70 + "line": 72 }, "start": { "column": 124, - "line": 61 + "line": 63 } } }, @@ -80174,11 +80200,11 @@ "location": { "end": { "column": 88, - "line": 62 + "line": 64 }, "start": { "column": 57, - "line": 62 + "line": 64 } } }, @@ -80199,11 +80225,11 @@ "location": { "end": { "column": 88, - "line": 62 + "line": 64 }, "start": { "column": 67, - "line": 62 + "line": 64 } } }, @@ -80227,11 +80253,11 @@ "location": { "end": { "column": 7, - "line": 67 + "line": 69 }, "start": { "column": 40, - "line": 63 + "line": 65 } } }, @@ -80255,11 +80281,11 @@ "location": { "end": { "column": 6, - "line": 67 + "line": 69 }, "start": { "column": 73, - "line": 63 + "line": 65 } } }, @@ -80283,11 +80309,11 @@ "location": { "end": { "column": 70, - "line": 66 + "line": 68 }, "start": { "column": 14, - "line": 66 + "line": 68 } } }, @@ -80311,11 +80337,11 @@ "location": { "end": { "column": 70, - "line": 66 + "line": 68 }, "start": { "column": 14, - "line": 66 + "line": 68 } } }, @@ -80339,11 +80365,11 @@ "location": { "end": { "column": 70, - "line": 66 + "line": 68 }, "start": { "column": 14, - "line": 66 + "line": 68 } } }, @@ -80364,11 +80390,11 @@ "location": { "end": { "column": 38, - "line": 66 + "line": 68 }, "start": { "column": 14, - "line": 66 + "line": 68 } } }, @@ -80389,11 +80415,11 @@ "location": { "end": { "column": 4, - "line": 81 + "line": 83 }, "start": { "column": 120, - "line": 72 + "line": 74 } } }, @@ -80414,11 +80440,11 @@ "location": { "end": { "column": 88, - "line": 73 + "line": 75 }, "start": { "column": 57, - "line": 73 + "line": 75 } } }, @@ -80439,11 +80465,11 @@ "location": { "end": { "column": 88, - "line": 73 + "line": 75 }, "start": { "column": 67, - "line": 73 + "line": 75 } } }, @@ -80467,11 +80493,11 @@ "location": { "end": { "column": 7, - "line": 78 + "line": 80 }, "start": { "column": 36, - "line": 74 + "line": 76 } } }, @@ -80495,11 +80521,11 @@ "location": { "end": { "column": 6, - "line": 78 + "line": 80 }, "start": { "column": 69, - "line": 74 + "line": 76 } } }, @@ -80523,11 +80549,11 @@ "location": { "end": { "column": 103, - "line": 77 + "line": 79 }, "start": { "column": 14, - "line": 77 + "line": 79 } } }, @@ -80551,11 +80577,11 @@ "location": { "end": { "column": 103, - "line": 77 + "line": 79 }, "start": { "column": 14, - "line": 77 + "line": 79 } } }, @@ -80579,11 +80605,11 @@ "location": { "end": { "column": 103, - "line": 77 + "line": 79 }, "start": { "column": 14, - "line": 77 + "line": 79 } } }, @@ -80607,11 +80633,11 @@ "location": { "end": { "column": 85, - "line": 77 + "line": 79 }, "start": { "column": 14, - "line": 77 + "line": 79 } } }, @@ -80635,11 +80661,11 @@ "location": { "end": { "column": 85, - "line": 77 + "line": 79 }, "start": { "column": 14, - "line": 77 + "line": 79 } } }, @@ -80663,11 +80689,11 @@ "location": { "end": { "column": 59, - "line": 77 + "line": 79 }, "start": { "column": 14, - "line": 77 + "line": 79 } } }, @@ -80691,11 +80717,11 @@ "location": { "end": { "column": 59, - "line": 77 + "line": 79 }, "start": { "column": 14, - "line": 77 + "line": 79 } } }, @@ -80716,11 +80742,11 @@ "location": { "end": { "column": 38, - "line": 77 + "line": 79 }, "start": { "column": 14, - "line": 77 + "line": 79 } } }, @@ -80744,11 +80770,11 @@ "location": { "end": { "column": 59, - "line": 77 + "line": 79 }, "start": { "column": 54, - "line": 77 + "line": 79 } } }, @@ -80768,11 +80794,11 @@ "location": { "end": { "column": 4, - "line": 95 + "line": 97 }, "start": { "column": 170, - "line": 83 + "line": 85 } } }, @@ -80791,11 +80817,11 @@ "location": { "end": { "column": 6, - "line": 94 + "line": 96 }, "start": { "column": 120, - "line": 84 + "line": 86 } } }, @@ -80817,11 +80843,11 @@ "location": { "end": { "column": 110, - "line": 85 + "line": 87 }, "start": { "column": 11, - "line": 85 + "line": 87 } } }, @@ -80843,11 +80869,11 @@ "location": { "end": { "column": 110, - "line": 85 + "line": 87 }, "start": { "column": 11, - "line": 85 + "line": 87 } } }, @@ -80869,11 +80895,11 @@ "location": { "end": { "column": 110, - "line": 85 + "line": 87 }, "start": { "column": 11, - "line": 85 + "line": 87 } } }, @@ -80895,11 +80921,11 @@ "location": { "end": { "column": 8, - "line": 92 + "line": 94 }, "start": { "column": 112, - "line": 85 + "line": 87 } } }, @@ -80918,11 +80944,11 @@ "location": { "end": { "column": 10, - "line": 91 + "line": 93 }, "start": { "column": 75, - "line": 86 + "line": 88 } } }, @@ -80941,11 +80967,11 @@ "location": { "end": { "column": 29, - "line": 90 + "line": 92 }, "start": { "column": 19, - "line": 90 + "line": 92 } } }, @@ -80965,11 +80991,11 @@ "location": { "end": { "column": 10, - "line": 94 + "line": 96 }, "start": { "column": 8, - "line": 94 + "line": 96 } } }, @@ -80989,11 +81015,11 @@ "location": { "end": { "column": 4, - "line": 109 + "line": 111 }, "start": { "column": 170, - "line": 97 + "line": 99 } } }, @@ -81011,11 +81037,11 @@ "location": { "end": { "column": 6, - "line": 108 + "line": 110 }, "start": { "column": 121, - "line": 98 + "line": 100 } } }, @@ -81036,11 +81062,11 @@ "location": { "end": { "column": 109, - "line": 99 + "line": 101 }, "start": { "column": 11, - "line": 99 + "line": 101 } } }, @@ -81061,11 +81087,11 @@ "location": { "end": { "column": 109, - "line": 99 + "line": 101 }, "start": { "column": 11, - "line": 99 + "line": 101 } } }, @@ -81086,11 +81112,11 @@ "location": { "end": { "column": 109, - "line": 99 + "line": 101 }, "start": { "column": 11, - "line": 99 + "line": 101 } } }, @@ -81111,11 +81137,11 @@ "location": { "end": { "column": 8, - "line": 106 + "line": 108 }, "start": { "column": 111, - "line": 99 + "line": 101 } } }, @@ -81133,11 +81159,11 @@ "location": { "end": { "column": 10, - "line": 105 + "line": 107 }, "start": { "column": 75, - "line": 100 + "line": 102 } } }, @@ -81155,11 +81181,11 @@ "location": { "end": { "column": 29, - "line": 104 + "line": 106 }, "start": { "column": 19, - "line": 104 + "line": 106 } } }, @@ -81179,11 +81205,11 @@ "location": { "end": { "column": 10, - "line": 108 + "line": 110 }, "start": { "column": 8, - "line": 108 + "line": 110 } } }, @@ -81203,11 +81229,11 @@ "location": { "end": { "column": 4, - "line": 126 + "line": 128 }, "start": { "column": 48, - "line": 112 + "line": 114 } } }, @@ -81226,11 +81252,11 @@ "location": { "end": { "column": 6, - "line": 125 + "line": 127 }, "start": { "column": 120, - "line": 113 + "line": 115 } } }, @@ -81252,11 +81278,11 @@ "location": { "end": { "column": 152, - "line": 115 + "line": 117 }, "start": { "column": 48, - "line": 115 + "line": 117 } } }, @@ -81278,11 +81304,11 @@ "location": { "end": { "column": 152, - "line": 115 + "line": 117 }, "start": { "column": 48, - "line": 115 + "line": 117 } } }, @@ -81304,11 +81330,11 @@ "location": { "end": { "column": 152, - "line": 115 + "line": 117 }, "start": { "column": 48, - "line": 115 + "line": 117 } } }, @@ -81330,11 +81356,11 @@ "location": { "end": { "column": 99, - "line": 115 + "line": 117 }, "start": { "column": 48, - "line": 115 + "line": 117 } } }, @@ -81356,11 +81382,11 @@ "location": { "end": { "column": 74, - "line": 116 + "line": 118 }, "start": { "column": 11, - "line": 116 + "line": 118 } } }, @@ -81382,11 +81408,11 @@ "location": { "end": { "column": 74, - "line": 116 + "line": 118 }, "start": { "column": 11, - "line": 116 + "line": 118 } } }, @@ -81408,11 +81434,11 @@ "location": { "end": { "column": 74, - "line": 116 + "line": 118 }, "start": { "column": 11, - "line": 116 + "line": 118 } } }, @@ -81433,11 +81459,11 @@ "location": { "end": { "column": 8, - "line": 123 + "line": 125 }, "start": { "column": 76, - "line": 116 + "line": 118 } } }, @@ -81455,11 +81481,11 @@ "location": { "end": { "column": 10, - "line": 122 + "line": 124 }, "start": { "column": 75, - "line": 117 + "line": 119 } } }, @@ -81477,11 +81503,11 @@ "location": { "end": { "column": 30, - "line": 121 + "line": 123 }, "start": { "column": 19, - "line": 121 + "line": 123 } } }, @@ -81501,11 +81527,11 @@ "location": { "end": { "column": 10, - "line": 125 + "line": 127 }, "start": { "column": 8, - "line": 125 + "line": 127 } } }, @@ -81529,11 +81555,11 @@ "location": { "end": { "column": 4, - "line": 143 + "line": 145 }, "start": { "column": 167, - "line": 128 + "line": 130 } } }, @@ -81557,11 +81583,11 @@ "location": { "end": { "column": 6, - "line": 140 + "line": 142 }, "start": { "column": 129, - "line": 130 + "line": 132 } } }, @@ -81585,11 +81611,11 @@ "location": { "end": { "column": 30, - "line": 132 + "line": 134 }, "start": { "column": 11, - "line": 132 + "line": 134 } } }, @@ -81613,11 +81639,11 @@ "location": { "end": { "column": 30, - "line": 132 + "line": 134 }, "start": { "column": 11, - "line": 132 + "line": 134 } } }, @@ -81641,11 +81667,11 @@ "location": { "end": { "column": 30, - "line": 132 + "line": 134 }, "start": { "column": 11, - "line": 132 + "line": 134 } } }, @@ -81664,11 +81690,11 @@ "location": { "end": { "column": 8, - "line": 134 + "line": 136 }, "start": { "column": 32, - "line": 132 + "line": 134 } } }, @@ -81692,11 +81718,11 @@ "location": { "end": { "column": 10, - "line": 140 + "line": 142 }, "start": { "column": 8, - "line": 140 + "line": 142 } } }, @@ -81718,11 +81744,11 @@ "location": { "end": { "column": 4, - "line": 155 + "line": 157 }, "start": { "column": 180, - "line": 145 + "line": 147 } } }, @@ -81744,11 +81770,11 @@ "location": { "end": { "column": 22, - "line": 146 + "line": 148 }, "start": { "column": 9, - "line": 146 + "line": 148 } } }, @@ -81770,11 +81796,11 @@ "location": { "end": { "column": 22, - "line": 146 + "line": 148 }, "start": { "column": 9, - "line": 146 + "line": 148 } } }, @@ -81796,11 +81822,11 @@ "location": { "end": { "column": 22, - "line": 146 + "line": 148 }, "start": { "column": 9, - "line": 146 + "line": 148 } } }, @@ -81819,11 +81845,11 @@ "location": { "end": { "column": 6, - "line": 148 + "line": 150 }, "start": { "column": 24, - "line": 146 + "line": 148 } } }, @@ -81846,11 +81872,11 @@ "location": { "end": { "column": 48, - "line": 149 + "line": 151 }, "start": { "column": 9, - "line": 149 + "line": 151 } } }, @@ -81870,11 +81896,11 @@ "location": { "end": { "column": 48, - "line": 149 + "line": 151 }, "start": { "column": 9, - "line": 149 + "line": 151 } } }, @@ -81897,11 +81923,11 @@ "location": { "end": { "column": 48, - "line": 149 + "line": 151 }, "start": { "column": 9, - "line": 149 + "line": 151 } } }, @@ -81921,11 +81947,11 @@ "location": { "end": { "column": 48, - "line": 149 + "line": 151 }, "start": { "column": 41, - "line": 149 + "line": 151 } } }, @@ -81946,11 +81972,11 @@ "location": { "end": { "column": 6, - "line": 153 + "line": 155 }, "start": { "column": 50, - "line": 149 + "line": 151 } } }, @@ -81968,11 +81994,11 @@ "location": { "end": { "column": 118, - "line": 152 + "line": 154 }, "start": { "column": 33, - "line": 152 + "line": 154 } } }, @@ -81990,11 +82016,11 @@ "location": { "end": { "column": 117, - "line": 152 + "line": 154 }, "start": { "column": 92, - "line": 152 + "line": 154 } } }, @@ -82014,11 +82040,11 @@ "location": { "end": { "column": 4, - "line": 171 + "line": 173 }, "start": { "column": 146, - "line": 157 + "line": 159 } } }, @@ -82038,11 +82064,11 @@ "location": { "end": { "column": 6, - "line": 168 + "line": 170 }, "start": { "column": 66, - "line": 158 + "line": 160 } } }, @@ -82069,11 +82095,11 @@ "location": { "end": { "column": 4, - "line": 198 + "line": 200 }, "start": { "column": 36, - "line": 178 + "line": 180 } } }, @@ -82100,11 +82126,11 @@ "location": { "end": { "column": 78, - "line": 179 + "line": 181 }, "start": { "column": 69, - "line": 179 + "line": 181 } } }, @@ -82134,11 +82160,11 @@ "location": { "end": { "column": 16, - "line": 184 + "line": 186 }, "start": { "column": 48, - "line": 180 + "line": 182 } } }, @@ -82168,11 +82194,11 @@ "location": { "end": { "column": 16, - "line": 184 + "line": 186 }, "start": { "column": 48, - "line": 180 + "line": 182 } } }, @@ -82202,11 +82228,11 @@ "location": { "end": { "column": 16, - "line": 184 + "line": 186 }, "start": { "column": 48, - "line": 180 + "line": 182 } } }, @@ -82236,11 +82262,11 @@ "location": { "end": { "column": 7, - "line": 184 + "line": 186 }, "start": { "column": 48, - "line": 180 + "line": 182 } } }, @@ -82267,11 +82293,11 @@ "location": { "end": { "column": 91, - "line": 180 + "line": 182 }, "start": { "column": 48, - "line": 180 + "line": 182 } } }, @@ -82298,11 +82324,11 @@ "location": { "end": { "column": 6, - "line": 184 + "line": 186 }, "start": { "column": 107, - "line": 180 + "line": 182 } } }, @@ -82326,11 +82352,11 @@ "location": { "end": { "column": 63, - "line": 181 + "line": 183 }, "start": { "column": 35, - "line": 181 + "line": 183 } } }, @@ -82357,11 +82383,11 @@ "location": { "end": { "column": 42, - "line": 181 + "line": 183 }, "start": { "column": 36, - "line": 181 + "line": 183 } } }, @@ -82388,11 +82414,11 @@ "location": { "end": { "column": 62, - "line": 181 + "line": 183 }, "start": { "column": 44, - "line": 181 + "line": 183 } } }, @@ -82422,11 +82448,11 @@ "location": { "end": { "column": 16, - "line": 184 + "line": 186 }, "start": { "column": 12, - "line": 184 + "line": 186 } } }, @@ -82453,11 +82479,11 @@ "location": { "end": { "column": 56, - "line": 185 + "line": 187 }, "start": { "column": 9, - "line": 185 + "line": 187 } } }, @@ -82487,11 +82513,11 @@ "location": { "end": { "column": 56, - "line": 185 + "line": 187 }, "start": { "column": 9, - "line": 185 + "line": 187 } } }, @@ -82521,11 +82547,11 @@ "location": { "end": { "column": 56, - "line": 185 + "line": 187 }, "start": { "column": 9, - "line": 185 + "line": 187 } } }, @@ -82552,11 +82578,11 @@ "location": { "end": { "column": 56, - "line": 185 + "line": 187 }, "start": { "column": 41, - "line": 185 + "line": 187 } } }, @@ -82578,11 +82604,11 @@ "location": { "end": { "column": 6, - "line": 187 + "line": 189 }, "start": { "column": 58, - "line": 185 + "line": 187 } } }, @@ -82600,11 +82626,11 @@ "location": { "end": { "column": 48, - "line": 186 + "line": 188 }, "start": { "column": 30, - "line": 186 + "line": 188 } } }, @@ -82622,11 +82648,11 @@ "location": { "end": { "column": 56, - "line": 186 + "line": 188 }, "start": { "column": 51, - "line": 186 + "line": 188 } } }, @@ -82654,11 +82680,11 @@ "location": { "end": { "column": 99, - "line": 188 + "line": 190 }, "start": { "column": 9, - "line": 188 + "line": 190 } } }, @@ -82686,11 +82712,11 @@ "location": { "end": { "column": 99, - "line": 188 + "line": 190 }, "start": { "column": 9, - "line": 188 + "line": 190 } } }, @@ -82715,11 +82741,11 @@ "location": { "end": { "column": 99, - "line": 188 + "line": 190 }, "start": { "column": 9, - "line": 188 + "line": 190 } } }, @@ -82744,11 +82770,11 @@ "location": { "end": { "column": 46, - "line": 188 + "line": 190 }, "start": { "column": 9, - "line": 188 + "line": 190 } } }, @@ -82775,11 +82801,11 @@ "location": { "end": { "column": 99, - "line": 188 + "line": 190 }, "start": { "column": 50, - "line": 188 + "line": 190 } } }, @@ -82806,11 +82832,11 @@ "location": { "end": { "column": 99, - "line": 188 + "line": 190 }, "start": { "column": 50, - "line": 188 + "line": 190 } } }, @@ -82832,11 +82858,11 @@ "location": { "end": { "column": 6, - "line": 190 + "line": 192 }, "start": { "column": 101, - "line": 188 + "line": 190 } } }, @@ -82855,11 +82881,11 @@ "location": { "end": { "column": 23, - "line": 189 + "line": 191 }, "start": { "column": 14, - "line": 189 + "line": 191 } } }, @@ -82885,11 +82911,11 @@ "location": { "end": { "column": 43, - "line": 191 + "line": 193 }, "start": { "column": 9, - "line": 191 + "line": 193 } } }, @@ -82915,11 +82941,11 @@ "location": { "end": { "column": 43, - "line": 191 + "line": 193 }, "start": { "column": 9, - "line": 191 + "line": 193 } } }, @@ -82941,11 +82967,11 @@ "location": { "end": { "column": 6, - "line": 193 + "line": 195 }, "start": { "column": 45, - "line": 191 + "line": 193 } } }, @@ -82964,11 +82990,11 @@ "location": { "end": { "column": 21, - "line": 192 + "line": 194 }, "start": { "column": 14, - "line": 192 + "line": 194 } } }, @@ -82992,11 +83018,11 @@ "location": { "end": { "column": 116, - "line": 194 + "line": 196 }, "start": { "column": 9, - "line": 194 + "line": 196 } } }, @@ -83020,11 +83046,11 @@ "location": { "end": { "column": 116, - "line": 194 + "line": 196 }, "start": { "column": 9, - "line": 194 + "line": 196 } } }, @@ -83048,11 +83074,11 @@ "location": { "end": { "column": 116, - "line": 194 + "line": 196 }, "start": { "column": 9, - "line": 194 + "line": 196 } } }, @@ -83073,11 +83099,11 @@ "location": { "end": { "column": 82, - "line": 194 + "line": 196 }, "start": { "column": 53, - "line": 194 + "line": 196 } } }, @@ -83100,11 +83126,11 @@ "location": { "end": { "column": 116, - "line": 194 + "line": 196 }, "start": { "column": 87, - "line": 194 + "line": 196 } } }, @@ -83127,11 +83153,11 @@ "location": { "end": { "column": 116, - "line": 194 + "line": 196 }, "start": { "column": 87, - "line": 194 + "line": 196 } } }, @@ -83153,11 +83179,11 @@ "location": { "end": { "column": 6, - "line": 196 + "line": 198 }, "start": { "column": 118, - "line": 194 + "line": 196 } } }, @@ -83176,11 +83202,11 @@ "location": { "end": { "column": 31, - "line": 195 + "line": 197 }, "start": { "column": 14, - "line": 195 + "line": 197 } } }, @@ -83199,11 +83225,11 @@ "location": { "end": { "column": 17, - "line": 197 + "line": 199 }, "start": { "column": 12, - "line": 197 + "line": 199 } } }, @@ -83226,11 +83252,11 @@ "location": { "end": { "column": 4, - "line": 212 + "line": 214 }, "start": { "column": 34, - "line": 204 + "line": 206 } } }, @@ -83253,11 +83279,11 @@ "location": { "end": { "column": 6, - "line": 209 + "line": 211 }, "start": { "column": 70, - "line": 206 + "line": 208 } } }, @@ -83277,16 +83303,16 @@ "location": { "end": { "column": 4, - "line": 216 + "line": 218 }, "start": { "column": 122, - "line": 214 + "line": 216 } } } ], - "source": "import { MakeGamePlayTargetWithRelationsDto } from \"@/modules/game/dto/make-game-play/make-game-play-target/make-game-play-target-with-relations.dto\";\nimport type { MakeGamePlayWithRelationsDto } from \"@/modules/game/dto/make-game-play/make-game-play-with-relations.dto\";\nimport { createGameHistoryRecordPlaySource } from \"@/modules/game/helpers/game-history-record/game-history-record-play/game-history-record-play-source/game-history-record-play-source.factory\";\nimport { createGameHistoryRecordPlayVoting } from \"@/modules/game/helpers/game-history-record/game-history-record-play/game-history-record-play-voting/game-history-record-play-voting.factory\";\nimport { createGameHistoryRecordPlay } from \"@/modules/game/helpers/game-history-record/game-history-record-play/game-history-record-play.factory\";\nimport { createGameHistoryRecordPlayerAttributeAlteration } from \"@/modules/game/helpers/game-history-record/game-history-record-player-attribute-alteration/game-history-record-player-attribute-alteration.factory\";\nimport { createGameHistoryRecordToInsert } from \"@/modules/game/helpers/game-history-record/game-history-record.factory\";\nimport { doesGamePlayHaveCause } from \"@/modules/game/helpers/game-play/game-play.helpers\";\nimport { getFoxSniffedPlayers, getPlayerWithActiveAttributeName, getPlayerWithId } from \"@/modules/game/helpers/game.helpers\";\nimport { doesPlayerHaveAttributeWithNameAndSource, isPlayerAttributeActive } from \"@/modules/game/helpers/player/player-attribute/player-attribute.helpers\";\nimport { GamePlayVoteService } from \"@/modules/game/providers/services/game-play/game-play-vote/game-play-vote.service\";\nimport { GameHistoryRecordPlaySource } from \"@/modules/game/schemas/game-history-record/game-history-record-play/game-history-record-play-source/game-history-record-play-source.schema\";\nimport { GameHistoryRecordPlayVoting } from \"@/modules/game/schemas/game-history-record/game-history-record-play/game-history-record-play-voting/game-history-record-play-voting.schema\";\nimport { GameHistoryRecordPlay } from \"@/modules/game/schemas/game-history-record/game-history-record-play/game-history-record-play.schema\";\nimport { GameHistoryRecordPlayerAttributeAlteration } from \"@/modules/game/schemas/game-history-record/game-history-record-player-attribute-alteration/game-history-record-player-attribute-alteration.schema\";\nimport type { Game } from \"@/modules/game/schemas/game.schema\";\nimport type { DeadPlayer } from \"@/modules/game/schemas/player/dead-player.schema\";\nimport type { Player } from \"@/modules/game/schemas/player/player.schema\";\nimport { GameHistoryRecordToInsert, GameHistoryRecordVotingResult } from \"@/modules/game/types/game-history-record/game-history-record.types\";\nimport type { GameWithCurrentPlay } from \"@/modules/game/types/game-with-current-play.types\";\nimport { createNoCurrentGamePlayUnexpectedException } from \"@/shared/exception/helpers/unexpected-exception.factory\";\nimport { Injectable } from \"@nestjs/common\";\n\n@Injectable()\nexport class GameHistoryRecordToInsertGeneratorService {\n public constructor(private readonly gamePlayVoteService: GamePlayVoteService) {}\n\n public generateCurrentGameHistoryRecordToInsert(baseGame: Game, newGame: Game, play: MakeGamePlayWithRelationsDto): GameHistoryRecordToInsert {\n if (baseGame.currentPlay === null) {\n throw createNoCurrentGamePlayUnexpectedException(\"generateCurrentGameHistoryRecordToInsert\", { gameId: baseGame._id });\n }\n const gameHistoryRecordToInsert: GameHistoryRecordToInsert = {\n gameId: baseGame._id,\n turn: baseGame.turn,\n phase: baseGame.phase,\n tick: baseGame.tick,\n events: baseGame.events,\n play: this.generateCurrentGameHistoryRecordPlayToInsert(baseGame as GameWithCurrentPlay, play),\n revealedPlayers: this.generateCurrentGameHistoryRecordRevealedPlayersToInsert(baseGame, newGame),\n switchedSidePlayers: this.generateCurrentGameHistoryRecordSwitchedSidePlayersToInsert(baseGame, newGame),\n deadPlayers: this.generateCurrentGameHistoryRecordDeadPlayersToInsert(baseGame, newGame),\n playerAttributeAlterations: this.generateCurrentGameHistoryRecordPlayerAttributeAlterationsToInsert(baseGame, newGame),\n };\n if (gameHistoryRecordToInsert.play.type === \"vote\") {\n gameHistoryRecordToInsert.play.voting = this.generateCurrentGameHistoryRecordPlayVotingToInsert(baseGame as GameWithCurrentPlay, newGame, gameHistoryRecordToInsert);\n }\n return createGameHistoryRecordToInsert(gameHistoryRecordToInsert);\n }\n\n private generateCurrentGameHistoryRecordDeadPlayersToInsert(baseGame: Game, newGame: Game): DeadPlayer[] | undefined {\n const basePlayersMap = new Map(baseGame.players.map(player => [player.name, player]));\n const currentDeadPlayers = newGame.players.filter(player => {\n const matchingBasePlayer = basePlayersMap.get(player.name);\n\n return matchingBasePlayer?.isAlive === true && !player.isAlive;\n }) as DeadPlayer[];\n\n return currentDeadPlayers.length ? currentDeadPlayers : undefined;\n }\n\n private generateCurrentGameHistoryRecordSwitchedSidePlayersToInsert(baseGame: Game, newGame: Game): Player[] | undefined {\n const basePlayersMap = new Map(baseGame.players.map(player => [player.name, player]));\n const currentSwitchedSidePlayers = newGame.players.filter(player => {\n const matchingBasePlayer = basePlayersMap.get(player.name);\n\n return matchingBasePlayer?.side.current !== player.side.current;\n });\n\n return currentSwitchedSidePlayers.length ? currentSwitchedSidePlayers : undefined;\n }\n\n private generateCurrentGameHistoryRecordRevealedPlayersToInsert(baseGame: Game, newGame: Game): Player[] | undefined {\n const basePlayersMap = new Map(baseGame.players.map(player => [player.name, player]));\n const currentRevealedPlayers = newGame.players.filter(player => {\n const matchingBasePlayer = basePlayersMap.get(player.name);\n\n return matchingBasePlayer?.role.isRevealed === false && player.role.isRevealed && player.isAlive;\n });\n\n return currentRevealedPlayers.length ? currentRevealedPlayers : undefined;\n }\n\n private generateCurrentGameHistoryRecordAttachedPlayerAttributesToInsertForPlayer(basePlayer: Player, newPlayer: Player): GameHistoryRecordPlayerAttributeAlteration[] {\n return newPlayer.attributes.reduce((alterations, playerAttribute) => {\n if (!doesPlayerHaveAttributeWithNameAndSource(basePlayer, playerAttribute.name, playerAttribute.source)) {\n alterations.push(createGameHistoryRecordPlayerAttributeAlteration({\n playerName: newPlayer.name,\n name: playerAttribute.name,\n source: playerAttribute.source,\n status: \"attached\",\n }));\n }\n return alterations;\n }, []);\n }\n\n private generateCurrentGameHistoryRecordDetachedPlayerAttributesToInsertForPlayer(basePlayer: Player, newPlayer: Player): GameHistoryRecordPlayerAttributeAlteration[] {\n return basePlayer.attributes.reduce((alterations, playerAttribute) => {\n if (!doesPlayerHaveAttributeWithNameAndSource(newPlayer, playerAttribute.name, playerAttribute.source)) {\n alterations.push(createGameHistoryRecordPlayerAttributeAlteration({\n playerName: newPlayer.name,\n name: playerAttribute.name,\n source: playerAttribute.source,\n status: \"detached\",\n }));\n }\n return alterations;\n }, []);\n }\n\n private generateCurrentGameHistoryRecordActivatedPlayerAttributesToInsertForPlayer(baseGame: Game, newGame: Game, basePlayer: Player, newPlayer: Player):\n GameHistoryRecordPlayerAttributeAlteration[] {\n return newPlayer.attributes.reduce((alterations, playerAttribute) => {\n const doesBasePlayerHaveAttribute = doesPlayerHaveAttributeWithNameAndSource(basePlayer, playerAttribute.name, playerAttribute.source);\n const doesPlayerAttributeBecomesActive = !isPlayerAttributeActive(playerAttribute, baseGame) && isPlayerAttributeActive(playerAttribute, newGame);\n if (doesBasePlayerHaveAttribute && doesPlayerAttributeBecomesActive) {\n alterations.push(createGameHistoryRecordPlayerAttributeAlteration({\n playerName: newPlayer.name,\n name: playerAttribute.name,\n source: playerAttribute.source,\n status: \"activated\",\n }));\n }\n return alterations;\n }, []);\n }\n\n private generateCurrentGameHistoryRecordPlayerAttributeAlterationsToInsert(baseGame: Game, newGame: Game): GameHistoryRecordPlayerAttributeAlteration[] | undefined {\n const { players: newPlayers } = newGame;\n const playerAttributeAlterations = newPlayers.reduce((alterations, player) => {\n const matchingBasePlayer = getPlayerWithId(baseGame, player._id);\n if (!matchingBasePlayer) {\n return alterations;\n }\n const attachedPlayerAttributes = this.generateCurrentGameHistoryRecordAttachedPlayerAttributesToInsertForPlayer(matchingBasePlayer, player);\n const detachedPlayerAttributes = this.generateCurrentGameHistoryRecordDetachedPlayerAttributesToInsertForPlayer(matchingBasePlayer, player);\n const activatedPlayerAttributes = this.generateCurrentGameHistoryRecordActivatedPlayerAttributesToInsertForPlayer(baseGame, newGame, matchingBasePlayer, player);\n\n return alterations.concat(attachedPlayerAttributes, detachedPlayerAttributes, activatedPlayerAttributes);\n }, []);\n\n return playerAttributeAlterations.length ? playerAttributeAlterations : undefined;\n }\n\n private generateCurrentGameHistoryRecordPlayTargetsToInsert(baseGame: GameWithCurrentPlay, play: MakeGamePlayWithRelationsDto): MakeGamePlayTargetWithRelationsDto[] | undefined {\n if (!play.targets) {\n return undefined;\n }\n if (baseGame.currentPlay.action === \"sniff\") {\n const sniffedPlayers = getFoxSniffedPlayers(play.targets[0].player._id, baseGame);\n\n return sniffedPlayers.map(sniffedPlayer => MakeGamePlayTargetWithRelationsDto.create({ player: sniffedPlayer }));\n }\n return play.targets;\n }\n\n private generateCurrentGameHistoryRecordPlayToInsert(baseGame: GameWithCurrentPlay, play: MakeGamePlayWithRelationsDto): GameHistoryRecordPlay {\n const gameHistoryRecordPlayToInsert: GameHistoryRecordPlay = {\n type: baseGame.currentPlay.type,\n source: this.generateCurrentGameHistoryRecordPlaySourceToInsert(baseGame),\n action: baseGame.currentPlay.action,\n causes: baseGame.currentPlay.causes,\n didJudgeRequestAnotherVote: play.doesJudgeRequestAnotherVote,\n targets: this.generateCurrentGameHistoryRecordPlayTargetsToInsert(baseGame, play),\n votes: play.votes,\n chosenCard: play.chosenCard,\n chosenSide: play.chosenSide,\n };\n\n return createGameHistoryRecordPlay(gameHistoryRecordPlayToInsert);\n }\n\n private generateCurrentGameHistoryRecordPlayVotingResultToInsert(\n baseGame: GameWithCurrentPlay,\n newGame: Game,\n nominatedPlayers: Player[],\n gameHistoryRecordToInsert: GameHistoryRecordToInsert,\n ): GameHistoryRecordVotingResult {\n const sheriffPlayer = getPlayerWithActiveAttributeName(newGame, \"sheriff\");\n const areSomePlayersDeadFromCurrentVotes = gameHistoryRecordToInsert.deadPlayers?.some(({ death }) => {\n const deathFromVoteCauses = [\"vote\", \"vote-scapegoated\"];\n\n return deathFromVoteCauses.includes(death.cause);\n }) === true;\n if (baseGame.currentPlay.action === \"elect-sheriff\") {\n return sheriffPlayer ? \"sheriff-election\" : \"tie\";\n }\n if (!gameHistoryRecordToInsert.play.votes || gameHistoryRecordToInsert.play.votes.length === 0) {\n return \"skipped\";\n }\n if (areSomePlayersDeadFromCurrentVotes) {\n return \"death\";\n }\n if (doesGamePlayHaveCause(baseGame.currentPlay, \"previous-votes-were-in-ties\") || nominatedPlayers.length === 1) {\n return \"inconsequential\";\n }\n return \"tie\";\n }\n\n private generateCurrentGameHistoryRecordPlayVotingToInsert(\n baseGame: GameWithCurrentPlay,\n newGame: Game,\n gameHistoryRecordToInsert: GameHistoryRecordToInsert,\n ): GameHistoryRecordPlayVoting {\n const nominatedPlayers = this.gamePlayVoteService.getNominatedPlayers(gameHistoryRecordToInsert.play.votes, baseGame);\n const gameHistoryRecordPlayVoting: GameHistoryRecordPlayVoting = {\n result: this.generateCurrentGameHistoryRecordPlayVotingResultToInsert(baseGame, newGame, nominatedPlayers, gameHistoryRecordToInsert),\n nominatedPlayers: nominatedPlayers.length ? nominatedPlayers : undefined,\n };\n\n return createGameHistoryRecordPlayVoting(gameHistoryRecordPlayVoting);\n }\n\n private generateCurrentGameHistoryRecordPlaySourceToInsert(baseGame: GameWithCurrentPlay): GameHistoryRecordPlaySource {\n return createGameHistoryRecordPlaySource(baseGame.currentPlay.source);\n }\n}" + "source": "import { Injectable } from \"@nestjs/common\";\n\nimport { MakeGamePlayTargetWithRelationsDto } from \"@/modules/game/dto/make-game-play/make-game-play-target/make-game-play-target-with-relations.dto\";\nimport type { MakeGamePlayWithRelationsDto } from \"@/modules/game/dto/make-game-play/make-game-play-with-relations.dto\";\nimport { createGameHistoryRecordPlaySource } from \"@/modules/game/helpers/game-history-record/game-history-record-play/game-history-record-play-source/game-history-record-play-source.factory\";\nimport { createGameHistoryRecordPlayVoting } from \"@/modules/game/helpers/game-history-record/game-history-record-play/game-history-record-play-voting/game-history-record-play-voting.factory\";\nimport { createGameHistoryRecordPlay } from \"@/modules/game/helpers/game-history-record/game-history-record-play/game-history-record-play.factory\";\nimport { createGameHistoryRecordPlayerAttributeAlteration } from \"@/modules/game/helpers/game-history-record/game-history-record-player-attribute-alteration/game-history-record-player-attribute-alteration.factory\";\nimport { createGameHistoryRecordToInsert } from \"@/modules/game/helpers/game-history-record/game-history-record.factory\";\nimport { doesGamePlayHaveCause } from \"@/modules/game/helpers/game-play/game-play.helpers\";\nimport { getFoxSniffedPlayers, getPlayerWithActiveAttributeName, getPlayerWithId } from \"@/modules/game/helpers/game.helpers\";\nimport { doesPlayerHaveAttributeWithNameAndSource, isPlayerAttributeActive } from \"@/modules/game/helpers/player/player-attribute/player-attribute.helpers\";\nimport { GamePlayVoteService } from \"@/modules/game/providers/services/game-play/game-play-vote/game-play-vote.service\";\nimport { GameHistoryRecordPlaySource } from \"@/modules/game/schemas/game-history-record/game-history-record-play/game-history-record-play-source/game-history-record-play-source.schema\";\nimport { GameHistoryRecordPlayVoting } from \"@/modules/game/schemas/game-history-record/game-history-record-play/game-history-record-play-voting/game-history-record-play-voting.schema\";\nimport { GameHistoryRecordPlay } from \"@/modules/game/schemas/game-history-record/game-history-record-play/game-history-record-play.schema\";\nimport { GameHistoryRecordPlayerAttributeAlteration } from \"@/modules/game/schemas/game-history-record/game-history-record-player-attribute-alteration/game-history-record-player-attribute-alteration.schema\";\nimport type { Game } from \"@/modules/game/schemas/game.schema\";\nimport type { DeadPlayer } from \"@/modules/game/schemas/player/dead-player.schema\";\nimport type { Player } from \"@/modules/game/schemas/player/player.schema\";\nimport { GameHistoryRecordToInsert, GameHistoryRecordVotingResult } from \"@/modules/game/types/game-history-record/game-history-record.types\";\nimport type { GameWithCurrentPlay } from \"@/modules/game/types/game-with-current-play.types\";\n\nimport { createNoCurrentGamePlayUnexpectedException } from \"@/shared/exception/helpers/unexpected-exception.factory\";\n\n@Injectable()\nexport class GameHistoryRecordToInsertGeneratorService {\n public constructor(private readonly gamePlayVoteService: GamePlayVoteService) {}\n\n public generateCurrentGameHistoryRecordToInsert(baseGame: Game, newGame: Game, play: MakeGamePlayWithRelationsDto): GameHistoryRecordToInsert {\n if (baseGame.currentPlay === null) {\n throw createNoCurrentGamePlayUnexpectedException(\"generateCurrentGameHistoryRecordToInsert\", { gameId: baseGame._id });\n }\n const gameHistoryRecordToInsert: GameHistoryRecordToInsert = {\n gameId: baseGame._id,\n turn: baseGame.turn,\n phase: baseGame.phase,\n tick: baseGame.tick,\n events: baseGame.events,\n play: this.generateCurrentGameHistoryRecordPlayToInsert(baseGame as GameWithCurrentPlay, play),\n revealedPlayers: this.generateCurrentGameHistoryRecordRevealedPlayersToInsert(baseGame, newGame),\n switchedSidePlayers: this.generateCurrentGameHistoryRecordSwitchedSidePlayersToInsert(baseGame, newGame),\n deadPlayers: this.generateCurrentGameHistoryRecordDeadPlayersToInsert(baseGame, newGame),\n playerAttributeAlterations: this.generateCurrentGameHistoryRecordPlayerAttributeAlterationsToInsert(baseGame, newGame),\n };\n if (gameHistoryRecordToInsert.play.type === \"vote\") {\n gameHistoryRecordToInsert.play.voting = this.generateCurrentGameHistoryRecordPlayVotingToInsert(baseGame as GameWithCurrentPlay, newGame, gameHistoryRecordToInsert);\n }\n return createGameHistoryRecordToInsert(gameHistoryRecordToInsert);\n }\n\n private generateCurrentGameHistoryRecordDeadPlayersToInsert(baseGame: Game, newGame: Game): DeadPlayer[] | undefined {\n const basePlayersMap = new Map(baseGame.players.map(player => [player.name, player]));\n const currentDeadPlayers = newGame.players.filter(player => {\n const matchingBasePlayer = basePlayersMap.get(player.name);\n\n return matchingBasePlayer?.isAlive === true && !player.isAlive;\n }) as DeadPlayer[];\n\n return currentDeadPlayers.length ? currentDeadPlayers : undefined;\n }\n\n private generateCurrentGameHistoryRecordSwitchedSidePlayersToInsert(baseGame: Game, newGame: Game): Player[] | undefined {\n const basePlayersMap = new Map(baseGame.players.map(player => [player.name, player]));\n const currentSwitchedSidePlayers = newGame.players.filter(player => {\n const matchingBasePlayer = basePlayersMap.get(player.name);\n\n return matchingBasePlayer?.side.current !== player.side.current;\n });\n\n return currentSwitchedSidePlayers.length ? currentSwitchedSidePlayers : undefined;\n }\n\n private generateCurrentGameHistoryRecordRevealedPlayersToInsert(baseGame: Game, newGame: Game): Player[] | undefined {\n const basePlayersMap = new Map(baseGame.players.map(player => [player.name, player]));\n const currentRevealedPlayers = newGame.players.filter(player => {\n const matchingBasePlayer = basePlayersMap.get(player.name);\n\n return matchingBasePlayer?.role.isRevealed === false && player.role.isRevealed && player.isAlive;\n });\n\n return currentRevealedPlayers.length ? currentRevealedPlayers : undefined;\n }\n\n private generateCurrentGameHistoryRecordAttachedPlayerAttributesToInsertForPlayer(basePlayer: Player, newPlayer: Player): GameHistoryRecordPlayerAttributeAlteration[] {\n return newPlayer.attributes.reduce((alterations, playerAttribute) => {\n if (!doesPlayerHaveAttributeWithNameAndSource(basePlayer, playerAttribute.name, playerAttribute.source)) {\n alterations.push(createGameHistoryRecordPlayerAttributeAlteration({\n playerName: newPlayer.name,\n name: playerAttribute.name,\n source: playerAttribute.source,\n status: \"attached\",\n }));\n }\n return alterations;\n }, []);\n }\n\n private generateCurrentGameHistoryRecordDetachedPlayerAttributesToInsertForPlayer(basePlayer: Player, newPlayer: Player): GameHistoryRecordPlayerAttributeAlteration[] {\n return basePlayer.attributes.reduce((alterations, playerAttribute) => {\n if (!doesPlayerHaveAttributeWithNameAndSource(newPlayer, playerAttribute.name, playerAttribute.source)) {\n alterations.push(createGameHistoryRecordPlayerAttributeAlteration({\n playerName: newPlayer.name,\n name: playerAttribute.name,\n source: playerAttribute.source,\n status: \"detached\",\n }));\n }\n return alterations;\n }, []);\n }\n\n private generateCurrentGameHistoryRecordActivatedPlayerAttributesToInsertForPlayer(baseGame: Game, newGame: Game, basePlayer: Player, newPlayer: Player):\n GameHistoryRecordPlayerAttributeAlteration[] {\n return newPlayer.attributes.reduce((alterations, playerAttribute) => {\n const doesBasePlayerHaveAttribute = doesPlayerHaveAttributeWithNameAndSource(basePlayer, playerAttribute.name, playerAttribute.source);\n const doesPlayerAttributeBecomesActive = !isPlayerAttributeActive(playerAttribute, baseGame) && isPlayerAttributeActive(playerAttribute, newGame);\n if (doesBasePlayerHaveAttribute && doesPlayerAttributeBecomesActive) {\n alterations.push(createGameHistoryRecordPlayerAttributeAlteration({\n playerName: newPlayer.name,\n name: playerAttribute.name,\n source: playerAttribute.source,\n status: \"activated\",\n }));\n }\n return alterations;\n }, []);\n }\n\n private generateCurrentGameHistoryRecordPlayerAttributeAlterationsToInsert(baseGame: Game, newGame: Game): GameHistoryRecordPlayerAttributeAlteration[] | undefined {\n const { players: newPlayers } = newGame;\n const playerAttributeAlterations = newPlayers.reduce((alterations, player) => {\n const matchingBasePlayer = getPlayerWithId(baseGame, player._id);\n if (!matchingBasePlayer) {\n return alterations;\n }\n const attachedPlayerAttributes = this.generateCurrentGameHistoryRecordAttachedPlayerAttributesToInsertForPlayer(matchingBasePlayer, player);\n const detachedPlayerAttributes = this.generateCurrentGameHistoryRecordDetachedPlayerAttributesToInsertForPlayer(matchingBasePlayer, player);\n const activatedPlayerAttributes = this.generateCurrentGameHistoryRecordActivatedPlayerAttributesToInsertForPlayer(baseGame, newGame, matchingBasePlayer, player);\n\n return alterations.concat(attachedPlayerAttributes, detachedPlayerAttributes, activatedPlayerAttributes);\n }, []);\n\n return playerAttributeAlterations.length ? playerAttributeAlterations : undefined;\n }\n\n private generateCurrentGameHistoryRecordPlayTargetsToInsert(baseGame: GameWithCurrentPlay, play: MakeGamePlayWithRelationsDto): MakeGamePlayTargetWithRelationsDto[] | undefined {\n if (!play.targets) {\n return undefined;\n }\n if (baseGame.currentPlay.action === \"sniff\") {\n const sniffedPlayers = getFoxSniffedPlayers(play.targets[0].player._id, baseGame);\n\n return sniffedPlayers.map(sniffedPlayer => MakeGamePlayTargetWithRelationsDto.create({ player: sniffedPlayer }));\n }\n return play.targets;\n }\n\n private generateCurrentGameHistoryRecordPlayToInsert(baseGame: GameWithCurrentPlay, play: MakeGamePlayWithRelationsDto): GameHistoryRecordPlay {\n const gameHistoryRecordPlayToInsert: GameHistoryRecordPlay = {\n type: baseGame.currentPlay.type,\n source: this.generateCurrentGameHistoryRecordPlaySourceToInsert(baseGame),\n action: baseGame.currentPlay.action,\n causes: baseGame.currentPlay.causes,\n didJudgeRequestAnotherVote: play.doesJudgeRequestAnotherVote,\n targets: this.generateCurrentGameHistoryRecordPlayTargetsToInsert(baseGame, play),\n votes: play.votes,\n chosenCard: play.chosenCard,\n chosenSide: play.chosenSide,\n };\n\n return createGameHistoryRecordPlay(gameHistoryRecordPlayToInsert);\n }\n\n private generateCurrentGameHistoryRecordPlayVotingResultToInsert(\n baseGame: GameWithCurrentPlay,\n newGame: Game,\n nominatedPlayers: Player[],\n gameHistoryRecordToInsert: GameHistoryRecordToInsert,\n ): GameHistoryRecordVotingResult {\n const sheriffPlayer = getPlayerWithActiveAttributeName(newGame, \"sheriff\");\n const areSomePlayersDeadFromCurrentVotes = gameHistoryRecordToInsert.deadPlayers?.some(({ death }) => {\n const deathFromVoteCauses = [\"vote\", \"vote-scapegoated\"];\n\n return deathFromVoteCauses.includes(death.cause);\n }) === true;\n if (baseGame.currentPlay.action === \"elect-sheriff\") {\n return sheriffPlayer ? \"sheriff-election\" : \"tie\";\n }\n if (!gameHistoryRecordToInsert.play.votes || gameHistoryRecordToInsert.play.votes.length === 0) {\n return \"skipped\";\n }\n if (areSomePlayersDeadFromCurrentVotes) {\n return \"death\";\n }\n if (doesGamePlayHaveCause(baseGame.currentPlay, \"previous-votes-were-in-ties\") || nominatedPlayers.length === 1) {\n return \"inconsequential\";\n }\n return \"tie\";\n }\n\n private generateCurrentGameHistoryRecordPlayVotingToInsert(\n baseGame: GameWithCurrentPlay,\n newGame: Game,\n gameHistoryRecordToInsert: GameHistoryRecordToInsert,\n ): GameHistoryRecordPlayVoting {\n const nominatedPlayers = this.gamePlayVoteService.getNominatedPlayers(gameHistoryRecordToInsert.play.votes, baseGame);\n const gameHistoryRecordPlayVoting: GameHistoryRecordPlayVoting = {\n result: this.generateCurrentGameHistoryRecordPlayVotingResultToInsert(baseGame, newGame, nominatedPlayers, gameHistoryRecordToInsert),\n nominatedPlayers: nominatedPlayers.length ? nominatedPlayers : undefined,\n };\n\n return createGameHistoryRecordPlayVoting(gameHistoryRecordPlayVoting);\n }\n\n private generateCurrentGameHistoryRecordPlaySourceToInsert(baseGame: GameWithCurrentPlay): GameHistoryRecordPlaySource {\n return createGameHistoryRecordPlaySource(baseGame.currentPlay.source);\n }\n}" }, "src/modules/game/providers/services/game-history/game-history-record.service.ts": { "language": "typescript", @@ -83307,11 +83333,11 @@ "location": { "end": { "column": 4, - "line": 31 + "line": 32 }, "start": { "column": 122, - "line": 27 + "line": 28 } } }, @@ -83329,11 +83355,11 @@ "location": { "end": { "column": 4, - "line": 35 + "line": 36 }, "start": { "column": 150, - "line": 33 + "line": 34 } } }, @@ -83351,11 +83377,11 @@ "location": { "end": { "column": 4, - "line": 39 + "line": 40 }, "start": { "column": 113, - "line": 37 + "line": 38 } } }, @@ -83374,11 +83400,11 @@ "location": { "end": { "column": 4, - "line": 43 + "line": 44 }, "start": { "column": 134, - "line": 41 + "line": 42 } } }, @@ -83396,11 +83422,11 @@ "location": { "end": { "column": 4, - "line": 47 + "line": 48 }, "start": { "column": 169, - "line": 45 + "line": 46 } } }, @@ -83419,11 +83445,11 @@ "location": { "end": { "column": 4, - "line": 51 + "line": 52 }, "start": { "column": 167, - "line": 49 + "line": 50 } } }, @@ -83441,11 +83467,11 @@ "location": { "end": { "column": 4, - "line": 55 + "line": 56 }, "start": { "column": 171, - "line": 53 + "line": 54 } } }, @@ -83463,11 +83489,11 @@ "location": { "end": { "column": 4, - "line": 59 + "line": 60 }, "start": { "column": 167, - "line": 57 + "line": 58 } } }, @@ -83485,11 +83511,11 @@ "location": { "end": { "column": 4, - "line": 63 + "line": 64 }, "start": { "column": 141, - "line": 61 + "line": 62 } } }, @@ -83507,11 +83533,11 @@ "location": { "end": { "column": 4, - "line": 67 + "line": 68 }, "start": { "column": 151, - "line": 65 + "line": 66 } } }, @@ -83531,11 +83557,11 @@ "location": { "end": { "column": 4, - "line": 71 + "line": 72 }, "start": { "column": 147, - "line": 69 + "line": 70 } } }, @@ -83553,11 +83579,11 @@ "location": { "end": { "column": 4, - "line": 75 + "line": 76 }, "start": { "column": 104, - "line": 73 + "line": 74 } } }, @@ -83578,11 +83604,11 @@ "location": { "end": { "column": 4, - "line": 79 + "line": 80 }, "start": { "column": 123, - "line": 77 + "line": 78 } } }, @@ -83602,11 +83628,11 @@ "location": { "end": { "column": 4, - "line": 85 + "line": 86 }, "start": { "column": 98, - "line": 81 + "line": 82 } } }, @@ -83629,11 +83655,11 @@ "location": { "end": { "column": 120, - "line": 82 + "line": 83 }, "start": { "column": 108, - "line": 82 + "line": 83 } } }, @@ -83656,11 +83682,11 @@ "location": { "end": { "column": 30, - "line": 84 + "line": 85 }, "start": { "column": 12, - "line": 84 + "line": 85 } } }, @@ -83683,11 +83709,11 @@ "location": { "end": { "column": 30, - "line": 84 + "line": 85 }, "start": { "column": 12, - "line": 84 + "line": 85 } } }, @@ -83710,11 +83736,11 @@ "location": { "end": { "column": 30, - "line": 84 + "line": 85 }, "start": { "column": 12, - "line": 84 + "line": 85 } } }, @@ -83737,11 +83763,11 @@ "location": { "end": { "column": 30, - "line": 84 + "line": 85 }, "start": { "column": 12, - "line": 84 + "line": 85 } } }, @@ -83761,11 +83787,11 @@ "location": { "end": { "column": 4, - "line": 91 + "line": 92 }, "start": { "column": 122, - "line": 87 + "line": 88 } } }, @@ -83788,11 +83814,11 @@ "location": { "end": { "column": 140, - "line": 88 + "line": 89 }, "start": { "column": 128, - "line": 88 + "line": 89 } } }, @@ -83815,11 +83841,11 @@ "location": { "end": { "column": 30, - "line": 90 + "line": 91 }, "start": { "column": 12, - "line": 90 + "line": 91 } } }, @@ -83842,11 +83868,11 @@ "location": { "end": { "column": 30, - "line": 90 + "line": 91 }, "start": { "column": 12, - "line": 90 + "line": 91 } } }, @@ -83869,11 +83895,11 @@ "location": { "end": { "column": 30, - "line": 90 + "line": 91 }, "start": { "column": 12, - "line": 90 + "line": 91 } } }, @@ -83896,11 +83922,11 @@ "location": { "end": { "column": 30, - "line": 90 + "line": 91 }, "start": { "column": 12, - "line": 90 + "line": 91 } } }, @@ -83929,11 +83955,11 @@ "location": { "end": { "column": 4, - "line": 113 + "line": 114 }, "start": { "column": 100, - "line": 93 + "line": 94 } } }, @@ -83959,11 +83985,11 @@ "location": { "end": { "column": 24, - "line": 95 + "line": 96 }, "start": { "column": 9, - "line": 95 + "line": 96 } } }, @@ -83989,11 +84015,11 @@ "location": { "end": { "column": 24, - "line": 95 + "line": 96 }, "start": { "column": 9, - "line": 95 + "line": 96 } } }, @@ -84014,11 +84040,11 @@ "location": { "end": { "column": 6, - "line": 97 + "line": 98 }, "start": { "column": 26, - "line": 95 + "line": 96 } } }, @@ -84043,11 +84069,11 @@ "location": { "end": { "column": 73, - "line": 98 + "line": 99 }, "start": { "column": 56, - "line": 98 + "line": 99 } } }, @@ -84067,11 +84093,11 @@ "location": { "end": { "column": 97, - "line": 98 + "line": 99 }, "start": { "column": 74, - "line": 98 + "line": 99 } } }, @@ -84096,11 +84122,11 @@ "location": { "end": { "column": 24, - "line": 99 + "line": 100 }, "start": { "column": 9, - "line": 99 + "line": 100 } } }, @@ -84125,11 +84151,11 @@ "location": { "end": { "column": 24, - "line": 99 + "line": 100 }, "start": { "column": 9, - "line": 99 + "line": 100 } } }, @@ -84150,11 +84176,11 @@ "location": { "end": { "column": 6, - "line": 101 + "line": 102 }, "start": { "column": 26, - "line": 99 + "line": 100 } } }, @@ -84178,11 +84204,11 @@ "location": { "end": { "column": 70, - "line": 102 + "line": 103 }, "start": { "column": 55, - "line": 102 + "line": 103 } } }, @@ -84203,11 +84229,11 @@ "location": { "end": { "column": 90, - "line": 102 + "line": 103 }, "start": { "column": 71, - "line": 102 + "line": 103 } } }, @@ -84231,11 +84257,11 @@ "location": { "end": { "column": 23, - "line": 103 + "line": 104 }, "start": { "column": 9, - "line": 103 + "line": 104 } } }, @@ -84259,11 +84285,11 @@ "location": { "end": { "column": 23, - "line": 103 + "line": 104 }, "start": { "column": 9, - "line": 103 + "line": 104 } } }, @@ -84284,11 +84310,11 @@ "location": { "end": { "column": 6, - "line": 105 + "line": 106 }, "start": { "column": 25, - "line": 103 + "line": 104 } } }, @@ -84311,11 +84337,11 @@ "location": { "end": { "column": 75, - "line": 106 + "line": 107 }, "start": { "column": 60, - "line": 106 + "line": 107 } } }, @@ -84335,11 +84361,11 @@ "location": { "end": { "column": 95, - "line": 106 + "line": 107 }, "start": { "column": 76, - "line": 106 + "line": 107 } } }, @@ -84362,11 +84388,11 @@ "location": { "end": { "column": 28, - "line": 107 + "line": 108 }, "start": { "column": 9, - "line": 107 + "line": 108 } } }, @@ -84389,11 +84415,11 @@ "location": { "end": { "column": 28, - "line": 107 + "line": 108 }, "start": { "column": 9, - "line": 107 + "line": 108 } } }, @@ -84414,11 +84440,11 @@ "location": { "end": { "column": 6, - "line": 109 + "line": 110 }, "start": { "column": 30, - "line": 107 + "line": 108 } } }, @@ -84440,11 +84466,11 @@ "location": { "end": { "column": 95, - "line": 110 + "line": 111 }, "start": { "column": 9, - "line": 110 + "line": 111 } } }, @@ -84466,11 +84492,11 @@ "location": { "end": { "column": 95, - "line": 110 + "line": 111 }, "start": { "column": 9, - "line": 110 + "line": 111 } } }, @@ -84492,11 +84518,11 @@ "location": { "end": { "column": 95, - "line": 110 + "line": 111 }, "start": { "column": 9, - "line": 110 + "line": 111 } } }, @@ -84518,11 +84544,11 @@ "location": { "end": { "column": 95, - "line": 110 + "line": 111 }, "start": { "column": 28, - "line": 110 + "line": 111 } } }, @@ -84543,11 +84569,11 @@ "location": { "end": { "column": 6, - "line": 112 + "line": 113 }, "start": { "column": 97, - "line": 110 + "line": 111 } } }, @@ -84573,11 +84599,11 @@ "location": { "end": { "column": 4, - "line": 130 + "line": 131 }, "start": { "column": 124, - "line": 115 + "line": 116 } } }, @@ -84603,11 +84629,11 @@ "location": { "end": { "column": 67, - "line": 117 + "line": 118 }, "start": { "column": 52, - "line": 117 + "line": 118 } } }, @@ -84630,11 +84656,11 @@ "location": { "end": { "column": 22, - "line": 118 + "line": 119 }, "start": { "column": 9, - "line": 118 + "line": 119 } } }, @@ -84657,11 +84683,11 @@ "location": { "end": { "column": 22, - "line": 118 + "line": 119 }, "start": { "column": 9, - "line": 118 + "line": 119 } } }, @@ -84684,11 +84710,11 @@ "location": { "end": { "column": 22, - "line": 118 + "line": 119 }, "start": { "column": 9, - "line": 118 + "line": 119 } } }, @@ -84706,11 +84732,11 @@ "location": { "end": { "column": 6, - "line": 120 + "line": 121 }, "start": { "column": 24, - "line": 118 + "line": 119 } } }, @@ -84732,11 +84758,11 @@ "location": { "end": { "column": 32, - "line": 122 + "line": 123 }, "start": { "column": 9, - "line": 122 + "line": 123 } } }, @@ -84758,11 +84784,11 @@ "location": { "end": { "column": 32, - "line": 122 + "line": 123 }, "start": { "column": 9, - "line": 122 + "line": 123 } } }, @@ -84783,11 +84809,11 @@ "location": { "end": { "column": 6, - "line": 124 + "line": 125 }, "start": { "column": 34, - "line": 122 + "line": 123 } } }, @@ -84808,11 +84834,11 @@ "location": { "end": { "column": 28, - "line": 126 + "line": 127 }, "start": { "column": 9, - "line": 126 + "line": 127 } } }, @@ -84833,11 +84859,11 @@ "location": { "end": { "column": 28, - "line": 126 + "line": 127 }, "start": { "column": 9, - "line": 126 + "line": 127 } } }, @@ -84858,16 +84884,16 @@ "location": { "end": { "column": 6, - "line": 128 + "line": 129 }, "start": { "column": 30, - "line": 126 + "line": 127 } } } ], - "source": "import type { GetGameHistoryDto } from \"@/modules/game/dto/get-game-history/get-game-history.dto\";\nimport { getAdditionalCardWithId, getNonexistentPlayer } from \"@/modules/game/helpers/game.helpers\";\nimport { GameHistoryRecordRepository } from \"@/modules/game/providers/repositories/game-history-record/game-history-record.repository\";\nimport { GameRepository } from \"@/modules/game/providers/repositories/game.repository\";\nimport { GameHistoryRecordPlay } from \"@/modules/game/schemas/game-history-record/game-history-record-play/game-history-record-play.schema\";\nimport type { GameHistoryRecord } from \"@/modules/game/schemas/game-history-record/game-history-record.schema\";\nimport type { GamePlay } from \"@/modules/game/schemas/game-play/game-play.schema\";\nimport type { Game } from \"@/modules/game/schemas/game.schema\";\nimport type { Player } from \"@/modules/game/schemas/player/player.schema\";\nimport { GameHistoryRecordToInsert } from \"@/modules/game/types/game-history-record/game-history-record.types\";\nimport { GamePhaseName } from \"@/modules/game/types/game-phase/game-phase.types\";\nimport { GamePlayAction, WitchPotion } from \"@/modules/game/types/game-play/game-play.types\";\n\nimport { ApiResources } from \"@/shared/api/enums/api.enums\";\nimport { ResourceNotFoundReasons } from \"@/shared/exception/enums/resource-not-found-error.enum\";\nimport { ResourceNotFoundException } from \"@/shared/exception/types/resource-not-found-exception.types\";\nimport { Injectable } from \"@nestjs/common\";\nimport type { Types } from \"mongoose\";\n\n@Injectable()\nexport class GameHistoryRecordService {\n public constructor(\n private readonly gameHistoryRecordRepository: GameHistoryRecordRepository,\n private readonly gameRepository: GameRepository,\n ) {}\n\n public async createGameHistoryRecord(gameHistoryRecordToInsert: GameHistoryRecordToInsert): Promise {\n await this.validateGameHistoryRecordToInsertData(gameHistoryRecordToInsert);\n\n return this.gameHistoryRecordRepository.create(gameHistoryRecordToInsert);\n }\n\n public async getLastGameHistoryDefenderProtectsRecord(gameId: Types.ObjectId, defenderPlayerId: Types.ObjectId): Promise {\n return this.gameHistoryRecordRepository.getLastGameHistoryDefenderProtectsRecord(gameId, defenderPlayerId);\n }\n\n public async getLastGameHistorySurvivorsVoteRecord(gameId: Types.ObjectId): Promise {\n return this.gameHistoryRecordRepository.getLastGameHistorySurvivorsVoteRecord(gameId);\n }\n\n public async getLastGameHistoryTieInVotesRecord(gameId: Types.ObjectId, action: GamePlayAction): Promise {\n return this.gameHistoryRecordRepository.getLastGameHistoryTieInVotesRecord(gameId, action);\n }\n\n public async getLastGameHistoryAccursedWolfFatherInfectsRecord(gameId: Types.ObjectId, accursedWolfFatherPlayerId: Types.ObjectId): Promise {\n return this.gameHistoryRecordRepository.getLastGameHistoryAccursedWolfFatherInfectsRecord(gameId, accursedWolfFatherPlayerId);\n }\n\n public async getGameHistoryWitchUsesSpecificPotionRecords(gameId: Types.ObjectId, witchPlayerId: Types.ObjectId, potion: WitchPotion): Promise {\n return this.gameHistoryRecordRepository.getGameHistoryWitchUsesSpecificPotionRecords(gameId, witchPlayerId, potion);\n }\n\n public async getGameHistoryAccursedWolfFatherInfectsWithTargetRecords(gameId: Types.ObjectId, accursedWolfFatherPlayerId: Types.ObjectId): Promise {\n return this.gameHistoryRecordRepository.getGameHistoryAccursedWolfFatherInfectsWithTargetRecords(gameId, accursedWolfFatherPlayerId);\n }\n\n public async getGameHistoryStutteringJudgeRequestsAnotherVoteRecords(gameId: Types.ObjectId, stutteringJudgePlayedId: Types.ObjectId): Promise {\n return this.gameHistoryRecordRepository.getGameHistoryStutteringJudgeRequestsAnotherVoteRecords(gameId, stutteringJudgePlayedId);\n }\n\n public async getGameHistoryWerewolvesEatElderRecords(gameId: Types.ObjectId, elderPlayerId: Types.ObjectId): Promise {\n return this.gameHistoryRecordRepository.getGameHistoryWerewolvesEatElderRecords(gameId, elderPlayerId);\n }\n\n public async getGameHistoryElderProtectedFromWerewolvesRecords(gameId: Types.ObjectId, elderPlayerId: Types.ObjectId): Promise {\n return this.gameHistoryRecordRepository.getGameHistoryElderProtectedFromWerewolvesRecords(gameId, elderPlayerId);\n }\n\n public async getGameHistoryRecordsForTurnAndPhases(gameId: Types.ObjectId, turn: number, phases: GamePhaseName[]): Promise {\n return this.gameHistoryRecordRepository.getGameHistoryRecordsForTurnAndPhases(gameId, turn, phases);\n }\n\n public async getPreviousGameHistoryRecord(gameId: Types.ObjectId): Promise {\n return this.gameHistoryRecordRepository.getPreviousGameHistoryRecord(gameId);\n }\n\n public async getGameHistory(gameId: Types.ObjectId, getGameHistoryDto: GetGameHistoryDto): Promise {\n return this.gameHistoryRecordRepository.getGameHistory(gameId, getGameHistoryDto);\n }\n\n public async hasGamePlayBeenMade(gameId: Types.ObjectId, gamePlay: GamePlay): Promise {\n const records = await this.gameHistoryRecordRepository.getGameHistoryGamePlayRecords(gameId, gamePlay, { limit: 1 });\n\n return records.length > 0;\n }\n\n public async hasGamePlayBeenMadeByPlayer(gameId: Types.ObjectId, gamePlay: GamePlay, player: Player): Promise {\n const records = await this.gameHistoryRecordRepository.getGameHistoryGamePlayMadeByPlayerRecords(gameId, gamePlay, player, { limit: 1 });\n\n return records.length > 0;\n }\n\n private validateGameHistoryRecordToInsertPlayData(play: GameHistoryRecordPlay, game: Game): void {\n const unmatchedSource = getNonexistentPlayer(game, play.source.players);\n if (unmatchedSource) {\n throw new ResourceNotFoundException(ApiResources.PLAYERS, unmatchedSource._id.toString(), ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_PLAYER_SOURCE);\n }\n const unmatchedTarget = getNonexistentPlayer(game, play.targets?.map(target => target.player));\n if (unmatchedTarget) {\n throw new ResourceNotFoundException(ApiResources.PLAYERS, unmatchedTarget._id.toString(), ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_PLAYER_TARGET);\n }\n const unmatchedVoter = getNonexistentPlayer(game, play.votes?.map(vote => vote.source));\n if (unmatchedVoter) {\n throw new ResourceNotFoundException(ApiResources.PLAYERS, unmatchedVoter._id.toString(), ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_PLAYER_VOTE_SOURCE);\n }\n const unmatchedVoteTarget = getNonexistentPlayer(game, play.votes?.map(vote => vote.target));\n if (unmatchedVoteTarget) {\n throw new ResourceNotFoundException(ApiResources.PLAYERS, unmatchedVoteTarget._id.toString(), ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_PLAYER_VOTE_TARGET);\n }\n if (play.chosenCard && !getAdditionalCardWithId(game.additionalCards, play.chosenCard._id)) {\n throw new ResourceNotFoundException(ApiResources.GAME_ADDITIONAL_CARDS, play.chosenCard._id.toString(), ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_CHOSEN_CARD);\n }\n }\n\n private async validateGameHistoryRecordToInsertData(gameHistoryRecordToInsert: GameHistoryRecordToInsert): Promise {\n const { gameId, play, revealedPlayers, deadPlayers } = gameHistoryRecordToInsert;\n const game = await this.gameRepository.findOne({ _id: gameId });\n if (game === null) {\n throw new ResourceNotFoundException(ApiResources.GAMES, gameId.toString(), ResourceNotFoundReasons.UNKNOWN_GAME_PLAY_GAME_ID);\n }\n const unmatchedRevealedPlayer = getNonexistentPlayer(game, revealedPlayers);\n if (unmatchedRevealedPlayer) {\n throw new ResourceNotFoundException(ApiResources.PLAYERS, unmatchedRevealedPlayer._id.toString(), ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_REVEALED_PLAYER);\n }\n const unmatchedDeadPlayer = getNonexistentPlayer(game, deadPlayers);\n if (unmatchedDeadPlayer) {\n throw new ResourceNotFoundException(ApiResources.PLAYERS, unmatchedDeadPlayer._id.toString(), ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_DEAD_PLAYER);\n }\n this.validateGameHistoryRecordToInsertPlayData(play, game);\n }\n}" + "source": "import { Injectable } from \"@nestjs/common\";\nimport type { Types } from \"mongoose\";\n\nimport type { GetGameHistoryDto } from \"@/modules/game/dto/get-game-history/get-game-history.dto\";\nimport { getAdditionalCardWithId, getNonexistentPlayer } from \"@/modules/game/helpers/game.helpers\";\nimport { GameHistoryRecordRepository } from \"@/modules/game/providers/repositories/game-history-record/game-history-record.repository\";\nimport { GameRepository } from \"@/modules/game/providers/repositories/game.repository\";\nimport { GameHistoryRecordPlay } from \"@/modules/game/schemas/game-history-record/game-history-record-play/game-history-record-play.schema\";\nimport type { GameHistoryRecord } from \"@/modules/game/schemas/game-history-record/game-history-record.schema\";\nimport type { GamePlay } from \"@/modules/game/schemas/game-play/game-play.schema\";\nimport type { Game } from \"@/modules/game/schemas/game.schema\";\nimport type { Player } from \"@/modules/game/schemas/player/player.schema\";\nimport { GameHistoryRecordToInsert } from \"@/modules/game/types/game-history-record/game-history-record.types\";\nimport { GamePhaseName } from \"@/modules/game/types/game-phase/game-phase.types\";\nimport { GamePlayAction, WitchPotion } from \"@/modules/game/types/game-play/game-play.types\";\n\nimport { ApiResources } from \"@/shared/api/enums/api.enums\";\nimport { ResourceNotFoundReasons } from \"@/shared/exception/enums/resource-not-found-error.enums\";\nimport { ResourceNotFoundException } from \"@/shared/exception/types/resource-not-found-exception.types\";\n\n@Injectable()\nexport class GameHistoryRecordService {\n public constructor(\n private readonly gameHistoryRecordRepository: GameHistoryRecordRepository,\n private readonly gameRepository: GameRepository,\n ) {}\n\n public async createGameHistoryRecord(gameHistoryRecordToInsert: GameHistoryRecordToInsert): Promise {\n await this.validateGameHistoryRecordToInsertData(gameHistoryRecordToInsert);\n\n return this.gameHistoryRecordRepository.create(gameHistoryRecordToInsert);\n }\n\n public async getLastGameHistoryDefenderProtectsRecord(gameId: Types.ObjectId, defenderPlayerId: Types.ObjectId): Promise {\n return this.gameHistoryRecordRepository.getLastGameHistoryDefenderProtectsRecord(gameId, defenderPlayerId);\n }\n\n public async getLastGameHistorySurvivorsVoteRecord(gameId: Types.ObjectId): Promise {\n return this.gameHistoryRecordRepository.getLastGameHistorySurvivorsVoteRecord(gameId);\n }\n\n public async getLastGameHistoryTieInVotesRecord(gameId: Types.ObjectId, action: GamePlayAction): Promise {\n return this.gameHistoryRecordRepository.getLastGameHistoryTieInVotesRecord(gameId, action);\n }\n\n public async getLastGameHistoryAccursedWolfFatherInfectsRecord(gameId: Types.ObjectId, accursedWolfFatherPlayerId: Types.ObjectId): Promise {\n return this.gameHistoryRecordRepository.getLastGameHistoryAccursedWolfFatherInfectsRecord(gameId, accursedWolfFatherPlayerId);\n }\n\n public async getGameHistoryWitchUsesSpecificPotionRecords(gameId: Types.ObjectId, witchPlayerId: Types.ObjectId, potion: WitchPotion): Promise {\n return this.gameHistoryRecordRepository.getGameHistoryWitchUsesSpecificPotionRecords(gameId, witchPlayerId, potion);\n }\n\n public async getGameHistoryAccursedWolfFatherInfectsWithTargetRecords(gameId: Types.ObjectId, accursedWolfFatherPlayerId: Types.ObjectId): Promise {\n return this.gameHistoryRecordRepository.getGameHistoryAccursedWolfFatherInfectsWithTargetRecords(gameId, accursedWolfFatherPlayerId);\n }\n\n public async getGameHistoryStutteringJudgeRequestsAnotherVoteRecords(gameId: Types.ObjectId, stutteringJudgePlayedId: Types.ObjectId): Promise {\n return this.gameHistoryRecordRepository.getGameHistoryStutteringJudgeRequestsAnotherVoteRecords(gameId, stutteringJudgePlayedId);\n }\n\n public async getGameHistoryWerewolvesEatElderRecords(gameId: Types.ObjectId, elderPlayerId: Types.ObjectId): Promise {\n return this.gameHistoryRecordRepository.getGameHistoryWerewolvesEatElderRecords(gameId, elderPlayerId);\n }\n\n public async getGameHistoryElderProtectedFromWerewolvesRecords(gameId: Types.ObjectId, elderPlayerId: Types.ObjectId): Promise {\n return this.gameHistoryRecordRepository.getGameHistoryElderProtectedFromWerewolvesRecords(gameId, elderPlayerId);\n }\n\n public async getGameHistoryRecordsForTurnAndPhases(gameId: Types.ObjectId, turn: number, phases: GamePhaseName[]): Promise {\n return this.gameHistoryRecordRepository.getGameHistoryRecordsForTurnAndPhases(gameId, turn, phases);\n }\n\n public async getPreviousGameHistoryRecord(gameId: Types.ObjectId): Promise {\n return this.gameHistoryRecordRepository.getPreviousGameHistoryRecord(gameId);\n }\n\n public async getGameHistory(gameId: Types.ObjectId, getGameHistoryDto: GetGameHistoryDto): Promise {\n return this.gameHistoryRecordRepository.getGameHistory(gameId, getGameHistoryDto);\n }\n\n public async hasGamePlayBeenMade(gameId: Types.ObjectId, gamePlay: GamePlay): Promise {\n const records = await this.gameHistoryRecordRepository.getGameHistoryGamePlayRecords(gameId, gamePlay, { limit: 1 });\n\n return records.length > 0;\n }\n\n public async hasGamePlayBeenMadeByPlayer(gameId: Types.ObjectId, gamePlay: GamePlay, player: Player): Promise {\n const records = await this.gameHistoryRecordRepository.getGameHistoryGamePlayMadeByPlayerRecords(gameId, gamePlay, player, { limit: 1 });\n\n return records.length > 0;\n }\n\n private validateGameHistoryRecordToInsertPlayData(play: GameHistoryRecordPlay, game: Game): void {\n const unmatchedSource = getNonexistentPlayer(game, play.source.players);\n if (unmatchedSource) {\n throw new ResourceNotFoundException(ApiResources.PLAYERS, unmatchedSource._id.toString(), ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_PLAYER_SOURCE);\n }\n const unmatchedTarget = getNonexistentPlayer(game, play.targets?.map(target => target.player));\n if (unmatchedTarget) {\n throw new ResourceNotFoundException(ApiResources.PLAYERS, unmatchedTarget._id.toString(), ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_PLAYER_TARGET);\n }\n const unmatchedVoter = getNonexistentPlayer(game, play.votes?.map(vote => vote.source));\n if (unmatchedVoter) {\n throw new ResourceNotFoundException(ApiResources.PLAYERS, unmatchedVoter._id.toString(), ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_PLAYER_VOTE_SOURCE);\n }\n const unmatchedVoteTarget = getNonexistentPlayer(game, play.votes?.map(vote => vote.target));\n if (unmatchedVoteTarget) {\n throw new ResourceNotFoundException(ApiResources.PLAYERS, unmatchedVoteTarget._id.toString(), ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_PLAYER_VOTE_TARGET);\n }\n if (play.chosenCard && !getAdditionalCardWithId(game.additionalCards, play.chosenCard._id)) {\n throw new ResourceNotFoundException(ApiResources.GAME_ADDITIONAL_CARDS, play.chosenCard._id.toString(), ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_CHOSEN_CARD);\n }\n }\n\n private async validateGameHistoryRecordToInsertData(gameHistoryRecordToInsert: GameHistoryRecordToInsert): Promise {\n const { gameId, play, revealedPlayers, deadPlayers } = gameHistoryRecordToInsert;\n const game = await this.gameRepository.findOne({ _id: gameId });\n if (game === null) {\n throw new ResourceNotFoundException(ApiResources.GAMES, gameId.toString(), ResourceNotFoundReasons.UNKNOWN_GAME_PLAY_GAME_ID);\n }\n const unmatchedRevealedPlayer = getNonexistentPlayer(game, revealedPlayers);\n if (unmatchedRevealedPlayer) {\n throw new ResourceNotFoundException(ApiResources.PLAYERS, unmatchedRevealedPlayer._id.toString(), ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_REVEALED_PLAYER);\n }\n const unmatchedDeadPlayer = getNonexistentPlayer(game, deadPlayers);\n if (unmatchedDeadPlayer) {\n throw new ResourceNotFoundException(ApiResources.PLAYERS, unmatchedDeadPlayer._id.toString(), ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_DEAD_PLAYER);\n }\n this.validateGameHistoryRecordToInsertPlayData(play, game);\n }\n}" }, "src/modules/game/providers/services/game-phase/game-phase.service.ts": { "language": "typescript", @@ -88713,7 +88739,7 @@ } } ], - "source": "import { GamePlayAction, GamePlaySourceName } from \"@/modules/game/types/game-play/game-play.types\";\nimport { Injectable } from \"@nestjs/common\";\n\nimport { createGame } from \"@/modules/game/helpers/game.factory\";\nimport { doesGameHaveCurrentOrUpcomingPlaySourceAndAction, getPlayerWithIdOrThrow } from \"@/modules/game/helpers/game.helpers\";\nimport { updatePlayerInGame } from \"@/modules/game/helpers/game.mutators\";\nimport { createPowerlessByAccursedWolfFatherPlayerAttribute } from \"@/modules/game/helpers/player/player-attribute/player-attribute.factory\";\nimport { doesPlayerHaveActiveAttributeWithName, doesPlayerHaveActiveAttributeWithNameAndSource, getActivePlayerAttributeWithName } from \"@/modules/game/helpers/player/player-attribute/player-attribute.helpers\";\nimport { createPlayer } from \"@/modules/game/helpers/player/player.factory\";\nimport { GamePlayService } from \"@/modules/game/providers/services/game-play/game-play.service\";\nimport { PlayerAttributeService } from \"@/modules/game/providers/services/player/player-attribute.service\";\nimport type { Game } from \"@/modules/game/schemas/game.schema\";\nimport type { PlayerAttribute } from \"@/modules/game/schemas/player/player-attribute/player-attribute.schema\";\nimport type { Player } from \"@/modules/game/schemas/player/player.schema\";\nimport type { GameSource } from \"@/modules/game/types/game.types\";\nimport { PlayerAttributeName } from \"@/modules/game/types/player/player-attribute/player-attribute.types\";\n\nimport { createCantFindPlayerWithIdUnexpectedException } from \"@/shared/exception/helpers/unexpected-exception.factory\";\n\n@Injectable()\nexport class GamePhaseService {\n public constructor(\n private readonly playerAttributeService: PlayerAttributeService,\n private readonly gamePlayService: GamePlayService,\n ) {}\n\n public async applyEndingGamePhaseOutcomes(game: Game): Promise {\n let clonedGame = createGame(game);\n clonedGame = await this.applyEndingGamePhasePlayerAttributesOutcomesToPlayers(clonedGame);\n\n return clonedGame;\n }\n\n public async switchPhaseAndAppendGamePhaseUpcomingPlays(game: Game): Promise {\n const clonedGame = createGame(game);\n const { name: phaseName } = clonedGame.phase;\n clonedGame.phase.name = phaseName === \"night\" ? \"day\" : \"night\";\n clonedGame.phase.tick = 1;\n if (clonedGame.phase.name === \"night\") {\n clonedGame.turn++;\n }\n const phaseUpcomingPlays = await this.gamePlayService.getPhaseUpcomingPlays(clonedGame);\n clonedGame.upcomingPlays = [...clonedGame.upcomingPlays, ...phaseUpcomingPlays];\n\n return clonedGame;\n }\n\n public applyStartingGamePhaseOutcomes(game: Game): Game {\n const clonedGame = createGame(game);\n if (clonedGame.phase.name === \"night\") {\n return this.applyStartingNightPlayerAttributesOutcomes(clonedGame);\n }\n return clonedGame;\n }\n\n public isTwilightPhaseOver(game: Game): boolean {\n if (game.turn !== 1 || game.phase.name !== \"twilight\") {\n return true;\n }\n const twilightPlaySourceAndActions: [GamePlaySourceName, GamePlayAction][] = [\n [\"sheriff\", \"settle-votes\"],\n [\"sheriff\", \"delegate\"],\n [\"survivors\", \"vote\"],\n [\"hunter\", \"shoot\"],\n [\"scapegoat\", \"ban-voting\"],\n [\"survivors\", \"elect-sheriff\"],\n [\"survivors\", \"bury-dead-bodies\"],\n [\"stuttering-judge\", \"request-another-vote\"],\n ];\n\n return !twilightPlaySourceAndActions.some(([source, action]) => doesGameHaveCurrentOrUpcomingPlaySourceAndAction(game, source, action));\n }\n\n private async applyEndingGamePhasePlayerAttributesOutcomesToPlayers(game: Game): Promise {\n let clonedGame = createGame(game);\n for (const player of clonedGame.players) {\n clonedGame = await this.applyEndingGamePhasePlayerAttributesOutcomesToPlayer(player, clonedGame);\n }\n return clonedGame;\n }\n\n private async applyEndingDayPlayerAttributesOutcomesToPlayer(player: Player, game: Game): Promise {\n let clonedGame = createGame(game);\n const clonedPlayer = createPlayer(player);\n if (doesPlayerHaveActiveAttributeWithName(clonedPlayer, \"contaminated\", clonedGame)) {\n clonedGame = await this.playerAttributeService.applyContaminatedAttributeOutcomes(clonedPlayer, clonedGame);\n }\n return clonedGame;\n }\n\n private async applyEndingNightPlayerAttributesOutcomesToPlayer(player: Player, game: Game): Promise {\n let clonedGame = createGame(game);\n let clonedPlayer = createPlayer(player);\n const eatenAttribute = getActivePlayerAttributeWithName(clonedPlayer, \"eaten\", clonedGame);\n const notFoundPlayerExceptionInterpolations = { gameId: clonedGame._id, playerId: clonedPlayer._id };\n const notFoundPlayerException = createCantFindPlayerWithIdUnexpectedException(\"applyEndingNightPlayerAttributesOutcomesToPlayer\", notFoundPlayerExceptionInterpolations);\n if (eatenAttribute) {\n clonedGame = await this.playerAttributeService.applyEatenAttributeOutcomes(clonedPlayer, clonedGame, eatenAttribute);\n }\n clonedPlayer = getPlayerWithIdOrThrow(clonedPlayer._id, clonedGame, notFoundPlayerException);\n if (doesPlayerHaveActiveAttributeWithName(clonedPlayer, \"drank-death-potion\", clonedGame)) {\n clonedGame = await this.playerAttributeService.applyDrankDeathPotionAttributeOutcomes(clonedPlayer, clonedGame);\n }\n return clonedGame;\n }\n\n private async applyEndingGamePhasePlayerAttributesOutcomesToPlayer(player: Player, game: Game): Promise {\n const clonedGame = createGame(game);\n const clonedPlayer = createPlayer(player);\n if (clonedGame.phase.name === \"night\") {\n return this.applyEndingNightPlayerAttributesOutcomesToPlayer(clonedPlayer, clonedGame);\n }\n return this.applyEndingDayPlayerAttributesOutcomesToPlayer(clonedPlayer, clonedGame);\n }\n\n private isActingPlayerAttributeRelevantOnStartingNight(attribute: PlayerAttribute, game: Game): boolean {\n const { isPowerlessOnWerewolvesSide: isActorPowerlessOnWerewolvesSide } = game.options.roles.actor;\n const { source, name } = attribute;\n const irrelevantAttributeNames: PlayerAttributeName[] = [\"acting\", \"powerless\"];\n const stickyPowerlessSourceNames: GameSource[] = [\"actor\", \"elder\"];\n const isStickyPowerlessAttributeFromAccursedWolfFather = source === \"accursed-wolf-father\" && isActorPowerlessOnWerewolvesSide;\n const isStickyPowerlessAttribute = name === \"powerless\" &&\n (stickyPowerlessSourceNames.includes(source) || isStickyPowerlessAttributeFromAccursedWolfFather);\n\n return !irrelevantAttributeNames.includes(name) || isStickyPowerlessAttribute;\n }\n\n private applyStartingNightActingPlayerOutcomes(actingPlayer: Player, game: Game): Game {\n const clonedGame = createGame(game);\n const { isPowerlessOnWerewolvesSide: isActorPowerlessOnWerewolvesSide } = clonedGame.options.roles.actor;\n const attributes = actingPlayer.attributes.filter(attribute => this.isActingPlayerAttributeRelevantOnStartingNight(attribute, clonedGame));\n const isActorAlreadyPowerlessFromAccursedWolfFather = doesPlayerHaveActiveAttributeWithNameAndSource(\n actingPlayer,\n \"powerless\",\n \"accursed-wolf-father\",\n clonedGame,\n );\n if (isActorPowerlessOnWerewolvesSide && !isActorAlreadyPowerlessFromAccursedWolfFather && actingPlayer.side.current === \"werewolves\") {\n attributes.push(createPowerlessByAccursedWolfFatherPlayerAttribute());\n }\n const playerDataToUpdate: Partial = { role: { ...actingPlayer.role, current: \"actor\", isRevealed: false }, attributes };\n\n return updatePlayerInGame(actingPlayer._id, playerDataToUpdate, clonedGame);\n }\n\n private applyStartingNightPlayerAttributesOutcomes(game: Game): Game {\n let clonedGame = createGame(game);\n for (const player of clonedGame.players) {\n if (doesPlayerHaveActiveAttributeWithName(player, \"acting\", clonedGame)) {\n clonedGame = this.applyStartingNightActingPlayerOutcomes(player, clonedGame);\n }\n }\n return clonedGame;\n }\n}" + "source": "import { Injectable } from \"@nestjs/common\";\n\nimport { GamePlayAction, GamePlaySourceName } from \"@/modules/game/types/game-play/game-play.types\";\nimport { createGame } from \"@/modules/game/helpers/game.factory\";\nimport { doesGameHaveCurrentOrUpcomingPlaySourceAndAction, getPlayerWithIdOrThrow } from \"@/modules/game/helpers/game.helpers\";\nimport { updatePlayerInGame } from \"@/modules/game/helpers/game.mutators\";\nimport { createPowerlessByAccursedWolfFatherPlayerAttribute } from \"@/modules/game/helpers/player/player-attribute/player-attribute.factory\";\nimport { doesPlayerHaveActiveAttributeWithName, doesPlayerHaveActiveAttributeWithNameAndSource, getActivePlayerAttributeWithName } from \"@/modules/game/helpers/player/player-attribute/player-attribute.helpers\";\nimport { createPlayer } from \"@/modules/game/helpers/player/player.factory\";\nimport { GamePlayService } from \"@/modules/game/providers/services/game-play/game-play.service\";\nimport { PlayerAttributeService } from \"@/modules/game/providers/services/player/player-attribute.service\";\nimport type { Game } from \"@/modules/game/schemas/game.schema\";\nimport type { PlayerAttribute } from \"@/modules/game/schemas/player/player-attribute/player-attribute.schema\";\nimport type { Player } from \"@/modules/game/schemas/player/player.schema\";\nimport type { GameSource } from \"@/modules/game/types/game.types\";\nimport { PlayerAttributeName } from \"@/modules/game/types/player/player-attribute/player-attribute.types\";\n\nimport { createCantFindPlayerWithIdUnexpectedException } from \"@/shared/exception/helpers/unexpected-exception.factory\";\n\n@Injectable()\nexport class GamePhaseService {\n public constructor(\n private readonly playerAttributeService: PlayerAttributeService,\n private readonly gamePlayService: GamePlayService,\n ) {}\n\n public async applyEndingGamePhaseOutcomes(game: Game): Promise {\n let clonedGame = createGame(game);\n clonedGame = await this.applyEndingGamePhasePlayerAttributesOutcomesToPlayers(clonedGame);\n\n return clonedGame;\n }\n\n public async switchPhaseAndAppendGamePhaseUpcomingPlays(game: Game): Promise {\n const clonedGame = createGame(game);\n const { name: phaseName } = clonedGame.phase;\n clonedGame.phase.name = phaseName === \"night\" ? \"day\" : \"night\";\n clonedGame.phase.tick = 1;\n if (clonedGame.phase.name === \"night\") {\n clonedGame.turn++;\n }\n const phaseUpcomingPlays = await this.gamePlayService.getPhaseUpcomingPlays(clonedGame);\n clonedGame.upcomingPlays = [...clonedGame.upcomingPlays, ...phaseUpcomingPlays];\n\n return clonedGame;\n }\n\n public applyStartingGamePhaseOutcomes(game: Game): Game {\n const clonedGame = createGame(game);\n if (clonedGame.phase.name === \"night\") {\n return this.applyStartingNightPlayerAttributesOutcomes(clonedGame);\n }\n return clonedGame;\n }\n\n public isTwilightPhaseOver(game: Game): boolean {\n if (game.turn !== 1 || game.phase.name !== \"twilight\") {\n return true;\n }\n const twilightPlaySourceAndActions: [GamePlaySourceName, GamePlayAction][] = [\n [\"sheriff\", \"settle-votes\"],\n [\"sheriff\", \"delegate\"],\n [\"survivors\", \"vote\"],\n [\"hunter\", \"shoot\"],\n [\"scapegoat\", \"ban-voting\"],\n [\"survivors\", \"elect-sheriff\"],\n [\"survivors\", \"bury-dead-bodies\"],\n [\"stuttering-judge\", \"request-another-vote\"],\n ];\n\n return !twilightPlaySourceAndActions.some(([source, action]) => doesGameHaveCurrentOrUpcomingPlaySourceAndAction(game, source, action));\n }\n\n private async applyEndingGamePhasePlayerAttributesOutcomesToPlayers(game: Game): Promise {\n let clonedGame = createGame(game);\n for (const player of clonedGame.players) {\n clonedGame = await this.applyEndingGamePhasePlayerAttributesOutcomesToPlayer(player, clonedGame);\n }\n return clonedGame;\n }\n\n private async applyEndingDayPlayerAttributesOutcomesToPlayer(player: Player, game: Game): Promise {\n let clonedGame = createGame(game);\n const clonedPlayer = createPlayer(player);\n if (doesPlayerHaveActiveAttributeWithName(clonedPlayer, \"contaminated\", clonedGame)) {\n clonedGame = await this.playerAttributeService.applyContaminatedAttributeOutcomes(clonedPlayer, clonedGame);\n }\n return clonedGame;\n }\n\n private async applyEndingNightPlayerAttributesOutcomesToPlayer(player: Player, game: Game): Promise {\n let clonedGame = createGame(game);\n let clonedPlayer = createPlayer(player);\n const eatenAttribute = getActivePlayerAttributeWithName(clonedPlayer, \"eaten\", clonedGame);\n const notFoundPlayerExceptionInterpolations = { gameId: clonedGame._id, playerId: clonedPlayer._id };\n const notFoundPlayerException = createCantFindPlayerWithIdUnexpectedException(\"applyEndingNightPlayerAttributesOutcomesToPlayer\", notFoundPlayerExceptionInterpolations);\n if (eatenAttribute) {\n clonedGame = await this.playerAttributeService.applyEatenAttributeOutcomes(clonedPlayer, clonedGame, eatenAttribute);\n }\n clonedPlayer = getPlayerWithIdOrThrow(clonedPlayer._id, clonedGame, notFoundPlayerException);\n if (doesPlayerHaveActiveAttributeWithName(clonedPlayer, \"drank-death-potion\", clonedGame)) {\n clonedGame = await this.playerAttributeService.applyDrankDeathPotionAttributeOutcomes(clonedPlayer, clonedGame);\n }\n return clonedGame;\n }\n\n private async applyEndingGamePhasePlayerAttributesOutcomesToPlayer(player: Player, game: Game): Promise {\n const clonedGame = createGame(game);\n const clonedPlayer = createPlayer(player);\n if (clonedGame.phase.name === \"night\") {\n return this.applyEndingNightPlayerAttributesOutcomesToPlayer(clonedPlayer, clonedGame);\n }\n return this.applyEndingDayPlayerAttributesOutcomesToPlayer(clonedPlayer, clonedGame);\n }\n\n private isActingPlayerAttributeRelevantOnStartingNight(attribute: PlayerAttribute, game: Game): boolean {\n const { isPowerlessOnWerewolvesSide: isActorPowerlessOnWerewolvesSide } = game.options.roles.actor;\n const { source, name } = attribute;\n const irrelevantAttributeNames: PlayerAttributeName[] = [\"acting\", \"powerless\"];\n const stickyPowerlessSourceNames: GameSource[] = [\"actor\", \"elder\"];\n const isStickyPowerlessAttributeFromAccursedWolfFather = source === \"accursed-wolf-father\" && isActorPowerlessOnWerewolvesSide;\n const isStickyPowerlessAttribute = name === \"powerless\" &&\n (stickyPowerlessSourceNames.includes(source) || isStickyPowerlessAttributeFromAccursedWolfFather);\n\n return !irrelevantAttributeNames.includes(name) || isStickyPowerlessAttribute;\n }\n\n private applyStartingNightActingPlayerOutcomes(actingPlayer: Player, game: Game): Game {\n const clonedGame = createGame(game);\n const { isPowerlessOnWerewolvesSide: isActorPowerlessOnWerewolvesSide } = clonedGame.options.roles.actor;\n const attributes = actingPlayer.attributes.filter(attribute => this.isActingPlayerAttributeRelevantOnStartingNight(attribute, clonedGame));\n const isActorAlreadyPowerlessFromAccursedWolfFather = doesPlayerHaveActiveAttributeWithNameAndSource(\n actingPlayer,\n \"powerless\",\n \"accursed-wolf-father\",\n clonedGame,\n );\n if (isActorPowerlessOnWerewolvesSide && !isActorAlreadyPowerlessFromAccursedWolfFather && actingPlayer.side.current === \"werewolves\") {\n attributes.push(createPowerlessByAccursedWolfFatherPlayerAttribute());\n }\n const playerDataToUpdate: Partial = { role: { ...actingPlayer.role, current: \"actor\", isRevealed: false }, attributes };\n\n return updatePlayerInGame(actingPlayer._id, playerDataToUpdate, clonedGame);\n }\n\n private applyStartingNightPlayerAttributesOutcomes(game: Game): Game {\n let clonedGame = createGame(game);\n for (const player of clonedGame.players) {\n if (doesPlayerHaveActiveAttributeWithName(player, \"acting\", clonedGame)) {\n clonedGame = this.applyStartingNightActingPlayerOutcomes(player, clonedGame);\n }\n }\n return clonedGame;\n }\n}" }, "src/modules/game/providers/services/game-play/game-play-augmenter.service.ts": { "language": "typescript", @@ -98149,6 +98175,28 @@ } } }, + { + "id": "2566", + "mutatorName": "BooleanLiteral", + "replacement": "lastProtectedPlayer", + "statusReason": "src/modules/game/providers/services/game-play/game-play-augmenter.service.ts(279,142): error TS18048: 'lastProtectedPlayer' is possibly 'undefined'.\n", + "status": "CompileError", + "static": false, + "killedBy": [], + "coveredBy": [ + "506" + ], + "location": { + "end": { + "column": 76, + "line": 279 + }, + "start": { + "column": 56, + "line": 279 + } + } + }, { "id": "2567", "mutatorName": "MethodExpression", @@ -104136,28 +104184,6 @@ "line": 519 } } - }, - { - "id": "2566", - "mutatorName": "BooleanLiteral", - "replacement": "lastProtectedPlayer", - "statusReason": "src/modules/game/providers/services/game-play/game-play-augmenter.service.ts(279,142): error TS18048: 'lastProtectedPlayer' is possibly 'undefined'.\n", - "status": "CompileError", - "static": false, - "coveredBy": [ - "504", - "506" - ], - "location": { - "end": { - "column": 76, - "line": 279 - }, - "start": { - "column": 56, - "line": 279 - } - } } ], "source": "import { Injectable } from \"@nestjs/common\";\nimport { isDefined } from \"class-validator\";\n\nimport { doesGamePlayHaveCause } from \"@/modules/game/helpers/game-play/game-play.helpers\";\nimport { DeadPlayer } from \"@/modules/game/schemas/player/dead-player.schema\";\nimport { createGamePlaySourceInteraction } from \"@/modules/game/helpers/game-play/game-play-source/game-play-source-interaction/game-play-source-interaction.factory\";\nimport { createGamePlay } from \"@/modules/game/helpers/game-play/game-play.factory\";\nimport { getAlivePlayers, getAllowedToVotePlayers, getEligibleBigBadWolfTargets, getEligibleCupidTargets, getEligiblePiedPiperTargets, getEligibleWerewolvesTargets, getEligibleWhiteWerewolfTargets, getGroupOfPlayers, getPlayersWithActiveAttributeName, getPlayersWithCurrentRole, getPlayerWithCurrentRole, isGameSourceGroup, isGameSourceRole } from \"@/modules/game/helpers/game.helpers\";\nimport { doesPlayerHaveActiveAttributeWithName, doesPlayerHaveActiveAttributeWithNameAndSource } from \"@/modules/game/helpers/player/player-attribute/player-attribute.helpers\";\nimport { createPlayer } from \"@/modules/game/helpers/player/player.factory\";\nimport { isPlayerAliveAndPowerful } from \"@/modules/game/helpers/player/player.helpers\";\nimport { GameHistoryRecordService } from \"@/modules/game/providers/services/game-history/game-history-record.service\";\nimport type { GamePlaySourceInteraction } from \"@/modules/game/schemas/game-play/game-play-source/game-play-source-interaction/game-play-source-interaction.schema\";\nimport type { GamePlay } from \"@/modules/game/schemas/game-play/game-play.schema\";\nimport type { Game } from \"@/modules/game/schemas/game.schema\";\nimport type { Player } from \"@/modules/game/schemas/player/player.schema\";\nimport { GamePlayAction, GamePlaySourceName } from \"@/modules/game/types/game-play/game-play.types\";\nimport { WEREWOLF_ROLES } from \"@/modules/role/constants/role-set.constants\";\nimport { RoleName } from \"@/modules/role/types/role.types\";\n\nimport { createCantFindLastDeadPlayersUnexpectedException, createCantFindLastNominatedPlayersUnexpectedException, createCantFindPlayerWithCurrentRoleUnexpectedException, createMalformedCurrentGamePlayUnexpectedException, createNoCurrentGamePlayUnexpectedException } from \"@/shared/exception/helpers/unexpected-exception.factory\";\n\n@Injectable()\nexport class GamePlayAugmenterService {\n private readonly getPlaySourceInteractionsMethods: Partial<\n Record GamePlaySourceInteraction[] | Promise>\n > = {\n \"sheriff\": async(game, gamePlay) => this.getSheriffGamePlaySourceInteractions(game, gamePlay),\n \"survivors\": async(game, gamePlay) => this.getSurvivorsGamePlaySourceInteractions(game, gamePlay),\n \"werewolves\": game => this.getWerewolvesGamePlaySourceInteractions(game),\n \"big-bad-wolf\": game => this.getBigBadWolfGamePlaySourceInteractions(game),\n \"cupid\": game => this.getCupidGamePlaySourceInteractions(game),\n \"fox\": game => this.getFoxGamePlaySourceInteractions(game),\n \"defender\": async game => this.getDefenderGamePlaySourceInteractions(game),\n \"hunter\": game => this.getHunterGamePlaySourceInteractions(game),\n \"pied-piper\": game => this.getPiedPiperGamePlaySourceInteractions(game),\n \"scandalmonger\": game => this.getScandalmongerGamePlaySourceInteractions(game),\n \"scapegoat\": game => this.getScapegoatGamePlaySourceInteractions(game),\n \"seer\": game => this.getSeerGamePlaySourceInteractions(game),\n \"white-werewolf\": game => this.getWhiteWerewolfGamePlaySourceInteractions(game),\n \"wild-child\": game => this.getWildChildGamePlaySourceInteractions(game),\n \"witch\": async game => this.getWitchGamePlaySourceInteractions(game),\n \"accursed-wolf-father\": async game => this.getAccursedWolfFatherGamePlaySourceInteractions(game),\n };\n\n private readonly canBeSkippedPlayMethods: Partial boolean>> = {\n \"charmed\": () => true,\n \"lovers\": () => true,\n \"survivors\": (game, gamePlay) => this.canSurvivorsSkipGamePlay(game, gamePlay),\n \"big-bad-wolf\": game => this.canBigBadWolfSkipGamePlay(game),\n \"fox\": () => true,\n \"scandalmonger\": () => true,\n \"scapegoat\": () => true,\n \"thief\": game => this.canThiefSkipGamePlay(game),\n \"two-sisters\": () => true,\n \"three-brothers\": () => true,\n \"white-werewolf\": () => true,\n \"witch\": () => true,\n \"actor\": () => true,\n \"cupid\": (game: Game) => this.canCupidSkipGamePlay(game),\n \"accursed-wolf-father\": () => true,\n \"stuttering-judge\": () => true,\n };\n\n public constructor(private readonly gameHistoryRecordService: GameHistoryRecordService) {}\n\n public setGamePlayCanBeSkipped(gamePlay: GamePlay, game: Game): GamePlay {\n const clonedGamePlay = createGamePlay(gamePlay);\n clonedGamePlay.canBeSkipped = this.canGamePlayBeSkipped(game, gamePlay);\n\n return clonedGamePlay;\n }\n\n public async setGamePlaySourceInteractions(gamePlay: GamePlay, game: Game): Promise {\n const clonedGamePlay = createGamePlay(gamePlay);\n clonedGamePlay.source.interactions = await this.getGamePlaySourceInteractions(gamePlay, game);\n\n return clonedGamePlay;\n }\n\n public setGamePlaySourcePlayers(gamePlay: GamePlay, game: Game): GamePlay {\n const clonedGamePlay = createGamePlay(gamePlay);\n clonedGamePlay.source.players = this.getExpectedPlayersToPlay(game);\n\n return clonedGamePlay;\n }\n\n private async getSheriffSettlesVotesGamePlaySourceInteractions(game: Game): Promise {\n const lastTieInVotesRecord = await this.gameHistoryRecordService.getLastGameHistoryTieInVotesRecord(game._id, \"vote\");\n if (lastTieInVotesRecord?.play.voting?.nominatedPlayers === undefined || lastTieInVotesRecord.play.voting.nominatedPlayers.length === 0) {\n throw createCantFindLastNominatedPlayersUnexpectedException(\"getSheriffSettlesVotesGamePlaySourceInteractions\", { gameId: game._id });\n }\n const eligibleTargets = lastTieInVotesRecord.play.voting.nominatedPlayers;\n const interaction = createGamePlaySourceInteraction({\n source: \"sheriff\",\n type: \"sentence-to-death\",\n eligibleTargets,\n boundaries: { min: 1, max: 1 },\n });\n\n return [interaction];\n }\n\n private getSheriffDelegatesGamePlaySourceInteractions(game: Game): GamePlaySourceInteraction[] {\n const alivePlayersWithoutCurrentSheriff = getAlivePlayers(game).filter(player => !doesPlayerHaveActiveAttributeWithName(player, \"sheriff\", game));\n const interaction = createGamePlaySourceInteraction({\n source: \"sheriff\",\n type: \"transfer-sheriff-role\",\n eligibleTargets: alivePlayersWithoutCurrentSheriff,\n boundaries: { min: 1, max: 1 },\n });\n\n return [interaction];\n }\n\n private async getSheriffGamePlaySourceInteractions(game: Game, gamePlay: GamePlay): Promise {\n if (gamePlay.action === \"delegate\") {\n return this.getSheriffDelegatesGamePlaySourceInteractions(game);\n }\n if (gamePlay.action === \"settle-votes\") {\n return this.getSheriffSettlesVotesGamePlaySourceInteractions(game);\n }\n throw createMalformedCurrentGamePlayUnexpectedException(\"getSheriffGamePlaySourceInteractions\", gamePlay, game._id);\n }\n\n private async getSurvivorsVoteGamePlaySourceInteractionEligibleTargets(game: Game, gamePlay: GamePlay): Promise {\n const alivePlayers = getAlivePlayers(game);\n if (doesGamePlayHaveCause(gamePlay, \"previous-votes-were-in-ties\")) {\n const lastTieInVotesRecord = await this.gameHistoryRecordService.getLastGameHistoryTieInVotesRecord(game._id, gamePlay.action);\n if (lastTieInVotesRecord?.play.voting?.nominatedPlayers === undefined || lastTieInVotesRecord.play.voting.nominatedPlayers.length === 0) {\n throw createCantFindLastNominatedPlayersUnexpectedException(\"getSurvivorsVoteGamePlaySourceInteractionEligibleTargets\", { gameId: game._id });\n }\n return lastTieInVotesRecord.play.voting.nominatedPlayers;\n }\n return alivePlayers;\n }\n\n private async getSurvivorsVoteGamePlaySourceInteractions(game: Game, gamePlay: GamePlay): Promise {\n const eligibleTargets = await this.getSurvivorsVoteGamePlaySourceInteractionEligibleTargets(game, gamePlay);\n const minBoundaries = gamePlay.canBeSkipped === true ? 0 : 1;\n const maxBoundaries = getAllowedToVotePlayers(game).length;\n const interaction = createGamePlaySourceInteraction({\n source: \"survivors\",\n type: \"vote\",\n eligibleTargets,\n boundaries: { min: minBoundaries, max: maxBoundaries },\n });\n\n return [interaction];\n }\n\n private async getSurvivorsElectSheriffGamePlaySourceInteractions(game: Game, gamePlay: GamePlay): Promise {\n const eligibleTargets = await this.getSurvivorsVoteGamePlaySourceInteractionEligibleTargets(game, gamePlay);\n const maxBoundaries = getAllowedToVotePlayers(game).length;\n const interaction = createGamePlaySourceInteraction({\n source: \"survivors\",\n type: \"choose-as-sheriff\",\n eligibleTargets,\n boundaries: { min: 1, max: maxBoundaries },\n });\n\n return [interaction];\n }\n\n private getSurvivorsBuryDeadBodiesGamePlaySourceDevotedServantInteraction(game: Game, previousDeadPlayers: DeadPlayer[]): GamePlaySourceInteraction | undefined {\n const devotedServantPlayer = getPlayerWithCurrentRole(game, \"devoted-servant\");\n if (!devotedServantPlayer || !isPlayerAliveAndPowerful(devotedServantPlayer, game) ||\n doesPlayerHaveActiveAttributeWithName(devotedServantPlayer, \"in-love\", game)) {\n return undefined;\n }\n return createGamePlaySourceInteraction({\n source: \"devoted-servant\",\n type: \"steal-role\",\n eligibleTargets: previousDeadPlayers,\n boundaries: { min: 0, max: 1 },\n });\n }\n\n private async getSurvivorsBuryDeadBodiesGamePlaySourceInteractions(game: Game): Promise {\n const previousGameHistoryRecord = await this.gameHistoryRecordService.getPreviousGameHistoryRecord(game._id);\n if (previousGameHistoryRecord?.deadPlayers === undefined || previousGameHistoryRecord.deadPlayers.length === 0) {\n throw createCantFindLastDeadPlayersUnexpectedException(\"getSurvivorsBuryDeadBodiesGamePlaySourceInteractions\", { gameId: game._id });\n }\n const interactions = [\n createGamePlaySourceInteraction({\n source: \"survivors\",\n type: \"bury\",\n eligibleTargets: previousGameHistoryRecord.deadPlayers,\n boundaries: { min: 0, max: previousGameHistoryRecord.deadPlayers.length },\n isInconsequential: true,\n }),\n ];\n const devotedServantInteraction = this.getSurvivorsBuryDeadBodiesGamePlaySourceDevotedServantInteraction(game, previousGameHistoryRecord.deadPlayers);\n if (devotedServantInteraction) {\n interactions.push(devotedServantInteraction);\n }\n return interactions;\n }\n\n private async getSurvivorsGamePlaySourceInteractions(game: Game, gamePlay: GamePlay): Promise {\n const survivorsGamePlaySourceInteractionMethods: Partial GamePlaySourceInteraction[] | Promise\n >> = {\n \"bury-dead-bodies\": async() => this.getSurvivorsBuryDeadBodiesGamePlaySourceInteractions(game),\n \"vote\": async() => this.getSurvivorsVoteGamePlaySourceInteractions(game, gamePlay),\n \"elect-sheriff\": async() => this.getSurvivorsElectSheriffGamePlaySourceInteractions(game, gamePlay),\n };\n const sourceInteractionsMethod = survivorsGamePlaySourceInteractionMethods[gamePlay.action];\n if (!sourceInteractionsMethod) {\n throw createMalformedCurrentGamePlayUnexpectedException(\"getSurvivorsGamePlaySourceInteractions\", gamePlay, game._id);\n }\n return sourceInteractionsMethod(game, gamePlay);\n }\n\n private getWerewolvesGamePlaySourceInteractions(game: Game): GamePlaySourceInteraction[] {\n const eligibleWerewolvesTargets = getEligibleWerewolvesTargets(game);\n const interaction = createGamePlaySourceInteraction({\n source: \"werewolves\",\n type: \"eat\",\n eligibleTargets: eligibleWerewolvesTargets,\n boundaries: { min: 1, max: 1 },\n });\n\n return [interaction];\n }\n\n private getBigBadWolfGamePlaySourceInteractions(game: Game): GamePlaySourceInteraction[] {\n const eligibleBigBadWolfTargets = getEligibleBigBadWolfTargets(game);\n if (eligibleBigBadWolfTargets.length === 0) {\n return [];\n }\n const interaction = createGamePlaySourceInteraction({\n source: \"big-bad-wolf\",\n type: \"eat\",\n eligibleTargets: eligibleBigBadWolfTargets,\n boundaries: { min: 1, max: 1 },\n });\n\n return [interaction];\n }\n\n private getCupidGamePlaySourceInteractions(game: Game): GamePlaySourceInteraction[] {\n const expectedPlayersToCharmCount = 2;\n const eligibleCupidTargets = getEligibleCupidTargets(game);\n if (eligibleCupidTargets.length < expectedPlayersToCharmCount) {\n return [];\n }\n const interaction = createGamePlaySourceInteraction({\n source: \"cupid\",\n type: \"charm\",\n eligibleTargets: eligibleCupidTargets,\n boundaries: { min: expectedPlayersToCharmCount, max: expectedPlayersToCharmCount },\n });\n\n return [interaction];\n }\n\n private getFoxGamePlaySourceInteractions(game: Game): GamePlaySourceInteraction[] {\n const alivePlayers = getAlivePlayers(game);\n const interaction = createGamePlaySourceInteraction({\n source: \"fox\",\n type: \"sniff\",\n eligibleTargets: alivePlayers,\n boundaries: { min: 0, max: 1 },\n });\n\n return [interaction];\n }\n\n private async getDefenderGamePlaySourceInteractions(game: Game): Promise {\n const { canProtectTwice } = game.options.roles.defender;\n const alivePlayers = getAlivePlayers(game);\n const defenderPlayer = getPlayerWithCurrentRole(game, \"defender\");\n if (!defenderPlayer) {\n throw createCantFindPlayerWithCurrentRoleUnexpectedException(\"getDefenderGamePlaySourceInteractions\", { gameId: game._id, roleName: \"defender\" });\n }\n const lastDefenderProtectRecord = await this.gameHistoryRecordService.getLastGameHistoryDefenderProtectsRecord(game._id, defenderPlayer._id);\n const lastProtectedPlayer = lastDefenderProtectRecord?.play.targets?.[0].player;\n const eligibleDefenderTargets = canProtectTwice || !lastProtectedPlayer ? alivePlayers : alivePlayers.filter(player => !player._id.equals(lastProtectedPlayer._id));\n const interaction = createGamePlaySourceInteraction({\n source: \"defender\",\n type: \"protect\",\n eligibleTargets: eligibleDefenderTargets,\n boundaries: { min: 1, max: 1 },\n });\n\n return [interaction];\n }\n\n private getHunterGamePlaySourceInteractions(game: Game): GamePlaySourceInteraction[] {\n const alivePlayers = getAlivePlayers(game);\n const interaction = createGamePlaySourceInteraction({\n source: \"hunter\",\n type: \"shoot\",\n eligibleTargets: alivePlayers,\n boundaries: { min: 1, max: 1 },\n });\n\n return [interaction];\n }\n\n private getPiedPiperGamePlaySourceInteractions(game: Game): GamePlaySourceInteraction[] {\n const { charmedPeopleCountPerNight } = game.options.roles.piedPiper;\n const eligiblePiedPiperTargets = getEligiblePiedPiperTargets(game);\n const leftToCharmByPiedPiperPlayersCount = eligiblePiedPiperTargets.length;\n const countToCharm = Math.min(charmedPeopleCountPerNight, leftToCharmByPiedPiperPlayersCount);\n const interaction = createGamePlaySourceInteraction({\n source: \"pied-piper\",\n type: \"charm\",\n eligibleTargets: eligiblePiedPiperTargets,\n boundaries: { min: countToCharm, max: countToCharm },\n });\n\n return [interaction];\n }\n\n private getScandalmongerGamePlaySourceInteractions(game: Game): GamePlaySourceInteraction[] {\n const alivePlayers = getAlivePlayers(game);\n const interaction = createGamePlaySourceInteraction({\n source: \"scandalmonger\",\n type: \"mark\",\n eligibleTargets: alivePlayers,\n boundaries: { min: 0, max: 1 },\n });\n\n return [interaction];\n }\n\n private getScapegoatGamePlaySourceInteractions(game: Game): GamePlaySourceInteraction[] {\n const alivePlayers = getAlivePlayers(game);\n const interaction = createGamePlaySourceInteraction({\n source: \"scapegoat\",\n type: \"ban-voting\",\n eligibleTargets: alivePlayers,\n boundaries: { min: 0, max: alivePlayers.length },\n });\n\n return [interaction];\n }\n\n private getSeerGamePlaySourceInteractions(game: Game): GamePlaySourceInteraction[] {\n const alivePlayers = getAlivePlayers(game);\n const alivePlayersWithoutSeer = alivePlayers.filter(({ role }) => role.current !== \"seer\");\n const interaction = createGamePlaySourceInteraction({\n source: \"seer\",\n type: \"look\",\n eligibleTargets: alivePlayersWithoutSeer,\n boundaries: { min: 1, max: 1 },\n });\n\n return [interaction];\n }\n\n private getWhiteWerewolfGamePlaySourceInteractions(game: Game): GamePlaySourceInteraction[] {\n const leftToEatByWhiteWerewolfPlayers = getEligibleWhiteWerewolfTargets(game);\n if (leftToEatByWhiteWerewolfPlayers.length === 0) {\n return [];\n }\n const interactions = createGamePlaySourceInteraction({\n source: \"white-werewolf\",\n type: \"eat\",\n eligibleTargets: leftToEatByWhiteWerewolfPlayers,\n boundaries: { min: 0, max: 1 },\n });\n\n return [interactions];\n }\n\n private getWildChildGamePlaySourceInteractions(game: Game): GamePlaySourceInteraction[] {\n const alivePlayers = getAlivePlayers(game);\n const alivePlayersWithoutWildChild = alivePlayers.filter(({ role }) => role.current !== \"wild-child\");\n const interaction = createGamePlaySourceInteraction({\n source: \"wild-child\",\n type: \"choose-as-model\",\n eligibleTargets: alivePlayersWithoutWildChild,\n boundaries: { min: 1, max: 1 },\n });\n\n return [interaction];\n }\n\n private getWitchGamePlaySourceGiveDeathPotionInteraction(game: Game, hasWitchUsedDeathPotion: boolean): GamePlaySourceInteraction | undefined {\n if (hasWitchUsedDeathPotion) {\n return undefined;\n }\n const alivePlayers = getAlivePlayers(game);\n const eligibleTargets = alivePlayers.filter(player => !doesPlayerHaveActiveAttributeWithName(player, \"eaten\", game));\n\n return createGamePlaySourceInteraction({\n source: \"witch\",\n type: \"give-death-potion\",\n eligibleTargets,\n boundaries: { min: 0, max: 1 },\n });\n }\n\n private getWitchGamePlaySourceGiveLifePotionInteraction(game: Game, hasWitchUsedLifePotion: boolean): GamePlaySourceInteraction | undefined {\n if (hasWitchUsedLifePotion) {\n return undefined;\n }\n const alivePlayers = getAlivePlayers(game);\n const eligibleTargets = alivePlayers.filter(player => doesPlayerHaveActiveAttributeWithName(player, \"eaten\", game));\n\n return createGamePlaySourceInteraction({\n source: \"witch\",\n type: \"give-life-potion\",\n eligibleTargets,\n boundaries: { min: 0, max: 1 },\n });\n }\n\n private async getWitchGamePlaySourceInteractions(game: Game): Promise {\n const witchPlayer = getPlayerWithCurrentRole(game, \"witch\");\n if (!witchPlayer) {\n throw createCantFindPlayerWithCurrentRoleUnexpectedException(\"getWitchGamePlaySourceInteractions\", { gameId: game._id, roleName: \"witch\" });\n }\n const [lifeRecords, deathRecords] = await Promise.all([\n this.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords(game._id, witchPlayer._id, \"life\"),\n this.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords(game._id, witchPlayer._id, \"death\"),\n ]);\n const hasWitchUsedLifePotion = lifeRecords.length > 0;\n const hasWitchUsedDeathPotion = deathRecords.length > 0;\n const giveLifePotionInteraction = this.getWitchGamePlaySourceGiveLifePotionInteraction(game, hasWitchUsedLifePotion);\n const giveDeathPotionInteraction = this.getWitchGamePlaySourceGiveDeathPotionInteraction(game, hasWitchUsedDeathPotion);\n\n return [giveLifePotionInteraction, giveDeathPotionInteraction].filter(isDefined);\n }\n\n private async getAccursedWolfFatherGamePlaySourceInteractions(game: Game): Promise {\n const accursedWolfFatherPlayer = getPlayerWithCurrentRole(game, \"accursed-wolf-father\");\n const exceptionInterpolations = { gameId: game._id, roleName: \"accursed-wolf-father\" as RoleName };\n if (!accursedWolfFatherPlayer) {\n throw createCantFindPlayerWithCurrentRoleUnexpectedException(\"getAccursedWolfFatherGamePlaySourceInteractions\", exceptionInterpolations);\n }\n const infectedTargetRecords = await this.gameHistoryRecordService.getGameHistoryAccursedWolfFatherInfectsWithTargetRecords(game._id, accursedWolfFatherPlayer._id);\n if (infectedTargetRecords.length) {\n return [];\n }\n const eatenByWerewolvesPlayers = game.players.filter(player => doesPlayerHaveActiveAttributeWithNameAndSource(player, \"eaten\", \"werewolves\", game));\n const interaction = createGamePlaySourceInteraction({\n source: \"accursed-wolf-father\",\n type: \"infect\",\n eligibleTargets: eatenByWerewolvesPlayers,\n boundaries: { min: 0, max: 1 },\n });\n\n return [interaction];\n }\n\n private async getGamePlaySourceInteractions(gamePlay: GamePlay, game: Game): Promise {\n const playSourceInteractionsMethod = this.getPlaySourceInteractionsMethods[gamePlay.source.name];\n if (!playSourceInteractionsMethod) {\n return undefined;\n }\n const gamePlaySourceInteractions = await playSourceInteractionsMethod(game, gamePlay);\n\n return gamePlaySourceInteractions.length ? gamePlaySourceInteractions : undefined;\n }\n\n private canSurvivorsSkipGamePlay(game: Game, gamePlay: GamePlay): boolean {\n const { canBeSkipped } = game.options.votes;\n const isGamePlayVoteCauseAngelPresence = gamePlay.action === \"vote\" && doesGamePlayHaveCause(gamePlay, \"angel-presence\");\n if (gamePlay.action === \"elect-sheriff\" || isGamePlayVoteCauseAngelPresence) {\n return false;\n }\n return gamePlay.action === \"bury-dead-bodies\" || canBeSkipped;\n }\n\n private canCupidSkipGamePlay(game: Game): boolean {\n const expectedPlayersToCharmCount = 2;\n const eligibleCupidTargets = getEligibleCupidTargets(game);\n\n return eligibleCupidTargets.length < expectedPlayersToCharmCount;\n }\n\n private canBigBadWolfSkipGamePlay(game: Game): boolean {\n const leftToEatByWerewolvesPlayers = getEligibleBigBadWolfTargets(game);\n\n return leftToEatByWerewolvesPlayers.length === 0;\n }\n\n private canThiefSkipGamePlay(game: Game): boolean {\n const { mustChooseBetweenWerewolves } = game.options.roles.thief;\n if (game.additionalCards === undefined) {\n return true;\n }\n const werewolfRoleNames = WEREWOLF_ROLES.map(role => role.name);\n const areAllAdditionalCardsWerewolves = game.additionalCards.every(({ roleName }) => werewolfRoleNames.includes(roleName));\n\n return !areAllAdditionalCardsWerewolves || !mustChooseBetweenWerewolves;\n }\n\n private canGamePlayBeSkipped(game: Game, gamePlay: GamePlay): boolean {\n const canBeSkippedGamePlayMethod = this.canBeSkippedPlayMethods[gamePlay.source.name];\n if (!canBeSkippedGamePlayMethod) {\n return false;\n }\n return canBeSkippedGamePlayMethod(game, gamePlay);\n }\n\n private getExpectedPlayersToPlay(game: Game): Player[] {\n const { currentPlay } = game;\n const mustIncludeDeadPlayersGamePlayActions: GamePlayAction[] = [\"shoot\", \"ban-voting\", \"delegate\"];\n if (currentPlay === null) {\n throw createNoCurrentGamePlayUnexpectedException(\"getExpectedPlayersToPlay\", { gameId: game._id });\n }\n let expectedPlayersToPlay = getPlayersWithActiveAttributeName(game, \"sheriff\");\n if (isGameSourceGroup(currentPlay.source.name)) {\n expectedPlayersToPlay = getGroupOfPlayers(game, currentPlay.source.name);\n } else if (isGameSourceRole(currentPlay.source.name)) {\n expectedPlayersToPlay = getPlayersWithCurrentRole(game, currentPlay.source.name);\n }\n if (!mustIncludeDeadPlayersGamePlayActions.includes(currentPlay.action)) {\n expectedPlayersToPlay = expectedPlayersToPlay.filter(player => player.isAlive);\n }\n if (currentPlay.type === \"vote\") {\n expectedPlayersToPlay = expectedPlayersToPlay.filter(player => !doesPlayerHaveActiveAttributeWithName(player, \"cant-vote\", game));\n }\n return expectedPlayersToPlay.map(player => createPlayer(player));\n }\n}" @@ -130541,7 +130567,7 @@ } } ], - "source": "import { Injectable } from \"@nestjs/common\";\n\nimport type { MakeGamePlayTargetWithRelationsDto } from \"@/modules/game/dto/make-game-play/make-game-play-target/make-game-play-target-with-relations.dto\";\nimport type { MakeGamePlayVoteWithRelationsDto } from \"@/modules/game/dto/make-game-play/make-game-play-vote/make-game-play-vote-with-relations.dto\";\nimport type { MakeGamePlayWithRelationsDto } from \"@/modules/game/dto/make-game-play/make-game-play-with-relations.dto\";\nimport { doesGamePlayHaveCause, isPlayerInteractableInCurrentGamePlay, isPlayerInteractableWithInteractionTypeInCurrentGamePlay } from \"@/modules/game/helpers/game-play/game-play.helpers\";\nimport { createGame } from \"@/modules/game/helpers/game.factory\";\nimport { getPlayerWithCurrentRole } from \"@/modules/game/helpers/game.helpers\";\nimport { doesPlayerHaveActiveAttributeWithName } from \"@/modules/game/helpers/player/player-attribute/player-attribute.helpers\";\nimport { isPlayerAliveAndPowerful } from \"@/modules/game/helpers/player/player.helpers\";\nimport { GameHistoryRecordService } from \"@/modules/game/providers/services/game-history/game-history-record.service\";\nimport type { GameAdditionalCard } from \"@/modules/game/schemas/game-additional-card/game-additional-card.schema\";\nimport type { Game } from \"@/modules/game/schemas/game.schema\";\nimport { GamePlaySourceName, GamePlayType } from \"@/modules/game/types/game-play/game-play.types\";\nimport type { GameWithCurrentPlay } from \"@/modules/game/types/game-with-current-play.types\";\nimport { PlayerInteractionType } from \"@/modules/game/types/player/player-interaction/player-interaction.types\";\n\nimport { BadGamePlayPayloadReasons } from \"@/shared/exception/enums/bad-game-play-payload-error.enum\";\nimport { createCantFindPlayerWithCurrentRoleUnexpectedException, createNoCurrentGamePlayUnexpectedException } from \"@/shared/exception/helpers/unexpected-exception.factory\";\nimport { BadGamePlayPayloadException } from \"@/shared/exception/types/bad-game-play-payload-exception.types\";\n\n@Injectable()\nexport class GamePlayValidatorService {\n public constructor(private readonly gameHistoryRecordService: GameHistoryRecordService) {}\n\n public async validateGamePlayWithRelationsDto(play: MakeGamePlayWithRelationsDto, game: Game): Promise {\n if (!game.currentPlay) {\n throw createNoCurrentGamePlayUnexpectedException(\"validateGamePlayWithRelationsDto\", { gameId: game._id });\n }\n const clonedGameWithCurrentPlay = createGame(game) as GameWithCurrentPlay;\n const { votes, targets } = play;\n this.validateGamePlayWithRelationsDtoJudgeRequest(play, clonedGameWithCurrentPlay);\n this.validateGamePlayWithRelationsDtoChosenSide(play, clonedGameWithCurrentPlay);\n this.validateGamePlayVotesWithRelationsDto(votes, clonedGameWithCurrentPlay);\n await this.validateGamePlayTargetsWithRelationsDto(targets, clonedGameWithCurrentPlay);\n this.validateGamePlayWithRelationsDtoChosenCard(play, clonedGameWithCurrentPlay);\n }\n\n private validateGamePlayActorChosenCard(chosenCard: GameAdditionalCard | undefined, game: GameWithCurrentPlay): void {\n if (!game.additionalCards) {\n return;\n }\n if (chosenCard) {\n if (chosenCard.recipient !== \"actor\") {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.CHOSEN_CARD_NOT_FOR_ACTOR);\n }\n if (chosenCard.isUsed) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.CHOSEN_CARD_ALREADY_USED);\n }\n }\n }\n\n private validateGamePlayThiefChosenCard(chosenCard: GameAdditionalCard | undefined, game: GameWithCurrentPlay): void {\n if (!game.additionalCards) {\n return;\n }\n if (!chosenCard && game.currentPlay.canBeSkipped === false) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.THIEF_MUST_CHOOSE_CARD);\n }\n if (chosenCard && chosenCard.recipient !== \"thief\") {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.CHOSEN_CARD_NOT_FOR_THIEF);\n }\n }\n\n private validateGamePlayWithRelationsDtoChosenCard({ chosenCard }: MakeGamePlayWithRelationsDto, game: GameWithCurrentPlay): void {\n const { action, source } = game.currentPlay;\n if (action !== \"choose-card\") {\n if (chosenCard) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.UNEXPECTED_CHOSEN_CARD);\n }\n return;\n }\n if (source.name === \"thief\") {\n this.validateGamePlayThiefChosenCard(chosenCard, game);\n } else if (source.name === \"actor\") {\n this.validateGamePlayActorChosenCard(chosenCard, game);\n }\n }\n\n private validateGamePlaySurvivorsTargets(playTargets: MakeGamePlayTargetWithRelationsDto[], game: GameWithCurrentPlay): void {\n const { action } = game.currentPlay;\n if (action !== \"bury-dead-bodies\") {\n return;\n }\n this.validateGamePlayTargetsBoundaries(playTargets, \"steal-role\", game);\n if (!playTargets.length) {\n return;\n }\n const devotedServantPlayer = getPlayerWithCurrentRole(game, \"devoted-servant\");\n if (!devotedServantPlayer || !isPlayerAliveAndPowerful(devotedServantPlayer, game) ||\n doesPlayerHaveActiveAttributeWithName(devotedServantPlayer, \"in-love\", game)) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.DEVOTED_SERVANT_CANT_STEAL_ROLE);\n }\n const targetedPlayer = playTargets[0].player;\n const canRoleTargetedPlayerBeStolen = isPlayerInteractableWithInteractionTypeInCurrentGamePlay(targetedPlayer._id, \"steal-role\", game);\n if (!canRoleTargetedPlayerBeStolen) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_DEVOTED_SERVANT_TARGET);\n }\n }\n\n private validateDrankLifePotionTargets(drankLifePotionTargets: MakeGamePlayTargetWithRelationsDto[], game: GameWithCurrentPlay): void {\n if (drankLifePotionTargets.length > 1) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.TOO_MUCH_DRANK_LIFE_POTION_TARGETS);\n }\n if (drankLifePotionTargets.length &&\n !isPlayerInteractableWithInteractionTypeInCurrentGamePlay(drankLifePotionTargets[0].player._id, \"give-life-potion\", game)) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_LIFE_POTION_TARGET);\n }\n }\n\n private validateDrankDeathPotionTargets(drankDeathPotionTargets: MakeGamePlayTargetWithRelationsDto[], game: GameWithCurrentPlay): void {\n if (drankDeathPotionTargets.length > 1) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.TOO_MUCH_DRANK_DEATH_POTION_TARGETS);\n }\n if (drankDeathPotionTargets.length &&\n !isPlayerInteractableWithInteractionTypeInCurrentGamePlay(drankDeathPotionTargets[0].player._id, \"give-death-potion\", game)) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_DEATH_POTION_TARGET);\n }\n }\n\n private async validateGamePlayWitchTargets(playTargets: MakeGamePlayTargetWithRelationsDto[], game: GameWithCurrentPlay): Promise {\n const witchPlayer = getPlayerWithCurrentRole(game, \"witch\");\n if (!witchPlayer) {\n throw createCantFindPlayerWithCurrentRoleUnexpectedException(\"validateGamePlayWitchTargets\", { gameId: game._id, roleName: \"witch\" });\n }\n const hasWitchUsedLifePotion = (await this.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords(game._id, witchPlayer._id, \"life\")).length > 0;\n const drankLifePotionTargets = playTargets.filter(({ drankPotion }) => drankPotion === \"life\");\n const hasWitchUsedDeathPotion = (await this.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords(game._id, witchPlayer._id, \"death\")).length > 0;\n const drankDeathPotionTargets = playTargets.filter(({ drankPotion }) => drankPotion === \"death\");\n if (hasWitchUsedLifePotion && drankLifePotionTargets.length || hasWitchUsedDeathPotion && drankDeathPotionTargets.length) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.UNEXPECTED_DRANK_POTION_TARGET);\n }\n this.validateDrankLifePotionTargets(drankLifePotionTargets, game);\n this.validateDrankDeathPotionTargets(drankDeathPotionTargets, game);\n }\n\n private validateGamePlayAccursedWolfFatherTargets(playTargets: MakeGamePlayTargetWithRelationsDto[], game: GameWithCurrentPlay): void {\n this.validateGamePlayTargetsBoundaries(playTargets, \"infect\", game);\n if (!playTargets.length) {\n return;\n }\n const targetedPlayer = playTargets[0].player;\n const canTargetedPlayerBeInfected = isPlayerInteractableWithInteractionTypeInCurrentGamePlay(targetedPlayer._id, \"infect\", game);\n if (!canTargetedPlayerBeInfected) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_ACCURSED_WOLF_FATHER_TARGET);\n }\n }\n\n private validateGamePlayWerewolvesTargets(playTargets: MakeGamePlayTargetWithRelationsDto[], game: GameWithCurrentPlay): void {\n this.validateGamePlayTargetsBoundaries(playTargets, \"eat\", game);\n if (!playTargets.length) {\n return;\n }\n const targetedPlayer = playTargets[0].player;\n const canTargetedPlayerBeEaten = isPlayerInteractableWithInteractionTypeInCurrentGamePlay(targetedPlayer._id, \"eat\", game);\n if (game.currentPlay.source.name === \"werewolves\" && !canTargetedPlayerBeEaten) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_WEREWOLVES_TARGET);\n }\n if (game.currentPlay.source.name === \"big-bad-wolf\" && !canTargetedPlayerBeEaten) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_BIG_BAD_WOLF_TARGET);\n }\n if (game.currentPlay.source.name === \"white-werewolf\" && !canTargetedPlayerBeEaten) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_WHITE_WEREWOLF_TARGET);\n }\n }\n\n private validateGamePlayHunterTargets(playTargets: MakeGamePlayTargetWithRelationsDto[], game: GameWithCurrentPlay): void {\n this.validateGamePlayTargetsBoundaries(playTargets, \"shoot\", game);\n const targetedPlayer = playTargets[0].player;\n const canTargetedPlayerBeShot = isPlayerInteractableWithInteractionTypeInCurrentGamePlay(targetedPlayer._id, \"shoot\", game);\n if (!canTargetedPlayerBeShot) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_HUNTER_TARGET);\n }\n }\n\n private validateGamePlayScapegoatTargets(playTargets: MakeGamePlayTargetWithRelationsDto[], game: GameWithCurrentPlay): void {\n this.validateGamePlayTargetsBoundaries(playTargets, \"ban-voting\", game);\n if (playTargets.some(({ player }) => !isPlayerInteractableWithInteractionTypeInCurrentGamePlay(player._id, \"ban-voting\", game))) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_SCAPEGOAT_TARGETS);\n }\n }\n\n private validateGamePlayCupidTargets(playTargets: MakeGamePlayTargetWithRelationsDto[], game: GameWithCurrentPlay): void {\n this.validateGamePlayTargetsBoundaries(playTargets, \"charm\", game);\n if (playTargets.some(({ player }) => !isPlayerInteractableWithInteractionTypeInCurrentGamePlay(player._id, \"charm\", game))) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_CUPID_TARGETS);\n }\n }\n\n private validateGamePlayFoxTargets(playTargets: MakeGamePlayTargetWithRelationsDto[], game: GameWithCurrentPlay): void {\n this.validateGamePlayTargetsBoundaries(playTargets, \"sniff\", game);\n if (!playTargets.length) {\n return;\n }\n const targetedPlayer = playTargets[0].player;\n const canTargetedPlayerBeSniffed = isPlayerInteractableWithInteractionTypeInCurrentGamePlay(targetedPlayer._id, \"sniff\", game);\n if (!canTargetedPlayerBeSniffed) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_FOX_TARGET);\n }\n }\n\n private validateGamePlaySeerTargets(playTargets: MakeGamePlayTargetWithRelationsDto[], game: GameWithCurrentPlay): void {\n this.validateGamePlayTargetsBoundaries(playTargets, \"look\", game);\n const targetedPlayer = playTargets[0].player;\n const canTargetedPlayerBeSeen = isPlayerInteractableWithInteractionTypeInCurrentGamePlay(targetedPlayer._id, \"look\", game);\n if (!canTargetedPlayerBeSeen) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_SEER_TARGET);\n }\n }\n\n private validateGamePlayScandalmongerTargets(playTargets: MakeGamePlayTargetWithRelationsDto[], game: GameWithCurrentPlay): void {\n this.validateGamePlayTargetsBoundaries(playTargets, \"mark\", game);\n if (!playTargets.length) {\n return;\n }\n const targetedPlayer = playTargets[0].player;\n const canTargetedPlayerBeMarked = isPlayerInteractableWithInteractionTypeInCurrentGamePlay(targetedPlayer._id, \"mark\", game);\n if (!canTargetedPlayerBeMarked) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_SCANDALMONGER_TARGET);\n }\n }\n\n private validateGamePlayWildChildTargets(playTargets: MakeGamePlayTargetWithRelationsDto[], game: GameWithCurrentPlay): void {\n this.validateGamePlayTargetsBoundaries(playTargets, \"choose-as-model\", game);\n const targetedPlayer = playTargets[0].player;\n const canTargetedPlayerBeChosenAsModel = isPlayerInteractableWithInteractionTypeInCurrentGamePlay(targetedPlayer._id, \"choose-as-model\", game);\n if (!canTargetedPlayerBeChosenAsModel) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_WILD_CHILD_TARGET);\n }\n }\n\n private validateGamePlayPiedPiperTargets(playTargets: MakeGamePlayTargetWithRelationsDto[], game: GameWithCurrentPlay): void {\n this.validateGamePlayTargetsBoundaries(playTargets, \"charm\", game);\n if (playTargets.some(({ player }) => !isPlayerInteractableWithInteractionTypeInCurrentGamePlay(player._id, \"charm\", game))) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_PIED_PIPER_TARGETS);\n }\n }\n\n private validateGamePlayDefenderTargets(playTargets: MakeGamePlayTargetWithRelationsDto[], game: GameWithCurrentPlay): void {\n this.validateGamePlayTargetsBoundaries(playTargets, \"protect\", game);\n const targetedPlayer = playTargets[0].player;\n const canTargetedPlayerBeProtected = isPlayerInteractableWithInteractionTypeInCurrentGamePlay(targetedPlayer._id, \"protect\", game);\n if (!canTargetedPlayerBeProtected) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_DEFENDER_TARGET);\n }\n }\n\n private validateGamePlaySheriffTargets(playTargets: MakeGamePlayTargetWithRelationsDto[], game: GameWithCurrentPlay): void {\n this.validateGamePlayTargetsBoundaries(playTargets, \"transfer-sheriff-role\", game);\n this.validateGamePlayTargetsBoundaries(playTargets, \"sentence-to-death\", game);\n const targetedPlayer = playTargets[0].player;\n const canTargetBecomeSheriff = isPlayerInteractableWithInteractionTypeInCurrentGamePlay(targetedPlayer._id, \"transfer-sheriff-role\", game);\n if (game.currentPlay.action === \"delegate\" && !canTargetBecomeSheriff) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_SHERIFF_DELEGATE_TARGET);\n }\n const canTargetBeSentencedToDeath = isPlayerInteractableWithInteractionTypeInCurrentGamePlay(targetedPlayer._id, \"sentence-to-death\", game);\n if (game.currentPlay.action === \"settle-votes\" && !canTargetBeSentencedToDeath) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_SHERIFF_SETTLE_VOTES_TARGET);\n }\n }\n\n private validateGamePlayTargetsBoundaries(playTargets: MakeGamePlayTargetWithRelationsDto[], interactionType: PlayerInteractionType, game: GameWithCurrentPlay): void {\n const { interactions } = game.currentPlay.source;\n const interaction = interactions?.find(({ type }) => type === interactionType);\n if (!interaction) {\n return;\n }\n if (playTargets.length < interaction.boundaries.min) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.TOO_LESS_TARGETS);\n }\n if (playTargets.length > interaction.boundaries.max) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.TOO_MUCH_TARGETS);\n }\n }\n\n private async validateGamePlaySourceTargets(playTargets: MakeGamePlayTargetWithRelationsDto[], game: GameWithCurrentPlay): Promise {\n const gamePlaySourceValidationMethods: Partial Promise | void>> = {\n \"sheriff\": () => this.validateGamePlaySheriffTargets(playTargets, game),\n \"survivors\": () => this.validateGamePlaySurvivorsTargets(playTargets, game),\n \"werewolves\": () => this.validateGamePlayWerewolvesTargets(playTargets, game),\n \"accursed-wolf-father\": () => this.validateGamePlayAccursedWolfFatherTargets(playTargets, game),\n \"big-bad-wolf\": () => this.validateGamePlayWerewolvesTargets(playTargets, game),\n \"white-werewolf\": () => this.validateGamePlayWerewolvesTargets(playTargets, game),\n \"defender\": () => this.validateGamePlayDefenderTargets(playTargets, game),\n \"pied-piper\": () => this.validateGamePlayPiedPiperTargets(playTargets, game),\n \"wild-child\": () => this.validateGamePlayWildChildTargets(playTargets, game),\n \"scandalmonger\": () => this.validateGamePlayScandalmongerTargets(playTargets, game),\n \"seer\": () => this.validateGamePlaySeerTargets(playTargets, game),\n \"fox\": () => this.validateGamePlayFoxTargets(playTargets, game),\n \"cupid\": () => this.validateGamePlayCupidTargets(playTargets, game),\n \"scapegoat\": () => this.validateGamePlayScapegoatTargets(playTargets, game),\n \"hunter\": () => this.validateGamePlayHunterTargets(playTargets, game),\n \"witch\": async() => this.validateGamePlayWitchTargets(playTargets, game),\n };\n const gamePlaySourceValidationMethod = gamePlaySourceValidationMethods[game.currentPlay.source.name];\n if (gamePlaySourceValidationMethod) {\n await gamePlaySourceValidationMethod();\n }\n }\n\n private validateTargetsPotionUsage(playTargets: MakeGamePlayTargetWithRelationsDto[], game: GameWithCurrentPlay): void {\n const { source: currentPlaySource, action: currentPlayAction } = game.currentPlay;\n const hasSomePlayerDrankPotion = playTargets.some(({ drankPotion }) => drankPotion);\n if (hasSomePlayerDrankPotion && (currentPlayAction !== \"use-potions\" || currentPlaySource.name !== \"witch\")) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.UNEXPECTED_DRANK_POTION_TARGET);\n }\n }\n\n private async validateGamePlayTargetsWithRelationsDto(playTargets: MakeGamePlayTargetWithRelationsDto[] | undefined, game: GameWithCurrentPlay): Promise {\n const targetActionsTypes: GamePlayType[] = [\"target\", \"bury-dead-bodies\"];\n const { currentPlay } = game;\n if (!targetActionsTypes.includes(game.currentPlay.type)) {\n if (playTargets) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.UNEXPECTED_TARGETS);\n }\n return;\n }\n if (playTargets === undefined || playTargets.length === 0) {\n if (currentPlay.canBeSkipped === false) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.REQUIRED_TARGETS);\n }\n return;\n }\n this.validateTargetsPotionUsage(playTargets, game);\n await this.validateGamePlaySourceTargets(playTargets, game);\n }\n\n private validateGamePlayVotesTieBreakerWithRelationsDto(playVotes: MakeGamePlayVoteWithRelationsDto[], game: GameWithCurrentPlay): void {\n const { action } = game.currentPlay;\n const interactionType = action === \"vote\" ? \"vote\" : \"choose-as-sheriff\";\n const areEveryTargetsInNominatedPlayers = playVotes.every(({ target }) => isPlayerInteractableWithInteractionTypeInCurrentGamePlay(target._id, interactionType, game));\n if (doesGamePlayHaveCause(game.currentPlay, \"previous-votes-were-in-ties\") && !areEveryTargetsInNominatedPlayers) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_VOTE_TARGET_FOR_TIE_BREAKER);\n }\n }\n\n private validateGamePlayVotesWithRelationsDtoSourceAndTarget(playVotes: MakeGamePlayVoteWithRelationsDto[], game: GameWithCurrentPlay): void {\n const { currentPlay } = game;\n if (playVotes.some(({ source }) => !currentPlay.source.players?.find(({ _id }) => _id.equals(source._id)))) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_VOTE_SOURCE);\n }\n if (playVotes.some(({ target }) => !isPlayerInteractableInCurrentGamePlay(target._id, game))) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_VOTE_TARGET);\n }\n if (playVotes.some(({ source, target }) => source._id.equals(target._id))) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.SAME_SOURCE_AND_TARGET_VOTE);\n }\n }\n\n private validateGamePlayVotesWithRelationsDto(playVotes: MakeGamePlayVoteWithRelationsDto[] | undefined, game: GameWithCurrentPlay): void {\n const { currentPlay } = game;\n if (currentPlay.type !== \"vote\") {\n if (playVotes) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.UNEXPECTED_VOTES);\n }\n return;\n }\n if (playVotes === undefined || playVotes.length === 0) {\n if (game.currentPlay.canBeSkipped === false) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.REQUIRED_VOTES);\n }\n return;\n }\n if (doesGamePlayHaveCause(currentPlay, \"previous-votes-were-in-ties\")) {\n this.validateGamePlayVotesTieBreakerWithRelationsDto(playVotes, game);\n }\n this.validateGamePlayVotesWithRelationsDtoSourceAndTarget(playVotes, game);\n }\n\n private validateGamePlayWithRelationsDtoChosenSide({ chosenSide }: MakeGamePlayWithRelationsDto, game: GameWithCurrentPlay): void {\n const { isSideRandomlyChosen } = game.options.roles.wolfHound;\n if (chosenSide !== undefined && (game.currentPlay.action !== \"choose-side\" || isSideRandomlyChosen)) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.UNEXPECTED_CHOSEN_SIDE);\n }\n if (chosenSide === undefined && game.currentPlay.action === \"choose-side\" && !isSideRandomlyChosen) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.REQUIRED_CHOSEN_SIDE);\n }\n }\n\n private validateGamePlayWithRelationsDtoJudgeRequest({ doesJudgeRequestAnotherVote }: MakeGamePlayWithRelationsDto, game: GameWithCurrentPlay): void {\n if (doesJudgeRequestAnotherVote !== undefined && game.currentPlay.action !== \"request-another-vote\") {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.UNEXPECTED_STUTTERING_JUDGE_VOTE_REQUEST);\n }\n }\n}" + "source": "import { Injectable } from \"@nestjs/common\";\n\nimport type { MakeGamePlayTargetWithRelationsDto } from \"@/modules/game/dto/make-game-play/make-game-play-target/make-game-play-target-with-relations.dto\";\nimport type { MakeGamePlayVoteWithRelationsDto } from \"@/modules/game/dto/make-game-play/make-game-play-vote/make-game-play-vote-with-relations.dto\";\nimport type { MakeGamePlayWithRelationsDto } from \"@/modules/game/dto/make-game-play/make-game-play-with-relations.dto\";\nimport { doesGamePlayHaveCause, isPlayerInteractableInCurrentGamePlay, isPlayerInteractableWithInteractionTypeInCurrentGamePlay } from \"@/modules/game/helpers/game-play/game-play.helpers\";\nimport { createGame } from \"@/modules/game/helpers/game.factory\";\nimport { getPlayerWithCurrentRole } from \"@/modules/game/helpers/game.helpers\";\nimport { doesPlayerHaveActiveAttributeWithName } from \"@/modules/game/helpers/player/player-attribute/player-attribute.helpers\";\nimport { isPlayerAliveAndPowerful } from \"@/modules/game/helpers/player/player.helpers\";\nimport { GameHistoryRecordService } from \"@/modules/game/providers/services/game-history/game-history-record.service\";\nimport type { GameAdditionalCard } from \"@/modules/game/schemas/game-additional-card/game-additional-card.schema\";\nimport type { Game } from \"@/modules/game/schemas/game.schema\";\nimport { GamePlaySourceName, GamePlayType } from \"@/modules/game/types/game-play/game-play.types\";\nimport type { GameWithCurrentPlay } from \"@/modules/game/types/game-with-current-play.types\";\nimport { PlayerInteractionType } from \"@/modules/game/types/player/player-interaction/player-interaction.types\";\n\nimport { BadGamePlayPayloadReasons } from \"@/shared/exception/enums/bad-game-play-payload-error.enums\";\nimport { createCantFindPlayerWithCurrentRoleUnexpectedException, createNoCurrentGamePlayUnexpectedException } from \"@/shared/exception/helpers/unexpected-exception.factory\";\nimport { BadGamePlayPayloadException } from \"@/shared/exception/types/bad-game-play-payload-exception.types\";\n\n@Injectable()\nexport class GamePlayValidatorService {\n public constructor(private readonly gameHistoryRecordService: GameHistoryRecordService) {}\n\n public async validateGamePlayWithRelationsDto(play: MakeGamePlayWithRelationsDto, game: Game): Promise {\n if (!game.currentPlay) {\n throw createNoCurrentGamePlayUnexpectedException(\"validateGamePlayWithRelationsDto\", { gameId: game._id });\n }\n const clonedGameWithCurrentPlay = createGame(game) as GameWithCurrentPlay;\n const { votes, targets } = play;\n this.validateGamePlayWithRelationsDtoJudgeRequest(play, clonedGameWithCurrentPlay);\n this.validateGamePlayWithRelationsDtoChosenSide(play, clonedGameWithCurrentPlay);\n this.validateGamePlayVotesWithRelationsDto(votes, clonedGameWithCurrentPlay);\n await this.validateGamePlayTargetsWithRelationsDto(targets, clonedGameWithCurrentPlay);\n this.validateGamePlayWithRelationsDtoChosenCard(play, clonedGameWithCurrentPlay);\n }\n\n private validateGamePlayActorChosenCard(chosenCard: GameAdditionalCard | undefined, game: GameWithCurrentPlay): void {\n if (!game.additionalCards) {\n return;\n }\n if (chosenCard) {\n if (chosenCard.recipient !== \"actor\") {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.CHOSEN_CARD_NOT_FOR_ACTOR);\n }\n if (chosenCard.isUsed) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.CHOSEN_CARD_ALREADY_USED);\n }\n }\n }\n\n private validateGamePlayThiefChosenCard(chosenCard: GameAdditionalCard | undefined, game: GameWithCurrentPlay): void {\n if (!game.additionalCards) {\n return;\n }\n if (!chosenCard && game.currentPlay.canBeSkipped === false) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.THIEF_MUST_CHOOSE_CARD);\n }\n if (chosenCard && chosenCard.recipient !== \"thief\") {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.CHOSEN_CARD_NOT_FOR_THIEF);\n }\n }\n\n private validateGamePlayWithRelationsDtoChosenCard({ chosenCard }: MakeGamePlayWithRelationsDto, game: GameWithCurrentPlay): void {\n const { action, source } = game.currentPlay;\n if (action !== \"choose-card\") {\n if (chosenCard) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.UNEXPECTED_CHOSEN_CARD);\n }\n return;\n }\n if (source.name === \"thief\") {\n this.validateGamePlayThiefChosenCard(chosenCard, game);\n } else if (source.name === \"actor\") {\n this.validateGamePlayActorChosenCard(chosenCard, game);\n }\n }\n\n private validateGamePlaySurvivorsTargets(playTargets: MakeGamePlayTargetWithRelationsDto[], game: GameWithCurrentPlay): void {\n const { action } = game.currentPlay;\n if (action !== \"bury-dead-bodies\") {\n return;\n }\n this.validateGamePlayTargetsBoundaries(playTargets, \"steal-role\", game);\n if (!playTargets.length) {\n return;\n }\n const devotedServantPlayer = getPlayerWithCurrentRole(game, \"devoted-servant\");\n if (!devotedServantPlayer || !isPlayerAliveAndPowerful(devotedServantPlayer, game) ||\n doesPlayerHaveActiveAttributeWithName(devotedServantPlayer, \"in-love\", game)) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.DEVOTED_SERVANT_CANT_STEAL_ROLE);\n }\n const targetedPlayer = playTargets[0].player;\n const canRoleTargetedPlayerBeStolen = isPlayerInteractableWithInteractionTypeInCurrentGamePlay(targetedPlayer._id, \"steal-role\", game);\n if (!canRoleTargetedPlayerBeStolen) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_DEVOTED_SERVANT_TARGET);\n }\n }\n\n private validateDrankLifePotionTargets(drankLifePotionTargets: MakeGamePlayTargetWithRelationsDto[], game: GameWithCurrentPlay): void {\n if (drankLifePotionTargets.length > 1) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.TOO_MUCH_DRANK_LIFE_POTION_TARGETS);\n }\n if (drankLifePotionTargets.length &&\n !isPlayerInteractableWithInteractionTypeInCurrentGamePlay(drankLifePotionTargets[0].player._id, \"give-life-potion\", game)) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_LIFE_POTION_TARGET);\n }\n }\n\n private validateDrankDeathPotionTargets(drankDeathPotionTargets: MakeGamePlayTargetWithRelationsDto[], game: GameWithCurrentPlay): void {\n if (drankDeathPotionTargets.length > 1) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.TOO_MUCH_DRANK_DEATH_POTION_TARGETS);\n }\n if (drankDeathPotionTargets.length &&\n !isPlayerInteractableWithInteractionTypeInCurrentGamePlay(drankDeathPotionTargets[0].player._id, \"give-death-potion\", game)) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_DEATH_POTION_TARGET);\n }\n }\n\n private async validateGamePlayWitchTargets(playTargets: MakeGamePlayTargetWithRelationsDto[], game: GameWithCurrentPlay): Promise {\n const witchPlayer = getPlayerWithCurrentRole(game, \"witch\");\n if (!witchPlayer) {\n throw createCantFindPlayerWithCurrentRoleUnexpectedException(\"validateGamePlayWitchTargets\", { gameId: game._id, roleName: \"witch\" });\n }\n const hasWitchUsedLifePotion = (await this.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords(game._id, witchPlayer._id, \"life\")).length > 0;\n const drankLifePotionTargets = playTargets.filter(({ drankPotion }) => drankPotion === \"life\");\n const hasWitchUsedDeathPotion = (await this.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords(game._id, witchPlayer._id, \"death\")).length > 0;\n const drankDeathPotionTargets = playTargets.filter(({ drankPotion }) => drankPotion === \"death\");\n if (hasWitchUsedLifePotion && drankLifePotionTargets.length || hasWitchUsedDeathPotion && drankDeathPotionTargets.length) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.UNEXPECTED_DRANK_POTION_TARGET);\n }\n this.validateDrankLifePotionTargets(drankLifePotionTargets, game);\n this.validateDrankDeathPotionTargets(drankDeathPotionTargets, game);\n }\n\n private validateGamePlayAccursedWolfFatherTargets(playTargets: MakeGamePlayTargetWithRelationsDto[], game: GameWithCurrentPlay): void {\n this.validateGamePlayTargetsBoundaries(playTargets, \"infect\", game);\n if (!playTargets.length) {\n return;\n }\n const targetedPlayer = playTargets[0].player;\n const canTargetedPlayerBeInfected = isPlayerInteractableWithInteractionTypeInCurrentGamePlay(targetedPlayer._id, \"infect\", game);\n if (!canTargetedPlayerBeInfected) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_ACCURSED_WOLF_FATHER_TARGET);\n }\n }\n\n private validateGamePlayWerewolvesTargets(playTargets: MakeGamePlayTargetWithRelationsDto[], game: GameWithCurrentPlay): void {\n this.validateGamePlayTargetsBoundaries(playTargets, \"eat\", game);\n if (!playTargets.length) {\n return;\n }\n const targetedPlayer = playTargets[0].player;\n const canTargetedPlayerBeEaten = isPlayerInteractableWithInteractionTypeInCurrentGamePlay(targetedPlayer._id, \"eat\", game);\n if (game.currentPlay.source.name === \"werewolves\" && !canTargetedPlayerBeEaten) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_WEREWOLVES_TARGET);\n }\n if (game.currentPlay.source.name === \"big-bad-wolf\" && !canTargetedPlayerBeEaten) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_BIG_BAD_WOLF_TARGET);\n }\n if (game.currentPlay.source.name === \"white-werewolf\" && !canTargetedPlayerBeEaten) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_WHITE_WEREWOLF_TARGET);\n }\n }\n\n private validateGamePlayHunterTargets(playTargets: MakeGamePlayTargetWithRelationsDto[], game: GameWithCurrentPlay): void {\n this.validateGamePlayTargetsBoundaries(playTargets, \"shoot\", game);\n const targetedPlayer = playTargets[0].player;\n const canTargetedPlayerBeShot = isPlayerInteractableWithInteractionTypeInCurrentGamePlay(targetedPlayer._id, \"shoot\", game);\n if (!canTargetedPlayerBeShot) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_HUNTER_TARGET);\n }\n }\n\n private validateGamePlayScapegoatTargets(playTargets: MakeGamePlayTargetWithRelationsDto[], game: GameWithCurrentPlay): void {\n this.validateGamePlayTargetsBoundaries(playTargets, \"ban-voting\", game);\n if (playTargets.some(({ player }) => !isPlayerInteractableWithInteractionTypeInCurrentGamePlay(player._id, \"ban-voting\", game))) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_SCAPEGOAT_TARGETS);\n }\n }\n\n private validateGamePlayCupidTargets(playTargets: MakeGamePlayTargetWithRelationsDto[], game: GameWithCurrentPlay): void {\n this.validateGamePlayTargetsBoundaries(playTargets, \"charm\", game);\n if (playTargets.some(({ player }) => !isPlayerInteractableWithInteractionTypeInCurrentGamePlay(player._id, \"charm\", game))) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_CUPID_TARGETS);\n }\n }\n\n private validateGamePlayFoxTargets(playTargets: MakeGamePlayTargetWithRelationsDto[], game: GameWithCurrentPlay): void {\n this.validateGamePlayTargetsBoundaries(playTargets, \"sniff\", game);\n if (!playTargets.length) {\n return;\n }\n const targetedPlayer = playTargets[0].player;\n const canTargetedPlayerBeSniffed = isPlayerInteractableWithInteractionTypeInCurrentGamePlay(targetedPlayer._id, \"sniff\", game);\n if (!canTargetedPlayerBeSniffed) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_FOX_TARGET);\n }\n }\n\n private validateGamePlaySeerTargets(playTargets: MakeGamePlayTargetWithRelationsDto[], game: GameWithCurrentPlay): void {\n this.validateGamePlayTargetsBoundaries(playTargets, \"look\", game);\n const targetedPlayer = playTargets[0].player;\n const canTargetedPlayerBeSeen = isPlayerInteractableWithInteractionTypeInCurrentGamePlay(targetedPlayer._id, \"look\", game);\n if (!canTargetedPlayerBeSeen) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_SEER_TARGET);\n }\n }\n\n private validateGamePlayScandalmongerTargets(playTargets: MakeGamePlayTargetWithRelationsDto[], game: GameWithCurrentPlay): void {\n this.validateGamePlayTargetsBoundaries(playTargets, \"mark\", game);\n if (!playTargets.length) {\n return;\n }\n const targetedPlayer = playTargets[0].player;\n const canTargetedPlayerBeMarked = isPlayerInteractableWithInteractionTypeInCurrentGamePlay(targetedPlayer._id, \"mark\", game);\n if (!canTargetedPlayerBeMarked) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_SCANDALMONGER_TARGET);\n }\n }\n\n private validateGamePlayWildChildTargets(playTargets: MakeGamePlayTargetWithRelationsDto[], game: GameWithCurrentPlay): void {\n this.validateGamePlayTargetsBoundaries(playTargets, \"choose-as-model\", game);\n const targetedPlayer = playTargets[0].player;\n const canTargetedPlayerBeChosenAsModel = isPlayerInteractableWithInteractionTypeInCurrentGamePlay(targetedPlayer._id, \"choose-as-model\", game);\n if (!canTargetedPlayerBeChosenAsModel) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_WILD_CHILD_TARGET);\n }\n }\n\n private validateGamePlayPiedPiperTargets(playTargets: MakeGamePlayTargetWithRelationsDto[], game: GameWithCurrentPlay): void {\n this.validateGamePlayTargetsBoundaries(playTargets, \"charm\", game);\n if (playTargets.some(({ player }) => !isPlayerInteractableWithInteractionTypeInCurrentGamePlay(player._id, \"charm\", game))) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_PIED_PIPER_TARGETS);\n }\n }\n\n private validateGamePlayDefenderTargets(playTargets: MakeGamePlayTargetWithRelationsDto[], game: GameWithCurrentPlay): void {\n this.validateGamePlayTargetsBoundaries(playTargets, \"protect\", game);\n const targetedPlayer = playTargets[0].player;\n const canTargetedPlayerBeProtected = isPlayerInteractableWithInteractionTypeInCurrentGamePlay(targetedPlayer._id, \"protect\", game);\n if (!canTargetedPlayerBeProtected) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_DEFENDER_TARGET);\n }\n }\n\n private validateGamePlaySheriffTargets(playTargets: MakeGamePlayTargetWithRelationsDto[], game: GameWithCurrentPlay): void {\n this.validateGamePlayTargetsBoundaries(playTargets, \"transfer-sheriff-role\", game);\n this.validateGamePlayTargetsBoundaries(playTargets, \"sentence-to-death\", game);\n const targetedPlayer = playTargets[0].player;\n const canTargetBecomeSheriff = isPlayerInteractableWithInteractionTypeInCurrentGamePlay(targetedPlayer._id, \"transfer-sheriff-role\", game);\n if (game.currentPlay.action === \"delegate\" && !canTargetBecomeSheriff) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_SHERIFF_DELEGATE_TARGET);\n }\n const canTargetBeSentencedToDeath = isPlayerInteractableWithInteractionTypeInCurrentGamePlay(targetedPlayer._id, \"sentence-to-death\", game);\n if (game.currentPlay.action === \"settle-votes\" && !canTargetBeSentencedToDeath) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_SHERIFF_SETTLE_VOTES_TARGET);\n }\n }\n\n private validateGamePlayTargetsBoundaries(playTargets: MakeGamePlayTargetWithRelationsDto[], interactionType: PlayerInteractionType, game: GameWithCurrentPlay): void {\n const { interactions } = game.currentPlay.source;\n const interaction = interactions?.find(({ type }) => type === interactionType);\n if (!interaction) {\n return;\n }\n if (playTargets.length < interaction.boundaries.min) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.TOO_LESS_TARGETS);\n }\n if (playTargets.length > interaction.boundaries.max) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.TOO_MUCH_TARGETS);\n }\n }\n\n private async validateGamePlaySourceTargets(playTargets: MakeGamePlayTargetWithRelationsDto[], game: GameWithCurrentPlay): Promise {\n const gamePlaySourceValidationMethods: Partial Promise | void>> = {\n \"sheriff\": () => this.validateGamePlaySheriffTargets(playTargets, game),\n \"survivors\": () => this.validateGamePlaySurvivorsTargets(playTargets, game),\n \"werewolves\": () => this.validateGamePlayWerewolvesTargets(playTargets, game),\n \"accursed-wolf-father\": () => this.validateGamePlayAccursedWolfFatherTargets(playTargets, game),\n \"big-bad-wolf\": () => this.validateGamePlayWerewolvesTargets(playTargets, game),\n \"white-werewolf\": () => this.validateGamePlayWerewolvesTargets(playTargets, game),\n \"defender\": () => this.validateGamePlayDefenderTargets(playTargets, game),\n \"pied-piper\": () => this.validateGamePlayPiedPiperTargets(playTargets, game),\n \"wild-child\": () => this.validateGamePlayWildChildTargets(playTargets, game),\n \"scandalmonger\": () => this.validateGamePlayScandalmongerTargets(playTargets, game),\n \"seer\": () => this.validateGamePlaySeerTargets(playTargets, game),\n \"fox\": () => this.validateGamePlayFoxTargets(playTargets, game),\n \"cupid\": () => this.validateGamePlayCupidTargets(playTargets, game),\n \"scapegoat\": () => this.validateGamePlayScapegoatTargets(playTargets, game),\n \"hunter\": () => this.validateGamePlayHunterTargets(playTargets, game),\n \"witch\": async() => this.validateGamePlayWitchTargets(playTargets, game),\n };\n const gamePlaySourceValidationMethod = gamePlaySourceValidationMethods[game.currentPlay.source.name];\n if (gamePlaySourceValidationMethod) {\n await gamePlaySourceValidationMethod();\n }\n }\n\n private validateTargetsPotionUsage(playTargets: MakeGamePlayTargetWithRelationsDto[], game: GameWithCurrentPlay): void {\n const { source: currentPlaySource, action: currentPlayAction } = game.currentPlay;\n const hasSomePlayerDrankPotion = playTargets.some(({ drankPotion }) => drankPotion);\n if (hasSomePlayerDrankPotion && (currentPlayAction !== \"use-potions\" || currentPlaySource.name !== \"witch\")) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.UNEXPECTED_DRANK_POTION_TARGET);\n }\n }\n\n private async validateGamePlayTargetsWithRelationsDto(playTargets: MakeGamePlayTargetWithRelationsDto[] | undefined, game: GameWithCurrentPlay): Promise {\n const targetActionsTypes: GamePlayType[] = [\"target\", \"bury-dead-bodies\"];\n const { currentPlay } = game;\n if (!targetActionsTypes.includes(game.currentPlay.type)) {\n if (playTargets) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.UNEXPECTED_TARGETS);\n }\n return;\n }\n if (playTargets === undefined || playTargets.length === 0) {\n if (currentPlay.canBeSkipped === false) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.REQUIRED_TARGETS);\n }\n return;\n }\n this.validateTargetsPotionUsage(playTargets, game);\n await this.validateGamePlaySourceTargets(playTargets, game);\n }\n\n private validateGamePlayVotesTieBreakerWithRelationsDto(playVotes: MakeGamePlayVoteWithRelationsDto[], game: GameWithCurrentPlay): void {\n const { action } = game.currentPlay;\n const interactionType = action === \"vote\" ? \"vote\" : \"choose-as-sheriff\";\n const areEveryTargetsInNominatedPlayers = playVotes.every(({ target }) => isPlayerInteractableWithInteractionTypeInCurrentGamePlay(target._id, interactionType, game));\n if (doesGamePlayHaveCause(game.currentPlay, \"previous-votes-were-in-ties\") && !areEveryTargetsInNominatedPlayers) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_VOTE_TARGET_FOR_TIE_BREAKER);\n }\n }\n\n private validateGamePlayVotesWithRelationsDtoSourceAndTarget(playVotes: MakeGamePlayVoteWithRelationsDto[], game: GameWithCurrentPlay): void {\n const { currentPlay } = game;\n if (playVotes.some(({ source }) => !currentPlay.source.players?.find(({ _id }) => _id.equals(source._id)))) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_VOTE_SOURCE);\n }\n if (playVotes.some(({ target }) => !isPlayerInteractableInCurrentGamePlay(target._id, game))) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_VOTE_TARGET);\n }\n if (playVotes.some(({ source, target }) => source._id.equals(target._id))) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.SAME_SOURCE_AND_TARGET_VOTE);\n }\n }\n\n private validateGamePlayVotesWithRelationsDto(playVotes: MakeGamePlayVoteWithRelationsDto[] | undefined, game: GameWithCurrentPlay): void {\n const { currentPlay } = game;\n if (currentPlay.type !== \"vote\") {\n if (playVotes) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.UNEXPECTED_VOTES);\n }\n return;\n }\n if (playVotes === undefined || playVotes.length === 0) {\n if (game.currentPlay.canBeSkipped === false) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.REQUIRED_VOTES);\n }\n return;\n }\n if (doesGamePlayHaveCause(currentPlay, \"previous-votes-were-in-ties\")) {\n this.validateGamePlayVotesTieBreakerWithRelationsDto(playVotes, game);\n }\n this.validateGamePlayVotesWithRelationsDtoSourceAndTarget(playVotes, game);\n }\n\n private validateGamePlayWithRelationsDtoChosenSide({ chosenSide }: MakeGamePlayWithRelationsDto, game: GameWithCurrentPlay): void {\n const { isSideRandomlyChosen } = game.options.roles.wolfHound;\n if (chosenSide !== undefined && (game.currentPlay.action !== \"choose-side\" || isSideRandomlyChosen)) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.UNEXPECTED_CHOSEN_SIDE);\n }\n if (chosenSide === undefined && game.currentPlay.action === \"choose-side\" && !isSideRandomlyChosen) {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.REQUIRED_CHOSEN_SIDE);\n }\n }\n\n private validateGamePlayWithRelationsDtoJudgeRequest({ doesJudgeRequestAnotherVote }: MakeGamePlayWithRelationsDto, game: GameWithCurrentPlay): void {\n if (doesJudgeRequestAnotherVote !== undefined && game.currentPlay.action !== \"request-another-vote\") {\n throw new BadGamePlayPayloadException(BadGamePlayPayloadReasons.UNEXPECTED_STUTTERING_JUDGE_VOTE_REQUEST);\n }\n }\n}" }, "src/modules/game/providers/services/game-play/game-play-vote/game-play-vote.service.ts": { "language": "typescript", @@ -136936,7 +136962,6 @@ "182", "736", "737", - "748", "749" ], "location": { @@ -136972,7 +136997,6 @@ "182", "736", "737", - "748", "749" ], "location": { @@ -142575,7 +142599,6 @@ "246" ], "coveredBy": [ - "165", "246", "248", "249" @@ -148296,7 +148319,7 @@ } } ], - "source": "import { DAY_GAME_PLAYS_PRIORITY_LIST, NIGHT_GAME_PLAYS_PRIORITY_LIST } from \"@/modules/game/constants/game.constants\";\nimport { CreateGamePlayerDto } from \"@/modules/game/dto/create-game/create-game-player/create-game-player.dto\";\nimport { CreateGameDto } from \"@/modules/game/dto/create-game/create-game.dto\";\nimport { isInNightOrTwilightPhase } from \"@/modules/game/helpers/game-phase/game-phase.helpers\";\nimport { createGamePlay, createGamePlayCupidCharms, createGamePlaySurvivorsElectSheriff } from \"@/modules/game/helpers/game-play/game-play.factory\";\nimport { areGamePlaysEqual, canSurvivorsVote, doesGamePlayHaveCause, findPlayPriorityIndex } from \"@/modules/game/helpers/game-play/game-play.helpers\";\nimport { createGame, createGameWithCurrentGamePlay } from \"@/modules/game/helpers/game.factory\";\nimport { getEligibleCupidTargets, getEligibleWerewolvesTargets, getEligibleWhiteWerewolfTargets, getGroupOfPlayers, getPlayerDtoWithRole, getPlayersWithActiveAttributeName, getPlayersWithCurrentRole, getPlayerWithActiveAttributeName, getPlayerWithCurrentRole, isGameSourceGroup, isGameSourceRole } from \"@/modules/game/helpers/game.helpers\";\nimport { isPlayerAliveAndPowerful, isPlayerPowerful } from \"@/modules/game/helpers/player/player.helpers\";\nimport { GameHistoryRecordService } from \"@/modules/game/providers/services/game-history/game-history-record.service\";\nimport { GamePlayAugmenterService } from \"@/modules/game/providers/services/game-play/game-play-augmenter.service\";\nimport type { GameHistoryRecord } from \"@/modules/game/schemas/game-history-record/game-history-record.schema\";\nimport type { SheriffGameOptions } from \"@/modules/game/schemas/game-options/roles-game-options/sheriff-game-options/sheriff-game-options.schema\";\nimport type { GamePlay } from \"@/modules/game/schemas/game-play/game-play.schema\";\nimport type { Game } from \"@/modules/game/schemas/game.schema\";\n\nimport { GamePhaseName } from \"@/modules/game/types/game-phase/game-phase.types\";\nimport type { GameWithCurrentPlay } from \"@/modules/game/types/game-with-current-play.types\";\nimport { PlayerGroup } from \"@/modules/game/types/player/player.types\";\nimport { RoleName } from \"@/modules/role/types/role.types\";\n\nimport { createNoGamePlayPriorityUnexpectedException } from \"@/shared/exception/helpers/unexpected-exception.factory\";\nimport { Injectable } from \"@nestjs/common\";\n\n@Injectable()\nexport class GamePlayService {\n private readonly specificRoleGamePlaySuitabilityMethods: Partial Promise | boolean>> = {\n \"cupid\": async(game: Game) => this.isCupidGamePlaySuitableForCurrentPhase(game),\n \"two-sisters\": (game: Game) => this.isTwoSistersGamePlaySuitableForCurrentPhase(game),\n \"three-brothers\": (game: Game) => this.isThreeBrothersGamePlaySuitableForCurrentPhase(game),\n \"big-bad-wolf\": (game: Game) => this.isBigBadWolfGamePlaySuitableForCurrentPhase(game),\n \"pied-piper\": (game: Game) => this.isPiedPiperGamePlaySuitableForCurrentPhase(game),\n \"white-werewolf\": (game: Game) => this.isWhiteWerewolfGamePlaySuitableForCurrentPhase(game),\n \"witch\": async(game: Game) => this.isWitchGamePlaySuitableForCurrentPhase(game),\n \"actor\": (game: Game) => this.isActorGamePlaySuitableForCurrentPhase(game),\n \"accursed-wolf-father\": async(game: Game) => this.isAccursedWolfFatherGamePlaySuitableForCurrentPhase(game),\n \"stuttering-judge\": async(game: Game) => this.isStutteringJudgeGamePlaySuitableForCurrentPhase(game),\n };\n\n public constructor(\n private readonly gamePlayAugmenterService: GamePlayAugmenterService,\n private readonly gameHistoryRecordService: GameHistoryRecordService,\n ) {}\n\n public async refreshUpcomingPlays(game: Game): Promise {\n let clonedGame = createGame(game);\n clonedGame = await this.removeObsoleteUpcomingPlays(clonedGame);\n const currentPhaseNewUpcomingPlays = await this.getNewUpcomingPlaysForCurrentPhase(clonedGame);\n const upcomingPlaysToSort = [...clonedGame.upcomingPlays, ...currentPhaseNewUpcomingPlays];\n clonedGame.upcomingPlays = this.sortUpcomingPlaysByPriority(upcomingPlaysToSort);\n\n return clonedGame;\n }\n\n public proceedToNextGamePlay(game: Game): Game {\n const clonedGame = createGame(game);\n if (!clonedGame.upcomingPlays.length) {\n clonedGame.currentPlay = null;\n\n return clonedGame;\n }\n clonedGame.currentPlay = clonedGame.upcomingPlays[0];\n clonedGame.upcomingPlays.shift();\n\n return clonedGame;\n }\n\n public async augmentCurrentGamePlay(game: GameWithCurrentPlay): Promise {\n const clonedGame = createGameWithCurrentGamePlay(game);\n clonedGame.currentPlay = this.gamePlayAugmenterService.setGamePlayCanBeSkipped(clonedGame.currentPlay, clonedGame);\n clonedGame.currentPlay = await this.gamePlayAugmenterService.setGamePlaySourceInteractions(clonedGame.currentPlay, clonedGame);\n clonedGame.currentPlay = this.gamePlayAugmenterService.setGamePlaySourcePlayers(clonedGame.currentPlay, clonedGame);\n\n return clonedGame;\n }\n\n public async getPhaseUpcomingPlays(game: CreateGameDto | Game): Promise {\n const isSheriffElectionTime = this.isSheriffElectionTime(game.options.roles.sheriff, game.turn, game.phase.name);\n const phaseGamePlaysPriorityList = isInNightOrTwilightPhase(game) ? NIGHT_GAME_PLAYS_PRIORITY_LIST : DAY_GAME_PLAYS_PRIORITY_LIST;\n const suitabilityPromises = phaseGamePlaysPriorityList.map(async eligiblePlay => this.isGamePlaySuitableForCurrentPhase(game, eligiblePlay as GamePlay));\n const suitabilityResults = await Promise.all(suitabilityPromises);\n const upcomingNightPlays = phaseGamePlaysPriorityList\n .filter((gamePlay, index) => suitabilityResults[index])\n .map(play => createGamePlay(play as GamePlay));\n\n return isSheriffElectionTime ? [createGamePlaySurvivorsElectSheriff(), ...upcomingNightPlays] : upcomingNightPlays;\n }\n\n private async removeObsoleteUpcomingPlays(game: Game): Promise {\n const clonedGame = createGame(game);\n const suitabilityPromises = clonedGame.upcomingPlays.map(async eligiblePlay => this.isGamePlaySuitableForCurrentPhase(game, eligiblePlay));\n const suitabilityResults = await Promise.all(suitabilityPromises);\n clonedGame.upcomingPlays = clonedGame.upcomingPlays.filter((gamePlay, index) => suitabilityResults[index]);\n\n return clonedGame;\n }\n\n private isUpcomingPlayNewForCurrentPhase(upcomingPlay: GamePlay, game: Game, gameHistoryPhaseRecords: GameHistoryRecord[]): boolean {\n const { currentPlay } = game;\n const isAlreadyPlayed = gameHistoryPhaseRecords.some(({ play }) => {\n const { occurrence } = upcomingPlay;\n const { type, source, action, causes } = play;\n\n return areGamePlaysEqual({ type, source, action, causes, occurrence }, upcomingPlay);\n });\n const isInUpcomingPlays = game.upcomingPlays.some(gamePlay => areGamePlaysEqual(gamePlay, upcomingPlay));\n const isCurrentPlay = !!currentPlay && areGamePlaysEqual(currentPlay, upcomingPlay);\n\n return !isInUpcomingPlays && !isAlreadyPlayed && !isCurrentPlay;\n }\n\n private async getNewUpcomingPlaysForCurrentPhase(game: Game): Promise {\n const { _id, turn, phase } = game;\n const currentPhaseUpcomingPlays = await this.getPhaseUpcomingPlays(game);\n const phaseNames: GamePhaseName[] = phase.name === \"day\" ? [\"day\"] : [\"night\", \"twilight\"];\n const gameHistoryPhaseRecords = await this.gameHistoryRecordService.getGameHistoryRecordsForTurnAndPhases(_id, turn, phaseNames);\n\n return currentPhaseUpcomingPlays.filter(gamePlay => this.isUpcomingPlayNewForCurrentPhase(gamePlay, game, gameHistoryPhaseRecords));\n }\n\n private validateUpcomingPlaysPriority(upcomingPlays: GamePlay[]): void {\n for (const upcomingPlay of upcomingPlays) {\n const playPriorityIndex = findPlayPriorityIndex(upcomingPlay);\n if (playPriorityIndex === -1) {\n throw createNoGamePlayPriorityUnexpectedException(this.validateUpcomingPlaysPriority.name, upcomingPlay);\n }\n }\n }\n\n private sortUpcomingPlaysByPriority(upcomingPlays: GamePlay[]): GamePlay[] {\n const clonedUpcomingPlays = upcomingPlays.map(upcomingPlay => createGamePlay(upcomingPlay));\n this.validateUpcomingPlaysPriority(clonedUpcomingPlays);\n\n return clonedUpcomingPlays.sort((playA, playB) => {\n const playAPriorityIndex = findPlayPriorityIndex(playA);\n const playBPriorityIndex = findPlayPriorityIndex(playB);\n\n return playAPriorityIndex - playBPriorityIndex;\n });\n }\n\n private isSheriffElectionTime(sheriffGameOptions: SheriffGameOptions, currentTurn: number, currentPhase: GamePhaseName): boolean {\n const { electedAt, isEnabled } = sheriffGameOptions;\n const currentGamePhaseAsDayOrNight = currentPhase === \"day\" ? \"day\" : \"night\";\n\n return isEnabled && electedAt.turn === currentTurn && electedAt.phaseName === currentGamePhaseAsDayOrNight;\n }\n\n private isCharmedGamePlaySuitableForCurrentPhase(game: CreateGameDto | Game): boolean {\n if (game instanceof CreateGameDto || !this.isPiedPiperGamePlaySuitableForCurrentPhase(game)) {\n return false;\n }\n const charmedPlayers = getPlayersWithActiveAttributeName(game, \"charmed\");\n const aliveCharmedPlayers = charmedPlayers.filter(player => player.isAlive);\n\n return aliveCharmedPlayers.length > 1;\n }\n\n private async isLoversGamePlaySuitableForCurrentPhase(game: CreateGameDto | Game, gamePlay: GamePlay): Promise {\n if (game instanceof CreateGameDto) {\n return false;\n }\n const inLovePlayers = getPlayersWithActiveAttributeName(game, \"in-love\");\n\n return inLovePlayers.length > 0 && inLovePlayers.every(player => player.isAlive) && !await this.gameHistoryRecordService.hasGamePlayBeenMade(game._id, gamePlay);\n }\n\n private async isStutteringJudgeGamePlaySuitableForCurrentPhase(game: CreateGameDto | Game): Promise {\n if (game instanceof CreateGameDto) {\n return false;\n }\n const stutteringJudgePlayer = getPlayerWithCurrentRole(game, \"stuttering-judge\");\n if (!stutteringJudgePlayer || !isPlayerAliveAndPowerful(stutteringJudgePlayer, game)) {\n return false;\n }\n const { voteRequestsCount } = game.options.roles.stutteringJudge;\n const judgeGamePlayRecords = await this.gameHistoryRecordService.getGameHistoryStutteringJudgeRequestsAnotherVoteRecords(game._id, stutteringJudgePlayer._id);\n\n return judgeGamePlayRecords.length < voteRequestsCount;\n }\n\n private async isAccursedWolfFatherGamePlaySuitableForCurrentPhase(game: CreateGameDto | Game): Promise {\n const { doSkipCallIfNoTarget: doesSkipCallIfNoTarget } = game.options.roles;\n if (game instanceof CreateGameDto) {\n return !!getPlayerDtoWithRole(game, \"accursed-wolf-father\");\n }\n const accursedWolfFatherPlayer = getPlayerWithCurrentRole(game, \"accursed-wolf-father\");\n if (!accursedWolfFatherPlayer || !isPlayerAliveAndPowerful(accursedWolfFatherPlayer, game)) {\n return false;\n }\n const lastAccursedWolfFatherGamePlayRecord = await this.gameHistoryRecordService.getLastGameHistoryAccursedWolfFatherInfectsRecord(game._id, accursedWolfFatherPlayer._id);\n\n return !doesSkipCallIfNoTarget || !lastAccursedWolfFatherGamePlayRecord;\n }\n\n private async isSurvivorsGamePlaySuitableForCurrentPhase(game: CreateGameDto | Game, gamePlay: GamePlay): Promise {\n if (gamePlay.action !== \"vote\") {\n return true;\n }\n if (!doesGamePlayHaveCause(gamePlay, \"angel-presence\")) {\n return game instanceof CreateGameDto ? true : canSurvivorsVote(game);\n }\n if (game instanceof CreateGameDto) {\n return !!getPlayerDtoWithRole(game, \"angel\");\n }\n const angelPlayer = getPlayerWithCurrentRole(game, \"angel\");\n\n return !!angelPlayer && isPlayerAliveAndPowerful(angelPlayer, game) && !await this.gameHistoryRecordService.hasGamePlayBeenMade(game._id, gamePlay);\n }\n\n private async isGroupGamePlaySuitableForCurrentPhase(game: CreateGameDto | Game, gamePlay: GamePlay): Promise {\n const source = gamePlay.source.name as PlayerGroup;\n const specificGroupMethods: Record Promise | boolean> = {\n survivors: async() => this.isSurvivorsGamePlaySuitableForCurrentPhase(game, gamePlay),\n lovers: async() => this.isLoversGamePlaySuitableForCurrentPhase(game, gamePlay),\n charmed: () => this.isCharmedGamePlaySuitableForCurrentPhase(game),\n werewolves: () => game instanceof CreateGameDto || getGroupOfPlayers(game, source).some(werewolf => werewolf.isAlive),\n villagers: () => false,\n };\n\n return specificGroupMethods[source](game, gamePlay);\n }\n\n private async isOneNightOnlyGamePlaySuitableForCurrentPhase(game: CreateGameDto | Game, gamePlay: GamePlay): Promise {\n if (game instanceof CreateGameDto) {\n return !!getPlayerDtoWithRole(game, gamePlay.source.name as RoleName);\n }\n const player = getPlayerWithCurrentRole(game, gamePlay.source.name as RoleName);\n if (!player || !isPlayerAliveAndPowerful(player, game)) {\n return false;\n }\n return !await this.gameHistoryRecordService.hasGamePlayBeenMadeByPlayer(game._id, gamePlay, player);\n }\n\n private isActorGamePlaySuitableForCurrentPhase(game: CreateGameDto | Game): boolean {\n if (game instanceof CreateGameDto) {\n return !!getPlayerDtoWithRole(game, \"actor\");\n }\n const actorPlayer = getPlayerWithCurrentRole(game, \"actor\");\n const notUsedActorGameAdditionalCards = game.additionalCards?.filter(({ recipient, isUsed }) => recipient === \"actor\" && !isUsed) ?? [];\n\n return !!actorPlayer && isPlayerAliveAndPowerful(actorPlayer, game) && notUsedActorGameAdditionalCards.length > 0;\n }\n\n private async isWitchGamePlaySuitableForCurrentPhase(game: CreateGameDto | Game): Promise {\n if (game instanceof CreateGameDto) {\n return !!getPlayerDtoWithRole(game, \"witch\");\n }\n const witchPlayer = getPlayerWithCurrentRole(game, \"witch\");\n if (!witchPlayer || !isPlayerAliveAndPowerful(witchPlayer, game)) {\n return false;\n }\n const [lifePotionRecords, deathPotionRecords] = await Promise.all([\n this.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords(game._id, witchPlayer._id, \"life\"),\n this.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords(game._id, witchPlayer._id, \"death\"),\n ]);\n const hasWitchUsedLifePotion = lifePotionRecords.length > 0;\n const hasWitchUsedDeathPotion = deathPotionRecords.length > 0;\n const { doSkipCallIfNoTarget } = game.options.roles;\n\n return !doSkipCallIfNoTarget || !hasWitchUsedLifePotion || !hasWitchUsedDeathPotion;\n }\n\n private shouldBeCalledOnCurrentTurnInterval(wakingUpInterval: number, game: CreateGameDto | Game): boolean {\n return (game.turn - 1) % wakingUpInterval === 0;\n }\n\n private isWhiteWerewolfGamePlaySuitableForCurrentPhase(game: CreateGameDto | Game): boolean {\n const { wakingUpInterval } = game.options.roles.whiteWerewolf;\n const shouldWhiteWerewolfBeCalledOnCurrentTurn = this.shouldBeCalledOnCurrentTurnInterval(wakingUpInterval, game);\n if (game instanceof CreateGameDto) {\n return shouldWhiteWerewolfBeCalledOnCurrentTurn && !!getPlayerDtoWithRole(game, \"white-werewolf\");\n }\n const { doSkipCallIfNoTarget } = game.options.roles;\n const availableTargets = getEligibleWhiteWerewolfTargets(game);\n const whiteWerewolfPlayer = getPlayerWithCurrentRole(game, \"white-werewolf\");\n\n return shouldWhiteWerewolfBeCalledOnCurrentTurn && !!whiteWerewolfPlayer && isPlayerAliveAndPowerful(whiteWerewolfPlayer, game) &&\n (!doSkipCallIfNoTarget || !!availableTargets.length);\n }\n\n private isPiedPiperGamePlaySuitableForCurrentPhase(game: CreateGameDto | Game): boolean {\n if (game instanceof CreateGameDto) {\n return !!getPlayerDtoWithRole(game, \"pied-piper\");\n }\n const piedPiperPlayer = getPlayerWithCurrentRole(game, \"pied-piper\");\n\n return !!piedPiperPlayer && isPlayerAliveAndPowerful(piedPiperPlayer, game);\n }\n\n private isBigBadWolfGamePlaySuitableForCurrentPhase(game: CreateGameDto | Game): boolean {\n if (game instanceof CreateGameDto) {\n return !!getPlayerDtoWithRole(game, \"big-bad-wolf\");\n }\n const { doSkipCallIfNoTarget } = game.options.roles;\n const availableTargets = getEligibleWerewolvesTargets(game);\n const bigBadWolfPlayer = getPlayerWithCurrentRole(game, \"big-bad-wolf\");\n\n return !!bigBadWolfPlayer && isPlayerAliveAndPowerful(bigBadWolfPlayer, game) && (!doSkipCallIfNoTarget || !!availableTargets.length);\n }\n\n private isThreeBrothersGamePlaySuitableForCurrentPhase(game: CreateGameDto | Game): boolean {\n const { wakingUpInterval } = game.options.roles.threeBrothers;\n const shouldThreeBrothersBeCalledOnCurrentTurn = this.shouldBeCalledOnCurrentTurnInterval(wakingUpInterval, game);\n if (game instanceof CreateGameDto) {\n return shouldThreeBrothersBeCalledOnCurrentTurn && !!getPlayerDtoWithRole(game, \"three-brothers\");\n }\n const threeBrothersPlayers = getPlayersWithCurrentRole(game, \"three-brothers\");\n const minimumBrotherCountToCall = 2;\n const aliveAndPowerfulBrothers = threeBrothersPlayers.filter(brother => isPlayerAliveAndPowerful(brother, game));\n\n return shouldThreeBrothersBeCalledOnCurrentTurn && aliveAndPowerfulBrothers.length >= minimumBrotherCountToCall;\n }\n\n private isTwoSistersGamePlaySuitableForCurrentPhase(game: CreateGameDto | Game): boolean {\n const { wakingUpInterval } = game.options.roles.twoSisters;\n const shouldTwoSistersBeCalledOnCurrentTurn = this.shouldBeCalledOnCurrentTurnInterval(wakingUpInterval, game);\n if (game instanceof CreateGameDto) {\n return shouldTwoSistersBeCalledOnCurrentTurn && !!getPlayerDtoWithRole(game, \"two-sisters\");\n }\n const twoSistersPlayers = getPlayersWithCurrentRole(game, \"two-sisters\");\n\n return shouldTwoSistersBeCalledOnCurrentTurn && twoSistersPlayers.length > 0 && twoSistersPlayers.every(sister => isPlayerAliveAndPowerful(sister, game));\n }\n\n private async isCupidGamePlaySuitableForCurrentPhase(game: CreateGameDto | Game): Promise {\n if (game instanceof CreateGameDto) {\n return !!getPlayerDtoWithRole(game, \"cupid\");\n }\n const { doSkipCallIfNoTarget } = game.options.roles;\n const expectedPlayersToCharmCount = 2;\n const cupidPlayer = getPlayerWithCurrentRole(game, \"cupid\");\n if (!cupidPlayer) {\n return false;\n }\n const inLovePlayers = getPlayersWithActiveAttributeName(game, \"in-love\");\n const availableTargets = getEligibleCupidTargets(game);\n const doesCupidHaveEnoughTargets = availableTargets.length >= expectedPlayersToCharmCount;\n const isCupidGamePlayAlreadyMade = await this.gameHistoryRecordService.hasGamePlayBeenMadeByPlayer(game._id, createGamePlayCupidCharms(), cupidPlayer);\n\n return isPlayerAliveAndPowerful(cupidPlayer, game) && (doesCupidHaveEnoughTargets || !doSkipCallIfNoTarget) && !isCupidGamePlayAlreadyMade && !inLovePlayers.length;\n }\n\n private async isRoleGamePlaySuitableForCurrentPhase(game: CreateGameDto | Game, gamePlay: GamePlay): Promise {\n const source = gamePlay.source.name as RoleName;\n const player = game instanceof CreateGameDto ? getPlayerDtoWithRole(game, source) : getPlayerWithCurrentRole(game, source);\n if (!player) {\n return false;\n }\n const canStillPlayAfterDeathRoles: RoleName[] = [\"hunter\", \"scapegoat\"];\n if (canStillPlayAfterDeathRoles.includes(source)) {\n return player instanceof CreateGamePlayerDto || isPlayerPowerful(player, game as Game);\n }\n if (this.specificRoleGamePlaySuitabilityMethods[source] !== undefined) {\n return this.specificRoleGamePlaySuitabilityMethods[source](game);\n }\n if (gamePlay.occurrence === \"one-night-only\") {\n return this.isOneNightOnlyGamePlaySuitableForCurrentPhase(game, gamePlay);\n }\n return player instanceof CreateGamePlayerDto || isPlayerAliveAndPowerful(player, game as Game);\n }\n\n private isSheriffGamePlaySuitableForCurrentPhase(game: CreateGameDto | Game): boolean {\n if (!game.options.roles.sheriff.isEnabled) {\n return false;\n }\n if (game instanceof CreateGameDto) {\n return true;\n }\n const sheriffPlayer = getPlayerWithActiveAttributeName(game, \"sheriff\");\n\n return !!sheriffPlayer;\n }\n\n private async isGamePlaySuitableForCurrentPhase(game: CreateGameDto | Game, gamePlay: GamePlay): Promise {\n if (isGameSourceRole(gamePlay.source.name)) {\n return this.isRoleGamePlaySuitableForCurrentPhase(game, gamePlay);\n } else if (isGameSourceGroup(gamePlay.source.name)) {\n return this.isGroupGamePlaySuitableForCurrentPhase(game, gamePlay);\n }\n return this.isSheriffGamePlaySuitableForCurrentPhase(game);\n }\n}" + "source": "import { Injectable } from \"@nestjs/common\";\n\nimport { DAY_GAME_PLAYS_PRIORITY_LIST, NIGHT_GAME_PLAYS_PRIORITY_LIST } from \"@/modules/game/constants/game.constants\";\nimport { CreateGamePlayerDto } from \"@/modules/game/dto/create-game/create-game-player/create-game-player.dto\";\nimport { CreateGameDto } from \"@/modules/game/dto/create-game/create-game.dto\";\nimport { isInNightOrTwilightPhase } from \"@/modules/game/helpers/game-phase/game-phase.helpers\";\nimport { createGamePlay, createGamePlayCupidCharms, createGamePlaySurvivorsElectSheriff } from \"@/modules/game/helpers/game-play/game-play.factory\";\nimport { areGamePlaysEqual, canSurvivorsVote, doesGamePlayHaveCause, findPlayPriorityIndex } from \"@/modules/game/helpers/game-play/game-play.helpers\";\nimport { createGame, createGameWithCurrentGamePlay } from \"@/modules/game/helpers/game.factory\";\nimport { getEligibleCupidTargets, getEligibleWerewolvesTargets, getEligibleWhiteWerewolfTargets, getGroupOfPlayers, getPlayerDtoWithRole, getPlayersWithActiveAttributeName, getPlayersWithCurrentRole, getPlayerWithActiveAttributeName, getPlayerWithCurrentRole, isGameSourceGroup, isGameSourceRole } from \"@/modules/game/helpers/game.helpers\";\nimport { isPlayerAliveAndPowerful, isPlayerPowerful } from \"@/modules/game/helpers/player/player.helpers\";\nimport { GameHistoryRecordService } from \"@/modules/game/providers/services/game-history/game-history-record.service\";\nimport { GamePlayAugmenterService } from \"@/modules/game/providers/services/game-play/game-play-augmenter.service\";\nimport type { GameHistoryRecord } from \"@/modules/game/schemas/game-history-record/game-history-record.schema\";\nimport type { SheriffGameOptions } from \"@/modules/game/schemas/game-options/roles-game-options/sheriff-game-options/sheriff-game-options.schema\";\nimport type { GamePlay } from \"@/modules/game/schemas/game-play/game-play.schema\";\nimport type { Game } from \"@/modules/game/schemas/game.schema\";\nimport { GamePhaseName } from \"@/modules/game/types/game-phase/game-phase.types\";\nimport type { GameWithCurrentPlay } from \"@/modules/game/types/game-with-current-play.types\";\nimport { PlayerGroup } from \"@/modules/game/types/player/player.types\";\nimport { RoleName } from \"@/modules/role/types/role.types\";\n\nimport { createNoGamePlayPriorityUnexpectedException } from \"@/shared/exception/helpers/unexpected-exception.factory\";\n\n@Injectable()\nexport class GamePlayService {\n private readonly specificRoleGamePlaySuitabilityMethods: Partial Promise | boolean>> = {\n \"cupid\": async(game: Game) => this.isCupidGamePlaySuitableForCurrentPhase(game),\n \"two-sisters\": (game: Game) => this.isTwoSistersGamePlaySuitableForCurrentPhase(game),\n \"three-brothers\": (game: Game) => this.isThreeBrothersGamePlaySuitableForCurrentPhase(game),\n \"big-bad-wolf\": (game: Game) => this.isBigBadWolfGamePlaySuitableForCurrentPhase(game),\n \"pied-piper\": (game: Game) => this.isPiedPiperGamePlaySuitableForCurrentPhase(game),\n \"white-werewolf\": (game: Game) => this.isWhiteWerewolfGamePlaySuitableForCurrentPhase(game),\n \"witch\": async(game: Game) => this.isWitchGamePlaySuitableForCurrentPhase(game),\n \"actor\": (game: Game) => this.isActorGamePlaySuitableForCurrentPhase(game),\n \"accursed-wolf-father\": async(game: Game) => this.isAccursedWolfFatherGamePlaySuitableForCurrentPhase(game),\n \"stuttering-judge\": async(game: Game) => this.isStutteringJudgeGamePlaySuitableForCurrentPhase(game),\n };\n\n public constructor(\n private readonly gamePlayAugmenterService: GamePlayAugmenterService,\n private readonly gameHistoryRecordService: GameHistoryRecordService,\n ) {}\n\n public async refreshUpcomingPlays(game: Game): Promise {\n let clonedGame = createGame(game);\n clonedGame = await this.removeObsoleteUpcomingPlays(clonedGame);\n const currentPhaseNewUpcomingPlays = await this.getNewUpcomingPlaysForCurrentPhase(clonedGame);\n const upcomingPlaysToSort = [...clonedGame.upcomingPlays, ...currentPhaseNewUpcomingPlays];\n clonedGame.upcomingPlays = this.sortUpcomingPlaysByPriority(upcomingPlaysToSort);\n\n return clonedGame;\n }\n\n public proceedToNextGamePlay(game: Game): Game {\n const clonedGame = createGame(game);\n if (!clonedGame.upcomingPlays.length) {\n clonedGame.currentPlay = null;\n\n return clonedGame;\n }\n clonedGame.currentPlay = clonedGame.upcomingPlays[0];\n clonedGame.upcomingPlays.shift();\n\n return clonedGame;\n }\n\n public async augmentCurrentGamePlay(game: GameWithCurrentPlay): Promise {\n const clonedGame = createGameWithCurrentGamePlay(game);\n clonedGame.currentPlay = this.gamePlayAugmenterService.setGamePlayCanBeSkipped(clonedGame.currentPlay, clonedGame);\n clonedGame.currentPlay = await this.gamePlayAugmenterService.setGamePlaySourceInteractions(clonedGame.currentPlay, clonedGame);\n clonedGame.currentPlay = this.gamePlayAugmenterService.setGamePlaySourcePlayers(clonedGame.currentPlay, clonedGame);\n\n return clonedGame;\n }\n\n public async getPhaseUpcomingPlays(game: CreateGameDto | Game): Promise {\n const isSheriffElectionTime = this.isSheriffElectionTime(game.options.roles.sheriff, game.turn, game.phase.name);\n const phaseGamePlaysPriorityList = isInNightOrTwilightPhase(game) ? NIGHT_GAME_PLAYS_PRIORITY_LIST : DAY_GAME_PLAYS_PRIORITY_LIST;\n const suitabilityPromises = phaseGamePlaysPriorityList.map(async eligiblePlay => this.isGamePlaySuitableForCurrentPhase(game, eligiblePlay as GamePlay));\n const suitabilityResults = await Promise.all(suitabilityPromises);\n const upcomingNightPlays = phaseGamePlaysPriorityList\n .filter((gamePlay, index) => suitabilityResults[index])\n .map(play => createGamePlay(play as GamePlay));\n\n return isSheriffElectionTime ? [createGamePlaySurvivorsElectSheriff(), ...upcomingNightPlays] : upcomingNightPlays;\n }\n\n private async removeObsoleteUpcomingPlays(game: Game): Promise {\n const clonedGame = createGame(game);\n const suitabilityPromises = clonedGame.upcomingPlays.map(async eligiblePlay => this.isGamePlaySuitableForCurrentPhase(game, eligiblePlay));\n const suitabilityResults = await Promise.all(suitabilityPromises);\n clonedGame.upcomingPlays = clonedGame.upcomingPlays.filter((gamePlay, index) => suitabilityResults[index]);\n\n return clonedGame;\n }\n\n private isUpcomingPlayNewForCurrentPhase(upcomingPlay: GamePlay, game: Game, gameHistoryPhaseRecords: GameHistoryRecord[]): boolean {\n const { currentPlay } = game;\n const isAlreadyPlayed = gameHistoryPhaseRecords.some(({ play }) => {\n const { occurrence } = upcomingPlay;\n const { type, source, action, causes } = play;\n\n return areGamePlaysEqual({ type, source, action, causes, occurrence }, upcomingPlay);\n });\n const isInUpcomingPlays = game.upcomingPlays.some(gamePlay => areGamePlaysEqual(gamePlay, upcomingPlay));\n const isCurrentPlay = !!currentPlay && areGamePlaysEqual(currentPlay, upcomingPlay);\n\n return !isInUpcomingPlays && !isAlreadyPlayed && !isCurrentPlay;\n }\n\n private async getNewUpcomingPlaysForCurrentPhase(game: Game): Promise {\n const { _id, turn, phase } = game;\n const currentPhaseUpcomingPlays = await this.getPhaseUpcomingPlays(game);\n const phaseNames: GamePhaseName[] = phase.name === \"day\" ? [\"day\"] : [\"night\", \"twilight\"];\n const gameHistoryPhaseRecords = await this.gameHistoryRecordService.getGameHistoryRecordsForTurnAndPhases(_id, turn, phaseNames);\n\n return currentPhaseUpcomingPlays.filter(gamePlay => this.isUpcomingPlayNewForCurrentPhase(gamePlay, game, gameHistoryPhaseRecords));\n }\n\n private validateUpcomingPlaysPriority(upcomingPlays: GamePlay[]): void {\n for (const upcomingPlay of upcomingPlays) {\n const playPriorityIndex = findPlayPriorityIndex(upcomingPlay);\n if (playPriorityIndex === -1) {\n throw createNoGamePlayPriorityUnexpectedException(this.validateUpcomingPlaysPriority.name, upcomingPlay);\n }\n }\n }\n\n private sortUpcomingPlaysByPriority(upcomingPlays: GamePlay[]): GamePlay[] {\n const clonedUpcomingPlays = upcomingPlays.map(upcomingPlay => createGamePlay(upcomingPlay));\n this.validateUpcomingPlaysPriority(clonedUpcomingPlays);\n\n return clonedUpcomingPlays.sort((playA, playB) => {\n const playAPriorityIndex = findPlayPriorityIndex(playA);\n const playBPriorityIndex = findPlayPriorityIndex(playB);\n\n return playAPriorityIndex - playBPriorityIndex;\n });\n }\n\n private isSheriffElectionTime(sheriffGameOptions: SheriffGameOptions, currentTurn: number, currentPhase: GamePhaseName): boolean {\n const { electedAt, isEnabled } = sheriffGameOptions;\n const currentGamePhaseAsDayOrNight = currentPhase === \"day\" ? \"day\" : \"night\";\n\n return isEnabled && electedAt.turn === currentTurn && electedAt.phaseName === currentGamePhaseAsDayOrNight;\n }\n\n private isCharmedGamePlaySuitableForCurrentPhase(game: CreateGameDto | Game): boolean {\n if (game instanceof CreateGameDto || !this.isPiedPiperGamePlaySuitableForCurrentPhase(game)) {\n return false;\n }\n const charmedPlayers = getPlayersWithActiveAttributeName(game, \"charmed\");\n const aliveCharmedPlayers = charmedPlayers.filter(player => player.isAlive);\n\n return aliveCharmedPlayers.length > 1;\n }\n\n private async isLoversGamePlaySuitableForCurrentPhase(game: CreateGameDto | Game, gamePlay: GamePlay): Promise {\n if (game instanceof CreateGameDto) {\n return false;\n }\n const inLovePlayers = getPlayersWithActiveAttributeName(game, \"in-love\");\n\n return inLovePlayers.length > 0 && inLovePlayers.every(player => player.isAlive) && !await this.gameHistoryRecordService.hasGamePlayBeenMade(game._id, gamePlay);\n }\n\n private async isStutteringJudgeGamePlaySuitableForCurrentPhase(game: CreateGameDto | Game): Promise {\n if (game instanceof CreateGameDto) {\n return false;\n }\n const stutteringJudgePlayer = getPlayerWithCurrentRole(game, \"stuttering-judge\");\n if (!stutteringJudgePlayer || !isPlayerAliveAndPowerful(stutteringJudgePlayer, game)) {\n return false;\n }\n const { voteRequestsCount } = game.options.roles.stutteringJudge;\n const judgeGamePlayRecords = await this.gameHistoryRecordService.getGameHistoryStutteringJudgeRequestsAnotherVoteRecords(game._id, stutteringJudgePlayer._id);\n\n return judgeGamePlayRecords.length < voteRequestsCount;\n }\n\n private async isAccursedWolfFatherGamePlaySuitableForCurrentPhase(game: CreateGameDto | Game): Promise {\n const { doSkipCallIfNoTarget: doesSkipCallIfNoTarget } = game.options.roles;\n if (game instanceof CreateGameDto) {\n return !!getPlayerDtoWithRole(game, \"accursed-wolf-father\");\n }\n const accursedWolfFatherPlayer = getPlayerWithCurrentRole(game, \"accursed-wolf-father\");\n if (!accursedWolfFatherPlayer || !isPlayerAliveAndPowerful(accursedWolfFatherPlayer, game)) {\n return false;\n }\n const lastAccursedWolfFatherGamePlayRecord = await this.gameHistoryRecordService.getLastGameHistoryAccursedWolfFatherInfectsRecord(game._id, accursedWolfFatherPlayer._id);\n\n return !doesSkipCallIfNoTarget || !lastAccursedWolfFatherGamePlayRecord;\n }\n\n private async isSurvivorsGamePlaySuitableForCurrentPhase(game: CreateGameDto | Game, gamePlay: GamePlay): Promise {\n if (gamePlay.action !== \"vote\") {\n return true;\n }\n if (!doesGamePlayHaveCause(gamePlay, \"angel-presence\")) {\n return game instanceof CreateGameDto ? true : canSurvivorsVote(game);\n }\n if (game instanceof CreateGameDto) {\n return !!getPlayerDtoWithRole(game, \"angel\");\n }\n const angelPlayer = getPlayerWithCurrentRole(game, \"angel\");\n\n return !!angelPlayer && isPlayerAliveAndPowerful(angelPlayer, game) && !await this.gameHistoryRecordService.hasGamePlayBeenMade(game._id, gamePlay);\n }\n\n private async isGroupGamePlaySuitableForCurrentPhase(game: CreateGameDto | Game, gamePlay: GamePlay): Promise {\n const source = gamePlay.source.name as PlayerGroup;\n const specificGroupMethods: Record Promise | boolean> = {\n survivors: async() => this.isSurvivorsGamePlaySuitableForCurrentPhase(game, gamePlay),\n lovers: async() => this.isLoversGamePlaySuitableForCurrentPhase(game, gamePlay),\n charmed: () => this.isCharmedGamePlaySuitableForCurrentPhase(game),\n werewolves: () => game instanceof CreateGameDto || getGroupOfPlayers(game, source).some(werewolf => werewolf.isAlive),\n villagers: () => false,\n };\n\n return specificGroupMethods[source](game, gamePlay);\n }\n\n private async isOneNightOnlyGamePlaySuitableForCurrentPhase(game: CreateGameDto | Game, gamePlay: GamePlay): Promise {\n if (game instanceof CreateGameDto) {\n return !!getPlayerDtoWithRole(game, gamePlay.source.name as RoleName);\n }\n const player = getPlayerWithCurrentRole(game, gamePlay.source.name as RoleName);\n if (!player || !isPlayerAliveAndPowerful(player, game)) {\n return false;\n }\n return !await this.gameHistoryRecordService.hasGamePlayBeenMadeByPlayer(game._id, gamePlay, player);\n }\n\n private isActorGamePlaySuitableForCurrentPhase(game: CreateGameDto | Game): boolean {\n if (game instanceof CreateGameDto) {\n return !!getPlayerDtoWithRole(game, \"actor\");\n }\n const actorPlayer = getPlayerWithCurrentRole(game, \"actor\");\n const notUsedActorGameAdditionalCards = game.additionalCards?.filter(({ recipient, isUsed }) => recipient === \"actor\" && !isUsed) ?? [];\n\n return !!actorPlayer && isPlayerAliveAndPowerful(actorPlayer, game) && notUsedActorGameAdditionalCards.length > 0;\n }\n\n private async isWitchGamePlaySuitableForCurrentPhase(game: CreateGameDto | Game): Promise {\n if (game instanceof CreateGameDto) {\n return !!getPlayerDtoWithRole(game, \"witch\");\n }\n const witchPlayer = getPlayerWithCurrentRole(game, \"witch\");\n if (!witchPlayer || !isPlayerAliveAndPowerful(witchPlayer, game)) {\n return false;\n }\n const [lifePotionRecords, deathPotionRecords] = await Promise.all([\n this.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords(game._id, witchPlayer._id, \"life\"),\n this.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords(game._id, witchPlayer._id, \"death\"),\n ]);\n const hasWitchUsedLifePotion = lifePotionRecords.length > 0;\n const hasWitchUsedDeathPotion = deathPotionRecords.length > 0;\n const { doSkipCallIfNoTarget } = game.options.roles;\n\n return !doSkipCallIfNoTarget || !hasWitchUsedLifePotion || !hasWitchUsedDeathPotion;\n }\n\n private shouldBeCalledOnCurrentTurnInterval(wakingUpInterval: number, game: CreateGameDto | Game): boolean {\n return (game.turn - 1) % wakingUpInterval === 0;\n }\n\n private isWhiteWerewolfGamePlaySuitableForCurrentPhase(game: CreateGameDto | Game): boolean {\n const { wakingUpInterval } = game.options.roles.whiteWerewolf;\n const shouldWhiteWerewolfBeCalledOnCurrentTurn = this.shouldBeCalledOnCurrentTurnInterval(wakingUpInterval, game);\n if (game instanceof CreateGameDto) {\n return shouldWhiteWerewolfBeCalledOnCurrentTurn && !!getPlayerDtoWithRole(game, \"white-werewolf\");\n }\n const { doSkipCallIfNoTarget } = game.options.roles;\n const availableTargets = getEligibleWhiteWerewolfTargets(game);\n const whiteWerewolfPlayer = getPlayerWithCurrentRole(game, \"white-werewolf\");\n\n return shouldWhiteWerewolfBeCalledOnCurrentTurn && !!whiteWerewolfPlayer && isPlayerAliveAndPowerful(whiteWerewolfPlayer, game) &&\n (!doSkipCallIfNoTarget || !!availableTargets.length);\n }\n\n private isPiedPiperGamePlaySuitableForCurrentPhase(game: CreateGameDto | Game): boolean {\n if (game instanceof CreateGameDto) {\n return !!getPlayerDtoWithRole(game, \"pied-piper\");\n }\n const piedPiperPlayer = getPlayerWithCurrentRole(game, \"pied-piper\");\n\n return !!piedPiperPlayer && isPlayerAliveAndPowerful(piedPiperPlayer, game);\n }\n\n private isBigBadWolfGamePlaySuitableForCurrentPhase(game: CreateGameDto | Game): boolean {\n if (game instanceof CreateGameDto) {\n return !!getPlayerDtoWithRole(game, \"big-bad-wolf\");\n }\n const { doSkipCallIfNoTarget } = game.options.roles;\n const availableTargets = getEligibleWerewolvesTargets(game);\n const bigBadWolfPlayer = getPlayerWithCurrentRole(game, \"big-bad-wolf\");\n\n return !!bigBadWolfPlayer && isPlayerAliveAndPowerful(bigBadWolfPlayer, game) && (!doSkipCallIfNoTarget || !!availableTargets.length);\n }\n\n private isThreeBrothersGamePlaySuitableForCurrentPhase(game: CreateGameDto | Game): boolean {\n const { wakingUpInterval } = game.options.roles.threeBrothers;\n const shouldThreeBrothersBeCalledOnCurrentTurn = this.shouldBeCalledOnCurrentTurnInterval(wakingUpInterval, game);\n if (game instanceof CreateGameDto) {\n return shouldThreeBrothersBeCalledOnCurrentTurn && !!getPlayerDtoWithRole(game, \"three-brothers\");\n }\n const threeBrothersPlayers = getPlayersWithCurrentRole(game, \"three-brothers\");\n const minimumBrotherCountToCall = 2;\n const aliveAndPowerfulBrothers = threeBrothersPlayers.filter(brother => isPlayerAliveAndPowerful(brother, game));\n\n return shouldThreeBrothersBeCalledOnCurrentTurn && aliveAndPowerfulBrothers.length >= minimumBrotherCountToCall;\n }\n\n private isTwoSistersGamePlaySuitableForCurrentPhase(game: CreateGameDto | Game): boolean {\n const { wakingUpInterval } = game.options.roles.twoSisters;\n const shouldTwoSistersBeCalledOnCurrentTurn = this.shouldBeCalledOnCurrentTurnInterval(wakingUpInterval, game);\n if (game instanceof CreateGameDto) {\n return shouldTwoSistersBeCalledOnCurrentTurn && !!getPlayerDtoWithRole(game, \"two-sisters\");\n }\n const twoSistersPlayers = getPlayersWithCurrentRole(game, \"two-sisters\");\n\n return shouldTwoSistersBeCalledOnCurrentTurn && twoSistersPlayers.length > 0 && twoSistersPlayers.every(sister => isPlayerAliveAndPowerful(sister, game));\n }\n\n private async isCupidGamePlaySuitableForCurrentPhase(game: CreateGameDto | Game): Promise {\n if (game instanceof CreateGameDto) {\n return !!getPlayerDtoWithRole(game, \"cupid\");\n }\n const { doSkipCallIfNoTarget } = game.options.roles;\n const expectedPlayersToCharmCount = 2;\n const cupidPlayer = getPlayerWithCurrentRole(game, \"cupid\");\n if (!cupidPlayer) {\n return false;\n }\n const inLovePlayers = getPlayersWithActiveAttributeName(game, \"in-love\");\n const availableTargets = getEligibleCupidTargets(game);\n const doesCupidHaveEnoughTargets = availableTargets.length >= expectedPlayersToCharmCount;\n const isCupidGamePlayAlreadyMade = await this.gameHistoryRecordService.hasGamePlayBeenMadeByPlayer(game._id, createGamePlayCupidCharms(), cupidPlayer);\n\n return isPlayerAliveAndPowerful(cupidPlayer, game) && (doesCupidHaveEnoughTargets || !doSkipCallIfNoTarget) && !isCupidGamePlayAlreadyMade && !inLovePlayers.length;\n }\n\n private async isRoleGamePlaySuitableForCurrentPhase(game: CreateGameDto | Game, gamePlay: GamePlay): Promise {\n const source = gamePlay.source.name as RoleName;\n const player = game instanceof CreateGameDto ? getPlayerDtoWithRole(game, source) : getPlayerWithCurrentRole(game, source);\n if (!player) {\n return false;\n }\n const canStillPlayAfterDeathRoles: RoleName[] = [\"hunter\", \"scapegoat\"];\n if (canStillPlayAfterDeathRoles.includes(source)) {\n return player instanceof CreateGamePlayerDto || isPlayerPowerful(player, game as Game);\n }\n if (this.specificRoleGamePlaySuitabilityMethods[source] !== undefined) {\n return this.specificRoleGamePlaySuitabilityMethods[source](game);\n }\n if (gamePlay.occurrence === \"one-night-only\") {\n return this.isOneNightOnlyGamePlaySuitableForCurrentPhase(game, gamePlay);\n }\n return player instanceof CreateGamePlayerDto || isPlayerAliveAndPowerful(player, game as Game);\n }\n\n private isSheriffGamePlaySuitableForCurrentPhase(game: CreateGameDto | Game): boolean {\n if (!game.options.roles.sheriff.isEnabled) {\n return false;\n }\n if (game instanceof CreateGameDto) {\n return true;\n }\n const sheriffPlayer = getPlayerWithActiveAttributeName(game, \"sheriff\");\n\n return !!sheriffPlayer;\n }\n\n private async isGamePlaySuitableForCurrentPhase(game: CreateGameDto | Game, gamePlay: GamePlay): Promise {\n if (isGameSourceRole(gamePlay.source.name)) {\n return this.isRoleGamePlaySuitableForCurrentPhase(game, gamePlay);\n } else if (isGameSourceGroup(gamePlay.source.name)) {\n return this.isGroupGamePlaySuitableForCurrentPhase(game, gamePlay);\n }\n return this.isSheriffGamePlaySuitableForCurrentPhase(game);\n }\n}" }, "src/modules/game/providers/services/game-random-composition.service.ts": { "language": "typescript", @@ -151915,13 +151938,16 @@ } }, { - "id": "4286", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/modules/game/providers/services/game-victory/game-victory.service.ts(51,39): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", - "status": "CompileError", + "id": "4288", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "statusReason": "Error: expect(received).toBeUndefined()\n\nReceived: {\"type\": \"villagers\", \"winners\": [{\"_id\": \"cae5e7da03bbebba9bc5fc35\", \"attributes\": [], \"death\": undefined, \"group\": undefined, \"isAlive\": true, \"name\": \"Lonzo\", \"position\": 6878748332785664, \"role\": {\"current\": \"villager\", \"isRevealed\": false, \"original\": \"villager\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}, {\"_id\": \"1f64d2f6e1bac8adf9ecdbb4\", \"attributes\": [], \"death\": undefined, \"group\": undefined, \"isAlive\": true, \"name\": \"Berniece\", \"position\": 8753368977637376, \"role\": {\"current\": \"seer\", \"isRevealed\": false, \"original\": \"seer\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}]}\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/providers/services/game-victory/game-victory.service.spec.ts:315:66)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "status": "Killed", + "testsCompleted": 9, "static": false, - "killedBy": [], + "killedBy": [ + "1035" + ], "coveredBy": [ "748", "749", @@ -151948,23 +151974,26 @@ ], "location": { "end": { - "column": 4, - "line": 55 + "column": 131, + "line": 54 }, "start": { - "column": 47, - "line": 51 + "column": 12, + "line": 54 } } }, { - "id": "4287", - "mutatorName": "StringLiteral", - "replacement": "\"\"", - "statusReason": "src/modules/game/providers/services/game-victory/game-victory.service.ts(52,67): error TS2345: Argument of type '\"\"' is not assignable to parameter of type '\"villagers\" | \"werewolves\"'.\n", - "status": "CompileError", + "id": "4289", + "mutatorName": "ConditionalExpression", + "replacement": "false", + "statusReason": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: true\nReceived: false\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/providers/services/game-victory/game-victory.service.spec.ts:125:53)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "status": "Killed", + "testsCompleted": 9, "static": false, - "killedBy": [], + "killedBy": [ + "1022" + ], "coveredBy": [ "748", "749", @@ -151991,20 +152020,20 @@ ], "location": { "end": { - "column": 78, - "line": 52 + "column": 131, + "line": 54 }, "start": { - "column": 67, - "line": 52 + "column": 12, + "line": 54 } } }, { - "id": "4288", - "mutatorName": "ConditionalExpression", - "replacement": "true", - "statusReason": "Error: expect(received).toBeUndefined()\n\nReceived: {\"type\": \"villagers\", \"winners\": [{\"_id\": \"cae5e7da03bbebba9bc5fc35\", \"attributes\": [], \"death\": undefined, \"group\": undefined, \"isAlive\": true, \"name\": \"Lonzo\", \"position\": 6878748332785664, \"role\": {\"current\": \"villager\", \"isRevealed\": false, \"original\": \"villager\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}, {\"_id\": \"1f64d2f6e1bac8adf9ecdbb4\", \"attributes\": [], \"death\": undefined, \"group\": undefined, \"isAlive\": true, \"name\": \"Berniece\", \"position\": 8753368977637376, \"role\": {\"current\": \"seer\", \"isRevealed\": false, \"original\": \"seer\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}]}\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/providers/services/game-victory/game-victory.service.spec.ts:315:66)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "id": "4290", + "mutatorName": "LogicalOperator", + "replacement": "villagersSidedPlayers.length > 0 || !game.players.some(({\n side,\n isAlive\n}) => side.current === \"werewolves\" && isAlive)", + "statusReason": "Error: expect(received).toBeUndefined()\n\nReceived: {\"type\": \"villagers\", \"winners\": [{\"_id\": \"ff0d1dfda7bb30fe6ab4eb5a\", \"attributes\": [], \"death\": undefined, \"group\": undefined, \"isAlive\": true, \"name\": \"Lura\", \"position\": 2524806211698688, \"role\": {\"current\": \"villager\", \"isRevealed\": false, \"original\": \"villager\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}, {\"_id\": \"cbdfc50f88ddc2ceffd85318\", \"attributes\": [], \"death\": undefined, \"group\": undefined, \"isAlive\": true, \"name\": \"Sarah\", \"position\": 4762490659405824, \"role\": {\"current\": \"seer\", \"isRevealed\": false, \"original\": \"seer\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}]}\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/providers/services/game-victory/game-victory.service.spec.ts:315:66)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", "status": "Killed", "testsCompleted": 9, "static": false, @@ -152047,10 +152076,10 @@ } }, { - "id": "4289", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "statusReason": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: true\nReceived: false\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/providers/services/game-victory/game-victory.service.spec.ts:125:53)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "id": "4293", + "mutatorName": "EqualityOperator", + "replacement": "villagersSidedPlayers.length <= 0", + "statusReason": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: true\nReceived: false\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox4062190/tests/unit/specs/modules/game/providers/services/game-victory/game-victory.service.spec.ts:126:53)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", "status": "Killed", "testsCompleted": 9, "static": false, @@ -152083,7 +152112,7 @@ ], "location": { "end": { - "column": 131, + "column": 44, "line": 54 }, "start": { @@ -152093,12 +152122,56 @@ } }, { - "id": "4290", - "mutatorName": "LogicalOperator", - "replacement": "villagersSidedPlayers.length > 0 || !game.players.some(({\n side,\n isAlive\n}) => side.current === \"werewolves\" && isAlive)", - "statusReason": "Error: expect(received).toBeUndefined()\n\nReceived: {\"type\": \"villagers\", \"winners\": [{\"_id\": \"ff0d1dfda7bb30fe6ab4eb5a\", \"attributes\": [], \"death\": undefined, \"group\": undefined, \"isAlive\": true, \"name\": \"Lura\", \"position\": 2524806211698688, \"role\": {\"current\": \"villager\", \"isRevealed\": false, \"original\": \"villager\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}, {\"_id\": \"cbdfc50f88ddc2ceffd85318\", \"attributes\": [], \"death\": undefined, \"group\": undefined, \"isAlive\": true, \"name\": \"Sarah\", \"position\": 4762490659405824, \"role\": {\"current\": \"seer\", \"isRevealed\": false, \"original\": \"seer\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}]}\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/providers/services/game-victory/game-victory.service.spec.ts:315:66)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "id": "4294", + "mutatorName": "BooleanLiteral", + "replacement": "game.players.some(({\n side,\n isAlive\n}) => side.current === \"werewolves\" && isAlive)", + "statusReason": "Error: expect(received).toStrictEqual(expected) // deep equality\n\n- Expected - 183\n+ Received + 38\n\n@@ -1,201 +1,19 @@\n Object {\n \"_id\": \"ccdba26bdcefabb14ef9e3ea\",\n \"createdAt\": Any,\n \"currentPlay\": Object {\n \"action\": \"vote\",\n- \"canBeSkipped\": false,\n \"causes\": Array [\n \"previous-votes-were-in-ties\",\n ],\n \"occurrence\": \"consequential\",\n \"source\": Object {\n- \"interactions\": Array [\n- Object {\n- \"boundaries\": Object {\n- \"max\": 4,\n- \"min\": 1,\n- },\n- \"eligibleTargets\": Array [\n- Object {\n- \"_id\": \"8ecedb4ce8ffa9f3ff92db8c\",\n- \"attributes\": Array [],\n- \"isAlive\": true,\n- \"name\": \"Seth\",\n- \"position\": 8542004982054912,\n- \"role\": Object {\n- \"current\": \"seer\",\n- \"isRevealed\": false,\n- \"original\": \"seer\",\n- },\n- \"side\": Object {\n- \"current\": \"villagers\",\n- \"original\": \"villagers\",\n- },\n- },\n- Object {\n- \"_id\": \"95b9abb4cffdd821c82fcca3\",\n- \"attributes\": Array [],\n- \"isAlive\": true,\n- \"name\": \"Sydney\",\n- \"position\": 596856212029440,\n- \"role\": Object {\n- \"current\": \"werewolf\",\n- \"isRevealed\": false,\n- \"original\": \"werewolf\",\n- },\n- \"side\": Object {\n- \"current\": \"werewolves\",\n- \"original\": \"werewolves\",\n- },\n- },\n- ],\n- \"source\": \"survivors\",\n- \"type\": \"vote\",\n- },\n- ],\n \"name\": \"survivors\",\n- \"players\": Array [\n- Object {\n- \"_id\": \"95b9abb4cffdd821c82fcca3\",\n- \"attributes\": Array [],\n- \"isAlive\": true,\n- \"name\": \"Sydney\",\n- \"position\": 596856212029440,\n- \"role\": Object {\n- \"current\": \"werewolf\",\n- \"isRevealed\": false,\n- \"original\": \"werewolf\",\n },\n- \"side\": Object {\n- \"current\": \"werewolves\",\n- \"original\": \"werewolves\",\n- },\n- },\n- Object {\n- \"_id\": \"8ecedb4ce8ffa9f3ff92db8c\",\n- \"attributes\": Array [],\n- \"isAlive\": true,\n- \"name\": \"Seth\",\n- \"position\": 8542004982054912,\n- \"role\": Object {\n- \"current\": \"seer\",\n- \"isRevealed\": false,\n- \"original\": \"seer\",\n- },\n- \"side\": Object {\n- \"current\": \"villagers\",\n- \"original\": \"villagers\",\n- },\n- },\n- Object {\n- \"_id\": \"6ffdbff67aee8ad8ecce70bc\",\n- \"attributes\": Array [],\n- \"isAlive\": true,\n- \"name\": \"Enos\",\n- \"position\": 5761836301418496,\n- \"role\": Object {\n- \"current\": \"villager\",\n- \"isRevealed\": false,\n- \"original\": \"villager\",\n- },\n- \"side\": Object {\n- \"current\": \"villagers\",\n- \"original\": \"villagers\",\n- },\n- },\n- Object {\n- \"_id\": \"c2fb8acf1addeb228f74a7c3\",\n- \"attributes\": Array [],\n- \"isAlive\": true,\n- \"name\": \"Ellsworth\",\n- \"position\": 4599418969915392,\n- \"role\": Object {\n- \"current\": \"werewolf\",\n- \"isRevealed\": false,\n- \"original\": \"werewolf\",\n- },\n- \"side\": Object {\n- \"current\": \"werewolves\",\n- \"original\": \"werewolves\",\n- },\n- },\n- ],\n- },\n \"type\": \"vote\",\n },\n- \"events\": Array [\n- Object {\n- \"players\": Array [\n- Object {\n- \"_id\": \"95b9abb4cffdd821c82fcca3\",\n- \"attributes\": Array [],\n- \"isAlive\": true,\n- \"name\": \"Sydney\",\n- \"position\": 596856212029440,\n- \"role\": Object {\n- \"current\": \"werewolf\",\n- \"isRevealed\": false,\n- \"original\": \"werewolf\",\n- },\n- \"side\": Object {\n- \"current\": \"werewolves\",\n- \"original\": \"werewolves\",\n- },\n- },\n- Object {\n- \"_id\": \"8ecedb4ce8ffa9f3ff92db8c\",\n- \"attributes\": Array [],\n- \"isAlive\": true,\n- \"name\": \"Seth\",\n- \"position\": 8542004982054912,\n- \"role\": Object {\n- \"current\": \"seer\",\n- \"isRevealed\": false,\n- \"original\": \"seer\",\n- },\n- \"side\": Object {\n- \"current\": \"villagers\",\n- \"original\": \"villagers\",\n- },\n- },\n- Object {\n- \"_id\": \"6ffdbff67aee8ad8ecce70bc\",\n- \"attributes\": Array [],\n- \"isAlive\": true,\n- \"name\": \"Enos\",\n- \"position\": 5761836301418496,\n- \"role\": Object {\n- \"current\": \"villager\",\n- \"isRevealed\": false,\n- \"original\": \"villager\",\n- },\n- \"side\": Object {\n- \"current\": \"villagers\",\n- \"original\": \"villagers\",\n- },\n- },\n- Object {\n- \"_id\": \"c2fb8acf1addeb228f74a7c3\",\n- \"attributes\": Array [],\n- \"isAlive\": true,\n- \"name\": \"Ellsworth\",\n- \"position\": 4599418969915392,\n- \"role\": Object {\n- \"current\": \"werewolf\",\n- \"isRevealed\": false,\n- \"original\": \"werewolf\",\n- },\n- \"side\": Object {\n- \"current\": \"werewolves\",\n- \"original\": \"werewolves\",\n- },\n- },\n- ],\n- \"type\": \"game-turn-starts\",\n- },\n- ],\n \"lastGameHistoryRecord\": Any,\n \"options\": Object {\n \"composition\": Object {\n \"isHidden\": true,\n },\n@@ -362,11 +180,11 @@\n \"current\": \"werewolves\",\n \"original\": \"werewolves\",\n },\n },\n ],\n- \"status\": \"playing\",\n+ \"status\": \"over\",\n \"tick\": 3907234033565697,\n \"turn\": 4394864355573760,\n \"upcomingPlays\": Array [\n Object {\n \"action\": \"look\",\n@@ -384,6 +202,43 @@\n },\n \"type\": \"target\",\n },\n ],\n \"updatedAt\": Any,\n+ \"victory\": Object {\n+ \"type\": \"villagers\",\n+ \"winners\": Array [\n+ Object {\n+ \"_id\": \"8ecedb4ce8ffa9f3ff92db8c\",\n+ \"attributes\": Array [],\n+ \"isAlive\": true,\n+ \"name\": \"Seth\",\n+ \"position\": 8542004982054912,\n+ \"role\": Object {\n+ \"current\": \"seer\",\n+ \"isRevealed\": false,\n+ \"original\": \"seer\",\n+ },\n+ \"side\": Object {\n+ \"current\": \"villagers\",\n+ \"original\": \"villagers\",\n+ },\n+ },\n+ Object {\n+ \"_id\": \"6ffdbff67aee8ad8ecce70bc\",\n+ \"attributes\": Array [],\n+ \"isAlive\": true,\n+ \"name\": \"Enos\",\n+ \"position\": 5761836301418496,\n+ \"role\": Object {\n+ \"current\": \"villager\",\n+ \"isRevealed\": false,\n+ \"original\": \"villager\",\n+ },\n+ \"side\": Object {\n+ \"current\": \"villagers\",\n+ \"original\": \"villagers\",\n+ },\n+ },\n+ ],\n+ },\n }\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox5172513/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:1317:37)\n at processTicksAndRejections (node:internal/process/task_queues:95:5)", "status": "Killed", - "testsCompleted": 9, + "testsCompleted": 20, + "static": false, + "killedBy": [ + "748" + ], + "coveredBy": [ + "748", + "749", + "1019", + "1020", + "1021", + "1022", + "1023", + "1024", + "1025", + "1026", + "1028", + "1029", + "1030", + "1031", + "1032", + "1033", + "1034", + "1035", + "1042", + "1043" + ], + "location": { + "end": { + "column": 131, + "line": 54 + }, + "start": { + "column": 48, + "line": 54 + } + } + }, + { + "id": "4295", + "mutatorName": "MethodExpression", + "replacement": "game.players.every(({\n side,\n isAlive\n}) => side.current === \"werewolves\" && isAlive)", + "statusReason": "Error: expect(received).toBeUndefined()\n\nReceived: {\"type\": \"villagers\", \"winners\": [{\"_id\": \"d2c908fc210ab193bb4c40bf\", \"attributes\": [], \"death\": undefined, \"group\": undefined, \"isAlive\": true, \"name\": \"Floy\", \"position\": 3222141686251520, \"role\": {\"current\": \"villager\", \"isRevealed\": false, \"original\": \"villager\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}, {\"_id\": \"5e5f0fb9311c04a2c8d8ac9a\", \"attributes\": [], \"death\": undefined, \"group\": undefined, \"isAlive\": true, \"name\": \"Lee\", \"position\": 3585745440735232, \"role\": {\"current\": \"seer\", \"isRevealed\": false, \"original\": \"seer\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}]}\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/providers/services/game-victory/game-victory.service.spec.ts:315:66)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "status": "Killed", + "testsCompleted": 7, "static": false, "killedBy": [ "1035" @@ -152122,8 +152195,6 @@ "1033", "1034", "1035", - "1040", - "1041", "1042", "1043" ], @@ -152133,21 +152204,21 @@ "line": 54 }, "start": { - "column": 12, + "column": 49, "line": 54 } } }, { - "id": "4291", - "mutatorName": "ConditionalExpression", - "replacement": "true", - "statusReason": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: false\nReceived: true\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox4062190/tests/unit/specs/modules/game/providers/services/game-victory/game-victory.service.spec.ts:425:60)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "id": "4296", + "mutatorName": "ArrowFunction", + "replacement": "() => undefined", + "statusReason": "Error: expect(received).toStrictEqual(expected) // deep equality\n\n- Expected - 183\n+ Received + 38\n\n@@ -1,201 +1,19 @@\n Object {\n \"_id\": \"d00cedc079387ab128dcba61\",\n \"createdAt\": Any,\n \"currentPlay\": Object {\n \"action\": \"vote\",\n- \"canBeSkipped\": false,\n \"causes\": Array [\n \"previous-votes-were-in-ties\",\n ],\n \"occurrence\": \"consequential\",\n \"source\": Object {\n- \"interactions\": Array [\n- Object {\n- \"boundaries\": Object {\n- \"max\": 4,\n- \"min\": 1,\n- },\n- \"eligibleTargets\": Array [\n- Object {\n- \"_id\": \"e4aee3f2ffe7cdb0fea618fb\",\n- \"attributes\": Array [],\n- \"isAlive\": true,\n- \"name\": \"Martina\",\n- \"position\": 532356737794048,\n- \"role\": Object {\n- \"current\": \"seer\",\n- \"isRevealed\": false,\n- \"original\": \"seer\",\n- },\n- \"side\": Object {\n- \"current\": \"villagers\",\n- \"original\": \"villagers\",\n- },\n- },\n- Object {\n- \"_id\": \"b1cc8d2a8eb8bdd5f8aafeed\",\n- \"attributes\": Array [],\n- \"isAlive\": true,\n- \"name\": \"Fabiola\",\n- \"position\": 4549261817544704,\n- \"role\": Object {\n- \"current\": \"werewolf\",\n- \"isRevealed\": false,\n- \"original\": \"werewolf\",\n- },\n- \"side\": Object {\n- \"current\": \"werewolves\",\n- \"original\": \"werewolves\",\n- },\n- },\n- ],\n- \"source\": \"survivors\",\n- \"type\": \"vote\",\n- },\n- ],\n \"name\": \"survivors\",\n- \"players\": Array [\n- Object {\n- \"_id\": \"b1cc8d2a8eb8bdd5f8aafeed\",\n- \"attributes\": Array [],\n- \"isAlive\": true,\n- \"name\": \"Fabiola\",\n- \"position\": 4549261817544704,\n- \"role\": Object {\n- \"current\": \"werewolf\",\n- \"isRevealed\": false,\n- \"original\": \"werewolf\",\n },\n- \"side\": Object {\n- \"current\": \"werewolves\",\n- \"original\": \"werewolves\",\n- },\n- },\n- Object {\n- \"_id\": \"e4aee3f2ffe7cdb0fea618fb\",\n- \"attributes\": Array [],\n- \"isAlive\": true,\n- \"name\": \"Martina\",\n- \"position\": 532356737794048,\n- \"role\": Object {\n- \"current\": \"seer\",\n- \"isRevealed\": false,\n- \"original\": \"seer\",\n- },\n- \"side\": Object {\n- \"current\": \"villagers\",\n- \"original\": \"villagers\",\n- },\n- },\n- Object {\n- \"_id\": \"7d50f2e183e95d13ca806ef1\",\n- \"attributes\": Array [],\n- \"isAlive\": true,\n- \"name\": \"Derick\",\n- \"position\": 8291364844339200,\n- \"role\": Object {\n- \"current\": \"villager\",\n- \"isRevealed\": false,\n- \"original\": \"villager\",\n- },\n- \"side\": Object {\n- \"current\": \"villagers\",\n- \"original\": \"villagers\",\n- },\n- },\n- Object {\n- \"_id\": \"a6b1c6cf4901d7cabde21abb\",\n- \"attributes\": Array [],\n- \"isAlive\": true,\n- \"name\": \"Maria\",\n- \"position\": 3743543197696000,\n- \"role\": Object {\n- \"current\": \"werewolf\",\n- \"isRevealed\": false,\n- \"original\": \"werewolf\",\n- },\n- \"side\": Object {\n- \"current\": \"werewolves\",\n- \"original\": \"werewolves\",\n- },\n- },\n- ],\n- },\n \"type\": \"vote\",\n },\n- \"events\": Array [\n- Object {\n- \"players\": Array [\n- Object {\n- \"_id\": \"b1cc8d2a8eb8bdd5f8aafeed\",\n- \"attributes\": Array [],\n- \"isAlive\": true,\n- \"name\": \"Fabiola\",\n- \"position\": 4549261817544704,\n- \"role\": Object {\n- \"current\": \"werewolf\",\n- \"isRevealed\": false,\n- \"original\": \"werewolf\",\n- },\n- \"side\": Object {\n- \"current\": \"werewolves\",\n- \"original\": \"werewolves\",\n- },\n- },\n- Object {\n- \"_id\": \"e4aee3f2ffe7cdb0fea618fb\",\n- \"attributes\": Array [],\n- \"isAlive\": true,\n- \"name\": \"Martina\",\n- \"position\": 532356737794048,\n- \"role\": Object {\n- \"current\": \"seer\",\n- \"isRevealed\": false,\n- \"original\": \"seer\",\n- },\n- \"side\": Object {\n- \"current\": \"villagers\",\n- \"original\": \"villagers\",\n- },\n- },\n- Object {\n- \"_id\": \"7d50f2e183e95d13ca806ef1\",\n- \"attributes\": Array [],\n- \"isAlive\": true,\n- \"name\": \"Derick\",\n- \"position\": 8291364844339200,\n- \"role\": Object {\n- \"current\": \"villager\",\n- \"isRevealed\": false,\n- \"original\": \"villager\",\n- },\n- \"side\": Object {\n- \"current\": \"villagers\",\n- \"original\": \"villagers\",\n- },\n- },\n- Object {\n- \"_id\": \"a6b1c6cf4901d7cabde21abb\",\n- \"attributes\": Array [],\n- \"isAlive\": true,\n- \"name\": \"Maria\",\n- \"position\": 3743543197696000,\n- \"role\": Object {\n- \"current\": \"werewolf\",\n- \"isRevealed\": false,\n- \"original\": \"werewolf\",\n- },\n- \"side\": Object {\n- \"current\": \"werewolves\",\n- \"original\": \"werewolves\",\n- },\n- },\n- ],\n- \"type\": \"game-turn-starts\",\n- },\n- ],\n \"lastGameHistoryRecord\": Any,\n \"options\": Object {\n \"composition\": Object {\n \"isHidden\": false,\n },\n@@ -362,11 +180,11 @@\n \"current\": \"werewolves\",\n \"original\": \"werewolves\",\n },\n },\n ],\n- \"status\": \"playing\",\n+ \"status\": \"over\",\n \"tick\": 6961294603190273,\n \"turn\": 8076890684260352,\n \"upcomingPlays\": Array [\n Object {\n \"action\": \"look\",\n@@ -384,6 +202,43 @@\n },\n \"type\": \"target\",\n },\n ],\n \"updatedAt\": Any,\n+ \"victory\": Object {\n+ \"type\": \"villagers\",\n+ \"winners\": Array [\n+ Object {\n+ \"_id\": \"e4aee3f2ffe7cdb0fea618fb\",\n+ \"attributes\": Array [],\n+ \"isAlive\": true,\n+ \"name\": \"Martina\",\n+ \"position\": 532356737794048,\n+ \"role\": Object {\n+ \"current\": \"seer\",\n+ \"isRevealed\": false,\n+ \"original\": \"seer\",\n+ },\n+ \"side\": Object {\n+ \"current\": \"villagers\",\n+ \"original\": \"villagers\",\n+ },\n+ },\n+ Object {\n+ \"_id\": \"7d50f2e183e95d13ca806ef1\",\n+ \"attributes\": Array [],\n+ \"isAlive\": true,\n+ \"name\": \"Derick\",\n+ \"position\": 8291364844339200,\n+ \"role\": Object {\n+ \"current\": \"villager\",\n+ \"isRevealed\": false,\n+ \"original\": \"villager\",\n+ },\n+ \"side\": Object {\n+ \"current\": \"villagers\",\n+ \"original\": \"villagers\",\n+ },\n+ },\n+ ],\n+ },\n }\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox5172513/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:1317:37)\n at processTicksAndRejections (node:internal/process/task_queues:95:5)", "status": "Killed", - "testsCompleted": 9, + "testsCompleted": 20, "static": false, "killedBy": [ - "1040" + "748" ], "coveredBy": [ "748", @@ -152168,32 +152239,30 @@ "1033", "1034", "1035", - "1040", - "1041", "1042", "1043" ], "location": { "end": { - "column": 44, + "column": 130, "line": 54 }, "start": { - "column": 12, + "column": 67, "line": 54 } } }, { - "id": "4292", - "mutatorName": "EqualityOperator", - "replacement": "villagersSidedPlayers.length >= 0", - "statusReason": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: false\nReceived: true\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/providers/services/game-victory/game-victory.service.spec.ts:412:60)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "id": "4297", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "statusReason": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: true\nReceived: false\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/providers/services/game-victory/game-victory.service.spec.ts:125:53)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", "status": "Killed", - "testsCompleted": 9, + "testsCompleted": 7, "static": false, "killedBy": [ - "1040" + "1022" ], "coveredBy": [ "748", @@ -152214,32 +152283,30 @@ "1033", "1034", "1035", - "1040", - "1041", "1042", "1043" ], "location": { "end": { - "column": 44, + "column": 130, "line": 54 }, "start": { - "column": 12, + "column": 90, "line": 54 } } }, { - "id": "4293", - "mutatorName": "EqualityOperator", - "replacement": "villagersSidedPlayers.length <= 0", - "statusReason": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: true\nReceived: false\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox4062190/tests/unit/specs/modules/game/providers/services/game-victory/game-victory.service.spec.ts:126:53)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "id": "4298", + "mutatorName": "ConditionalExpression", + "replacement": "false", + "statusReason": "Error: expect(received).toBeUndefined()\n\nReceived: {\"type\": \"villagers\", \"winners\": [{\"_id\": \"6af4028f204d6bf35eaaf7f9\", \"attributes\": [], \"death\": undefined, \"group\": undefined, \"isAlive\": true, \"name\": \"Tristian\", \"position\": 2641132792053760, \"role\": {\"current\": \"villager\", \"isRevealed\": false, \"original\": \"villager\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}, {\"_id\": \"1bea2aa5237dda3be69fd0f3\", \"attributes\": [], \"death\": undefined, \"group\": undefined, \"isAlive\": true, \"name\": \"Lonny\", \"position\": 4335335093829632, \"role\": {\"current\": \"seer\", \"isRevealed\": false, \"original\": \"seer\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}]}\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/providers/services/game-victory/game-victory.service.spec.ts:315:66)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", "status": "Killed", - "testsCompleted": 9, + "testsCompleted": 7, "static": false, "killedBy": [ - "1022" + "1035" ], "coveredBy": [ "748", @@ -152260,32 +152327,30 @@ "1033", "1034", "1035", - "1040", - "1041", "1042", "1043" ], "location": { "end": { - "column": 44, + "column": 130, "line": 54 }, "start": { - "column": 12, + "column": 90, "line": 54 } } }, { - "id": "4294", - "mutatorName": "BooleanLiteral", - "replacement": "game.players.some(({\n side,\n isAlive\n}) => side.current === \"werewolves\" && isAlive)", - "statusReason": "Error: expect(received).toStrictEqual(expected) // deep equality\n\n- Expected - 183\n+ Received + 38\n\n@@ -1,201 +1,19 @@\n Object {\n \"_id\": \"ccdba26bdcefabb14ef9e3ea\",\n \"createdAt\": Any,\n \"currentPlay\": Object {\n \"action\": \"vote\",\n- \"canBeSkipped\": false,\n \"causes\": Array [\n \"previous-votes-were-in-ties\",\n ],\n \"occurrence\": \"consequential\",\n \"source\": Object {\n- \"interactions\": Array [\n- Object {\n- \"boundaries\": Object {\n- \"max\": 4,\n- \"min\": 1,\n- },\n- \"eligibleTargets\": Array [\n- Object {\n- \"_id\": \"8ecedb4ce8ffa9f3ff92db8c\",\n- \"attributes\": Array [],\n- \"isAlive\": true,\n- \"name\": \"Seth\",\n- \"position\": 8542004982054912,\n- \"role\": Object {\n- \"current\": \"seer\",\n- \"isRevealed\": false,\n- \"original\": \"seer\",\n- },\n- \"side\": Object {\n- \"current\": \"villagers\",\n- \"original\": \"villagers\",\n- },\n- },\n- Object {\n- \"_id\": \"95b9abb4cffdd821c82fcca3\",\n- \"attributes\": Array [],\n- \"isAlive\": true,\n- \"name\": \"Sydney\",\n- \"position\": 596856212029440,\n- \"role\": Object {\n- \"current\": \"werewolf\",\n- \"isRevealed\": false,\n- \"original\": \"werewolf\",\n- },\n- \"side\": Object {\n- \"current\": \"werewolves\",\n- \"original\": \"werewolves\",\n- },\n- },\n- ],\n- \"source\": \"survivors\",\n- \"type\": \"vote\",\n- },\n- ],\n \"name\": \"survivors\",\n- \"players\": Array [\n- Object {\n- \"_id\": \"95b9abb4cffdd821c82fcca3\",\n- \"attributes\": Array [],\n- \"isAlive\": true,\n- \"name\": \"Sydney\",\n- \"position\": 596856212029440,\n- \"role\": Object {\n- \"current\": \"werewolf\",\n- \"isRevealed\": false,\n- \"original\": \"werewolf\",\n },\n- \"side\": Object {\n- \"current\": \"werewolves\",\n- \"original\": \"werewolves\",\n- },\n- },\n- Object {\n- \"_id\": \"8ecedb4ce8ffa9f3ff92db8c\",\n- \"attributes\": Array [],\n- \"isAlive\": true,\n- \"name\": \"Seth\",\n- \"position\": 8542004982054912,\n- \"role\": Object {\n- \"current\": \"seer\",\n- \"isRevealed\": false,\n- \"original\": \"seer\",\n- },\n- \"side\": Object {\n- \"current\": \"villagers\",\n- \"original\": \"villagers\",\n- },\n- },\n- Object {\n- \"_id\": \"6ffdbff67aee8ad8ecce70bc\",\n- \"attributes\": Array [],\n- \"isAlive\": true,\n- \"name\": \"Enos\",\n- \"position\": 5761836301418496,\n- \"role\": Object {\n- \"current\": \"villager\",\n- \"isRevealed\": false,\n- \"original\": \"villager\",\n- },\n- \"side\": Object {\n- \"current\": \"villagers\",\n- \"original\": \"villagers\",\n- },\n- },\n- Object {\n- \"_id\": \"c2fb8acf1addeb228f74a7c3\",\n- \"attributes\": Array [],\n- \"isAlive\": true,\n- \"name\": \"Ellsworth\",\n- \"position\": 4599418969915392,\n- \"role\": Object {\n- \"current\": \"werewolf\",\n- \"isRevealed\": false,\n- \"original\": \"werewolf\",\n- },\n- \"side\": Object {\n- \"current\": \"werewolves\",\n- \"original\": \"werewolves\",\n- },\n- },\n- ],\n- },\n \"type\": \"vote\",\n },\n- \"events\": Array [\n- Object {\n- \"players\": Array [\n- Object {\n- \"_id\": \"95b9abb4cffdd821c82fcca3\",\n- \"attributes\": Array [],\n- \"isAlive\": true,\n- \"name\": \"Sydney\",\n- \"position\": 596856212029440,\n- \"role\": Object {\n- \"current\": \"werewolf\",\n- \"isRevealed\": false,\n- \"original\": \"werewolf\",\n- },\n- \"side\": Object {\n- \"current\": \"werewolves\",\n- \"original\": \"werewolves\",\n- },\n- },\n- Object {\n- \"_id\": \"8ecedb4ce8ffa9f3ff92db8c\",\n- \"attributes\": Array [],\n- \"isAlive\": true,\n- \"name\": \"Seth\",\n- \"position\": 8542004982054912,\n- \"role\": Object {\n- \"current\": \"seer\",\n- \"isRevealed\": false,\n- \"original\": \"seer\",\n- },\n- \"side\": Object {\n- \"current\": \"villagers\",\n- \"original\": \"villagers\",\n- },\n- },\n- Object {\n- \"_id\": \"6ffdbff67aee8ad8ecce70bc\",\n- \"attributes\": Array [],\n- \"isAlive\": true,\n- \"name\": \"Enos\",\n- \"position\": 5761836301418496,\n- \"role\": Object {\n- \"current\": \"villager\",\n- \"isRevealed\": false,\n- \"original\": \"villager\",\n- },\n- \"side\": Object {\n- \"current\": \"villagers\",\n- \"original\": \"villagers\",\n- },\n- },\n- Object {\n- \"_id\": \"c2fb8acf1addeb228f74a7c3\",\n- \"attributes\": Array [],\n- \"isAlive\": true,\n- \"name\": \"Ellsworth\",\n- \"position\": 4599418969915392,\n- \"role\": Object {\n- \"current\": \"werewolf\",\n- \"isRevealed\": false,\n- \"original\": \"werewolf\",\n- },\n- \"side\": Object {\n- \"current\": \"werewolves\",\n- \"original\": \"werewolves\",\n- },\n- },\n- ],\n- \"type\": \"game-turn-starts\",\n- },\n- ],\n \"lastGameHistoryRecord\": Any,\n \"options\": Object {\n \"composition\": Object {\n \"isHidden\": true,\n },\n@@ -362,11 +180,11 @@\n \"current\": \"werewolves\",\n \"original\": \"werewolves\",\n },\n },\n ],\n- \"status\": \"playing\",\n+ \"status\": \"over\",\n \"tick\": 3907234033565697,\n \"turn\": 4394864355573760,\n \"upcomingPlays\": Array [\n Object {\n \"action\": \"look\",\n@@ -384,6 +202,43 @@\n },\n \"type\": \"target\",\n },\n ],\n \"updatedAt\": Any,\n+ \"victory\": Object {\n+ \"type\": \"villagers\",\n+ \"winners\": Array [\n+ Object {\n+ \"_id\": \"8ecedb4ce8ffa9f3ff92db8c\",\n+ \"attributes\": Array [],\n+ \"isAlive\": true,\n+ \"name\": \"Seth\",\n+ \"position\": 8542004982054912,\n+ \"role\": Object {\n+ \"current\": \"seer\",\n+ \"isRevealed\": false,\n+ \"original\": \"seer\",\n+ },\n+ \"side\": Object {\n+ \"current\": \"villagers\",\n+ \"original\": \"villagers\",\n+ },\n+ },\n+ Object {\n+ \"_id\": \"6ffdbff67aee8ad8ecce70bc\",\n+ \"attributes\": Array [],\n+ \"isAlive\": true,\n+ \"name\": \"Enos\",\n+ \"position\": 5761836301418496,\n+ \"role\": Object {\n+ \"current\": \"villager\",\n+ \"isRevealed\": false,\n+ \"original\": \"villager\",\n+ },\n+ \"side\": Object {\n+ \"current\": \"villagers\",\n+ \"original\": \"villagers\",\n+ },\n+ },\n+ ],\n+ },\n }\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox5172513/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:1317:37)\n at processTicksAndRejections (node:internal/process/task_queues:95:5)", + "id": "4299", + "mutatorName": "LogicalOperator", + "replacement": "side.current === \"werewolves\" || isAlive", + "statusReason": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: true\nReceived: false\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/providers/services/game-victory/game-victory.service.spec.ts:125:53)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", "status": "Killed", - "testsCompleted": 20, + "testsCompleted": 7, "static": false, "killedBy": [ - "748" + "1022" ], "coveredBy": [ "748", @@ -152311,25 +152376,25 @@ ], "location": { "end": { - "column": 131, + "column": 130, "line": 54 }, "start": { - "column": 48, + "column": 90, "line": 54 } } }, { - "id": "4295", - "mutatorName": "MethodExpression", - "replacement": "game.players.every(({\n side,\n isAlive\n}) => side.current === \"werewolves\" && isAlive)", - "statusReason": "Error: expect(received).toBeUndefined()\n\nReceived: {\"type\": \"villagers\", \"winners\": [{\"_id\": \"d2c908fc210ab193bb4c40bf\", \"attributes\": [], \"death\": undefined, \"group\": undefined, \"isAlive\": true, \"name\": \"Floy\", \"position\": 3222141686251520, \"role\": {\"current\": \"villager\", \"isRevealed\": false, \"original\": \"villager\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}, {\"_id\": \"5e5f0fb9311c04a2c8d8ac9a\", \"attributes\": [], \"death\": undefined, \"group\": undefined, \"isAlive\": true, \"name\": \"Lee\", \"position\": 3585745440735232, \"role\": {\"current\": \"seer\", \"isRevealed\": false, \"original\": \"seer\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}]}\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/providers/services/game-victory/game-victory.service.spec.ts:315:66)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "id": "4300", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "statusReason": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: true\nReceived: false\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/providers/services/game-victory/game-victory.service.spec.ts:125:53)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", "status": "Killed", "testsCompleted": 7, "static": false, "killedBy": [ - "1035" + "1022" ], "coveredBy": [ "748", @@ -152355,25 +152420,25 @@ ], "location": { "end": { - "column": 131, + "column": 119, "line": 54 }, "start": { - "column": 49, + "column": 90, "line": 54 } } }, { - "id": "4296", - "mutatorName": "ArrowFunction", - "replacement": "() => undefined", - "statusReason": "Error: expect(received).toStrictEqual(expected) // deep equality\n\n- Expected - 183\n+ Received + 38\n\n@@ -1,201 +1,19 @@\n Object {\n \"_id\": \"d00cedc079387ab128dcba61\",\n \"createdAt\": Any,\n \"currentPlay\": Object {\n \"action\": \"vote\",\n- \"canBeSkipped\": false,\n \"causes\": Array [\n \"previous-votes-were-in-ties\",\n ],\n \"occurrence\": \"consequential\",\n \"source\": Object {\n- \"interactions\": Array [\n- Object {\n- \"boundaries\": Object {\n- \"max\": 4,\n- \"min\": 1,\n- },\n- \"eligibleTargets\": Array [\n- Object {\n- \"_id\": \"e4aee3f2ffe7cdb0fea618fb\",\n- \"attributes\": Array [],\n- \"isAlive\": true,\n- \"name\": \"Martina\",\n- \"position\": 532356737794048,\n- \"role\": Object {\n- \"current\": \"seer\",\n- \"isRevealed\": false,\n- \"original\": \"seer\",\n- },\n- \"side\": Object {\n- \"current\": \"villagers\",\n- \"original\": \"villagers\",\n- },\n- },\n- Object {\n- \"_id\": \"b1cc8d2a8eb8bdd5f8aafeed\",\n- \"attributes\": Array [],\n- \"isAlive\": true,\n- \"name\": \"Fabiola\",\n- \"position\": 4549261817544704,\n- \"role\": Object {\n- \"current\": \"werewolf\",\n- \"isRevealed\": false,\n- \"original\": \"werewolf\",\n- },\n- \"side\": Object {\n- \"current\": \"werewolves\",\n- \"original\": \"werewolves\",\n- },\n- },\n- ],\n- \"source\": \"survivors\",\n- \"type\": \"vote\",\n- },\n- ],\n \"name\": \"survivors\",\n- \"players\": Array [\n- Object {\n- \"_id\": \"b1cc8d2a8eb8bdd5f8aafeed\",\n- \"attributes\": Array [],\n- \"isAlive\": true,\n- \"name\": \"Fabiola\",\n- \"position\": 4549261817544704,\n- \"role\": Object {\n- \"current\": \"werewolf\",\n- \"isRevealed\": false,\n- \"original\": \"werewolf\",\n },\n- \"side\": Object {\n- \"current\": \"werewolves\",\n- \"original\": \"werewolves\",\n- },\n- },\n- Object {\n- \"_id\": \"e4aee3f2ffe7cdb0fea618fb\",\n- \"attributes\": Array [],\n- \"isAlive\": true,\n- \"name\": \"Martina\",\n- \"position\": 532356737794048,\n- \"role\": Object {\n- \"current\": \"seer\",\n- \"isRevealed\": false,\n- \"original\": \"seer\",\n- },\n- \"side\": Object {\n- \"current\": \"villagers\",\n- \"original\": \"villagers\",\n- },\n- },\n- Object {\n- \"_id\": \"7d50f2e183e95d13ca806ef1\",\n- \"attributes\": Array [],\n- \"isAlive\": true,\n- \"name\": \"Derick\",\n- \"position\": 8291364844339200,\n- \"role\": Object {\n- \"current\": \"villager\",\n- \"isRevealed\": false,\n- \"original\": \"villager\",\n- },\n- \"side\": Object {\n- \"current\": \"villagers\",\n- \"original\": \"villagers\",\n- },\n- },\n- Object {\n- \"_id\": \"a6b1c6cf4901d7cabde21abb\",\n- \"attributes\": Array [],\n- \"isAlive\": true,\n- \"name\": \"Maria\",\n- \"position\": 3743543197696000,\n- \"role\": Object {\n- \"current\": \"werewolf\",\n- \"isRevealed\": false,\n- \"original\": \"werewolf\",\n- },\n- \"side\": Object {\n- \"current\": \"werewolves\",\n- \"original\": \"werewolves\",\n- },\n- },\n- ],\n- },\n \"type\": \"vote\",\n },\n- \"events\": Array [\n- Object {\n- \"players\": Array [\n- Object {\n- \"_id\": \"b1cc8d2a8eb8bdd5f8aafeed\",\n- \"attributes\": Array [],\n- \"isAlive\": true,\n- \"name\": \"Fabiola\",\n- \"position\": 4549261817544704,\n- \"role\": Object {\n- \"current\": \"werewolf\",\n- \"isRevealed\": false,\n- \"original\": \"werewolf\",\n- },\n- \"side\": Object {\n- \"current\": \"werewolves\",\n- \"original\": \"werewolves\",\n- },\n- },\n- Object {\n- \"_id\": \"e4aee3f2ffe7cdb0fea618fb\",\n- \"attributes\": Array [],\n- \"isAlive\": true,\n- \"name\": \"Martina\",\n- \"position\": 532356737794048,\n- \"role\": Object {\n- \"current\": \"seer\",\n- \"isRevealed\": false,\n- \"original\": \"seer\",\n- },\n- \"side\": Object {\n- \"current\": \"villagers\",\n- \"original\": \"villagers\",\n- },\n- },\n- Object {\n- \"_id\": \"7d50f2e183e95d13ca806ef1\",\n- \"attributes\": Array [],\n- \"isAlive\": true,\n- \"name\": \"Derick\",\n- \"position\": 8291364844339200,\n- \"role\": Object {\n- \"current\": \"villager\",\n- \"isRevealed\": false,\n- \"original\": \"villager\",\n- },\n- \"side\": Object {\n- \"current\": \"villagers\",\n- \"original\": \"villagers\",\n- },\n- },\n- Object {\n- \"_id\": \"a6b1c6cf4901d7cabde21abb\",\n- \"attributes\": Array [],\n- \"isAlive\": true,\n- \"name\": \"Maria\",\n- \"position\": 3743543197696000,\n- \"role\": Object {\n- \"current\": \"werewolf\",\n- \"isRevealed\": false,\n- \"original\": \"werewolf\",\n- },\n- \"side\": Object {\n- \"current\": \"werewolves\",\n- \"original\": \"werewolves\",\n- },\n- },\n- ],\n- \"type\": \"game-turn-starts\",\n- },\n- ],\n \"lastGameHistoryRecord\": Any,\n \"options\": Object {\n \"composition\": Object {\n \"isHidden\": false,\n },\n@@ -362,11 +180,11 @@\n \"current\": \"werewolves\",\n \"original\": \"werewolves\",\n },\n },\n ],\n- \"status\": \"playing\",\n+ \"status\": \"over\",\n \"tick\": 6961294603190273,\n \"turn\": 8076890684260352,\n \"upcomingPlays\": Array [\n Object {\n \"action\": \"look\",\n@@ -384,6 +202,43 @@\n },\n \"type\": \"target\",\n },\n ],\n \"updatedAt\": Any,\n+ \"victory\": Object {\n+ \"type\": \"villagers\",\n+ \"winners\": Array [\n+ Object {\n+ \"_id\": \"e4aee3f2ffe7cdb0fea618fb\",\n+ \"attributes\": Array [],\n+ \"isAlive\": true,\n+ \"name\": \"Martina\",\n+ \"position\": 532356737794048,\n+ \"role\": Object {\n+ \"current\": \"seer\",\n+ \"isRevealed\": false,\n+ \"original\": \"seer\",\n+ },\n+ \"side\": Object {\n+ \"current\": \"villagers\",\n+ \"original\": \"villagers\",\n+ },\n+ },\n+ Object {\n+ \"_id\": \"7d50f2e183e95d13ca806ef1\",\n+ \"attributes\": Array [],\n+ \"isAlive\": true,\n+ \"name\": \"Derick\",\n+ \"position\": 8291364844339200,\n+ \"role\": Object {\n+ \"current\": \"villager\",\n+ \"isRevealed\": false,\n+ \"original\": \"villager\",\n+ },\n+ \"side\": Object {\n+ \"current\": \"villagers\",\n+ \"original\": \"villagers\",\n+ },\n+ },\n+ ],\n+ },\n }\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox5172513/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:1317:37)\n at processTicksAndRejections (node:internal/process/task_queues:95:5)", + "id": "4301", + "mutatorName": "EqualityOperator", + "replacement": "side.current !== \"werewolves\"", + "statusReason": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: true\nReceived: false\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/providers/services/game-victory/game-victory.service.spec.ts:125:53)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", "status": "Killed", - "testsCompleted": 20, + "testsCompleted": 7, "static": false, "killedBy": [ - "748" + "1022" ], "coveredBy": [ "748", @@ -152399,26 +152464,23 @@ ], "location": { "end": { - "column": 130, + "column": 119, "line": 54 }, "start": { - "column": 67, + "column": 90, "line": 54 } } }, { - "id": "4297", - "mutatorName": "ConditionalExpression", - "replacement": "true", - "statusReason": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: true\nReceived: false\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/providers/services/game-victory/game-victory.service.spec.ts:125:53)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", - "status": "Killed", - "testsCompleted": 7, + "id": "4302", + "mutatorName": "StringLiteral", + "replacement": "\"\"", + "statusReason": "src/modules/game/providers/services/game-victory/game-victory.service.ts(54,90): error TS2367: This comparison appears to be unintentional because the types '\"villagers\" | \"werewolves\"' and '\"\"' have no overlap.\n", + "status": "CompileError", "static": false, - "killedBy": [ - "1022" - ], + "killedBy": [], "coveredBy": [ "748", "749", @@ -152443,26 +152505,23 @@ ], "location": { "end": { - "column": 130, + "column": 119, "line": 54 }, "start": { - "column": 90, + "column": 107, "line": 54 } } }, { - "id": "4298", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "statusReason": "Error: expect(received).toBeUndefined()\n\nReceived: {\"type\": \"villagers\", \"winners\": [{\"_id\": \"6af4028f204d6bf35eaaf7f9\", \"attributes\": [], \"death\": undefined, \"group\": undefined, \"isAlive\": true, \"name\": \"Tristian\", \"position\": 2641132792053760, \"role\": {\"current\": \"villager\", \"isRevealed\": false, \"original\": \"villager\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}, {\"_id\": \"1bea2aa5237dda3be69fd0f3\", \"attributes\": [], \"death\": undefined, \"group\": undefined, \"isAlive\": true, \"name\": \"Lonny\", \"position\": 4335335093829632, \"role\": {\"current\": \"seer\", \"isRevealed\": false, \"original\": \"seer\"}, \"side\": {\"current\": \"villagers\", \"original\": \"villagers\"}}]}\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/providers/services/game-victory/game-victory.service.spec.ts:315:66)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", - "status": "Killed", - "testsCompleted": 7, + "id": "4303", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/modules/game/providers/services/game-victory/game-victory.service.ts(57,36): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", + "status": "CompileError", "static": false, - "killedBy": [ - "1035" - ], + "killedBy": [], "coveredBy": [ "748", "749", @@ -152482,31 +152541,31 @@ "1033", "1034", "1035", - "1042", - "1043" + "1044", + "1045", + "1046", + "1047", + "1048" ], "location": { "end": { - "column": 130, - "line": 54 + "column": 4, + "line": 67 }, "start": { - "column": 90, - "line": 54 + "column": 44, + "line": 57 } } }, { - "id": "4299", - "mutatorName": "LogicalOperator", - "replacement": "side.current === \"werewolves\" || isAlive", - "statusReason": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: true\nReceived: false\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/providers/services/game-victory/game-victory.service.spec.ts:125:53)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", - "status": "Killed", - "testsCompleted": 7, + "id": "4304", + "mutatorName": "StringLiteral", + "replacement": "\"\"", + "statusReason": "src/modules/game/providers/services/game-victory/game-victory.service.ts(59,60): error TS2345: Argument of type '\"\"' is not assignable to parameter of type '\"sheriff\" | \"seen\" | \"eaten\" | \"drank-life-potion\" | \"drank-death-potion\" | \"protected\" | \"scandalmonger-marked\" | \"in-love\" | \"worshiped\" | \"powerless\" | \"cant-vote\" | \"charmed\" | \"contaminated\" | \"stolen-role\" | \"acting\"'.\n", + "status": "CompileError", "static": false, - "killedBy": [ - "1022" - ], + "killedBy": [], "coveredBy": [ "748", "749", @@ -152526,30 +152585,33 @@ "1033", "1034", "1035", - "1042", - "1043" + "1044", + "1045", + "1046", + "1047", + "1048" ], "location": { "end": { - "column": 130, - "line": 54 + "column": 69, + "line": 59 }, "start": { - "column": 90, - "line": 54 + "column": 60, + "line": 59 } } }, { - "id": "4300", + "id": "4305", "mutatorName": "ConditionalExpression", "replacement": "true", - "statusReason": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: true\nReceived: false\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/providers/services/game-victory/game-victory.service.spec.ts:125:53)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "statusReason": "Error: expect(received).toStrictEqual(expected) // deep equality\n\n- Expected - 21\n+ Received + 2\n\n GameVictory {\n- \"type\": \"pied-piper\",\n- \"winners\": Array [\n- Player {\n- \"_id\": \"3b65acec9c08946f2109a913\",\n- \"attributes\": Array [],\n- \"death\": undefined,\n- \"group\": undefined,\n- \"isAlive\": true,\n- \"name\": \"Amie\",\n- \"position\": 5046019551133696,\n- \"role\": PlayerRole {\n- \"current\": \"pied-piper\",\n- \"isRevealed\": false,\n- \"original\": \"pied-piper\",\n- },\n- \"side\": PlayerSide {\n- \"current\": \"werewolves\",\n- \"original\": \"villagers\",\n- },\n- },\n- ],\n+ \"type\": \"lovers\",\n+ \"winners\": Array [],\n }\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox4853956/tests/unit/specs/modules/game/providers/services/game-victory/game-victory.service.spec.ts:265:66)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", "status": "Killed", - "testsCompleted": 7, + "testsCompleted": 23, "static": false, "killedBy": [ - "1022" + "1030" ], "coveredBy": [ "748", @@ -152570,30 +152632,33 @@ "1033", "1034", "1035", - "1042", - "1043" + "1044", + "1045", + "1046", + "1047", + "1048" ], "location": { "end": { - "column": 119, - "line": 54 + "column": 7, + "line": 66 }, "start": { - "column": 90, - "line": 54 + "column": 12, + "line": 61 } } }, { - "id": "4301", - "mutatorName": "EqualityOperator", - "replacement": "side.current !== \"werewolves\"", - "statusReason": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: true\nReceived: false\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/providers/services/game-victory/game-victory.service.spec.ts:125:53)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "id": "4306", + "mutatorName": "ConditionalExpression", + "replacement": "false", + "statusReason": "Error: expect(received).toStrictEqual(expected) // deep equality\n\n- Expected - 1\n+ Received + 1\n\n@@ -1,7 +1,7 @@\n GameVictory {\n- \"type\": \"lovers\",\n+ \"type\": \"werewolves\",\n \"winners\": Array [\n Player {\n \"_id\": \"dcd20a7e772bde33ca80dec7\",\n \"attributes\": Array [\n PlayerAttribute {\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox4853956/tests/unit/specs/modules/game/providers/services/game-victory/game-victory.service.spec.ts:251:66)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", "status": "Killed", - "testsCompleted": 7, + "testsCompleted": 23, "static": false, "killedBy": [ - "1022" + "1029" ], "coveredBy": [ "748", @@ -152614,28 +152679,34 @@ "1033", "1034", "1035", - "1042", - "1043" + "1044", + "1045", + "1046", + "1047", + "1048" ], "location": { "end": { - "column": 119, - "line": 54 + "column": 7, + "line": 66 }, "start": { - "column": 90, - "line": 54 + "column": 12, + "line": 61 } } }, { - "id": "4302", - "mutatorName": "StringLiteral", - "replacement": "\"\"", - "statusReason": "src/modules/game/providers/services/game-victory/game-victory.service.ts(54,90): error TS2367: This comparison appears to be unintentional because the types '\"villagers\" | \"werewolves\"' and '\"\"' have no overlap.\n", - "status": "CompileError", + "id": "4307", + "mutatorName": "LogicalOperator", + "replacement": "lovers.length > 0 || game.players.every(player => {\n const isPlayerCupid = player.role.current === \"cupid\";\n const isPlayerInLove = doesPlayerHaveActiveAttributeWithName(player, \"in-love\", game);\n return isPlayerInLove && player.isAlive || !isPlayerInLove && !player.isAlive || isPlayerCupid && mustCupidWinWithLovers;\n})", + "statusReason": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: false\nReceived: true\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox4853956/tests/unit/specs/modules/game/providers/services/game-victory/game-victory.service.spec.ts:527:57\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-each@29.7.0/node_modules/jest-each/build/bind.js:81:13)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "status": "Killed", + "testsCompleted": 23, "static": false, - "killedBy": [], + "killedBy": [ + "1044" + ], "coveredBy": [ "748", "749", @@ -152655,260 +152726,34 @@ "1033", "1034", "1035", - "1042", - "1043" + "1044", + "1045", + "1046", + "1047", + "1048" ], "location": { "end": { - "column": 119, - "line": 54 + "column": 7, + "line": 66 }, "start": { - "column": 107, - "line": 54 + "column": 12, + "line": 61 } } }, { - "id": "4303", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/modules/game/providers/services/game-victory/game-victory.service.ts(57,36): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", - "status": "CompileError", + "id": "4308", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "statusReason": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: false\nReceived: true\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/providers/services/game-victory/game-victory.service.spec.ts:514:57\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-each@29.7.0/node_modules/jest-each/build/bind.js:81:13)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "status": "Killed", + "testsCompleted": 21, "static": false, - "killedBy": [], - "coveredBy": [ - "748", - "749", - "1019", - "1020", - "1021", - "1022", - "1023", - "1024", - "1025", - "1026", - "1028", - "1029", - "1030", - "1031", - "1032", - "1033", - "1034", - "1035", - "1044", - "1045", - "1046", - "1047", - "1048" - ], - "location": { - "end": { - "column": 4, - "line": 67 - }, - "start": { - "column": 44, - "line": 57 - } - } - }, - { - "id": "4304", - "mutatorName": "StringLiteral", - "replacement": "\"\"", - "statusReason": "src/modules/game/providers/services/game-victory/game-victory.service.ts(59,60): error TS2345: Argument of type '\"\"' is not assignable to parameter of type '\"sheriff\" | \"seen\" | \"eaten\" | \"drank-life-potion\" | \"drank-death-potion\" | \"protected\" | \"scandalmonger-marked\" | \"in-love\" | \"worshiped\" | \"powerless\" | \"cant-vote\" | \"charmed\" | \"contaminated\" | \"stolen-role\" | \"acting\"'.\n", - "status": "CompileError", - "static": false, - "killedBy": [], - "coveredBy": [ - "748", - "749", - "1019", - "1020", - "1021", - "1022", - "1023", - "1024", - "1025", - "1026", - "1028", - "1029", - "1030", - "1031", - "1032", - "1033", - "1034", - "1035", - "1044", - "1045", - "1046", - "1047", - "1048" - ], - "location": { - "end": { - "column": 69, - "line": 59 - }, - "start": { - "column": 60, - "line": 59 - } - } - }, - { - "id": "4305", - "mutatorName": "ConditionalExpression", - "replacement": "true", - "statusReason": "Error: expect(received).toStrictEqual(expected) // deep equality\n\n- Expected - 21\n+ Received + 2\n\n GameVictory {\n- \"type\": \"pied-piper\",\n- \"winners\": Array [\n- Player {\n- \"_id\": \"3b65acec9c08946f2109a913\",\n- \"attributes\": Array [],\n- \"death\": undefined,\n- \"group\": undefined,\n- \"isAlive\": true,\n- \"name\": \"Amie\",\n- \"position\": 5046019551133696,\n- \"role\": PlayerRole {\n- \"current\": \"pied-piper\",\n- \"isRevealed\": false,\n- \"original\": \"pied-piper\",\n- },\n- \"side\": PlayerSide {\n- \"current\": \"werewolves\",\n- \"original\": \"villagers\",\n- },\n- },\n- ],\n+ \"type\": \"lovers\",\n+ \"winners\": Array [],\n }\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox4853956/tests/unit/specs/modules/game/providers/services/game-victory/game-victory.service.spec.ts:265:66)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", - "status": "Killed", - "testsCompleted": 23, - "static": false, - "killedBy": [ - "1030" - ], - "coveredBy": [ - "748", - "749", - "1019", - "1020", - "1021", - "1022", - "1023", - "1024", - "1025", - "1026", - "1028", - "1029", - "1030", - "1031", - "1032", - "1033", - "1034", - "1035", - "1044", - "1045", - "1046", - "1047", - "1048" - ], - "location": { - "end": { - "column": 7, - "line": 66 - }, - "start": { - "column": 12, - "line": 61 - } - } - }, - { - "id": "4306", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "statusReason": "Error: expect(received).toStrictEqual(expected) // deep equality\n\n- Expected - 1\n+ Received + 1\n\n@@ -1,7 +1,7 @@\n GameVictory {\n- \"type\": \"lovers\",\n+ \"type\": \"werewolves\",\n \"winners\": Array [\n Player {\n \"_id\": \"dcd20a7e772bde33ca80dec7\",\n \"attributes\": Array [\n PlayerAttribute {\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox4853956/tests/unit/specs/modules/game/providers/services/game-victory/game-victory.service.spec.ts:251:66)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", - "status": "Killed", - "testsCompleted": 23, - "static": false, - "killedBy": [ - "1029" - ], - "coveredBy": [ - "748", - "749", - "1019", - "1020", - "1021", - "1022", - "1023", - "1024", - "1025", - "1026", - "1028", - "1029", - "1030", - "1031", - "1032", - "1033", - "1034", - "1035", - "1044", - "1045", - "1046", - "1047", - "1048" - ], - "location": { - "end": { - "column": 7, - "line": 66 - }, - "start": { - "column": 12, - "line": 61 - } - } - }, - { - "id": "4307", - "mutatorName": "LogicalOperator", - "replacement": "lovers.length > 0 || game.players.every(player => {\n const isPlayerCupid = player.role.current === \"cupid\";\n const isPlayerInLove = doesPlayerHaveActiveAttributeWithName(player, \"in-love\", game);\n return isPlayerInLove && player.isAlive || !isPlayerInLove && !player.isAlive || isPlayerCupid && mustCupidWinWithLovers;\n})", - "statusReason": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: false\nReceived: true\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox4853956/tests/unit/specs/modules/game/providers/services/game-victory/game-victory.service.spec.ts:527:57\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-each@29.7.0/node_modules/jest-each/build/bind.js:81:13)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", - "status": "Killed", - "testsCompleted": 23, - "static": false, - "killedBy": [ - "1044" - ], - "coveredBy": [ - "748", - "749", - "1019", - "1020", - "1021", - "1022", - "1023", - "1024", - "1025", - "1026", - "1028", - "1029", - "1030", - "1031", - "1032", - "1033", - "1034", - "1035", - "1044", - "1045", - "1046", - "1047", - "1048" - ], - "location": { - "end": { - "column": 7, - "line": 66 - }, - "start": { - "column": 12, - "line": 61 - } - } - }, - { - "id": "4308", - "mutatorName": "ConditionalExpression", - "replacement": "true", - "statusReason": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: false\nReceived: true\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/providers/services/game-victory/game-victory.service.spec.ts:514:57\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-each@29.7.0/node_modules/jest-each/build/bind.js:81:13)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", - "status": "Killed", - "testsCompleted": 21, - "static": false, - "killedBy": [ - "1044" - ], + "killedBy": [ + "1044" + ], "coveredBy": [ "748", "749", @@ -156788,9 +156633,185 @@ "line": 102 } } + }, + { + "id": "4286", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/modules/game/providers/services/game-victory/game-victory.service.ts(51,39): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", + "status": "CompileError", + "static": false, + "coveredBy": [ + "748", + "749", + "1019", + "1020", + "1021", + "1022", + "1023", + "1024", + "1025", + "1026", + "1028", + "1029", + "1030", + "1031", + "1032", + "1033", + "1034", + "1035", + "1040", + "1041", + "1042", + "1043" + ], + "location": { + "end": { + "column": 4, + "line": 55 + }, + "start": { + "column": 47, + "line": 51 + } + } + }, + { + "id": "4287", + "mutatorName": "StringLiteral", + "replacement": "\"\"", + "statusReason": "src/modules/game/providers/services/game-victory/game-victory.service.ts(52,67): error TS2345: Argument of type '\"\"' is not assignable to parameter of type '\"villagers\" | \"werewolves\"'.\n", + "status": "CompileError", + "static": false, + "coveredBy": [ + "748", + "749", + "1019", + "1020", + "1021", + "1022", + "1023", + "1024", + "1025", + "1026", + "1028", + "1029", + "1030", + "1031", + "1032", + "1033", + "1034", + "1035", + "1040", + "1041", + "1042", + "1043" + ], + "location": { + "end": { + "column": 78, + "line": 52 + }, + "start": { + "column": 67, + "line": 52 + } + } + }, + { + "id": "4292", + "mutatorName": "EqualityOperator", + "replacement": "villagersSidedPlayers.length >= 0", + "statusReason": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: false\nReceived: true\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox621460/tests/unit/specs/modules/game/providers/services/game-victory/game-victory.service.spec.ts:426:60)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "status": "Killed", + "static": false, + "testsCompleted": 22, + "killedBy": [ + "1040" + ], + "coveredBy": [ + "748", + "749", + "1019", + "1020", + "1021", + "1022", + "1023", + "1024", + "1025", + "1026", + "1028", + "1029", + "1030", + "1031", + "1032", + "1033", + "1034", + "1035", + "1040", + "1041", + "1042", + "1043" + ], + "location": { + "end": { + "column": 44, + "line": 54 + }, + "start": { + "column": 12, + "line": 54 + } + } + }, + { + "id": "4291", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "statusReason": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: 200\nReceived: 404\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox621460/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:1306:35)\n at processTicksAndRejections (node:internal/process/task_queues:105:5)", + "status": "Killed", + "static": false, + "testsCompleted": 22, + "killedBy": [ + "748" + ], + "coveredBy": [ + "748", + "749", + "1019", + "1020", + "1021", + "1022", + "1023", + "1024", + "1025", + "1026", + "1028", + "1029", + "1030", + "1031", + "1032", + "1033", + "1034", + "1035", + "1040", + "1041", + "1042", + "1043" + ], + "location": { + "end": { + "column": 44, + "line": 54 + }, + "start": { + "column": 12, + "line": 54 + } + } } ], - "source": "import { isInNightOrTwilightPhase } from \"@/modules/game/helpers/game-phase/game-phase.helpers\";\nimport { Injectable } from \"@nestjs/common\";\n\nimport { createAngelGameVictory, createLoversGameVictory, createNoneGameVictory, createPiedPiperGameVictory, createPrejudicedManipulatorGameVictory, createVillagersGameVictory, createWerewolvesGameVictory, createWhiteWerewolfGameVictory } from \"@/modules/game/helpers/game-victory/game-victory.factory\";\nimport { areAllPlayersDead, doesGameHaveCurrentOrUpcomingPlaySourceAndAction, getEligiblePiedPiperTargets, getPlayersWithActiveAttributeName, getPlayersWithCurrentSide, getPlayerWithCurrentRole } from \"@/modules/game/helpers/game.helpers\";\nimport { doesPlayerHaveActiveAttributeWithName } from \"@/modules/game/helpers/player/player-attribute/player-attribute.helpers\";\nimport { isPlayerAliveAndPowerful, isPlayerPowerful } from \"@/modules/game/helpers/player/player.helpers\";\nimport type { GameVictory } from \"@/modules/game/schemas/game-victory/game-victory.schema\";\nimport type { Game } from \"@/modules/game/schemas/game.schema\";\n\nimport { createNoCurrentGamePlayUnexpectedException } from \"@/shared/exception/helpers/unexpected-exception.factory\";\n\n@Injectable()\nexport class GameVictoryService {\n public isGameOver(game: Game): boolean {\n const { currentPlay } = game;\n if (!currentPlay) {\n throw createNoCurrentGamePlayUnexpectedException(\"isGameOver\", { gameId: game._id });\n }\n const isHunterShootPlayIncoming = doesGameHaveCurrentOrUpcomingPlaySourceAndAction(game, \"hunter\", \"shoot\");\n const isSurvivorsBuryDeadBodiesPlayIncoming = doesGameHaveCurrentOrUpcomingPlaySourceAndAction(game, \"survivors\", \"bury-dead-bodies\");\n const gameVictoryData = this.generateGameVictoryData(game);\n\n return areAllPlayersDead(game) || !isHunterShootPlayIncoming && !isSurvivorsBuryDeadBodiesPlayIncoming && !!gameVictoryData;\n }\n\n public generateGameVictoryData(game: Game): GameVictory | undefined {\n if (areAllPlayersDead(game)) {\n return createNoneGameVictory();\n }\n const victoryWinConditions: { doesWin: boolean; victoryFactoryMethod: (game: Game) => GameVictory }[] = [\n { doesWin: this.doesAngelWin(game), victoryFactoryMethod: createAngelGameVictory },\n { doesWin: this.doLoversWin(game), victoryFactoryMethod: createLoversGameVictory },\n { doesWin: this.doesPiedPiperWin(game), victoryFactoryMethod: createPiedPiperGameVictory },\n { doesWin: this.doesWhiteWerewolfWin(game), victoryFactoryMethod: createWhiteWerewolfGameVictory },\n { doesWin: this.doesPrejudicedManipulatorWin(game), victoryFactoryMethod: createPrejudicedManipulatorGameVictory },\n { doesWin: this.doWerewolvesWin(game), victoryFactoryMethod: createWerewolvesGameVictory },\n { doesWin: this.doVillagersWin(game), victoryFactoryMethod: createVillagersGameVictory },\n ];\n const victoryCondition = victoryWinConditions.find(({ doesWin }) => doesWin);\n\n return victoryCondition?.victoryFactoryMethod(game);\n }\n\n private doWerewolvesWin(game: Game): boolean {\n const werewolvesSidedPlayers = getPlayersWithCurrentSide(game, \"werewolves\");\n\n return werewolvesSidedPlayers.length > 0 && !game.players.some(({ side, isAlive }) => side.current === \"villagers\" && isAlive);\n }\n\n private doVillagersWin(game: Game): boolean {\n const villagersSidedPlayers = getPlayersWithCurrentSide(game, \"villagers\");\n\n return villagersSidedPlayers.length > 0 && !game.players.some(({ side, isAlive }) => side.current === \"werewolves\" && isAlive);\n }\n\n private doLoversWin(game: Game): boolean {\n const { mustWinWithLovers: mustCupidWinWithLovers } = game.options.roles.cupid;\n const lovers = getPlayersWithActiveAttributeName(game, \"in-love\");\n\n return lovers.length > 0 && game.players.every(player => {\n const isPlayerCupid = player.role.current === \"cupid\";\n const isPlayerInLove = doesPlayerHaveActiveAttributeWithName(player, \"in-love\", game);\n\n return isPlayerInLove && player.isAlive || !isPlayerInLove && !player.isAlive || isPlayerCupid && mustCupidWinWithLovers;\n });\n }\n\n private doesWhiteWerewolfWin(game: Game): boolean {\n const whiteWerewolfPlayer = getPlayerWithCurrentRole(game, \"white-werewolf\");\n\n return !!whiteWerewolfPlayer && game.players.every(({ role, isAlive }) => role.current === \"white-werewolf\" && isAlive || role.current !== \"white-werewolf\" && !isAlive);\n }\n\n private doesPiedPiperWin(game: Game): boolean {\n const { isPowerlessOnWerewolvesSide } = game.options.roles.piedPiper;\n const piedPiperPlayer = getPlayerWithCurrentRole(game, \"pied-piper\");\n const leftToCharmPlayers = getEligiblePiedPiperTargets(game);\n\n return !!piedPiperPlayer && isPlayerAliveAndPowerful(piedPiperPlayer, game) && !leftToCharmPlayers.length &&\n (!isPowerlessOnWerewolvesSide || piedPiperPlayer.side.current === \"villagers\");\n }\n\n private doesAngelWin(game: Game): boolean {\n const angelPlayer = getPlayerWithCurrentRole(game, \"angel\");\n const { turn } = game;\n if (!angelPlayer?.death || angelPlayer.isAlive || !isPlayerPowerful(angelPlayer, game) || turn > 1) {\n return false;\n }\n const { cause: deathCause } = angelPlayer.death;\n\n return deathCause === \"eaten\" || deathCause === \"vote\" && isInNightOrTwilightPhase(game);\n }\n\n private doesPrejudicedManipulatorWin(game: Game): boolean {\n const prejudicedManipulatorPlayer = getPlayerWithCurrentRole(game, \"prejudiced-manipulator\");\n if (!prejudicedManipulatorPlayer || !isPlayerAliveAndPowerful(prejudicedManipulatorPlayer, game)) {\n return false;\n }\n const playersNotInPrejudicedManipulatorGroup = game.players.filter(({ group }) => group !== prejudicedManipulatorPlayer.group);\n\n return playersNotInPrejudicedManipulatorGroup.every(({ isAlive }) => !isAlive);\n }\n}" + "source": "import { Injectable } from \"@nestjs/common\";\n\nimport { isInNightOrTwilightPhase } from \"@/modules/game/helpers/game-phase/game-phase.helpers\";\nimport { createAngelGameVictory, createLoversGameVictory, createNoneGameVictory, createPiedPiperGameVictory, createPrejudicedManipulatorGameVictory, createVillagersGameVictory, createWerewolvesGameVictory, createWhiteWerewolfGameVictory } from \"@/modules/game/helpers/game-victory/game-victory.factory\";\nimport { areAllPlayersDead, doesGameHaveCurrentOrUpcomingPlaySourceAndAction, getEligiblePiedPiperTargets, getPlayersWithActiveAttributeName, getPlayersWithCurrentSide, getPlayerWithCurrentRole } from \"@/modules/game/helpers/game.helpers\";\nimport { doesPlayerHaveActiveAttributeWithName } from \"@/modules/game/helpers/player/player-attribute/player-attribute.helpers\";\nimport { isPlayerAliveAndPowerful, isPlayerPowerful } from \"@/modules/game/helpers/player/player.helpers\";\nimport type { GameVictory } from \"@/modules/game/schemas/game-victory/game-victory.schema\";\nimport type { Game } from \"@/modules/game/schemas/game.schema\";\n\nimport { createNoCurrentGamePlayUnexpectedException } from \"@/shared/exception/helpers/unexpected-exception.factory\";\n\n@Injectable()\nexport class GameVictoryService {\n public isGameOver(game: Game): boolean {\n const { currentPlay } = game;\n if (!currentPlay) {\n throw createNoCurrentGamePlayUnexpectedException(\"isGameOver\", { gameId: game._id });\n }\n const isHunterShootPlayIncoming = doesGameHaveCurrentOrUpcomingPlaySourceAndAction(game, \"hunter\", \"shoot\");\n const isSurvivorsBuryDeadBodiesPlayIncoming = doesGameHaveCurrentOrUpcomingPlaySourceAndAction(game, \"survivors\", \"bury-dead-bodies\");\n const gameVictoryData = this.generateGameVictoryData(game);\n\n return areAllPlayersDead(game) || !isHunterShootPlayIncoming && !isSurvivorsBuryDeadBodiesPlayIncoming && !!gameVictoryData;\n }\n\n public generateGameVictoryData(game: Game): GameVictory | undefined {\n if (areAllPlayersDead(game)) {\n return createNoneGameVictory();\n }\n const victoryWinConditions: { doesWin: boolean; victoryFactoryMethod: (game: Game) => GameVictory }[] = [\n { doesWin: this.doesAngelWin(game), victoryFactoryMethod: createAngelGameVictory },\n { doesWin: this.doLoversWin(game), victoryFactoryMethod: createLoversGameVictory },\n { doesWin: this.doesPiedPiperWin(game), victoryFactoryMethod: createPiedPiperGameVictory },\n { doesWin: this.doesWhiteWerewolfWin(game), victoryFactoryMethod: createWhiteWerewolfGameVictory },\n { doesWin: this.doesPrejudicedManipulatorWin(game), victoryFactoryMethod: createPrejudicedManipulatorGameVictory },\n { doesWin: this.doWerewolvesWin(game), victoryFactoryMethod: createWerewolvesGameVictory },\n { doesWin: this.doVillagersWin(game), victoryFactoryMethod: createVillagersGameVictory },\n ];\n const victoryCondition = victoryWinConditions.find(({ doesWin }) => doesWin);\n\n return victoryCondition?.victoryFactoryMethod(game);\n }\n\n private doWerewolvesWin(game: Game): boolean {\n const werewolvesSidedPlayers = getPlayersWithCurrentSide(game, \"werewolves\");\n\n return werewolvesSidedPlayers.length > 0 && !game.players.some(({ side, isAlive }) => side.current === \"villagers\" && isAlive);\n }\n\n private doVillagersWin(game: Game): boolean {\n const villagersSidedPlayers = getPlayersWithCurrentSide(game, \"villagers\");\n\n return villagersSidedPlayers.length > 0 && !game.players.some(({ side, isAlive }) => side.current === \"werewolves\" && isAlive);\n }\n\n private doLoversWin(game: Game): boolean {\n const { mustWinWithLovers: mustCupidWinWithLovers } = game.options.roles.cupid;\n const lovers = getPlayersWithActiveAttributeName(game, \"in-love\");\n\n return lovers.length > 0 && game.players.every(player => {\n const isPlayerCupid = player.role.current === \"cupid\";\n const isPlayerInLove = doesPlayerHaveActiveAttributeWithName(player, \"in-love\", game);\n\n return isPlayerInLove && player.isAlive || !isPlayerInLove && !player.isAlive || isPlayerCupid && mustCupidWinWithLovers;\n });\n }\n\n private doesWhiteWerewolfWin(game: Game): boolean {\n const whiteWerewolfPlayer = getPlayerWithCurrentRole(game, \"white-werewolf\");\n\n return !!whiteWerewolfPlayer && game.players.every(({ role, isAlive }) => role.current === \"white-werewolf\" && isAlive || role.current !== \"white-werewolf\" && !isAlive);\n }\n\n private doesPiedPiperWin(game: Game): boolean {\n const { isPowerlessOnWerewolvesSide } = game.options.roles.piedPiper;\n const piedPiperPlayer = getPlayerWithCurrentRole(game, \"pied-piper\");\n const leftToCharmPlayers = getEligiblePiedPiperTargets(game);\n\n return !!piedPiperPlayer && isPlayerAliveAndPowerful(piedPiperPlayer, game) && !leftToCharmPlayers.length &&\n (!isPowerlessOnWerewolvesSide || piedPiperPlayer.side.current === \"villagers\");\n }\n\n private doesAngelWin(game: Game): boolean {\n const angelPlayer = getPlayerWithCurrentRole(game, \"angel\");\n const { turn } = game;\n if (!angelPlayer?.death || angelPlayer.isAlive || !isPlayerPowerful(angelPlayer, game) || turn > 1) {\n return false;\n }\n const { cause: deathCause } = angelPlayer.death;\n\n return deathCause === \"eaten\" || deathCause === \"vote\" && isInNightOrTwilightPhase(game);\n }\n\n private doesPrejudicedManipulatorWin(game: Game): boolean {\n const prejudicedManipulatorPlayer = getPlayerWithCurrentRole(game, \"prejudiced-manipulator\");\n if (!prejudicedManipulatorPlayer || !isPlayerAliveAndPowerful(prejudicedManipulatorPlayer, game)) {\n return false;\n }\n const playersNotInPrejudicedManipulatorGroup = game.players.filter(({ group }) => group !== prejudicedManipulatorPlayer.group);\n\n return playersNotInPrejudicedManipulatorGroup.every(({ isAlive }) => !isAlive);\n }\n}" }, "src/modules/game/providers/services/game.service.ts": { "language": "typescript", @@ -156819,6 +156840,38 @@ } } }, + { + "id": "4418", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/modules/game/providers/services/game.service.ts(52,49): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", + "status": "CompileError", + "static": false, + "killedBy": [], + "coveredBy": [ + "736", + "737", + "738", + "1080", + "1081", + "1082", + "1083", + "1084", + "1085", + "1086", + "1087" + ], + "location": { + "end": { + "column": 4, + "line": 74 + }, + "start": { + "column": 63, + "line": 52 + } + } + }, { "id": "4419", "mutatorName": "BooleanLiteral", @@ -156974,6 +157027,40 @@ } } }, + { + "id": "4424", + "mutatorName": "ObjectLiteral", + "replacement": "{}", + "statusReason": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: 201\nReceived: 500\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:887:35)\n at processTicksAndRejections (node:internal/process/task_queues:105:5)", + "status": "Killed", + "testsCompleted": 10, + "static": false, + "killedBy": [ + "736" + ], + "coveredBy": [ + "736", + "737", + "738", + "1081", + "1082", + "1083", + "1084", + "1085", + "1086", + "1087" + ], + "location": { + "end": { + "column": 6, + "line": 65 + }, + "start": { + "column": 57, + "line": 60 + } + } + }, { "id": "4425", "mutatorName": "ConditionalExpression", @@ -158464,74 +158551,9 @@ "line": 161 } } - }, - { - "id": "4418", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/modules/game/providers/services/game.service.ts(52,49): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", - "status": "CompileError", - "static": false, - "coveredBy": [ - "736", - "737", - "738", - "1080", - "1081", - "1082", - "1083", - "1084", - "1085", - "1086", - "1087" - ], - "location": { - "end": { - "column": 4, - "line": 74 - }, - "start": { - "column": 63, - "line": 52 - } - } - }, - { - "id": "4424", - "mutatorName": "ObjectLiteral", - "replacement": "{}", - "statusReason": "Error: expect(received).toBe(expected) // Object.is equality\n\nExpected: 201\nReceived: 500\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox3091882/tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts:887:35)\n at processTicksAndRejections (node:internal/process/task_queues:105:5)", - "status": "Killed", - "static": false, - "testsCompleted": 10, - "killedBy": [ - "736" - ], - "coveredBy": [ - "736", - "737", - "738", - "1081", - "1082", - "1083", - "1084", - "1085", - "1086", - "1087" - ], - "location": { - "end": { - "column": 6, - "line": 65 - }, - "start": { - "column": 57, - "line": 60 - } - } } ], - "source": "import { CreateGameFeedbackDto } from \"@/modules/game/dto/create-game-feedback/create-game-feedback.dto\";\n\nimport { CreateGameDto } from \"@/modules/game/dto/create-game/create-game.dto\";\nimport type { MakeGamePlayDto } from \"@/modules/game/dto/make-game-play/make-game-play.dto\";\nimport { isGamePhaseOver } from \"@/modules/game/helpers/game-phase/game-phase.helpers\";\nimport { createMakeGamePlayDtoWithRelations } from \"@/modules/game/helpers/game-play/game-play.helpers\";\nimport { createGame as createGameFromFactory } from \"@/modules/game/helpers/game.factory\";\nimport { getDistinctPlayerGroups } from \"@/modules/game/helpers/game.helpers\";\nimport { GameRepository } from \"@/modules/game/providers/repositories/game.repository\";\nimport { GameEventsGeneratorService } from \"@/modules/game/providers/services/game-event/game-events-generator.service\";\nimport { GameFeedbackService } from \"@/modules/game/providers/services/game-feedback/game-feedback.service\";\nimport { GameHistoryRecordToInsertGeneratorService } from \"@/modules/game/providers/services/game-history/game-history-record-to-insert-generator.service\";\nimport { GameHistoryRecordService } from \"@/modules/game/providers/services/game-history/game-history-record.service\";\nimport { GamePhaseService } from \"@/modules/game/providers/services/game-phase/game-phase.service\";\nimport { GamePlayMakerService } from \"@/modules/game/providers/services/game-play/game-play-maker/game-play-maker.service\";\nimport { GamePlayValidatorService } from \"@/modules/game/providers/services/game-play/game-play-validator.service\";\nimport { GamePlayService } from \"@/modules/game/providers/services/game-play/game-play.service\";\nimport { GameVictoryService } from \"@/modules/game/providers/services/game-victory/game-victory.service\";\nimport { PlayerAttributeService } from \"@/modules/game/providers/services/player/player-attribute.service\";\nimport type { Game } from \"@/modules/game/schemas/game.schema\";\nimport type { GameWithCurrentPlay } from \"@/modules/game/types/game-with-current-play.types\";\n\nimport { ApiResources } from \"@/shared/api/enums/api.enums\";\nimport { BadResourceMutationReasons } from \"@/shared/exception/enums/bad-resource-mutation-error.enum\";\nimport { createCantGenerateGamePlaysUnexpectedException } from \"@/shared/exception/helpers/unexpected-exception.factory\";\nimport { BadResourceMutationException } from \"@/shared/exception/types/bad-resource-mutation-exception.types\";\nimport { ResourceNotFoundException } from \"@/shared/exception/types/resource-not-found-exception.types\";\nimport { Injectable } from \"@nestjs/common\";\nimport { plainToInstance } from \"class-transformer\";\nimport type { Types } from \"mongoose\";\n\n@Injectable()\nexport class GameService {\n public constructor(\n private readonly gamePlayService: GamePlayService,\n private readonly gamePlayValidatorService: GamePlayValidatorService,\n private readonly gamePlayMakerService: GamePlayMakerService,\n private readonly gamePhaseService: GamePhaseService,\n private readonly gameVictoryService: GameVictoryService,\n private readonly gameRepository: GameRepository,\n private readonly playerAttributeService: PlayerAttributeService,\n private readonly gameEventsGeneratorService: GameEventsGeneratorService,\n private readonly gameHistoryRecordService: GameHistoryRecordService,\n private readonly gameHistoryRecordToInsertGeneratorService: GameHistoryRecordToInsertGeneratorService,\n private readonly gameFeedbackService: GameFeedbackService,\n ) {}\n\n public async getGames(): Promise {\n return this.gameRepository.find();\n }\n\n public async createGame(game: CreateGameDto): Promise {\n const upcomingPlays = await this.gamePlayService.getPhaseUpcomingPlays(game);\n if (!upcomingPlays.length) {\n throw createCantGenerateGamePlaysUnexpectedException(\"createGame\");\n }\n const currentPlay = upcomingPlays[0];\n upcomingPlays.shift();\n const distinctPlayerGroups = getDistinctPlayerGroups(game);\n const gameToCreate = plainToInstance(CreateGameDto, {\n ...game,\n currentPlay,\n upcomingPlays,\n playerGroups: distinctPlayerGroups.length ? distinctPlayerGroups : undefined,\n });\n let createdGame = await this.gameRepository.create(gameToCreate) as GameWithCurrentPlay;\n createdGame = await this.gamePlayService.augmentCurrentGamePlay(createdGame);\n if (this.gamePhaseService.isTwilightPhaseOver(createdGame)) {\n createdGame.phase.name = \"night\";\n }\n createdGame.events = this.gameEventsGeneratorService.generateGameEventsFromGameAndLastRecord(createdGame);\n\n return this.updateGame(createdGame._id, createdGame);\n }\n\n public async cancelGame(game: Game): Promise {\n this.validateGameIsPlaying(game);\n\n return this.updateGame(game._id, { status: \"canceled\" });\n }\n\n public async makeGamePlay(game: Game, makeGamePlayDto: MakeGamePlayDto): Promise {\n let clonedGame = createGameFromFactory(game);\n this.validateGameIsPlaying(clonedGame);\n const play = createMakeGamePlayDtoWithRelations(makeGamePlayDto, clonedGame);\n await this.gamePlayValidatorService.validateGamePlayWithRelationsDto(play, clonedGame);\n clonedGame = await this.gamePlayMakerService.makeGamePlay(play, clonedGame);\n clonedGame = await this.gamePlayService.refreshUpcomingPlays(clonedGame);\n clonedGame = this.gamePlayService.proceedToNextGamePlay(clonedGame);\n clonedGame.tick++;\n clonedGame.phase.tick++;\n if (game.phase.name === \"twilight\" && this.gamePhaseService.isTwilightPhaseOver(clonedGame)) {\n clonedGame = this.handleTwilightPhaseCompletion(clonedGame);\n }\n if (isGamePhaseOver(clonedGame)) {\n clonedGame = await this.handleGamePhaseCompletion(clonedGame);\n }\n const gameHistoryRecordToInsert = this.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordToInsert(game, clonedGame, play);\n const gameHistoryRecord = await this.gameHistoryRecordService.createGameHistoryRecord(gameHistoryRecordToInsert);\n if (this.gameVictoryService.isGameOver(clonedGame)) {\n return this.updateGameAsOver(clonedGame);\n }\n clonedGame = await this.gamePlayService.augmentCurrentGamePlay(clonedGame as GameWithCurrentPlay);\n clonedGame.events = this.gameEventsGeneratorService.generateGameEventsFromGameAndLastRecord(clonedGame, gameHistoryRecord);\n\n return this.updateGame(clonedGame._id, clonedGame);\n }\n\n public async createGameFeedback(game: Game, createGameFeedbackDto: CreateGameFeedbackDto): Promise {\n const clonedGame = createGameFromFactory(game);\n clonedGame.feedback = await this.gameFeedbackService.createGameFeedback(clonedGame, createGameFeedbackDto);\n\n return clonedGame;\n }\n\n private validateGameIsPlaying(game: Game): void {\n if (game.status !== \"playing\") {\n throw new BadResourceMutationException(ApiResources.GAMES, game._id.toString(), BadResourceMutationReasons.GAME_NOT_PLAYING);\n }\n }\n\n private handleTwilightPhaseCompletion(game: Game): Game {\n const clonedGame = createGameFromFactory(game);\n clonedGame.phase.name = \"night\";\n clonedGame.phase.tick = 1;\n\n return clonedGame;\n }\n\n private async handleGamePhaseCompletion(game: Game): Promise {\n let clonedGame = createGameFromFactory(game);\n clonedGame = await this.gamePhaseService.applyEndingGamePhaseOutcomes(clonedGame);\n clonedGame = this.playerAttributeService.decreaseRemainingPhasesAndRemoveObsoletePlayerAttributes(clonedGame);\n clonedGame = await this.gamePhaseService.switchPhaseAndAppendGamePhaseUpcomingPlays(clonedGame);\n clonedGame = this.gamePhaseService.applyStartingGamePhaseOutcomes(clonedGame);\n clonedGame = await this.gamePlayService.refreshUpcomingPlays(clonedGame);\n clonedGame = this.gamePlayService.proceedToNextGamePlay(clonedGame);\n if (isGamePhaseOver(clonedGame)) {\n clonedGame = await this.handleGamePhaseCompletion(clonedGame);\n clonedGame = await this.gamePlayService.refreshUpcomingPlays(clonedGame);\n }\n return clonedGame;\n }\n\n private async updateGame(gameId: Types.ObjectId, gameDataToUpdate: Partial): Promise {\n const updatedGame = await this.gameRepository.updateOne({ _id: gameId }, gameDataToUpdate);\n if (updatedGame === null) {\n throw new ResourceNotFoundException(ApiResources.GAMES, gameId.toString());\n }\n return updatedGame;\n }\n\n private setGameAsOver(game: Game): Game {\n const clonedGame = createGameFromFactory(game);\n clonedGame.status = \"over\";\n clonedGame.victory = this.gameVictoryService.generateGameVictoryData(clonedGame);\n\n return clonedGame;\n }\n\n private async updateGameAsOver(game: Game): Promise {\n const clonedGame = this.setGameAsOver(game);\n\n return this.updateGame(clonedGame._id, clonedGame);\n }\n}" + "source": "import { Injectable } from \"@nestjs/common\";\nimport { plainToInstance } from \"class-transformer\";\nimport type { Types } from \"mongoose\";\n\nimport { CreateGameFeedbackDto } from \"@/modules/game/dto/create-game-feedback/create-game-feedback.dto\";\nimport { CreateGameDto } from \"@/modules/game/dto/create-game/create-game.dto\";\nimport type { MakeGamePlayDto } from \"@/modules/game/dto/make-game-play/make-game-play.dto\";\nimport { isGamePhaseOver } from \"@/modules/game/helpers/game-phase/game-phase.helpers\";\nimport { createMakeGamePlayDtoWithRelations } from \"@/modules/game/helpers/game-play/game-play.helpers\";\nimport { createGame as createGameFromFactory } from \"@/modules/game/helpers/game.factory\";\nimport { getDistinctPlayerGroups } from \"@/modules/game/helpers/game.helpers\";\nimport { GameRepository } from \"@/modules/game/providers/repositories/game.repository\";\nimport { GameEventsGeneratorService } from \"@/modules/game/providers/services/game-event/game-events-generator.service\";\nimport { GameFeedbackService } from \"@/modules/game/providers/services/game-feedback/game-feedback.service\";\nimport { GameHistoryRecordToInsertGeneratorService } from \"@/modules/game/providers/services/game-history/game-history-record-to-insert-generator.service\";\nimport { GameHistoryRecordService } from \"@/modules/game/providers/services/game-history/game-history-record.service\";\nimport { GamePhaseService } from \"@/modules/game/providers/services/game-phase/game-phase.service\";\nimport { GamePlayMakerService } from \"@/modules/game/providers/services/game-play/game-play-maker/game-play-maker.service\";\nimport { GamePlayValidatorService } from \"@/modules/game/providers/services/game-play/game-play-validator.service\";\nimport { GamePlayService } from \"@/modules/game/providers/services/game-play/game-play.service\";\nimport { GameVictoryService } from \"@/modules/game/providers/services/game-victory/game-victory.service\";\nimport { PlayerAttributeService } from \"@/modules/game/providers/services/player/player-attribute.service\";\nimport type { Game } from \"@/modules/game/schemas/game.schema\";\nimport type { GameWithCurrentPlay } from \"@/modules/game/types/game-with-current-play.types\";\n\nimport { ApiResources } from \"@/shared/api/enums/api.enums\";\nimport { BadResourceMutationReasons } from \"@/shared/exception/enums/bad-resource-mutation-error.enums\";\nimport { createCantGenerateGamePlaysUnexpectedException } from \"@/shared/exception/helpers/unexpected-exception.factory\";\nimport { BadResourceMutationException } from \"@/shared/exception/types/bad-resource-mutation-exception.types\";\nimport { ResourceNotFoundException } from \"@/shared/exception/types/resource-not-found-exception.types\";\n\n@Injectable()\nexport class GameService {\n public constructor(\n private readonly gamePlayService: GamePlayService,\n private readonly gamePlayValidatorService: GamePlayValidatorService,\n private readonly gamePlayMakerService: GamePlayMakerService,\n private readonly gamePhaseService: GamePhaseService,\n private readonly gameVictoryService: GameVictoryService,\n private readonly gameRepository: GameRepository,\n private readonly playerAttributeService: PlayerAttributeService,\n private readonly gameEventsGeneratorService: GameEventsGeneratorService,\n private readonly gameHistoryRecordService: GameHistoryRecordService,\n private readonly gameHistoryRecordToInsertGeneratorService: GameHistoryRecordToInsertGeneratorService,\n private readonly gameFeedbackService: GameFeedbackService,\n ) {}\n\n public async getGames(): Promise {\n return this.gameRepository.find();\n }\n\n public async createGame(game: CreateGameDto): Promise {\n const upcomingPlays = await this.gamePlayService.getPhaseUpcomingPlays(game);\n if (!upcomingPlays.length) {\n throw createCantGenerateGamePlaysUnexpectedException(\"createGame\");\n }\n const currentPlay = upcomingPlays[0];\n upcomingPlays.shift();\n const distinctPlayerGroups = getDistinctPlayerGroups(game);\n const gameToCreate = plainToInstance(CreateGameDto, {\n ...game,\n currentPlay,\n upcomingPlays,\n playerGroups: distinctPlayerGroups.length ? distinctPlayerGroups : undefined,\n });\n let createdGame = await this.gameRepository.create(gameToCreate) as GameWithCurrentPlay;\n createdGame = await this.gamePlayService.augmentCurrentGamePlay(createdGame);\n if (this.gamePhaseService.isTwilightPhaseOver(createdGame)) {\n createdGame.phase.name = \"night\";\n }\n createdGame.events = this.gameEventsGeneratorService.generateGameEventsFromGameAndLastRecord(createdGame);\n\n return this.updateGame(createdGame._id, createdGame);\n }\n\n public async cancelGame(game: Game): Promise {\n this.validateGameIsPlaying(game);\n\n return this.updateGame(game._id, { status: \"canceled\" });\n }\n\n public async makeGamePlay(game: Game, makeGamePlayDto: MakeGamePlayDto): Promise {\n let clonedGame = createGameFromFactory(game);\n this.validateGameIsPlaying(clonedGame);\n const play = createMakeGamePlayDtoWithRelations(makeGamePlayDto, clonedGame);\n await this.gamePlayValidatorService.validateGamePlayWithRelationsDto(play, clonedGame);\n clonedGame = await this.gamePlayMakerService.makeGamePlay(play, clonedGame);\n clonedGame = await this.gamePlayService.refreshUpcomingPlays(clonedGame);\n clonedGame = this.gamePlayService.proceedToNextGamePlay(clonedGame);\n clonedGame.tick++;\n clonedGame.phase.tick++;\n if (game.phase.name === \"twilight\" && this.gamePhaseService.isTwilightPhaseOver(clonedGame)) {\n clonedGame = this.handleTwilightPhaseCompletion(clonedGame);\n }\n if (isGamePhaseOver(clonedGame)) {\n clonedGame = await this.handleGamePhaseCompletion(clonedGame);\n }\n const gameHistoryRecordToInsert = this.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordToInsert(game, clonedGame, play);\n const gameHistoryRecord = await this.gameHistoryRecordService.createGameHistoryRecord(gameHistoryRecordToInsert);\n if (this.gameVictoryService.isGameOver(clonedGame)) {\n return this.updateGameAsOver(clonedGame);\n }\n clonedGame = await this.gamePlayService.augmentCurrentGamePlay(clonedGame as GameWithCurrentPlay);\n clonedGame.events = this.gameEventsGeneratorService.generateGameEventsFromGameAndLastRecord(clonedGame, gameHistoryRecord);\n\n return this.updateGame(clonedGame._id, clonedGame);\n }\n\n public async createGameFeedback(game: Game, createGameFeedbackDto: CreateGameFeedbackDto): Promise {\n const clonedGame = createGameFromFactory(game);\n clonedGame.feedback = await this.gameFeedbackService.createGameFeedback(clonedGame, createGameFeedbackDto);\n\n return clonedGame;\n }\n\n private validateGameIsPlaying(game: Game): void {\n if (game.status !== \"playing\") {\n throw new BadResourceMutationException(ApiResources.GAMES, game._id.toString(), BadResourceMutationReasons.GAME_NOT_PLAYING);\n }\n }\n\n private handleTwilightPhaseCompletion(game: Game): Game {\n const clonedGame = createGameFromFactory(game);\n clonedGame.phase.name = \"night\";\n clonedGame.phase.tick = 1;\n\n return clonedGame;\n }\n\n private async handleGamePhaseCompletion(game: Game): Promise {\n let clonedGame = createGameFromFactory(game);\n clonedGame = await this.gamePhaseService.applyEndingGamePhaseOutcomes(clonedGame);\n clonedGame = this.playerAttributeService.decreaseRemainingPhasesAndRemoveObsoletePlayerAttributes(clonedGame);\n clonedGame = await this.gamePhaseService.switchPhaseAndAppendGamePhaseUpcomingPlays(clonedGame);\n clonedGame = this.gamePhaseService.applyStartingGamePhaseOutcomes(clonedGame);\n clonedGame = await this.gamePlayService.refreshUpcomingPlays(clonedGame);\n clonedGame = this.gamePlayService.proceedToNextGamePlay(clonedGame);\n if (isGamePhaseOver(clonedGame)) {\n clonedGame = await this.handleGamePhaseCompletion(clonedGame);\n clonedGame = await this.gamePlayService.refreshUpcomingPlays(clonedGame);\n }\n return clonedGame;\n }\n\n private async updateGame(gameId: Types.ObjectId, gameDataToUpdate: Partial): Promise {\n const updatedGame = await this.gameRepository.updateOne({ _id: gameId }, gameDataToUpdate);\n if (updatedGame === null) {\n throw new ResourceNotFoundException(ApiResources.GAMES, gameId.toString());\n }\n return updatedGame;\n }\n\n private setGameAsOver(game: Game): Game {\n const clonedGame = createGameFromFactory(game);\n clonedGame.status = \"over\";\n clonedGame.victory = this.gameVictoryService.generateGameVictoryData(clonedGame);\n\n return clonedGame;\n }\n\n private async updateGameAsOver(game: Game): Promise {\n const clonedGame = this.setGameAsOver(game);\n\n return this.updateGame(clonedGame._id, clonedGame);\n }\n}" }, "src/modules/game/providers/services/player/player-attribute.service.ts": { "language": "typescript", @@ -159310,30 +159332,6 @@ "src/modules/game/providers/services/player/player-killer.service.ts": { "language": "typescript", "mutants": [ - { - "id": "4501", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/modules/game/providers/services/player/player-killer.service.ts(27,94): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", - "status": "CompileError", - "static": false, - "killedBy": [], - "coveredBy": [ - "587", - "588", - "589" - ], - "location": { - "end": { - "column": 4, - "line": 37 - }, - "start": { - "column": 108, - "line": 27 - } - } - }, { "id": "4502", "mutatorName": "ConditionalExpression", @@ -159361,58 +159359,6 @@ } } }, - { - "id": "4503", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "statusReason": "Error: expect(received).toHaveBeenCalledExactlyOnceWith(expected)\n\nExpected mock function to have been called exactly once, but it was called 0 times\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/providers/services/player/player-killer.service.spec.ts:164:52)", - "status": "Killed", - "testsCompleted": 3, - "static": false, - "killedBy": [ - "588" - ], - "coveredBy": [ - "587", - "588", - "589" - ], - "location": { - "end": { - "column": 75, - "line": 30 - }, - "start": { - "column": 9, - "line": 30 - } - } - }, - { - "id": "4504", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "Error: expect(received).toHaveBeenCalledExactlyOnceWith(expected)\n\nExpected mock function to have been called exactly once, but it was called 0 times\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/providers/services/player/player-killer.service.spec.ts:164:52)", - "status": "Killed", - "testsCompleted": 1, - "static": false, - "killedBy": [ - "588" - ], - "coveredBy": [ - "588" - ], - "location": { - "end": { - "column": 6, - "line": 32 - }, - "start": { - "column": 77, - "line": 30 - } - } - }, { "id": "4505", "mutatorName": "ConditionalExpression", @@ -159439,57 +159385,6 @@ } } }, - { - "id": "4506", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "statusReason": "Error: expect(received).toHaveBeenCalledExactlyOnceWith(expected)\n\nExpected mock function to have been called exactly once, but it was called 0 times\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/providers/services/player/player-killer.service.spec.ts:183:58)", - "status": "Killed", - "testsCompleted": 2, - "static": false, - "killedBy": [ - "589" - ], - "coveredBy": [ - "587", - "589" - ], - "location": { - "end": { - "column": 69, - "line": 33 - }, - "start": { - "column": 9, - "line": 33 - } - } - }, - { - "id": "4507", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "Error: expect(received).toHaveBeenCalledExactlyOnceWith(expected)\n\nExpected mock function to have been called exactly once, but it was called 0 times\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/providers/services/player/player-killer.service.spec.ts:183:58)", - "status": "Killed", - "testsCompleted": 1, - "static": false, - "killedBy": [ - "589" - ], - "coveredBy": [ - "589" - ], - "location": { - "end": { - "column": 6, - "line": 35 - }, - "start": { - "column": 71, - "line": 33 - } - } - }, { "id": "4508", "mutatorName": "BlockStatement", @@ -159854,30 +159749,6 @@ } } }, - { - "id": "4522", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/modules/game/providers/services/player/player-killer.service.ts(61,64): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", - "status": "CompileError", - "static": false, - "killedBy": [], - "coveredBy": [ - "589", - "595", - "596" - ], - "location": { - "end": { - "column": 4, - "line": 70 - }, - "start": { - "column": 69, - "line": 61 - } - } - }, { "id": "4523", "mutatorName": "StringLiteral", @@ -159905,30 +159776,6 @@ } } }, - { - "id": "4524", - "mutatorName": "ObjectLiteral", - "replacement": "{}", - "statusReason": "src/modules/game/providers/services/player/player-killer.service.ts(62,103): error TS2345: Argument of type '{}' is not assignable to parameter of type '{ gameId: ObjectId; playerId: ObjectId; }'.\n Type '{}' is missing the following properties from type '{ gameId: ObjectId; playerId: ObjectId; }': gameId, playerId\n", - "status": "CompileError", - "static": false, - "killedBy": [], - "coveredBy": [ - "589", - "595", - "596" - ], - "location": { - "end": { - "column": 153, - "line": 64 - }, - "start": { - "column": 103, - "line": 64 - } - } - }, { "id": "4525", "mutatorName": "BooleanLiteral", @@ -160616,32 +160463,6 @@ } } }, - { - "id": "4550", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/modules/game/providers/services/player/player-killer.service.ts(84,82): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", - "status": "CompileError", - "static": false, - "killedBy": [], - "coveredBy": [ - "589", - "595", - "596", - "604", - "605" - ], - "location": { - "end": { - "column": 4, - "line": 94 - }, - "start": { - "column": 87, - "line": 88 - } - } - }, { "id": "4551", "mutatorName": "ConditionalExpression", @@ -160729,32 +160550,6 @@ } } }, - { - "id": "4554", - "mutatorName": "StringLiteral", - "replacement": "\"\"", - "statusReason": "src/modules/game/providers/services/player/player-killer.service.ts(86,9): error TS2367: This comparison appears to be unintentional because the types '\"werewolf\" | \"big-bad-wolf\" | \"accursed-wolf-father\" | \"white-werewolf\" | \"villager\" | \"villager-villager\" | \"seer\" | \"cupid\" | \"witch\" | \"hunter\" | \"little-girl\" | \"defender\" | ... 17 more ... | \"devoted-servant\"' and '\"\"' have no overlap.\n", - "status": "CompileError", - "static": false, - "killedBy": [], - "coveredBy": [ - "589", - "595", - "596", - "604", - "605" - ], - "location": { - "end": { - "column": 48, - "line": 90 - }, - "start": { - "column": 41, - "line": 90 - } - } - }, { "id": "4555", "mutatorName": "BlockStatement", @@ -166972,32 +166767,6 @@ } } }, - { - "id": "4782", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/modules/game/providers/services/player/player-killer.service.ts(240,79): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", - "status": "CompileError", - "static": false, - "killedBy": [], - "coveredBy": [ - "677", - "678", - "679", - "680", - "681" - ], - "location": { - "end": { - "column": 4, - "line": 261 - }, - "start": { - "column": 84, - "line": 248 - } - } - }, { "id": "4783", "mutatorName": "ObjectLiteral", @@ -167027,162 +166796,6 @@ } } }, - { - "id": "4784", - "mutatorName": "ArrowFunction", - "replacement": "() => undefined", - "statusReason": "src/modules/game/providers/services/player/player-killer.service.ts(243,17): error TS2322: Type '() => undefined' is not assignable to type '(killedPlayer: DeadPlayer, game: Game) => Game'.\n Type 'undefined' is not assignable to type 'Game'.\n", - "status": "CompileError", - "static": false, - "killedBy": [], - "coveredBy": [ - "677", - "678", - "679", - "680", - "681" - ], - "location": { - "end": { - "column": 78, - "line": 251 - }, - "start": { - "column": 17, - "line": 251 - } - } - }, - { - "id": "4785", - "mutatorName": "ArrowFunction", - "replacement": "() => undefined", - "statusReason": "src/modules/game/providers/services/player/player-killer.service.ts(244,16): error TS2322: Type '() => undefined' is not assignable to type '(killedPlayer: DeadPlayer, game: Game) => Game'.\n Type 'undefined' is not assignable to type 'Game'.\n", - "status": "CompileError", - "static": false, - "killedBy": [], - "coveredBy": [ - "677", - "678", - "679", - "680", - "681" - ], - "location": { - "end": { - "column": 76, - "line": 252 - }, - "start": { - "column": 16, - "line": 252 - } - } - }, - { - "id": "4786", - "mutatorName": "ArrowFunction", - "replacement": "() => undefined", - "statusReason": "src/modules/game/providers/services/player/player-killer.service.ts(245,20): error TS2322: Type '() => undefined' is not assignable to type '(killedPlayer: DeadPlayer, game: Game) => Game'.\n Type 'undefined' is not assignable to type 'Game'.\n", - "status": "CompileError", - "static": false, - "killedBy": [], - "coveredBy": [ - "677", - "678", - "679", - "680", - "681" - ], - "location": { - "end": { - "column": 84, - "line": 253 - }, - "start": { - "column": 20, - "line": 253 - } - } - }, - { - "id": "4787", - "mutatorName": "ArrowFunction", - "replacement": "() => undefined", - "statusReason": "src/modules/game/providers/services/player/player-killer.service.ts(246,29): error TS2322: Type '() => undefined' is not assignable to type '(killedPlayer: DeadPlayer, game: Game) => Game'.\n Type 'undefined' is not assignable to type 'Game'.\n", - "status": "CompileError", - "static": false, - "killedBy": [], - "coveredBy": [ - "677", - "678", - "679", - "680", - "681" - ], - "location": { - "end": { - "column": 100, - "line": 254 - }, - "start": { - "column": 29, - "line": 254 - } - } - }, - { - "id": "4788", - "mutatorName": "ConditionalExpression", - "replacement": "true", - "statusReason": "src/modules/game/providers/services/player/player-killer.service.ts(250,14): error TS2722: Cannot invoke an object which is possibly 'undefined'.\n", - "status": "CompileError", - "static": false, - "killedBy": [], - "coveredBy": [ - "677", - "678", - "679", - "680", - "681" - ], - "location": { - "end": { - "column": 32, - "line": 257 - }, - "start": { - "column": 9, - "line": 257 - } - } - }, - { - "id": "4789", - "mutatorName": "ConditionalExpression", - "replacement": "false", - "statusReason": "src/modules/game/providers/services/player/player-killer.service.ts(250,14): error TS2722: Cannot invoke an object which is possibly 'undefined'.\n", - "status": "CompileError", - "static": false, - "killedBy": [], - "coveredBy": [ - "677", - "678", - "679", - "680", - "681" - ], - "location": { - "end": { - "column": 32, - "line": 257 - }, - "start": { - "column": 9, - "line": 257 - } - } - }, { "id": "4790", "mutatorName": "BlockStatement", @@ -167211,30 +166824,6 @@ } } }, - { - "id": "4791", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/modules/game/providers/services/player/player-killer.service.ts(255,77): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", - "status": "CompileError", - "static": false, - "killedBy": [], - "coveredBy": [ - "588", - "682", - "683" - ], - "location": { - "end": { - "column": 4, - "line": 273 - }, - "start": { - "column": 82, - "line": 263 - } - } - }, { "id": "4792", "mutatorName": "BooleanLiteral", @@ -167343,14 +166932,556 @@ } } }, + { + "id": "4798", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "Error: expect(received).toStrictEqual(expected) // deep equality\n\n- Expected - 14\n+ Received + 1\n\n@@ -176,22 +176,9 @@\n },\n ],\n \"status\": \"canceled\",\n \"tick\": 7944561779277824,\n \"turn\": 3818008185143296,\n- \"upcomingPlays\": Array [\n- GamePlay {\n- \"action\": \"bury-dead-bodies\",\n- \"canBeSkipped\": undefined,\n- \"cause\": undefined,\n- \"occurrence\": \"consequential\",\n- \"source\": GamePlaySource {\n- \"interactions\": undefined,\n- \"name\": \"survivors\",\n- \"players\": undefined,\n- },\n- \"type\": \"bury-dead-bodies\",\n- },\n- ],\n+ \"upcomingPlays\": Array [],\n \"updatedAt\": 2024-04-08T22:02:38.738Z,\n \"victory\": undefined,\n }\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/providers/services/player/player-killer.service.spec.ts:1651:76)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "status": "Killed", + "testsCompleted": 2, + "static": false, + "killedBy": [ + "682" + ], + "coveredBy": [ + "588", + "682" + ], + "location": { + "end": { + "column": 6, + "line": 271 + }, + "start": { + "column": 96, + "line": 269 + } + } + }, + { + "id": "4799", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/modules/game/providers/services/player/player-killer.service.ts(267,80): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", + "status": "CompileError", + "static": false, + "killedBy": [], + "coveredBy": [ + "684", + "685" + ], + "location": { + "end": { + "column": 4, + "line": 282 + }, + "start": { + "column": 87, + "line": 275 + } + } + }, + { + "id": "4800", + "mutatorName": "ObjectLiteral", + "replacement": "{}", + "statusReason": "src/modules/game/providers/services/player/player-killer.service.ts(269,144): error TS2345: Argument of type '{}' is not assignable to parameter of type '{ gameId: ObjectId; playerId: ObjectId; }'.\n Type '{}' is missing the following properties from type '{ gameId: ObjectId; playerId: ObjectId; }': gameId, playerId\nsrc/modules/game/providers/services/player/player-killer.service.ts(271,84): error TS2345: Argument of type '{}' is not assignable to parameter of type '{ gameId: ObjectId; playerId: ObjectId; }'.\n Type '{}' is missing the following properties from type '{ gameId: ObjectId; playerId: ObjectId; }': gameId, playerId\n", + "status": "CompileError", + "static": false, + "killedBy": [], + "coveredBy": [ + "684", + "685" + ], + "location": { + "end": { + "column": 67, + "line": 276 + }, + "start": { + "column": 37, + "line": 276 + } + } + }, + { + "id": "4801", + "mutatorName": "StringLiteral", + "replacement": "\"\"", + "statusReason": "Error: expect(received).toHaveBeenCalledExactlyOnceWith(expected)\n\nExpected mock function to have been called exactly once with [\"getPlayerToKillOrRevealInGame\", {\"gameId\": \"cffaffc276e3c0409d2daa1c\", \"playerId\": \"4ace7385b1d98b5aeabf3e69\"}], but it was called with \"\"\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/providers/services/player/player-killer.service.spec.ts:1705:94)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "status": "Killed", + "testsCompleted": 2, + "static": false, + "killedBy": [ + "684" + ], + "coveredBy": [ + "684", + "685" + ], + "location": { + "end": { + "column": 142, + "line": 277 + }, + "start": { + "column": 111, + "line": 277 + } + } + }, + { + "id": "4802", + "mutatorName": "BooleanLiteral", + "replacement": "playerToKill.isAlive", + "statusReason": "Error: expect(received).toThrow(expected)\n\nExpected message: \"Unexpected exception in getPlayerToKillOrRevealInGame\"\n\nReceived function did not throw\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/providers/services/player/player-killer.service.spec.ts:1704:98)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "status": "Killed", + "testsCompleted": 2, + "static": false, + "killedBy": [ + "684" + ], + "coveredBy": [ + "684", + "685" + ], + "location": { + "end": { + "column": 30, + "line": 278 + }, + "start": { + "column": 9, + "line": 278 + } + } + }, + { + "id": "4803", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "statusReason": "Error: thrown: undefined\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/providers/services/player/player-killer.service.spec.ts:1709:5\n at _dispatchDescribe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:91:26)\n at describe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:55:5)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/providers/services/player/player-killer.service.spec.ts:1686:3\n at _dispatchDescribe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:91:26)\n at describe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:55:5)\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/providers/services/player/player-killer.service.spec.ts:28:1)\n at Runtime._execModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:1439:24)\n at Runtime._loadModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:1022:12)\n at Runtime.requireModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:882:12)\n at jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:77:13)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "status": "Killed", + "testsCompleted": 2, + "static": false, + "killedBy": [ + "685" + ], + "coveredBy": [ + "684", + "685" + ], + "location": { + "end": { + "column": 30, + "line": 278 + }, + "start": { + "column": 9, + "line": 278 + } + } + }, + { + "id": "4804", + "mutatorName": "ConditionalExpression", + "replacement": "false", + "statusReason": "Error: expect(received).toThrow(expected)\n\nExpected message: \"Unexpected exception in getPlayerToKillOrRevealInGame\"\n\nReceived function did not throw\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/providers/services/player/player-killer.service.spec.ts:1704:98)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "status": "Killed", + "testsCompleted": 2, + "static": false, + "killedBy": [ + "684" + ], + "coveredBy": [ + "684", + "685" + ], + "location": { + "end": { + "column": 30, + "line": 278 + }, + "start": { + "column": 9, + "line": 278 + } + } + }, + { + "id": "4805", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "Error: expect(received).toThrow(expected)\n\nExpected message: \"Unexpected exception in getPlayerToKillOrRevealInGame\"\n\nReceived function did not throw\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/providers/services/player/player-killer.service.spec.ts:1704:98)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "status": "Killed", + "testsCompleted": 1, + "static": false, + "killedBy": [ + "684" + ], + "coveredBy": [ + "684" + ], + "location": { + "end": { + "column": 6, + "line": 280 + }, + "start": { + "column": 32, + "line": 278 + } + } + }, + { + "id": "4806", + "mutatorName": "StringLiteral", + "replacement": "\"\"", + "statusReason": "Error: expect(received).toHaveBeenCalledExactlyOnceWith(expected)\n\nExpected mock function to have been called exactly once with [\"getPlayerToKillOrRevealInGame\", {\"gameId\": \"ab1af641cedf0c4d31fba24c\", \"playerId\": \"7d20ffb3b5d138ee2a753ba0\"}], but it was called with \"\"\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/providers/services/player/player-killer.service.spec.ts:1706:86)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "status": "Killed", + "testsCompleted": 1, + "static": false, + "killedBy": [ + "684" + ], + "coveredBy": [ + "684" + ], + "location": { + "end": { + "column": 82, + "line": 279 + }, + "start": { + "column": 51, + "line": 279 + } + } + }, + { + "id": "4501", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/modules/game/providers/services/player/player-killer.service.ts(27,94): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", + "status": "CompileError", + "static": false, + "coveredBy": [ + "587", + "588", + "589" + ], + "location": { + "end": { + "column": 4, + "line": 37 + }, + "start": { + "column": 108, + "line": 27 + } + } + }, + { + "id": "4522", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/modules/game/providers/services/player/player-killer.service.ts(61,64): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", + "status": "CompileError", + "static": false, + "coveredBy": [ + "589", + "595", + "596" + ], + "location": { + "end": { + "column": 4, + "line": 70 + }, + "start": { + "column": 69, + "line": 61 + } + } + }, + { + "id": "4524", + "mutatorName": "ObjectLiteral", + "replacement": "{}", + "statusReason": "src/modules/game/providers/services/player/player-killer.service.ts(64,103): error TS2345: Argument of type '{}' is not assignable to parameter of type '{ gameId: ObjectId; playerId: ObjectId; }'.\n Type '{}' is missing the following properties from type '{ gameId: ObjectId; playerId: ObjectId; }': gameId, playerId\n", + "status": "CompileError", + "static": false, + "coveredBy": [ + "589", + "595", + "596" + ], + "location": { + "end": { + "column": 153, + "line": 64 + }, + "start": { + "column": 103, + "line": 64 + } + } + }, + { + "id": "4554", + "mutatorName": "StringLiteral", + "replacement": "\"\"", + "statusReason": "src/modules/game/providers/services/player/player-killer.service.ts(90,9): error TS2367: This comparison appears to be unintentional because the types '\"werewolf\" | \"big-bad-wolf\" | \"accursed-wolf-father\" | \"white-werewolf\" | \"villager\" | \"villager-villager\" | \"seer\" | \"cupid\" | \"witch\" | \"hunter\" | \"little-girl\" | \"defender\" | ... 17 more ... | \"devoted-servant\"' and '\"\"' have no overlap.\n", + "status": "CompileError", + "static": false, + "coveredBy": [ + "589", + "595", + "596", + "604", + "605" + ], + "location": { + "end": { + "column": 48, + "line": 90 + }, + "start": { + "column": 41, + "line": 90 + } + } + }, + { + "id": "4550", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/modules/game/providers/services/player/player-killer.service.ts(88,82): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", + "status": "CompileError", + "static": false, + "coveredBy": [ + "589", + "595", + "596", + "604", + "605" + ], + "location": { + "end": { + "column": 4, + "line": 94 + }, + "start": { + "column": 87, + "line": 88 + } + } + }, + { + "id": "4782", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/modules/game/providers/services/player/player-killer.service.ts(248,79): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", + "status": "CompileError", + "static": false, + "coveredBy": [ + "677", + "678", + "679", + "680", + "681" + ], + "location": { + "end": { + "column": 4, + "line": 261 + }, + "start": { + "column": 84, + "line": 248 + } + } + }, + { + "id": "4784", + "mutatorName": "ArrowFunction", + "replacement": "() => undefined", + "statusReason": "src/modules/game/providers/services/player/player-killer.service.ts(251,17): error TS2322: Type '() => undefined' is not assignable to type '(killedPlayer: DeadPlayer, game: Game) => Game'.\n Type 'undefined' is not assignable to type 'Game'.\n", + "status": "CompileError", + "static": false, + "coveredBy": [ + "677", + "678", + "679", + "680", + "681" + ], + "location": { + "end": { + "column": 78, + "line": 251 + }, + "start": { + "column": 17, + "line": 251 + } + } + }, + { + "id": "4785", + "mutatorName": "ArrowFunction", + "replacement": "() => undefined", + "statusReason": "src/modules/game/providers/services/player/player-killer.service.ts(252,16): error TS2322: Type '() => undefined' is not assignable to type '(killedPlayer: DeadPlayer, game: Game) => Game'.\n Type 'undefined' is not assignable to type 'Game'.\n", + "status": "CompileError", + "static": false, + "coveredBy": [ + "677", + "678", + "679", + "680", + "681" + ], + "location": { + "end": { + "column": 76, + "line": 252 + }, + "start": { + "column": 16, + "line": 252 + } + } + }, + { + "id": "4787", + "mutatorName": "ArrowFunction", + "replacement": "() => undefined", + "statusReason": "src/modules/game/providers/services/player/player-killer.service.ts(254,29): error TS2322: Type '() => undefined' is not assignable to type '(killedPlayer: DeadPlayer, game: Game) => Game'.\n Type 'undefined' is not assignable to type 'Game'.\n", + "status": "CompileError", + "static": false, + "coveredBy": [ + "677", + "678", + "679", + "680", + "681" + ], + "location": { + "end": { + "column": 100, + "line": 254 + }, + "start": { + "column": 29, + "line": 254 + } + } + }, + { + "id": "4786", + "mutatorName": "ArrowFunction", + "replacement": "() => undefined", + "statusReason": "src/modules/game/providers/services/player/player-killer.service.ts(253,20): error TS2322: Type '() => undefined' is not assignable to type '(killedPlayer: DeadPlayer, game: Game) => Game'.\n Type 'undefined' is not assignable to type 'Game'.\n", + "status": "CompileError", + "static": false, + "coveredBy": [ + "677", + "678", + "679", + "680", + "681" + ], + "location": { + "end": { + "column": 84, + "line": 253 + }, + "start": { + "column": 20, + "line": 253 + } + } + }, + { + "id": "4788", + "mutatorName": "ConditionalExpression", + "replacement": "true", + "statusReason": "src/modules/game/providers/services/player/player-killer.service.ts(258,14): error TS2722: Cannot invoke an object which is possibly 'undefined'.\n", + "status": "CompileError", + "static": false, + "coveredBy": [ + "677", + "678", + "679", + "680", + "681" + ], + "location": { + "end": { + "column": 32, + "line": 257 + }, + "start": { + "column": 9, + "line": 257 + } + } + }, + { + "id": "4789", + "mutatorName": "ConditionalExpression", + "replacement": "false", + "statusReason": "src/modules/game/providers/services/player/player-killer.service.ts(258,14): error TS2722: Cannot invoke an object which is possibly 'undefined'.\n", + "status": "CompileError", + "static": false, + "coveredBy": [ + "677", + "678", + "679", + "680", + "681" + ], + "location": { + "end": { + "column": 32, + "line": 257 + }, + "start": { + "column": 9, + "line": 257 + } + } + }, + { + "id": "4791", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "src/modules/game/providers/services/player/player-killer.service.ts(263,77): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", + "status": "CompileError", + "static": false, + "coveredBy": [ + "588", + "682", + "683" + ], + "location": { + "end": { + "column": 4, + "line": 273 + }, + "start": { + "column": 82, + "line": 263 + } + } + }, { "id": "4796", "mutatorName": "StringLiteral", "replacement": "\"\"", - "statusReason": "src/modules/game/providers/services/player/player-killer.service.ts(261,62): error TS2345: Argument of type '\"\"' is not assignable to parameter of type '\"werewolf\" | \"big-bad-wolf\" | \"accursed-wolf-father\" | \"white-werewolf\" | \"villager\" | \"villager-villager\" | \"seer\" | \"cupid\" | \"witch\" | \"hunter\" | \"little-girl\" | \"defender\" | ... 23 more ... | \"lovers\"'.\n", + "statusReason": "src/modules/game/providers/services/player/player-killer.service.ts(269,62): error TS2345: Argument of type '\"\"' is not assignable to parameter of type '\"sheriff\" | \"charmed\" | \"werewolf\" | \"big-bad-wolf\" | \"accursed-wolf-father\" | \"white-werewolf\" | \"villager\" | \"villager-villager\" | \"seer\" | \"cupid\" | \"witch\" | \"hunter\" | ... 23 more ... | \"lovers\"'.\n", "status": "CompileError", "static": false, - "killedBy": [], "coveredBy": [ "588", "682", @@ -167371,10 +167502,9 @@ "id": "4797", "mutatorName": "StringLiteral", "replacement": "\"\"", - "statusReason": "src/modules/game/providers/services/player/player-killer.service.ts(261,75): error TS2345: Argument of type '\"\"' is not assignable to parameter of type '\"vote\" | \"choose-card\" | \"choose-side\" | \"request-another-vote\" | \"bury-dead-bodies\" | \"eat\" | \"look\" | \"charm\" | \"use-potions\" | \"shoot\" | \"protect\" | \"mark\" | \"meet-each-other\" | ... 7 more ... | \"infect\"'.\n", + "statusReason": "src/modules/game/providers/services/player/player-killer.service.ts(269,75): error TS2345: Argument of type '\"\"' is not assignable to parameter of type '\"vote\" | \"eat\" | \"look\" | \"charm\" | \"use-potions\" | \"shoot\" | \"protect\" | \"mark\" | \"meet-each-other\" | \"sniff\" | \"choose-model\" | \"choose-side\" | \"ban-voting\" | \"choose-card\" | ... 5 more ... | \"request-another-vote\"'.\n", "status": "CompileError", "static": false, - "killedBy": [], "coveredBy": [ "588", "682", @@ -167392,228 +167522,100 @@ } }, { - "id": "4798", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "Error: expect(received).toStrictEqual(expected) // deep equality\n\n- Expected - 14\n+ Received + 1\n\n@@ -176,22 +176,9 @@\n },\n ],\n \"status\": \"canceled\",\n \"tick\": 7944561779277824,\n \"turn\": 3818008185143296,\n- \"upcomingPlays\": Array [\n- GamePlay {\n- \"action\": \"bury-dead-bodies\",\n- \"canBeSkipped\": undefined,\n- \"cause\": undefined,\n- \"occurrence\": \"consequential\",\n- \"source\": GamePlaySource {\n- \"interactions\": undefined,\n- \"name\": \"survivors\",\n- \"players\": undefined,\n- },\n- \"type\": \"bury-dead-bodies\",\n- },\n- ],\n+ \"upcomingPlays\": Array [],\n \"updatedAt\": 2024-04-08T22:02:38.738Z,\n \"victory\": undefined,\n }\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/providers/services/player/player-killer.service.spec.ts:1651:76)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", - "status": "Killed", - "testsCompleted": 2, - "static": false, - "killedBy": [ - "682" - ], - "coveredBy": [ - "588", - "682" - ], - "location": { - "end": { - "column": 6, - "line": 271 - }, - "start": { - "column": 96, - "line": 269 - } - } - }, - { - "id": "4799", - "mutatorName": "BlockStatement", - "replacement": "{}", - "statusReason": "src/modules/game/providers/services/player/player-killer.service.ts(267,80): error TS2355: A function whose declared type is neither 'undefined', 'void', nor 'any' must return a value.\n", - "status": "CompileError", - "static": false, - "killedBy": [], - "coveredBy": [ - "684", - "685" - ], - "location": { - "end": { - "column": 4, - "line": 282 - }, - "start": { - "column": 87, - "line": 275 - } - } - }, - { - "id": "4800", - "mutatorName": "ObjectLiteral", - "replacement": "{}", - "statusReason": "src/modules/game/providers/services/player/player-killer.service.ts(269,144): error TS2345: Argument of type '{}' is not assignable to parameter of type '{ gameId: ObjectId; playerId: ObjectId; }'.\n Type '{}' is missing the following properties from type '{ gameId: ObjectId; playerId: ObjectId; }': gameId, playerId\nsrc/modules/game/providers/services/player/player-killer.service.ts(271,84): error TS2345: Argument of type '{}' is not assignable to parameter of type '{ gameId: ObjectId; playerId: ObjectId; }'.\n Type '{}' is missing the following properties from type '{ gameId: ObjectId; playerId: ObjectId; }': gameId, playerId\n", - "status": "CompileError", - "static": false, - "killedBy": [], - "coveredBy": [ - "684", - "685" - ], - "location": { - "end": { - "column": 67, - "line": 276 - }, - "start": { - "column": 37, - "line": 276 - } - } - }, - { - "id": "4801", - "mutatorName": "StringLiteral", - "replacement": "\"\"", - "statusReason": "Error: expect(received).toHaveBeenCalledExactlyOnceWith(expected)\n\nExpected mock function to have been called exactly once with [\"getPlayerToKillOrRevealInGame\", {\"gameId\": \"cffaffc276e3c0409d2daa1c\", \"playerId\": \"4ace7385b1d98b5aeabf3e69\"}], but it was called with \"\"\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/providers/services/player/player-killer.service.spec.ts:1705:94)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", - "status": "Killed", - "testsCompleted": 2, - "static": false, - "killedBy": [ - "684" - ], - "coveredBy": [ - "684", - "685" - ], - "location": { - "end": { - "column": 142, - "line": 277 - }, - "start": { - "column": 111, - "line": 277 - } - } - }, - { - "id": "4802", - "mutatorName": "BooleanLiteral", - "replacement": "playerToKill.isAlive", - "statusReason": "Error: expect(received).toThrow(expected)\n\nExpected message: \"Unexpected exception in getPlayerToKillOrRevealInGame\"\n\nReceived function did not throw\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/providers/services/player/player-killer.service.spec.ts:1704:98)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", - "status": "Killed", - "testsCompleted": 2, - "static": false, - "killedBy": [ - "684" - ], - "coveredBy": [ - "684", - "685" - ], - "location": { - "end": { - "column": 30, - "line": 278 - }, - "start": { - "column": 9, - "line": 278 - } - } - }, - { - "id": "4803", + "id": "4503", "mutatorName": "ConditionalExpression", - "replacement": "true", - "statusReason": "Error: thrown: undefined\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/providers/services/player/player-killer.service.spec.ts:1709:5\n at _dispatchDescribe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:91:26)\n at describe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:55:5)\n at /Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/providers/services/player/player-killer.service.spec.ts:1686:3\n at _dispatchDescribe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:91:26)\n at describe (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:55:5)\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/providers/services/player/player-killer.service.spec.ts:28:1)\n at Runtime._execModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:1439:24)\n at Runtime._loadModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:1022:12)\n at Runtime.requireModule (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:882:12)\n at jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:77:13)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", - "status": "Killed", - "testsCompleted": 2, + "replacement": "false", + "status": "Timeout", "static": false, - "killedBy": [ - "685" - ], "coveredBy": [ - "684", - "685" + "587", + "588", + "589" ], "location": { "end": { - "column": 30, - "line": 278 + "column": 75, + "line": 30 }, "start": { "column": 9, - "line": 278 + "line": 30 } } }, { - "id": "4804", + "id": "4506", "mutatorName": "ConditionalExpression", "replacement": "false", - "statusReason": "Error: expect(received).toThrow(expected)\n\nExpected message: \"Unexpected exception in getPlayerToKillOrRevealInGame\"\n\nReceived function did not throw\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/providers/services/player/player-killer.service.spec.ts:1704:98)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "statusReason": "Error: expect(received).toHaveBeenCalledExactlyOnceWith(expected)\n\nExpected mock function to have been called exactly once, but it was called 0 times\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox621460/tests/unit/specs/modules/game/providers/services/player/player-killer.service.spec.ts:185:58)", "status": "Killed", - "testsCompleted": 2, "static": false, + "testsCompleted": 2, "killedBy": [ - "684" + "589" ], "coveredBy": [ - "684", - "685" + "587", + "589" ], "location": { "end": { - "column": 30, - "line": 278 + "column": 69, + "line": 33 }, "start": { "column": 9, - "line": 278 + "line": 33 } } }, { - "id": "4805", + "id": "4504", "mutatorName": "BlockStatement", "replacement": "{}", - "statusReason": "Error: expect(received).toThrow(expected)\n\nExpected message: \"Unexpected exception in getPlayerToKillOrRevealInGame\"\n\nReceived function did not throw\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/providers/services/player/player-killer.service.spec.ts:1704:98)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "statusReason": "Error: expect(received).toHaveBeenCalledExactlyOnceWith(expected)\n\nExpected mock function to have been called exactly once, but it was called 0 times\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox621460/tests/unit/specs/modules/game/providers/services/player/player-killer.service.spec.ts:165:52)", "status": "Killed", - "testsCompleted": 1, "static": false, + "testsCompleted": 1, "killedBy": [ - "684" + "588" ], "coveredBy": [ - "684" + "588" ], "location": { "end": { "column": 6, - "line": 280 + "line": 32 }, "start": { - "column": 32, - "line": 278 + "column": 77, + "line": 30 } } }, { - "id": "4806", - "mutatorName": "StringLiteral", - "replacement": "\"\"", - "statusReason": "Error: expect(received).toHaveBeenCalledExactlyOnceWith(expected)\n\nExpected mock function to have been called exactly once with [\"getPlayerToKillOrRevealInGame\", {\"gameId\": \"ab1af641cedf0c4d31fba24c\", \"playerId\": \"7d20ffb3b5d138ee2a753ba0\"}], but it was called with \"\"\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox7677424/tests/unit/specs/modules/game/providers/services/player/player-killer.service.spec.ts:1706:86)\n at Promise.then.completed (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:298:28)\n at new Promise ()\n at callAsyncCircusFn (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/utils.js:231:10)\n at _callCircusTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:316:40)\n at async _runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:252:3)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:126:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async _runTestsForDescribeBlock (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:121:9)\n at async run (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/run.js:71:3)\n at async runAndTransformResultsToJestFormat (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapterInit.js:122:21)\n at async jestAdapter (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:79:19)\n at async runTestInternal (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)\n at async runTest (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)", + "id": "4507", + "mutatorName": "BlockStatement", + "replacement": "{}", + "statusReason": "Error: expect(received).toHaveBeenCalledExactlyOnceWith(expected)\n\nExpected mock function to have been called exactly once, but it was called 0 times\n at Object. (/Users/antoinezanardi/WebstormProjects/werewolves-assistant-api-next/.stryker-tmp/sandbox621460/tests/unit/specs/modules/game/providers/services/player/player-killer.service.spec.ts:185:58)", "status": "Killed", - "testsCompleted": 1, "static": false, + "testsCompleted": 1, "killedBy": [ - "684" + "589" ], "coveredBy": [ - "684" + "589" ], "location": { "end": { - "column": 82, - "line": 279 + "column": 6, + "line": 35 }, "start": { - "column": 51, - "line": 279 + "column": 71, + "line": 33 } } } @@ -169417,9 +169419,9 @@ } }, { - "id": "4822", - "mutatorName": "ArrowFunction", - "replacement": "() => undefined", + "id": "4825", + "mutatorName": "EqualityOperator", + "replacement": "role.name !== name", "status": "Timeout", "static": true, "coveredBy": [ @@ -170095,15 +170097,15 @@ "line": 9 }, "start": { - "column": 21, + "column": 29, "line": 9 } } }, { - "id": "4824", - "mutatorName": "ConditionalExpression", - "replacement": "false", + "id": "4822", + "mutatorName": "ArrowFunction", + "replacement": "() => undefined", "status": "Timeout", "static": true, "coveredBy": [ @@ -170779,15 +170781,15 @@ "line": 9 }, "start": { - "column": 29, + "column": 21, "line": 9 } } }, { - "id": "4825", - "mutatorName": "EqualityOperator", - "replacement": "role.name !== name", + "id": "4824", + "mutatorName": "ConditionalExpression", + "replacement": "false", "status": "Timeout", "static": true, "coveredBy": [ @@ -173861,7 +173863,7 @@ } } ], - "source": "import type { Types } from \"mongoose\";\n\nimport type { RoleName } from \"@/modules/role/types/role.types\";\nimport type { GamePlay } from \"@/modules/game/schemas/game-play/game-play.schema\";\n\nimport { UnexpectedExceptionReasons } from \"@/shared/exception/enums/unexpected-exception.enum\";\nimport { UnexpectedException } from \"@/shared/exception/types/unexpected-exception.types\";\n\nfunction createCantFindPlayerWithIdUnexpectedException(scope: string, interpolations: { gameId: Types.ObjectId; playerId: Types.ObjectId }): UnexpectedException {\n const { gameId, playerId } = interpolations;\n\n return new UnexpectedException(scope, UnexpectedExceptionReasons.CANT_FIND_PLAYER_WITH_ID_IN_GAME, { gameId: gameId.toString(), playerId: playerId.toString() });\n}\n\nfunction createCantFindPlayerWithCurrentRoleUnexpectedException(scope: string, interpolations: { gameId: Types.ObjectId; roleName: RoleName }): UnexpectedException {\n const { gameId, roleName } = interpolations;\n\n return new UnexpectedException(scope, UnexpectedExceptionReasons.CANT_FIND_PLAYER_WITH_CURRENT_ROLE_IN_GAME, { gameId: gameId.toString(), roleName });\n}\n\nfunction createPlayerIsDeadUnexpectedException(scope: string, interpolations: { gameId: Types.ObjectId; playerId: Types.ObjectId }): UnexpectedException {\n const { gameId, playerId } = interpolations;\n\n return new UnexpectedException(scope, UnexpectedExceptionReasons.PLAYER_IS_DEAD, { gameId: gameId.toString(), playerId: playerId.toString() });\n}\n\nfunction createCantGenerateGamePlaysUnexpectedException(scope: string): UnexpectedException {\n return new UnexpectedException(scope, UnexpectedExceptionReasons.CANT_GENERATE_GAME_PLAYS);\n}\n\nfunction createNoCurrentGamePlayUnexpectedException(scope: string, interpolations: { gameId: Types.ObjectId }): UnexpectedException {\n const { gameId } = interpolations;\n\n return new UnexpectedException(scope, UnexpectedExceptionReasons.NO_CURRENT_GAME_PLAY, { gameId: gameId.toString() });\n}\n\nfunction createNoGamePlayPriorityUnexpectedException(scope: string, gamePlay: GamePlay): UnexpectedException {\n return new UnexpectedException(scope, UnexpectedExceptionReasons.NO_GAME_PLAY_PRIORITY, { gamePlay: JSON.stringify(gamePlay) });\n}\n\nfunction createMalformedCurrentGamePlayUnexpectedException(scope: string, gamePlay: GamePlay, gameId: Types.ObjectId): UnexpectedException {\n const interpolations = { action: gamePlay.action, source: gamePlay.source.name, gameId: gameId.toString() };\n\n return new UnexpectedException(scope, UnexpectedExceptionReasons.MALFORMED_CURRENT_GAME_PLAY, interpolations);\n}\n\nfunction createCantFindLastNominatedPlayersUnexpectedException(scope: string, interpolations: { gameId: Types.ObjectId }): UnexpectedException {\n const { gameId } = interpolations;\n\n return new UnexpectedException(scope, UnexpectedExceptionReasons.CANT_FIND_LAST_NOMINATED_PLAYERS, { gameId: gameId.toString() });\n}\n\nfunction createCantFindLastDeadPlayersUnexpectedException(scope: string, interpolations: { gameId: Types.ObjectId }): UnexpectedException {\n const { gameId } = interpolations;\n\n return new UnexpectedException(scope, UnexpectedExceptionReasons.CANT_FIND_LAST_DEAD_PLAYERS, { gameId: gameId.toString() });\n}\n\nexport {\n createCantFindPlayerWithIdUnexpectedException,\n createCantFindPlayerWithCurrentRoleUnexpectedException,\n createPlayerIsDeadUnexpectedException,\n createCantGenerateGamePlaysUnexpectedException,\n createNoCurrentGamePlayUnexpectedException,\n createNoGamePlayPriorityUnexpectedException,\n createMalformedCurrentGamePlayUnexpectedException,\n createCantFindLastNominatedPlayersUnexpectedException,\n createCantFindLastDeadPlayersUnexpectedException,\n};" + "source": "import type { Types } from \"mongoose\";\n\nimport type { RoleName } from \"@/modules/role/types/role.types\";\nimport type { GamePlay } from \"@/modules/game/schemas/game-play/game-play.schema\";\n\nimport { UnexpectedExceptionReasons } from \"@/shared/exception/enums/unexpected-exception.enums\";\nimport { UnexpectedException } from \"@/shared/exception/types/unexpected-exception.types\";\n\nfunction createCantFindPlayerWithIdUnexpectedException(scope: string, interpolations: { gameId: Types.ObjectId; playerId: Types.ObjectId }): UnexpectedException {\n const { gameId, playerId } = interpolations;\n\n return new UnexpectedException(scope, UnexpectedExceptionReasons.CANT_FIND_PLAYER_WITH_ID_IN_GAME, { gameId: gameId.toString(), playerId: playerId.toString() });\n}\n\nfunction createCantFindPlayerWithCurrentRoleUnexpectedException(scope: string, interpolations: { gameId: Types.ObjectId; roleName: RoleName }): UnexpectedException {\n const { gameId, roleName } = interpolations;\n\n return new UnexpectedException(scope, UnexpectedExceptionReasons.CANT_FIND_PLAYER_WITH_CURRENT_ROLE_IN_GAME, { gameId: gameId.toString(), roleName });\n}\n\nfunction createPlayerIsDeadUnexpectedException(scope: string, interpolations: { gameId: Types.ObjectId; playerId: Types.ObjectId }): UnexpectedException {\n const { gameId, playerId } = interpolations;\n\n return new UnexpectedException(scope, UnexpectedExceptionReasons.PLAYER_IS_DEAD, { gameId: gameId.toString(), playerId: playerId.toString() });\n}\n\nfunction createCantGenerateGamePlaysUnexpectedException(scope: string): UnexpectedException {\n return new UnexpectedException(scope, UnexpectedExceptionReasons.CANT_GENERATE_GAME_PLAYS);\n}\n\nfunction createNoCurrentGamePlayUnexpectedException(scope: string, interpolations: { gameId: Types.ObjectId }): UnexpectedException {\n const { gameId } = interpolations;\n\n return new UnexpectedException(scope, UnexpectedExceptionReasons.NO_CURRENT_GAME_PLAY, { gameId: gameId.toString() });\n}\n\nfunction createNoGamePlayPriorityUnexpectedException(scope: string, gamePlay: GamePlay): UnexpectedException {\n return new UnexpectedException(scope, UnexpectedExceptionReasons.NO_GAME_PLAY_PRIORITY, { gamePlay: JSON.stringify(gamePlay) });\n}\n\nfunction createMalformedCurrentGamePlayUnexpectedException(scope: string, gamePlay: GamePlay, gameId: Types.ObjectId): UnexpectedException {\n const interpolations = { action: gamePlay.action, source: gamePlay.source.name, gameId: gameId.toString() };\n\n return new UnexpectedException(scope, UnexpectedExceptionReasons.MALFORMED_CURRENT_GAME_PLAY, interpolations);\n}\n\nfunction createCantFindLastNominatedPlayersUnexpectedException(scope: string, interpolations: { gameId: Types.ObjectId }): UnexpectedException {\n const { gameId } = interpolations;\n\n return new UnexpectedException(scope, UnexpectedExceptionReasons.CANT_FIND_LAST_NOMINATED_PLAYERS, { gameId: gameId.toString() });\n}\n\nfunction createCantFindLastDeadPlayersUnexpectedException(scope: string, interpolations: { gameId: Types.ObjectId }): UnexpectedException {\n const { gameId } = interpolations;\n\n return new UnexpectedException(scope, UnexpectedExceptionReasons.CANT_FIND_LAST_DEAD_PLAYERS, { gameId: gameId.toString() });\n}\n\nexport {\n createCantFindPlayerWithIdUnexpectedException,\n createCantFindPlayerWithCurrentRoleUnexpectedException,\n createPlayerIsDeadUnexpectedException,\n createCantGenerateGamePlaysUnexpectedException,\n createNoCurrentGamePlayUnexpectedException,\n createNoGamePlayPriorityUnexpectedException,\n createMalformedCurrentGamePlayUnexpectedException,\n createCantFindLastNominatedPlayersUnexpectedException,\n createCantFindLastDeadPlayersUnexpectedException,\n};" }, "src/shared/exception/types/bad-game-play-payload-exception.types.ts": { "language": "typescript", @@ -174098,7 +174100,7 @@ } } ], - "source": "import { BadRequestException } from \"@nestjs/common\";\n\nimport type { BadGamePlayPayloadReasons } from \"@/shared/exception/enums/bad-game-play-payload-error.enum\";\n\nclass BadGamePlayPayloadException extends BadRequestException {\n public constructor(reason: BadGamePlayPayloadReasons) {\n const message = `Bad game play payload`;\n super(message, { description: reason });\n }\n}\n\nexport { BadGamePlayPayloadException };" + "source": "import { BadRequestException } from \"@nestjs/common\";\n\nimport type { BadGamePlayPayloadReasons } from \"@/shared/exception/enums/bad-game-play-payload-error.enums\";\n\nclass BadGamePlayPayloadException extends BadRequestException {\n public constructor(reason: BadGamePlayPayloadReasons) {\n const message = `Bad game play payload`;\n super(message, { description: reason });\n }\n}\n\nexport { BadGamePlayPayloadException };" }, "src/shared/exception/types/bad-resource-mutation-exception.types.ts": { "language": "typescript", @@ -174194,7 +174196,7 @@ } } ], - "source": "import { BadRequestException } from \"@nestjs/common\";\nimport { upperFirst } from \"lodash\";\n\nimport type { ApiResources } from \"@/shared/api/enums/api.enums\";\nimport type { BadResourceMutationReasons } from \"@/shared/exception/enums/bad-resource-mutation-error.enum\";\nimport { getResourceSingularForm } from \"@/shared/api/helpers/api.helpers\";\n\nclass BadResourceMutationException extends BadRequestException {\n public constructor(resource: ApiResources, id: string, reason?: BadResourceMutationReasons) {\n const resourceSingularForm = getResourceSingularForm(resource);\n const message = `Bad mutation for ${upperFirst(resourceSingularForm)} with id \"${id}\"`;\n super(message, { description: reason });\n }\n}\n\nexport { BadResourceMutationException };" + "source": "import { BadRequestException } from \"@nestjs/common\";\nimport { upperFirst } from \"lodash\";\n\nimport type { ApiResources } from \"@/shared/api/enums/api.enums\";\nimport type { BadResourceMutationReasons } from \"@/shared/exception/enums/bad-resource-mutation-error.enums\";\nimport { getResourceSingularForm } from \"@/shared/api/helpers/api.helpers\";\n\nclass BadResourceMutationException extends BadRequestException {\n public constructor(resource: ApiResources, id: string, reason?: BadResourceMutationReasons) {\n const resourceSingularForm = getResourceSingularForm(resource);\n const message = `Bad mutation for ${upperFirst(resourceSingularForm)} with id \"${id}\"`;\n super(message, { description: reason });\n }\n}\n\nexport { BadResourceMutationException };" }, "src/shared/exception/types/resource-not-found-exception.types.ts": { "language": "typescript", @@ -174359,7 +174361,7 @@ } } ], - "source": "import { NotFoundException } from \"@nestjs/common\";\nimport { upperFirst } from \"lodash\";\n\nimport type { ApiResources } from \"@/shared/api/enums/api.enums\";\nimport type { ResourceNotFoundReasons } from \"@/shared/exception/enums/resource-not-found-error.enum\";\nimport { getResourceSingularForm } from \"@/shared/api/helpers/api.helpers\";\n\nclass ResourceNotFoundException extends NotFoundException {\n public constructor(resource: ApiResources, id: string, reason?: ResourceNotFoundReasons) {\n const resourceSingularForm = getResourceSingularForm(resource);\n const message = `${upperFirst(resourceSingularForm)} with id \"${id}\" not found`;\n super(message, { description: reason });\n }\n}\n\nexport { ResourceNotFoundException };" + "source": "import { NotFoundException } from \"@nestjs/common\";\nimport { upperFirst } from \"lodash\";\n\nimport type { ApiResources } from \"@/shared/api/enums/api.enums\";\nimport type { ResourceNotFoundReasons } from \"@/shared/exception/enums/resource-not-found-error.enums\";\nimport { getResourceSingularForm } from \"@/shared/api/helpers/api.helpers\";\n\nclass ResourceNotFoundException extends NotFoundException {\n public constructor(resource: ApiResources, id: string, reason?: ResourceNotFoundReasons) {\n const resourceSingularForm = getResourceSingularForm(resource);\n const message = `${upperFirst(resourceSingularForm)} with id \"${id}\" not found`;\n super(message, { description: reason });\n }\n}\n\nexport { ResourceNotFoundException };" }, "src/shared/exception/types/unexpected-exception.types.ts": { "language": "typescript", @@ -174632,7 +174634,7 @@ } } ], - "source": "import { InternalServerErrorException } from \"@nestjs/common\";\nimport { template } from \"radash\";\n\nimport type { UnexpectedExceptionReasons } from \"@/shared/exception/enums/unexpected-exception.enum\";\nimport type { ExceptionInterpolations } from \"@/shared/exception/types/exception.types\";\n\nclass UnexpectedException extends InternalServerErrorException {\n public constructor(scope: string, reason: UnexpectedExceptionReasons, interpolations: ExceptionInterpolations = {}) {\n const message = `Unexpected exception in ${scope}`;\n super(message, { description: template(reason, interpolations) });\n }\n}\n\nexport { UnexpectedException };" + "source": "import { InternalServerErrorException } from \"@nestjs/common\";\nimport { template } from \"radash\";\n\nimport type { UnexpectedExceptionReasons } from \"@/shared/exception/enums/unexpected-exception.enums\";\nimport type { ExceptionInterpolations } from \"@/shared/exception/types/exception.types\";\n\nclass UnexpectedException extends InternalServerErrorException {\n public constructor(scope: string, reason: UnexpectedExceptionReasons, interpolations: ExceptionInterpolations = {}) {\n const message = `Unexpected exception in ${scope}`;\n super(message, { description: template(reason, interpolations) });\n }\n}\n\nexport { UnexpectedException };" }, "src/shared/mongoose/helpers/mongoose.helpers.ts": { "language": "typescript", @@ -177255,7 +177257,7 @@ "1681", "1682", "1690", - "1698" + "1695" ], "location": { "end": { @@ -178256,7 +178258,7 @@ "1681", "1682", "1690", - "1698" + "1695" ], "location": { "end": { @@ -179257,7 +179259,7 @@ "1681", "1682", "1690", - "1698" + "1695" ], "location": { "end": { @@ -180258,7 +180260,7 @@ "1681", "1682", "1690", - "1698" + "1695" ], "location": { "end": { @@ -180272,9 +180274,9 @@ } }, { - "id": "4933", - "mutatorName": "StringLiteral", - "replacement": "\"\"", + "id": "4935", + "mutatorName": "BooleanLiteral", + "replacement": "isValidObjectId(_id)", "status": "Timeout", "static": true, "coveredBy": [ @@ -181241,8 +181243,6 @@ "1598", "1599", "1602", - "1627", - "1628", "1629", "1630", "1660", @@ -181259,23 +181259,23 @@ "1681", "1682", "1690", - "1698" + "1695" ], "location": { "end": { - "column": 22, - "line": 16 + "column": 28, + "line": 20 }, "start": { - "column": 17, - "line": 16 + "column": 7, + "line": 20 } } }, { - "id": "4935", - "mutatorName": "BooleanLiteral", - "replacement": "isValidObjectId(_id)", + "id": "4936", + "mutatorName": "ConditionalExpression", + "replacement": "true", "status": "Timeout", "static": true, "coveredBy": [ @@ -182258,7 +182258,7 @@ "1681", "1682", "1690", - "1698" + "1695" ], "location": { "end": { @@ -182272,9 +182272,9 @@ } }, { - "id": "4936", + "id": "4937", "mutatorName": "ConditionalExpression", - "replacement": "true", + "replacement": "false", "status": "Timeout", "static": true, "coveredBy": [ @@ -183257,7 +183257,7 @@ "1681", "1682", "1690", - "1698" + "1695" ], "location": { "end": { @@ -183271,9 +183271,9 @@ } }, { - "id": "4937", - "mutatorName": "ConditionalExpression", - "replacement": "false", + "id": "4933", + "mutatorName": "StringLiteral", + "replacement": "\"\"", "status": "Timeout", "static": true, "coveredBy": [ @@ -184240,6 +184240,8 @@ "1598", "1599", "1602", + "1627", + "1628", "1629", "1630", "1660", @@ -184256,16 +184258,16 @@ "1681", "1682", "1690", - "1698" + "1695" ], "location": { "end": { - "column": 28, - "line": 20 + "column": 22, + "line": 16 }, "start": { - "column": 7, - "line": 20 + "column": 17, + "line": 16 } } } @@ -184792,7 +184794,7 @@ "1681", "1682", "1690", - "1698", + "1695", "1699", "1704", "1705", @@ -186333,7 +186335,7 @@ } } ], - "source": "import { GameHistoryRecordRepository } from \"@/modules/game/providers/repositories/game-history-record/game-history-record.repository\";\nimport type { TestingModule } from \"@nestjs/testing\";\nimport { Test } from \"@nestjs/testing\";\nimport { when } from \"jest-when\";\n\nimport * as GamePlayHelper from \"@/modules/game/helpers/game-play/game-play.helpers\";\nimport { GameRepository } from \"@/modules/game/providers/repositories/game.repository\";\nimport { GameHistoryRecordService } from \"@/modules/game/providers/services/game-history/game-history-record.service\";\nimport { GamePlayValidatorService } from \"@/modules/game/providers/services/game-play/game-play-validator.service\";\n\nimport { BadGamePlayPayloadReasons } from \"@/shared/exception/enums/bad-game-play-payload-error.enum\";\nimport { UnexpectedExceptionReasons } from \"@/shared/exception/enums/unexpected-exception.enum\";\nimport * as UnexpectedExceptionFactory from \"@/shared/exception/helpers/unexpected-exception.factory\";\nimport { BadGamePlayPayloadException } from \"@/shared/exception/types/bad-game-play-payload-exception.types\";\nimport { UnexpectedException } from \"@/shared/exception/types/unexpected-exception.types\";\n\nimport { createFakeMakeGamePlayTargetWithRelationsDto } from \"@tests/factories/game/dto/make-game-play/make-game-play-with-relations/make-game-play-target-with-relations.dto.factory\";\nimport { createFakeMakeGamePlayVoteWithRelationsDto } from \"@tests/factories/game/dto/make-game-play/make-game-play-with-relations/make-game-play-vote-with-relations.dto.factory\";\nimport { createFakeMakeGamePlayWithRelationsDto } from \"@tests/factories/game/dto/make-game-play/make-game-play-with-relations/make-game-play-with-relations.dto.factory\";\nimport { createFakeGameAdditionalCard } from \"@tests/factories/game/schemas/game-additional-card/game-additional-card.schema.factory\";\nimport { createFakeGameHistoryRecord, createFakeGameHistoryRecordSurvivorsVotePlay, createFakeGameHistoryRecordWitchUsePotionsPlay } from \"@tests/factories/game/schemas/game-history-record/game-history-record.schema.factory\";\nimport { createFakeGameOptions } from \"@tests/factories/game/schemas/game-options/game-options.schema.factory\";\nimport { createFakePiedPiperGameOptions, createFakeRolesGameOptions, createFakeWolfHoundGameOptions } from \"@tests/factories/game/schemas/game-options/game-roles-options/game-roles-options.schema.factory\";\nimport { createFakeGamePlaySourceInteractionBoundaries } from \"@tests/factories/game/schemas/game-play/game-play-source/game-play-source-interaction/game-play-source-interaction-boundaries/game-play-source-interaction-boundaries.schema.factory\";\nimport { createFakeGamePlaySourceInteraction } from \"@tests/factories/game/schemas/game-play/game-play-source/game-play-source-interaction/game-play-source-interaction.schema.factory\";\nimport { createFakeGamePlaySource } from \"@tests/factories/game/schemas/game-play/game-play-source/game-play-source.schema.factory\";\nimport { createFakeGamePlayAccursedWolfFatherInfects, createFakeGamePlayActorChoosesCard, createFakeGamePlayBigBadWolfEats, createFakeGamePlayCupidCharms, createFakeGamePlayDefenderProtects, createFakeGamePlayFoxSniffs, createFakeGamePlayHunterShoots, createFakeGamePlayPiedPiperCharms, createFakeGamePlayScandalmongerMarks, createFakeGamePlayScapegoatBansVoting, createFakeGamePlaySeerLooks, createFakeGamePlaySheriffDelegates, createFakeGamePlaySheriffSettlesVotes, createFakeGamePlayStutteringJudgeRequestsAnotherVote, createFakeGamePlaySurvivorsBuryDeadBodies, createFakeGamePlaySurvivorsElectSheriff, createFakeGamePlaySurvivorsVote, createFakeGamePlayThiefChoosesCard, createFakeGamePlayWerewolvesEat, createFakeGamePlayWhiteWerewolfEats, createFakeGamePlayWildChildChoosesModel, createFakeGamePlayWitchUsesPotions, createFakeGamePlayWolfHoundChoosesSide } from \"@tests/factories/game/schemas/game-play/game-play.schema.factory\";\nimport { createFakeGame, createFakeGameWithCurrentPlay } from \"@tests/factories/game/schemas/game.schema.factory\";\nimport { createFakeCantVoteBySurvivorsPlayerAttribute, createFakeEatenByWerewolvesPlayerAttribute, createFakeInLoveByCupidPlayerAttribute, createFakePowerlessByElderPlayerAttribute } from \"@tests/factories/game/schemas/player/player-attribute/player-attribute.schema.factory\";\nimport { createFakeDevotedServantAlivePlayer, createFakeIdiotAlivePlayer, createFakeSeerAlivePlayer, createFakeVillagerAlivePlayer, createFakeWerewolfAlivePlayer, createFakeWhiteWerewolfAlivePlayer, createFakeWildChildAlivePlayer, createFakeWitchAlivePlayer } from \"@tests/factories/game/schemas/player/player-with-role.schema.factory\";\nimport { createFakePlayer } from \"@tests/factories/game/schemas/player/player.schema.factory\";\nimport { getError } from \"@tests/helpers/exception/exception.helpers\";\n\ndescribe(\"Game Play Validator Service\", () => {\n let mocks: {\n gamePlayValidatorService: {\n validateGamePlayWithRelationsDtoJudgeRequest: jest.SpyInstance;\n validateGamePlayWithRelationsDtoChosenSide: jest.SpyInstance;\n validateGamePlayVotesWithRelationsDto: jest.SpyInstance;\n validateGamePlayTargetsWithRelationsDto: jest.SpyInstance;\n validateGamePlayWithRelationsDtoChosenCard: jest.SpyInstance;\n validateGamePlayActorChosenCard: jest.SpyInstance;\n validateGamePlayWitchTargets: jest.SpyInstance;\n validateGamePlayWithRelationsDto: jest.SpyInstance;\n validateGamePlayThiefChosenCard: jest.SpyInstance;\n validateDrankLifePotionTargets: jest.SpyInstance;\n validateDrankDeathPotionTargets: jest.SpyInstance;\n validateGamePlaySheriffTargets: jest.SpyInstance;\n validateGamePlayDefenderTargets: jest.SpyInstance;\n validateGamePlayPiedPiperTargets: jest.SpyInstance;\n validateGamePlayWildChildTargets: jest.SpyInstance;\n validateGamePlayScandalmongerTargets: jest.SpyInstance;\n validateGamePlaySeerTargets: jest.SpyInstance;\n validateGamePlayFoxTargets: jest.SpyInstance;\n validateGamePlayCupidTargets: jest.SpyInstance;\n validateGamePlayScapegoatTargets: jest.SpyInstance;\n validateGamePlayHunterTargets: jest.SpyInstance;\n validateGamePlayWerewolvesTargets: jest.SpyInstance;\n validateGamePlayAccursedWolfFatherTargets: jest.SpyInstance;\n validateGamePlayTargetsBoundaries: jest.SpyInstance;\n validateTargetsPotionUsage: jest.SpyInstance;\n validateGamePlaySourceTargets: jest.SpyInstance;\n validateGamePlayVotesTieBreakerWithRelationsDto: jest.SpyInstance;\n validateGamePlayVotesWithRelationsDtoSourceAndTarget: jest.SpyInstance;\n validateGamePlaySurvivorsTargets: jest.SpyInstance;\n };\n gameRepository: {\n find: jest.SpyInstance;\n findOne: jest.SpyInstance;\n create: jest.SpyInstance;\n updateOne: jest.SpyInstance;\n };\n gameHistoryRecordRepository: {\n find: jest.SpyInstance;\n create: jest.SpyInstance;\n };\n gameHistoryRecordService: {\n getLastGameHistoryDefenderProtectsRecord: jest.SpyInstance;\n getLastGameHistoryTieInVotesRecord: jest.SpyInstance;\n getGameHistoryWitchUsesSpecificPotionRecords: jest.SpyInstance;\n getLastGameHistoryAccursedWolfFatherInfectsRecord: jest.SpyInstance;\n getGameHistoryStutteringJudgeRequestsAnotherVoteRecords: jest.SpyInstance;\n didJudgeMakeHisSign: jest.SpyInstance;\n };\n gamePlayHelper: {\n isPlayerInteractableWithInteractionTypeInCurrentGamePlay: jest.SpyInstance;\n isPlayerInteractableInCurrentGamePlay: jest.SpyInstance;\n };\n unexpectedExceptionFactory: {\n createNoCurrentGamePlayUnexpectedException: jest.SpyInstance;\n createCantFindPlayerWithCurrentRoleUnexpectedException: jest.SpyInstance;\n };\n };\n let services: { gamePlayValidator: GamePlayValidatorService };\n\n beforeEach(async() => {\n mocks = {\n gamePlayValidatorService: {\n validateGamePlayWithRelationsDtoJudgeRequest: jest.fn(),\n validateGamePlayWithRelationsDtoChosenSide: jest.fn(),\n validateGamePlayVotesWithRelationsDto: jest.fn(),\n validateGamePlayTargetsWithRelationsDto: jest.fn(),\n validateGamePlayWithRelationsDtoChosenCard: jest.fn(),\n validateGamePlayActorChosenCard: jest.fn(),\n validateGamePlayWitchTargets: jest.fn(),\n validateGamePlayWithRelationsDto: jest.fn(),\n validateGamePlayThiefChosenCard: jest.fn(),\n validateDrankLifePotionTargets: jest.fn(),\n validateDrankDeathPotionTargets: jest.fn(),\n validateGamePlaySheriffTargets: jest.fn(),\n validateGamePlayDefenderTargets: jest.fn(),\n validateGamePlayPiedPiperTargets: jest.fn(),\n validateGamePlayWildChildTargets: jest.fn(),\n validateGamePlayScandalmongerTargets: jest.fn(),\n validateGamePlaySeerTargets: jest.fn(),\n validateGamePlayFoxTargets: jest.fn(),\n validateGamePlayCupidTargets: jest.fn(),\n validateGamePlayScapegoatTargets: jest.fn(),\n validateGamePlayHunterTargets: jest.fn(),\n validateGamePlayWerewolvesTargets: jest.fn(),\n validateGamePlayAccursedWolfFatherTargets: jest.fn(),\n validateGamePlayTargetsBoundaries: jest.fn(),\n validateTargetsPotionUsage: jest.fn(),\n validateGamePlaySourceTargets: jest.fn(),\n validateGamePlayVotesTieBreakerWithRelationsDto: jest.fn(),\n validateGamePlayVotesWithRelationsDtoSourceAndTarget: jest.fn(),\n validateGamePlaySurvivorsTargets: jest.fn(),\n },\n gameRepository: {\n find: jest.fn(),\n findOne: jest.fn(),\n create: jest.fn(),\n updateOne: jest.fn(),\n },\n gameHistoryRecordRepository: {\n find: jest.fn(),\n create: jest.fn(),\n },\n gameHistoryRecordService: {\n getLastGameHistoryDefenderProtectsRecord: jest.fn(),\n getLastGameHistoryTieInVotesRecord: jest.fn(),\n getGameHistoryWitchUsesSpecificPotionRecords: jest.fn(),\n getLastGameHistoryAccursedWolfFatherInfectsRecord: jest.fn(),\n getGameHistoryStutteringJudgeRequestsAnotherVoteRecords: jest.fn(),\n didJudgeMakeHisSign: jest.fn(),\n },\n gamePlayHelper: {\n isPlayerInteractableInCurrentGamePlay: jest.spyOn(GamePlayHelper, \"isPlayerInteractableInCurrentGamePlay\").mockImplementation(),\n isPlayerInteractableWithInteractionTypeInCurrentGamePlay: jest.spyOn(GamePlayHelper, \"isPlayerInteractableWithInteractionTypeInCurrentGamePlay\").mockImplementation(),\n },\n unexpectedExceptionFactory: {\n createNoCurrentGamePlayUnexpectedException: jest.spyOn(UnexpectedExceptionFactory, \"createNoCurrentGamePlayUnexpectedException\").mockImplementation(),\n createCantFindPlayerWithCurrentRoleUnexpectedException: jest.spyOn(UnexpectedExceptionFactory, \"createCantFindPlayerWithCurrentRoleUnexpectedException\").mockImplementation(),\n },\n };\n\n const module: TestingModule = await Test.createTestingModule({\n providers: [\n {\n provide: GameHistoryRecordService,\n useValue: mocks.gameHistoryRecordService,\n },\n {\n provide: GameRepository,\n useValue: mocks.gameRepository,\n },\n {\n provide: GameHistoryRecordRepository,\n useValue: mocks.gameHistoryRecordRepository,\n },\n GamePlayValidatorService,\n ],\n }).compile();\n\n services = { gamePlayValidator: module.get(GamePlayValidatorService) };\n });\n\n describe(\"validateGamePlayWithRelationsDto\", () => {\n beforeEach(() => {\n mocks.gamePlayValidatorService.validateGamePlayWithRelationsDtoJudgeRequest = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayWithRelationsDtoJudgeRequest }, \"validateGamePlayWithRelationsDtoJudgeRequest\").mockImplementation();\n mocks.gamePlayValidatorService.validateGamePlayWithRelationsDtoChosenSide = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayWithRelationsDtoChosenSide }, \"validateGamePlayWithRelationsDtoChosenSide\").mockImplementation();\n mocks.gamePlayValidatorService.validateGamePlayVotesWithRelationsDto = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayVotesWithRelationsDto }, \"validateGamePlayVotesWithRelationsDto\").mockImplementation();\n mocks.gamePlayValidatorService.validateGamePlayTargetsWithRelationsDto = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayTargetsWithRelationsDto }, \"validateGamePlayTargetsWithRelationsDto\").mockImplementation();\n mocks.gamePlayValidatorService.validateGamePlayWithRelationsDtoChosenCard = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayWithRelationsDtoChosenCard }, \"validateGamePlayWithRelationsDtoChosenCard\").mockImplementation();\n });\n\n it(\"should throw error when game's current play is not set.\", async() => {\n const game = createFakeGame();\n const makeGamePlayWithRelationsDto = createFakeMakeGamePlayWithRelationsDto({ doesJudgeRequestAnotherVote: true });\n const interpolations = { gameId: game._id };\n const mockedError = new UnexpectedException(\"validateGamePlayWithRelationsDto\", UnexpectedExceptionReasons.NO_CURRENT_GAME_PLAY, { gameId: game._id.toString() });\n mocks.unexpectedExceptionFactory.createNoCurrentGamePlayUnexpectedException.mockReturnValue(mockedError);\n\n await expect(services.gamePlayValidator.validateGamePlayWithRelationsDto(makeGamePlayWithRelationsDto, game)).rejects.toStrictEqual(mockedError);\n expect(mocks.unexpectedExceptionFactory.createNoCurrentGamePlayUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"validateGamePlayWithRelationsDto\", interpolations);\n });\n\n it(\"should call validators when called.\", async() => {\n const game = createFakeGame({ currentPlay: createFakeGamePlaySurvivorsVote() });\n const makeGamePlayWithRelationsDto = createFakeMakeGamePlayWithRelationsDto({ doesJudgeRequestAnotherVote: true });\n await services.gamePlayValidator.validateGamePlayWithRelationsDto(makeGamePlayWithRelationsDto, game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlayWithRelationsDtoJudgeRequest).toHaveBeenCalledOnce();\n expect(mocks.gamePlayValidatorService.validateGamePlayWithRelationsDtoChosenSide).toHaveBeenCalledOnce();\n expect(mocks.gamePlayValidatorService.validateGamePlayVotesWithRelationsDto).toHaveBeenCalledOnce();\n expect(mocks.gamePlayValidatorService.validateGamePlayTargetsWithRelationsDto).toHaveBeenCalledOnce();\n expect(mocks.gamePlayValidatorService.validateGamePlayWithRelationsDtoChosenCard).toHaveBeenCalledOnce();\n });\n });\n\n describe(\"validateGamePlayActorChosenCard\", () => {\n it(\"should do nothing when game additional cards are not set.\", () => {\n const chosenCard = createFakeGameAdditionalCard({ isUsed: true });\n const game = createFakeGameWithCurrentPlay();\n\n expect(() => services.gamePlayValidator[\"validateGamePlayActorChosenCard\"](chosenCard, game)).not.toThrow();\n });\n\n it(\"should do nothing when chosen card is not defined.\", () => {\n const chosenCard = undefined;\n const additionalCards = [\n createFakeGameAdditionalCard({ roleName: \"werewolf\", recipient: \"actor\", isUsed: false }),\n createFakeGameAdditionalCard({ roleName: \"white-werewolf\", recipient: \"actor\", isUsed: false }),\n ];\n const game = createFakeGameWithCurrentPlay({ additionalCards });\n\n expect(() => services.gamePlayValidator[\"validateGamePlayActorChosenCard\"](chosenCard, game)).not.toThrow();\n });\n\n it(\"should do nothing when chosen card is for actor.\", () => {\n const chosenCard = createFakeGameAdditionalCard({ roleName: \"white-werewolf\", recipient: \"actor\", isUsed: false });\n const additionalCards = [\n createFakeGameAdditionalCard({ roleName: \"werewolf\", recipient: \"actor\", isUsed: false }),\n createFakeGameAdditionalCard({ roleName: \"white-werewolf\", recipient: \"actor\", isUsed: false }),\n ];\n const game = createFakeGameWithCurrentPlay({ additionalCards });\n\n expect(() => services.gamePlayValidator[\"validateGamePlayActorChosenCard\"](chosenCard, game)).not.toThrow();\n });\n\n it(\"should throw an error when chosen card is not for the actor.\", async() => {\n const chosenCard = createFakeGameAdditionalCard({ roleName: \"werewolf\", recipient: \"thief\", isUsed: false });\n const additionalCards = [\n createFakeGameAdditionalCard({ roleName: \"werewolf\", recipient: \"actor\", isUsed: false }),\n createFakeGameAdditionalCard({ roleName: \"white-werewolf\", recipient: \"actor\", isUsed: false }),\n ];\n const game = createFakeGameWithCurrentPlay({ additionalCards });\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.CHOSEN_CARD_NOT_FOR_ACTOR);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayActorChosenCard\"](chosenCard, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Chosen card is not for actor\" });\n });\n\n it(\"should throw an error when chosen card is already used.\", async() => {\n const chosenCard = createFakeGameAdditionalCard({ roleName: \"werewolf\", recipient: \"actor\", isUsed: true });\n const additionalCards = [\n createFakeGameAdditionalCard({ roleName: \"werewolf\", recipient: \"actor\", isUsed: false }),\n createFakeGameAdditionalCard({ roleName: \"white-werewolf\", recipient: \"actor\", isUsed: false }),\n ];\n const game = createFakeGameWithCurrentPlay({ additionalCards });\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.CHOSEN_CARD_NOT_FOR_ACTOR);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayActorChosenCard\"](chosenCard, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Chosen card is already used\" });\n });\n });\n\n describe(\"validateGamePlayThiefChosenCard\", () => {\n it(\"should do nothing when game additional cards are not set.\", () => {\n const chosenCard = createFakeGameAdditionalCard({ recipient: \"actor\" });\n const currentPlay = createFakeGamePlayThiefChoosesCard({ canBeSkipped: false });\n const game = createFakeGameWithCurrentPlay({ currentPlay });\n\n expect(() => services.gamePlayValidator[\"validateGamePlayThiefChosenCard\"](chosenCard, game)).not.toThrow();\n });\n\n it(\"should do nothing when thief didn't choose a card but he can skip.\", () => {\n const chosenCard = undefined;\n const currentPlay = createFakeGamePlayThiefChoosesCard({ canBeSkipped: true });\n const additionalCards = [\n createFakeGameAdditionalCard({ roleName: \"werewolf\", recipient: \"thief\" }),\n createFakeGameAdditionalCard({ roleName: \"seer\", recipient: \"thief\" }),\n ];\n const game = createFakeGameWithCurrentPlay({ additionalCards, currentPlay });\n\n expect(() => services.gamePlayValidator[\"validateGamePlayThiefChosenCard\"](chosenCard, game)).not.toThrow();\n });\n\n it(\"should do nothing when thief chose a card for him.\", () => {\n const chosenCard = createFakeGameAdditionalCard({ recipient: \"thief\" });\n const currentPlay = createFakeGamePlayThiefChoosesCard({ canBeSkipped: false });\n const additionalCards = [\n createFakeGameAdditionalCard({ roleName: \"werewolf\", recipient: \"thief\" }),\n createFakeGameAdditionalCard({ roleName: \"white-werewolf\", recipient: \"thief\" }),\n ];\n const game = createFakeGameWithCurrentPlay({ additionalCards, currentPlay });\n\n expect(() => services.gamePlayValidator[\"validateGamePlayThiefChosenCard\"](chosenCard, game)).not.toThrow();\n });\n\n it(\"should throw error when thief can't skip and he didn't choose a card.\", async() => {\n const chosenCard = undefined;\n const additionalCards = [\n createFakeGameAdditionalCard({ roleName: \"werewolf\", recipient: \"thief\" }),\n createFakeGameAdditionalCard({ roleName: \"white-werewolf\", recipient: \"thief\" }),\n ];\n const currentPlay = createFakeGamePlayThiefChoosesCard({ canBeSkipped: false });\n const game = createFakeGameWithCurrentPlay({ additionalCards, currentPlay });\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.THIEF_MUST_CHOOSE_CARD);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayThiefChosenCard\"](chosenCard, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Thief must choose a card (`chosenCard`)\" });\n });\n\n it(\"should throw error when chosen card is not for thief.\", async() => {\n const chosenCard = createFakeGameAdditionalCard({ roleName: \"werewolf\", recipient: \"actor\" });\n const additionalCards = [\n createFakeGameAdditionalCard({ roleName: \"werewolf\", recipient: \"thief\" }),\n createFakeGameAdditionalCard({ roleName: \"white-werewolf\", recipient: \"thief\" }),\n ];\n const currentPlay = createFakeGamePlayThiefChoosesCard({ canBeSkipped: true });\n const game = createFakeGameWithCurrentPlay({ additionalCards, currentPlay });\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.CHOSEN_CARD_NOT_FOR_THIEF);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayThiefChosenCard\"](chosenCard, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Chosen card is not for thief\" });\n });\n });\n\n describe(\"validateGamePlayWithRelationsDtoChosenCard\", () => {\n beforeEach(() => {\n mocks.gamePlayValidatorService.validateGamePlayThiefChosenCard = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayThiefChosenCard }, \"validateGamePlayThiefChosenCard\").mockImplementation();\n mocks.gamePlayValidatorService.validateGamePlayActorChosenCard = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayActorChosenCard }, \"validateGamePlayActorChosenCard\").mockImplementation();\n });\n\n it(\"should do nothing when chosen card is not defined and not expected.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWolfHoundChoosesSide() });\n const makeGamePlayWithRelationsDto = createFakeMakeGamePlayWithRelationsDto();\n\n expect(() => services.gamePlayValidator[\"validateGamePlayWithRelationsDtoChosenCard\"](makeGamePlayWithRelationsDto, game)).not.toThrow();\n });\n\n it(\"should throw error when chosen card is defined but not expected.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWolfHoundChoosesSide() });\n const makeGamePlayWithRelationsDto = createFakeMakeGamePlayWithRelationsDto({ chosenCard: createFakeGameAdditionalCard() });\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.UNEXPECTED_CHOSEN_CARD);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayWithRelationsDtoChosenCard\"](makeGamePlayWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"`chosenCard` can't be set on this current game's state\" });\n });\n\n it(\"should call validateGamePlayThiefChosenCard method when action is choose card and source is thief.\", () => {\n const chosenCard = createFakeGameAdditionalCard();\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayThiefChoosesCard() });\n const makeGamePlayWithRelationsDto = createFakeMakeGamePlayWithRelationsDto({ chosenCard });\n services.gamePlayValidator[\"validateGamePlayWithRelationsDtoChosenCard\"](makeGamePlayWithRelationsDto, game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlayThiefChosenCard).toHaveBeenCalledExactlyOnceWith(chosenCard, game);\n });\n\n it(\"should call validateGamePlayActorChosenCard method when action is choose card and source is actor.\", () => {\n const chosenCard = createFakeGameAdditionalCard();\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayActorChoosesCard() });\n const makeGamePlayWithRelationsDto = createFakeMakeGamePlayWithRelationsDto({ chosenCard });\n services.gamePlayValidator[\"validateGamePlayWithRelationsDtoChosenCard\"](makeGamePlayWithRelationsDto, game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlayActorChosenCard).toHaveBeenCalledExactlyOnceWith(chosenCard, game);\n });\n\n it(\"should not call neither thief or actor validation methods when game source is any of them.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWolfHoundChoosesSide({ action: \"choose-card\" }) });\n const makeGamePlayWithRelationsDto = createFakeMakeGamePlayWithRelationsDto();\n services.gamePlayValidator[\"validateGamePlayWithRelationsDtoChosenCard\"](makeGamePlayWithRelationsDto, game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlayThiefChosenCard).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayActorChosenCard).not.toHaveBeenCalled();\n });\n });\n\n describe(\"validateGamePlaySurvivorsTargets\", () => {\n beforeEach(() => {\n mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayTargetsBoundaries }, \"validateGamePlayTargetsBoundaries\").mockImplementation();\n });\n\n it(\"should do nothing when game's current play action is not bury dead bodies.\", () => {\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer({ isAlive: false }) })];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsVote() });\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n\n expect(() => services.gamePlayValidator[\"validateGamePlaySurvivorsTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n\n it(\"should validate targets boundaries when game's current play action is bury dead bodies.\", () => {\n const players = [\n createFakeDevotedServantAlivePlayer(),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer(),\n ];\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer({ isAlive: false }) })];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsBuryDeadBodies(), players });\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n services.gamePlayValidator[\"validateGamePlaySurvivorsTargets\"](makeGamePlayTargetsWithRelationsDto, game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries).toHaveBeenCalledExactlyOnceWith(makeGamePlayTargetsWithRelationsDto, \"steal-role\", game);\n });\n\n it(\"should do nothing when there is no target.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsBuryDeadBodies() });\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n\n expect(() => services.gamePlayValidator[\"validateGamePlaySurvivorsTargets\"]([], game)).not.toThrow();\n });\n\n it(\"should throw error when there is a target but no devoted servant in the game.\", async() => {\n const players = [\n createFakeDevotedServantAlivePlayer({ isAlive: false }),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer(),\n ];\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer({ isAlive: false }) })];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsBuryDeadBodies(), players });\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.DEVOTED_SERVANT_CANT_STEAL_ROLE);\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlaySurvivorsTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Devoted servant can't steal the role of this target because she's not in the game or dead or powerless or in love with another player\" });\n });\n\n it(\"should throw error when there is a target but the devoted servant is dead.\", async() => {\n const players = [\n createFakeDevotedServantAlivePlayer({ isAlive: false }),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer(),\n ];\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer({ isAlive: false }) })];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsBuryDeadBodies(), players });\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.DEVOTED_SERVANT_CANT_STEAL_ROLE);\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlaySurvivorsTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Devoted servant can't steal the role of this target because she's not in the game or dead or powerless or in love with another player\" });\n });\n\n it(\"should throw error when there is a target but devoted servant is powerless.\", async() => {\n const players = [\n createFakeDevotedServantAlivePlayer({ attributes: [createFakePowerlessByElderPlayerAttribute()] }),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer(),\n ];\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer({ isAlive: false }) })];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsBuryDeadBodies(), players });\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.DEVOTED_SERVANT_CANT_STEAL_ROLE);\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlaySurvivorsTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Devoted servant can't steal the role of this target because she's not in the game or dead or powerless or in love with another player\" });\n });\n\n it(\"should throw error when there is a target but devoted servant is in-love.\", async() => {\n const players = [\n createFakeDevotedServantAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer(),\n ];\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer({ isAlive: false }) })];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsBuryDeadBodies(), players });\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.DEVOTED_SERVANT_CANT_STEAL_ROLE);\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlaySurvivorsTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Devoted servant can't steal the role of this target because she's not in the game or dead or powerless or in love with another player\" });\n });\n\n it(\"should throw error when there is a target but he can't be interacted with the devoted servant.\", async() => {\n const players = [\n createFakeDevotedServantAlivePlayer(),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer(),\n ];\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer({ isAlive: false }) })];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsBuryDeadBodies(), players });\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_DEVOTED_SERVANT_TARGET);\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlaySurvivorsTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Devoted servant can't steal the role of this target because he's not about to be buried\" });\n });\n\n it(\"should do nothing when target is valid for devoted servant.\", () => {\n const players = [\n createFakeDevotedServantAlivePlayer(),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer(),\n ];\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer({ isAlive: false }) })];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsBuryDeadBodies(), players });\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n\n expect(() => services.gamePlayValidator[\"validateGamePlaySurvivorsTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n });\n\n describe(\"validateDrankLifePotionTargets\", () => {\n it(\"should throw error when there are too much targets for life potion.\", async() => {\n const game = createFakeGameWithCurrentPlay();\n const drankLifePotionTargets = [\n createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"life\" }),\n createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"life\" }),\n ];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.TOO_MUCH_DRANK_LIFE_POTION_TARGETS);\n const error = await getError(() => services.gamePlayValidator[\"validateDrankLifePotionTargets\"](drankLifePotionTargets, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"There are too much targets which drank life potion (`targets.drankPotion`)\" });\n });\n\n it(\"should throw error when life potion target can't drink it.\", async() => {\n const game = createFakeGameWithCurrentPlay();\n const targetedPlayer = createFakePlayer({ isAlive: true, attributes: [] });\n const drankLifePotionTargets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: targetedPlayer, drankPotion: \"life\" })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_LIFE_POTION_TARGET);\n const error = await getError(() => services.gamePlayValidator[\"validateDrankLifePotionTargets\"](drankLifePotionTargets, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Life potion can't be applied to this target (`targets.drankPotion`)\" });\n });\n\n it(\"should do nothing when there is no life potion target.\", () => {\n const game = createFakeGameWithCurrentPlay();\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n\n expect(() => services.gamePlayValidator[\"validateDrankLifePotionTargets\"]([], game)).not.toThrow();\n });\n\n it(\"should do nothing when life potion target is applied on valid target.\", () => {\n const game = createFakeGameWithCurrentPlay();\n const targetedPlayer = createFakePlayer({ attributes: [createFakeEatenByWerewolvesPlayerAttribute()], isAlive: true });\n const drankLifePotionTargets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: targetedPlayer, drankPotion: \"life\" })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n\n expect(() => services.gamePlayValidator[\"validateDrankLifePotionTargets\"](drankLifePotionTargets, game)).not.toThrow();\n });\n });\n\n describe(\"validateDrankDeathPotionTargets\", () => {\n it(\"should throw error when there are too much targets for death potion.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWitchUsesPotions() });\n const drankDeathPotionTargets = [\n createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"death\" }),\n createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"death\" }),\n ];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.TOO_MUCH_DRANK_DEATH_POTION_TARGETS);\n const error = await getError(() => services.gamePlayValidator[\"validateDrankDeathPotionTargets\"](drankDeathPotionTargets, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"There are too much targets which drank death potion (`targets.drankPotion`)\" });\n });\n\n it(\"should throw error when death potion target can't drink it.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWitchUsesPotions() });\n const targetedPlayer = createFakePlayer({ isAlive: false });\n const drankDeathPotionTargets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: targetedPlayer, drankPotion: \"death\" })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_DEATH_POTION_TARGET);\n const error = await getError(() => services.gamePlayValidator[\"validateDrankDeathPotionTargets\"](drankDeathPotionTargets, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Death potion can't be applied to this target (`targets.drankPotion`)\" });\n });\n\n it(\"should do nothing when there is no death potion target.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWitchUsesPotions() });\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n\n expect(() => services.gamePlayValidator[\"validateDrankDeathPotionTargets\"]([], game)).not.toThrow();\n });\n\n it(\"should do nothing when death potion target is applied on valid target.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWitchUsesPotions() });\n const targetedPlayer = createFakePlayer({ isAlive: true });\n const drankDeathPotionTargets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: targetedPlayer, drankPotion: \"death\" })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n\n expect(() => services.gamePlayValidator[\"validateDrankDeathPotionTargets\"](drankDeathPotionTargets, game)).not.toThrow();\n });\n });\n\n describe(\"validateGamePlayWitchTargets\", () => {\n beforeEach(() => {\n mocks.gamePlayValidatorService.validateDrankLifePotionTargets = jest.spyOn(services.gamePlayValidator as unknown as { validateDrankLifePotionTargets }, \"validateDrankLifePotionTargets\").mockImplementation();\n mocks.gamePlayValidatorService.validateDrankDeathPotionTargets = jest.spyOn(services.gamePlayValidator as unknown as { validateDrankDeathPotionTargets }, \"validateDrankDeathPotionTargets\").mockImplementation();\n });\n\n it(\"should throw error when witch is not in the game.\", async() => {\n const players = [\n createFakeIdiotAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlayWitchUsesPotions() });\n const makeGamePlayTargetsWithRelationsDto = [\n createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"life\" }),\n createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"death\" }),\n ];\n const mockedError = new UnexpectedException(\"validateGamePlayWitchTargets\", UnexpectedExceptionReasons.CANT_FIND_PLAYER_WITH_CURRENT_ROLE_IN_GAME, { gameId: game._id.toString(), roleName: \"witch\" });\n mocks.unexpectedExceptionFactory.createCantFindPlayerWithCurrentRoleUnexpectedException.mockReturnValue(mockedError);\n\n await expect(services.gamePlayValidator[\"validateGamePlayWitchTargets\"](makeGamePlayTargetsWithRelationsDto, game)).rejects.toStrictEqual(mockedError);\n expect(mocks.unexpectedExceptionFactory.createCantFindPlayerWithCurrentRoleUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"validateGamePlayWitchTargets\", { gameId: game._id, roleName: \"witch\" });\n });\n\n it(\"should throw error when witch targeted someone with life potion but already used it with death potion before.\", async() => {\n const players = [\n createFakeWitchAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlayWitchUsesPotions() });\n const makeGamePlayTargetsWithRelationsDto = [\n createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"life\" }),\n createFakeMakeGamePlayTargetWithRelationsDto(),\n ];\n const gameHistoryRecordTargets = [\n createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"death\" }),\n createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"life\" }),\n ];\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ play: createFakeGameHistoryRecordSurvivorsVotePlay() }),\n createFakeGameHistoryRecord({ play: createFakeGameHistoryRecordWitchUsePotionsPlay({ targets: gameHistoryRecordTargets }) }),\n ];\n when(mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords).calledWith(game._id, players[0]._id, \"life\").mockResolvedValue(gameHistoryRecords);\n when(mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords).calledWith(game._id, players[0]._id, \"death\").mockResolvedValue(gameHistoryRecords);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.UNEXPECTED_DRANK_POTION_TARGET);\n const error = await getError(async() => services.gamePlayValidator[\"validateGamePlayWitchTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"`targets.drankPotion` can't be set on this current game's state\" });\n });\n\n it(\"should throw error when witch targeted someone with life potion but already used it alone before.\", async() => {\n const players = [\n createFakeWitchAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlayWitchUsesPotions() });\n const makeGamePlayTargetsWithRelationsDto = [\n createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"life\" }),\n createFakeMakeGamePlayTargetWithRelationsDto({}),\n ];\n const gameHistoryRecordTargets = [createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"life\" })];\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ play: createFakeGameHistoryRecordSurvivorsVotePlay() }),\n createFakeGameHistoryRecord({ play: createFakeGameHistoryRecordWitchUsePotionsPlay({ targets: gameHistoryRecordTargets }) }),\n ];\n when(mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords).calledWith(game._id, players[0]._id, \"life\").mockResolvedValue(gameHistoryRecords);\n when(mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords).calledWith(game._id, players[0]._id, \"death\").mockResolvedValue([]);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.UNEXPECTED_DRANK_POTION_TARGET);\n const error = await getError(async() => services.gamePlayValidator[\"validateGamePlayWitchTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"`targets.drankPotion` can't be set on this current game's state\" });\n });\n\n it(\"should throw error when witch targeted someone with death potion but already used it with life potion before.\", async() => {\n const players = [\n createFakeWitchAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlayWitchUsesPotions() });\n const makeGamePlayTargetsWithRelationsDto = [\n createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"death\" }),\n createFakeMakeGamePlayTargetWithRelationsDto(),\n ];\n const gameHistoryRecordTargets = [\n createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"death\" }),\n createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"life\" }),\n ];\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ play: createFakeGameHistoryRecordSurvivorsVotePlay() }),\n createFakeGameHistoryRecord({ play: createFakeGameHistoryRecordWitchUsePotionsPlay({ targets: gameHistoryRecordTargets }) }),\n ];\n when(mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords).calledWith(game._id, players[0]._id, \"life\").mockResolvedValue(gameHistoryRecords);\n when(mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords).calledWith(game._id, players[0]._id, \"death\").mockResolvedValue(gameHistoryRecords);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.UNEXPECTED_DRANK_POTION_TARGET);\n const error = await getError(async() => services.gamePlayValidator[\"validateGamePlayWitchTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"`targets.drankPotion` can't be set on this current game's state\" });\n });\n\n it(\"should throw error when witch targeted someone with death potion but already used it alone before.\", async() => {\n const players = [\n createFakeWitchAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlayWitchUsesPotions() });\n const makeGamePlayTargetsWithRelationsDto = [\n createFakeMakeGamePlayTargetWithRelationsDto({ player: game.players[1], drankPotion: \"death\" }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: game.players[2] }),\n ];\n const gameHistoryRecordTargets = [createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"death\" })];\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ play: createFakeGameHistoryRecordSurvivorsVotePlay() }),\n createFakeGameHistoryRecord({ play: createFakeGameHistoryRecordWitchUsePotionsPlay({ targets: gameHistoryRecordTargets }) }),\n ];\n when(mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords).calledWith(game._id, players[0]._id, \"life\").mockResolvedValue([]);\n when(mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords).calledWith(game._id, players[0]._id, \"death\").mockResolvedValue(gameHistoryRecords);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.UNEXPECTED_DRANK_POTION_TARGET);\n const error = await getError(async() => services.gamePlayValidator[\"validateGamePlayWitchTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"`targets.drankPotion` can't be set on this current game's state\" });\n });\n\n it(\"should call potions validators without players when called with valid data but no target drank potions.\", async() => {\n const players = [\n createFakeWitchAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlayWitchUsesPotions() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeSeerAlivePlayer() })];\n when(mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords).calledWith(game._id, players[0]._id, \"life\").mockResolvedValue([]);\n when(mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords).calledWith(game._id, players[0]._id, \"death\").mockResolvedValue([]);\n\n await expect(services.gamePlayValidator[\"validateGamePlayWitchTargets\"](makeGamePlayTargetsWithRelationsDto, game)).toResolve();\n expect(mocks.gamePlayValidatorService.validateDrankLifePotionTargets).toHaveBeenCalledExactlyOnceWith([], game);\n expect(mocks.gamePlayValidatorService.validateDrankDeathPotionTargets).toHaveBeenCalledExactlyOnceWith([], game);\n });\n\n it(\"should call potions validators with players when called without bad data and without witch history.\", async() => {\n const players = [\n createFakeWitchAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlayWitchUsesPotions() });\n const makeGamePlayTargetsWithRelationsDto = [\n createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"life\" }),\n createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"death\" }),\n ];\n when(mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords).calledWith(game._id, players[0]._id, \"life\").mockResolvedValue([]);\n when(mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords).calledWith(game._id, players[0]._id, \"death\").mockResolvedValue([]);\n\n await expect(services.gamePlayValidator[\"validateGamePlayWitchTargets\"](makeGamePlayTargetsWithRelationsDto, game)).toResolve();\n expect(mocks.gamePlayValidatorService.validateDrankLifePotionTargets).toHaveBeenCalledExactlyOnceWith([makeGamePlayTargetsWithRelationsDto[0]], game);\n expect(mocks.gamePlayValidatorService.validateDrankDeathPotionTargets).toHaveBeenCalledExactlyOnceWith([makeGamePlayTargetsWithRelationsDto[1]], game);\n });\n\n it(\"should call potions validators with players when called for valid life potion data and some witch history.\", async() => {\n const players = [\n createFakeWitchAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlayWitchUsesPotions() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"life\" })];\n const gameHistoryRecordTargets = [createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"death\" })];\n const gameHistoryRecords = [createFakeGameHistoryRecord({ play: createFakeGameHistoryRecordWitchUsePotionsPlay({ targets: gameHistoryRecordTargets }) })];\n when(mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords).calledWith(game._id, players[0]._id, \"life\").mockReturnValue([]);\n when(mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords).calledWith(game._id, players[0]._id, \"death\").mockResolvedValue(gameHistoryRecords);\n\n await expect(services.gamePlayValidator[\"validateGamePlayWitchTargets\"](makeGamePlayTargetsWithRelationsDto, game)).toResolve();\n expect(mocks.gamePlayValidatorService.validateDrankLifePotionTargets).toHaveBeenCalledExactlyOnceWith([makeGamePlayTargetsWithRelationsDto[0]], game);\n expect(mocks.gamePlayValidatorService.validateDrankDeathPotionTargets).toHaveBeenCalledExactlyOnceWith([], game);\n });\n\n it(\"should call potions validators with players when called for valid death potion data and some witch history.\", async() => {\n const players = [\n createFakeWitchAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlayWitchUsesPotions() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"death\" })];\n const gameHistoryRecordTargets = [createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"life\" })];\n const gameHistoryRecords = [createFakeGameHistoryRecord({ play: createFakeGameHistoryRecordWitchUsePotionsPlay({ targets: gameHistoryRecordTargets }) })];\n when(mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords).calledWith(game._id, players[0]._id, \"life\").mockResolvedValue(gameHistoryRecords);\n when(mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords).calledWith(game._id, players[0]._id, \"death\").mockResolvedValue([]);\n\n await expect(services.gamePlayValidator[\"validateGamePlayWitchTargets\"](makeGamePlayTargetsWithRelationsDto, game)).toResolve();\n expect(mocks.gamePlayValidatorService.validateDrankLifePotionTargets).toHaveBeenCalledExactlyOnceWith([], game);\n expect(mocks.gamePlayValidatorService.validateDrankDeathPotionTargets).toHaveBeenCalledExactlyOnceWith([makeGamePlayTargetsWithRelationsDto[0]], game);\n });\n });\n\n describe(\"validateGamePlayAccursedWolfFatherTargets\", () => {\n beforeEach(() => {\n mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayTargetsBoundaries }, \"validateGamePlayTargetsBoundaries\").mockImplementation();\n });\n\n it(\"should call validateGamePlayTargetsBoundaries when called.\", () => {\n const players = [\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWerewolvesEat(), players });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: game.players[0] })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n services.gamePlayValidator[\"validateGamePlayAccursedWolfFatherTargets\"](makeGamePlayTargetsWithRelationsDto, game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries).toHaveBeenCalledExactlyOnceWith(makeGamePlayTargetsWithRelationsDto, \"infect\", game);\n });\n\n it(\"should do nothing when there is no target.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayAccursedWolfFatherInfects() });\n const makeGamePlayTargetsWithRelationsDto = [];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n\n expect(() => services.gamePlayValidator[\"validateGamePlayAccursedWolfFatherTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n\n it(\"should throw error when there is a target but he can't be interacted with the accursed wolf father.\", async() => {\n const players = [\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWerewolvesEat(), players });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: game.players[1] })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_ACCURSED_WOLF_FATHER_TARGET);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayAccursedWolfFatherTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Accursed Wolf-father can't infect this target\" });\n });\n\n it(\"should do nothing when target is valid for accursed wolf father.\", () => {\n const players = [\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWerewolvesEat(), players });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: game.players[0] })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n\n expect(() => services.gamePlayValidator[\"validateGamePlayAccursedWolfFatherTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n });\n\n describe(\"validateGamePlayWerewolvesTargets\", () => {\n beforeEach(() => {\n mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayTargetsBoundaries }, \"validateGamePlayTargetsBoundaries\").mockImplementation();\n });\n\n it(\"should call validateGamePlayTargetsBoundaries when called.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayAccursedWolfFatherInfects() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto()];\n services.gamePlayValidator[\"validateGamePlayWerewolvesTargets\"](makeGamePlayTargetsWithRelationsDto, game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries).toHaveBeenCalledExactlyOnceWith(makeGamePlayTargetsWithRelationsDto, \"eat\", game);\n });\n\n it(\"should do nothing when there is no target.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWerewolvesEat() });\n const makeGamePlayTargetsWithRelationsDto = [];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n\n expect(() => services.gamePlayValidator[\"validateGamePlayWerewolvesTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n\n it(\"should do nothing when game's current play action is not werewolves eat.\", () => {\n const players = [\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySeerLooks(), players });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: game.players[1] })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n\n expect(() => services.gamePlayValidator[\"validateGamePlayWerewolvesTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n\n it(\"should throw error when source are werewolves and targeted player can't be eaten by them.\", async() => {\n const players = [\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWerewolvesEat(), players });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: game.players[1] })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_WEREWOLVES_TARGET);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayWerewolvesTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Werewolves can't eat this target\" });\n });\n\n it(\"should throw error when source is big bad wolf and targeted player can't be eaten by him.\", async() => {\n const players = [\n createFakeVillagerAlivePlayer({ attributes: [createFakeEatenByWerewolvesPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayBigBadWolfEats(), players });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: game.players[0] })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_BIG_BAD_WOLF_TARGET);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayWerewolvesTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Big bad wolf can't eat this target\" });\n });\n\n it(\"should throw error when source is white werewolf and targeted player can't be eaten by him.\", async() => {\n const whiteWerewolfPlayer = createFakeWhiteWerewolfAlivePlayer();\n const players = [\n whiteWerewolfPlayer,\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWhiteWerewolfEats(), players });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: whiteWerewolfPlayer })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_ACCURSED_WOLF_FATHER_TARGET);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayWerewolvesTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"White werewolf can't eat this target\" });\n });\n\n it(\"should do nothing when white werewolf eaten target is valid.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWhiteWerewolfEats(), players });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[0] })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n\n expect(() => services.gamePlayValidator[\"validateGamePlayWerewolvesTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n\n it(\"should do nothing when big bad wolf eaten target is valid.\", () => {\n const players = [createFakeVillagerAlivePlayer()];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayBigBadWolfEats(), players });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[0] })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n\n expect(() => services.gamePlayValidator[\"validateGamePlayWerewolvesTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n\n it(\"should do nothing when werewolves eaten target is valid.\", () => {\n const players = [createFakeVillagerAlivePlayer()];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWerewolvesEat(), players });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[0] })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n\n expect(() => services.gamePlayValidator[\"validateGamePlayWerewolvesTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n });\n\n describe(\"validateGamePlayHunterTargets\", () => {\n beforeEach(() => {\n mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayTargetsBoundaries }, \"validateGamePlayTargetsBoundaries\").mockImplementation();\n });\n\n it(\"should call validateGamePlayTargetsBoundaries when called.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayHunterShoots() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer() })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n services.gamePlayValidator[\"validateGamePlayHunterTargets\"](makeGamePlayTargetsWithRelationsDto, game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries).toHaveBeenCalledExactlyOnceWith(makeGamePlayTargetsWithRelationsDto, \"shoot\", game);\n });\n\n it(\"should throw error when targeted player can't be shot.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayHunterShoots() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer({ isAlive: false }) })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_HUNTER_TARGET);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayHunterTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Hunter can't shoot this target\" });\n });\n\n it(\"should do nothing when targeted player for hunter is valid.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayHunterShoots() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer() })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n\n expect(() => services.gamePlayValidator[\"validateGamePlayHunterTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n });\n\n describe(\"validateGamePlayScapeGoatTargets\", () => {\n beforeEach(() => {\n mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayTargetsBoundaries }, \"validateGamePlayTargetsBoundaries\").mockImplementation();\n });\n\n it(\"should call validateGamePlayTargetsBoundaries when called.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayScapegoatBansVoting() });\n const makeGamePlayTargetsWithRelationsDto = [\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer() }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer() }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeWerewolfAlivePlayer() }),\n ];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n services.gamePlayValidator[\"validateGamePlayScapegoatTargets\"](makeGamePlayTargetsWithRelationsDto, game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries).toHaveBeenCalledExactlyOnceWith(makeGamePlayTargetsWithRelationsDto, \"ban-voting\", game);\n });\n\n it(\"should throw error when one of the targeted player can't be banned from voting.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayScapegoatBansVoting() });\n const makeGamePlayTargetsWithRelationsDto = [\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer() }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer({ isAlive: false }) }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeWerewolfAlivePlayer() }),\n ];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValueOnce(true);\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValueOnce(false);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_SCAPEGOAT_TARGETS);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayScapegoatTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"At least one of the scapegoat targets can't be banned from voting\" });\n });\n\n it(\"should do nothing when all scapegoat's targets are valid.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayScapegoatBansVoting() });\n const makeGamePlayTargetsWithRelationsDto = [\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer() }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer() }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeWerewolfAlivePlayer() }),\n ];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n\n expect(() => services.gamePlayValidator[\"validateGamePlayScapegoatTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n });\n\n describe(\"validateGamePlayCupidTargets\", () => {\n beforeEach(() => {\n mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayTargetsBoundaries }, \"validateGamePlayTargetsBoundaries\").mockImplementation();\n });\n\n it(\"should call validateGamePlayTargetsBoundaries when called.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayCupidCharms() });\n const makeGamePlayTargetsWithRelationsDto = [\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer() }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer() }),\n ];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n services.gamePlayValidator[\"validateGamePlayCupidTargets\"](makeGamePlayTargetsWithRelationsDto, game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries).toHaveBeenCalledExactlyOnceWith(makeGamePlayTargetsWithRelationsDto, \"charm\", game);\n });\n\n it(\"should throw error when one of the targeted player can't be charmed.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayCupidCharms() });\n const makeGamePlayTargetsWithRelationsDto = [\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer() }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer({ isAlive: false }) }),\n ];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValueOnce(true);\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValueOnce(false);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_CUPID_TARGETS);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayCupidTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"At least one of the cupid targets can't be charmed\" });\n });\n\n it(\"should do nothing when all cupid's targets are valid.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayCupidCharms() });\n const makeGamePlayTargetsWithRelationsDto = [\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer() }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer() }),\n ];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n\n expect(() => services.gamePlayValidator[\"validateGamePlayCupidTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n });\n\n describe(\"validateGamePlayFoxTargets\", () => {\n beforeEach(() => {\n mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayTargetsBoundaries }, \"validateGamePlayTargetsBoundaries\").mockImplementation();\n });\n\n it(\"should call validateGamePlayTargetsBoundaries when called.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayFoxSniffs() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer() })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n services.gamePlayValidator[\"validateGamePlayFoxTargets\"](makeGamePlayTargetsWithRelationsDto, game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries).toHaveBeenCalledExactlyOnceWith(makeGamePlayTargetsWithRelationsDto, \"sniff\", game);\n });\n\n it(\"should do nothing when there are no targets.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayFoxSniffs() });\n const makeGamePlayTargetsWithRelationsDto = [];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n\n expect(() => services.gamePlayValidator[\"validateGamePlayFoxTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n\n it(\"should throw error when targeted player can't be sniffed.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayFoxSniffs() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer({ isAlive: false }) })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_FOX_TARGET);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayFoxTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Fox can't sniff this target\" });\n });\n\n it(\"should do nothing when targeted player for fox is valid.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayFoxSniffs() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer() })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n\n expect(() => services.gamePlayValidator[\"validateGamePlayFoxTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n });\n\n describe(\"validateGamePlaySeerTargets\", () => {\n beforeEach(() => {\n mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayTargetsBoundaries }, \"validateGamePlayTargetsBoundaries\").mockImplementation();\n });\n\n it(\"should call validateGamePlayTargetsBoundaries when called.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySeerLooks() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeWerewolfAlivePlayer() })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n services.gamePlayValidator[\"validateGamePlaySeerTargets\"](makeGamePlayTargetsWithRelationsDto, game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries).toHaveBeenCalledExactlyOnceWith(makeGamePlayTargetsWithRelationsDto, \"look\", game);\n });\n\n it(\"should throw error when targeted player can't be seen.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySeerLooks() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer({ isAlive: false }) })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_SEER_TARGET);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlaySeerTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Seer can't look at this target\" });\n });\n\n it(\"should do nothing when seer's targeted player is valid.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySeerLooks() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeWerewolfAlivePlayer() })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n\n expect(() => services.gamePlayValidator[\"validateGamePlaySeerTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n });\n\n describe(\"validateGamePlayScandalmongerTargets\", () => {\n beforeEach(() => {\n mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayTargetsBoundaries }, \"validateGamePlayTargetsBoundaries\").mockImplementation();\n });\n\n it(\"should call validateGamePlayTargetsBoundaries when called.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayScandalmongerMarks() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeWerewolfAlivePlayer() })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n services.gamePlayValidator[\"validateGamePlayScandalmongerTargets\"](makeGamePlayTargetsWithRelationsDto, game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries).toHaveBeenCalledExactlyOnceWith(makeGamePlayTargetsWithRelationsDto, \"mark\", game);\n });\n\n it(\"should throw error when targeted player can't be marked.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayScandalmongerMarks() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer({ isAlive: false }) })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_SCANDALMONGER_TARGET);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayScandalmongerTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Scandalmonger can't mark this target\" });\n });\n\n it(\"should do nothing when there are no targets.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayScandalmongerMarks() });\n const makeGamePlayTargetsWithRelationsDto = [];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n\n expect(() => services.gamePlayValidator[\"validateGamePlayScandalmongerTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n\n it(\"should do nothing when scandalmonger's target is valid.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayScandalmongerMarks() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeWerewolfAlivePlayer() })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n\n expect(() => services.gamePlayValidator[\"validateGamePlayScandalmongerTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n });\n\n describe(\"validateGamePlayWildChildTargets\", () => {\n beforeEach(() => {\n mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayTargetsBoundaries }, \"validateGamePlayTargetsBoundaries\").mockImplementation();\n });\n\n it(\"should call validateGamePlayTargetsBoundaries when called.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWildChildChoosesModel() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeWerewolfAlivePlayer() })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n services.gamePlayValidator[\"validateGamePlayWildChildTargets\"](makeGamePlayTargetsWithRelationsDto, game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries).toHaveBeenCalledExactlyOnceWith(makeGamePlayTargetsWithRelationsDto, \"choose-as-model\", game);\n });\n\n it(\"should throw error when targeted player can't be chosen as model.\", async() => {\n const wildChildPlayer = createFakeWildChildAlivePlayer();\n const players = [\n wildChildPlayer,\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWildChildChoosesModel(), players });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: wildChildPlayer })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_WILD_CHILD_TARGET);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayWildChildTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Wild child can't choose this target as a model\" });\n });\n\n it(\"should do nothing when wild child's targeted player is valid.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWildChildChoosesModel() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeWerewolfAlivePlayer() })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n\n expect(() => services.gamePlayValidator[\"validateGamePlayWildChildTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n });\n\n describe(\"validateGamePlayPiedPiperTargets\", () => {\n beforeEach(() => {\n mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayTargetsBoundaries }, \"validateGamePlayTargetsBoundaries\").mockImplementation();\n });\n\n it(\"should call validateGamePlayTargetsBoundaries when called.\", () => {\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ piedPiper: createFakePiedPiperGameOptions({ charmedPeopleCountPerNight: 5 }) }) });\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayPiedPiperCharms(), options });\n const leftToCharmPlayers = [createFakeWildChildAlivePlayer()];\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: leftToCharmPlayers[0] })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n services.gamePlayValidator[\"validateGamePlayPiedPiperTargets\"](makeGamePlayTargetsWithRelationsDto, game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries).toHaveBeenCalledExactlyOnceWith(makeGamePlayTargetsWithRelationsDto, \"charm\", game);\n });\n\n it(\"should throw error when one of the targeted player is not in the last to charm.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayPiedPiperCharms() });\n const leftToCharmPlayers = [\n createFakeWildChildAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const makeGamePlayTargetsWithRelationsDto = [\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer() }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: leftToCharmPlayers[0] }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: leftToCharmPlayers[1] }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: leftToCharmPlayers[2] }),\n ];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValueOnce(true);\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValueOnce(false);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_PIED_PIPER_TARGETS);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayPiedPiperTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"At least one of the pied piper targets can't be charmed\" });\n });\n\n it(\"should do nothing when pied piper targets are valid and limited to game options.\", () => {\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ piedPiper: createFakePiedPiperGameOptions({ charmedPeopleCountPerNight: 2 }) }) });\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayPiedPiperCharms(), options });\n const leftToCharmPlayers = [\n createFakeWildChildAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const makeGamePlayTargetsWithRelationsDto = [\n createFakeMakeGamePlayTargetWithRelationsDto({ player: leftToCharmPlayers[0] }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: leftToCharmPlayers[1] }),\n ];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n\n expect(() => services.gamePlayValidator[\"validateGamePlayPiedPiperTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n\n it(\"should do nothing when pied piper targets are valid and limited to left players to charm count.\", () => {\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ piedPiper: createFakePiedPiperGameOptions({ charmedPeopleCountPerNight: 5 }) }) });\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayPiedPiperCharms(), options });\n const leftToCharmPlayers = [createFakeWildChildAlivePlayer()];\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: leftToCharmPlayers[0] })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n\n expect(() => services.gamePlayValidator[\"validateGamePlayPiedPiperTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n });\n\n describe(\"validateGamePlayDefenderTargets\", () => {\n beforeEach(() => {\n mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayTargetsBoundaries }, \"validateGamePlayTargetsBoundaries\").mockImplementation();\n });\n\n it(\"should call validateGamePlayTargetsBoundaries when called.\", () => {\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ defender: { canProtectTwice: false } }) });\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayDefenderProtects(), options });\n const targetedPlayer = createFakeVillagerAlivePlayer();\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: targetedPlayer })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n services.gamePlayValidator[\"validateGamePlayDefenderTargets\"](makeGamePlayTargetsWithRelationsDto, game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries).toHaveBeenCalledExactlyOnceWith(makeGamePlayTargetsWithRelationsDto, \"protect\", game);\n });\n\n it(\"should throw error when targeted player can't be targeted.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayDefenderProtects() });\n const targetedPlayer = createFakeVillagerAlivePlayer({ isAlive: false });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: targetedPlayer })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_DEFENDER_TARGET);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayDefenderTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Defender can't protect this target\" });\n });\n\n it(\"should do nothing when targeted player can be protected.\", () => {\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ defender: { canProtectTwice: false } }) });\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayDefenderProtects(), options });\n const targetedPlayer = createFakeVillagerAlivePlayer();\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: targetedPlayer })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n\n expect(() => services.gamePlayValidator[\"validateGamePlayDefenderTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n });\n\n describe(\"validateGamePlaySheriffTargets\", () => {\n beforeEach(() => {\n mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayTargetsBoundaries }, \"validateGamePlayTargetsBoundaries\").mockImplementation();\n });\n\n it(\"should call validateGamePlayTargetsBoundaries when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlaySheriffDelegates() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: game.players[0] })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValueOnce(true);\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValueOnce(false);\n services.gamePlayValidator[\"validateGamePlaySheriffTargets\"](makeGamePlayTargetsWithRelationsDto, game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries).toHaveBeenNthCalledWith(1, makeGamePlayTargetsWithRelationsDto, \"transfer-sheriff-role\", game);\n expect(mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries).toHaveBeenNthCalledWith(2, makeGamePlayTargetsWithRelationsDto, \"sentence-to-death\", game);\n });\n\n it(\"should do nothing when game play action is not DELEGATE nor SETTLE_VOTES.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySheriffDelegates({ action: \"use-potions\" }) });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto()];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n\n expect(() => services.gamePlayValidator[\"validateGamePlaySheriffTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n\n it(\"should do nothing when targeted player for sheriff delegation is valid.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySheriffDelegates() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeSeerAlivePlayer() })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n\n expect(() => services.gamePlayValidator[\"validateGamePlaySheriffTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n\n it(\"should throw error when targeted player is not in last tie in votes and upcoming action is SETTLE_VOTES.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySheriffSettlesVotes() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer({ isAlive: false }) })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_SHERIFF_SETTLE_VOTES_TARGET);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlaySheriffTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Sheriff can't break the tie in votes with this target\" });\n });\n\n it(\"should throw error when targeted player is not in last tie in votes and upcoming action is DELEGATE.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySheriffDelegates() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer({ isAlive: false }) })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_SHERIFF_DELEGATE_TARGET);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlaySheriffTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Sheriff can't delegate his role to this target\" });\n });\n\n it(\"should do nothing when targeted player for sheriff settling votes is valid for delegate.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlaySheriffDelegates() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: game.players[0] })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValueOnce(true);\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValueOnce(false);\n\n expect(() => services.gamePlayValidator[\"validateGamePlaySheriffTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n\n it(\"should do nothing when targeted player for sheriff settling votes is valid for settle votes.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlaySheriffSettlesVotes() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: game.players[0] })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValueOnce(false);\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValueOnce(true);\n\n expect(() => services.gamePlayValidator[\"validateGamePlaySheriffTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n });\n\n describe(\"validateGamePlayTargetsBoundaries\", () => {\n it(\"should do nothing when interaction is not found.\", () => {\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto()];\n const game = createFakeGameWithCurrentPlay({\n currentPlay: createFakeGamePlaySheriffDelegates({\n source: createFakeGamePlaySource({\n interactions: [\n createFakeGamePlaySourceInteraction({\n type: \"transfer-sheriff-role\",\n boundaries: createFakeGamePlaySourceInteractionBoundaries({ min: 4, max: 4 }),\n }),\n ],\n }),\n }),\n });\n\n expect(() => services.gamePlayValidator[\"validateGamePlayTargetsBoundaries\"](makeGamePlayTargetsWithRelationsDto, \"charm\", game)).not.toThrow();\n });\n\n it(\"should throw error when min boundary is not respected.\", async() => {\n const makeGamePlayTargetsWithRelationsDto = [\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeSeerAlivePlayer() }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer() }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeWerewolfAlivePlayer() }),\n ];\n const game = createFakeGameWithCurrentPlay({\n currentPlay: createFakeGamePlaySheriffDelegates({\n source: createFakeGamePlaySource({\n interactions: [\n createFakeGamePlaySourceInteraction({\n type: \"transfer-sheriff-role\",\n boundaries: createFakeGamePlaySourceInteractionBoundaries({ min: 4, max: 4 }),\n }),\n ],\n }),\n }),\n });\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.TOO_LESS_TARGETS);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayTargetsBoundaries\"](makeGamePlayTargetsWithRelationsDto, \"transfer-sheriff-role\", game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"There are too less targets for this current game's state\" });\n });\n\n it(\"should throw error when max boundary is not respected.\", async() => {\n const makeGamePlayTargetsWithRelationsDto = [\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeSeerAlivePlayer() }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer() }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeWerewolfAlivePlayer() }),\n ];\n const game = createFakeGameWithCurrentPlay({\n currentPlay: createFakeGamePlaySheriffDelegates({\n source: createFakeGamePlaySource({\n interactions: [\n createFakeGamePlaySourceInteraction({\n type: \"transfer-sheriff-role\",\n boundaries: createFakeGamePlaySourceInteractionBoundaries({ min: 1, max: 2 }),\n }),\n ],\n }),\n }),\n });\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.TOO_MUCH_TARGETS);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayTargetsBoundaries\"](makeGamePlayTargetsWithRelationsDto, \"transfer-sheriff-role\", game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"There are too much targets for this current game's state\" });\n });\n\n it(\"should do nothing when boundaries are respected, even equal to max.\", () => {\n const makeGamePlayTargetsWithRelationsDto = [\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeSeerAlivePlayer() }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer() }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeWerewolfAlivePlayer() }),\n ];\n const game = createFakeGameWithCurrentPlay({\n currentPlay: createFakeGamePlaySheriffDelegates({\n source: createFakeGamePlaySource({\n interactions: [\n createFakeGamePlaySourceInteraction({\n type: \"transfer-sheriff-role\",\n boundaries: createFakeGamePlaySourceInteractionBoundaries({ min: 3, max: 3 }),\n }),\n ],\n }),\n }),\n });\n\n expect(() => services.gamePlayValidator[\"validateGamePlayTargetsBoundaries\"](makeGamePlayTargetsWithRelationsDto, \"transfer-sheriff-role\", game)).not.toThrow();\n });\n\n it(\"should do nothing when boundaries are respected, even equal to min.\", () => {\n const makeGamePlayTargetsWithRelationsDto = [\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeSeerAlivePlayer() }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer() }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeWerewolfAlivePlayer() }),\n ];\n const game = createFakeGameWithCurrentPlay({\n currentPlay: createFakeGamePlaySheriffDelegates({\n source: createFakeGamePlaySource({\n interactions: [\n createFakeGamePlaySourceInteraction({\n type: \"transfer-sheriff-role\",\n boundaries: createFakeGamePlaySourceInteractionBoundaries({ min: 3, max: 4 }),\n }),\n ],\n }),\n }),\n });\n\n expect(() => services.gamePlayValidator[\"validateGamePlayTargetsBoundaries\"](makeGamePlayTargetsWithRelationsDto, \"transfer-sheriff-role\", game)).not.toThrow();\n });\n });\n\n describe(\"validateGamePlaySourceTargets\", () => {\n beforeEach(() => {\n mocks.gamePlayValidatorService.validateGamePlaySheriffTargets = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlaySheriffTargets }, \"validateGamePlaySheriffTargets\").mockImplementation();\n mocks.gamePlayValidatorService.validateGamePlayDefenderTargets = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayDefenderTargets }, \"validateGamePlayDefenderTargets\").mockImplementation();\n mocks.gamePlayValidatorService.validateGamePlayPiedPiperTargets = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayPiedPiperTargets }, \"validateGamePlayPiedPiperTargets\").mockImplementation();\n mocks.gamePlayValidatorService.validateGamePlayWildChildTargets = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayWildChildTargets }, \"validateGamePlayWildChildTargets\").mockImplementation();\n mocks.gamePlayValidatorService.validateGamePlayScandalmongerTargets = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayScandalmongerTargets }, \"validateGamePlayScandalmongerTargets\").mockImplementation();\n mocks.gamePlayValidatorService.validateGamePlaySeerTargets = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlaySeerTargets }, \"validateGamePlaySeerTargets\").mockImplementation();\n mocks.gamePlayValidatorService.validateGamePlayFoxTargets = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayFoxTargets }, \"validateGamePlayFoxTargets\").mockImplementation();\n mocks.gamePlayValidatorService.validateGamePlayCupidTargets = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayCupidTargets }, \"validateGamePlayCupidTargets\").mockImplementation();\n mocks.gamePlayValidatorService.validateGamePlayScapegoatTargets = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayScapegoatTargets }, \"validateGamePlayScapegoatTargets\").mockImplementation();\n mocks.gamePlayValidatorService.validateGamePlayHunterTargets = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayHunterTargets }, \"validateGamePlayHunterTargets\").mockImplementation();\n mocks.gamePlayValidatorService.validateGamePlayWerewolvesTargets = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayWerewolvesTargets }, \"validateGamePlayWerewolvesTargets\").mockImplementation();\n mocks.gamePlayValidatorService.validateGamePlayAccursedWolfFatherTargets = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayAccursedWolfFatherTargets }, \"validateGamePlayAccursedWolfFatherTargets\").mockImplementation();\n mocks.gamePlayValidatorService.validateGamePlayWitchTargets = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayWitchTargets }, \"validateGamePlayWitchTargets\").mockImplementation();\n mocks.gamePlayValidatorService.validateGamePlaySurvivorsTargets = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlaySurvivorsTargets }, \"validateGamePlaySurvivorsTargets\").mockImplementation();\n });\n\n it(\"should call sheriff validator when game current play is for the sheriff.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySheriffSettlesVotes() });\n await services.gamePlayValidator[\"validateGamePlaySourceTargets\"]([], game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlaySheriffTargets).toHaveBeenCalledExactlyOnceWith([], game);\n expect(mocks.gamePlayValidatorService.validateGamePlaySurvivorsTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayDefenderTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayPiedPiperTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWildChildTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScandalmongerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySeerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayFoxTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayCupidTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScapegoatTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayHunterTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWitchTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayAccursedWolfFatherTargets).not.toHaveBeenCalled();\n });\n\n it(\"should call survivors validator when game current play is for the survivors.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsVote() });\n await services.gamePlayValidator[\"validateGamePlaySourceTargets\"]([], game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlaySheriffTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySurvivorsTargets).toHaveBeenCalledExactlyOnceWith([], game);\n expect(mocks.gamePlayValidatorService.validateGamePlayDefenderTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayPiedPiperTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWildChildTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScandalmongerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySeerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayFoxTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayCupidTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScapegoatTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayHunterTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWitchTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayAccursedWolfFatherTargets).not.toHaveBeenCalled();\n });\n\n it(\"should call werewolves validator when game current play is for the werewolves.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWerewolvesEat() });\n await services.gamePlayValidator[\"validateGamePlaySourceTargets\"]([], game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlaySheriffTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySurvivorsTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWerewolvesTargets).toHaveBeenCalledExactlyOnceWith([], game);\n expect(mocks.gamePlayValidatorService.validateGamePlayAccursedWolfFatherTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayDefenderTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayPiedPiperTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWildChildTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScandalmongerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySeerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayFoxTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayCupidTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScapegoatTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayHunterTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWitchTargets).not.toHaveBeenCalled();\n });\n\n it(\"should call accursed wolf-father validator when game current play is for the accursed wolf father.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayAccursedWolfFatherInfects() });\n await services.gamePlayValidator[\"validateGamePlaySourceTargets\"]([], game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlaySheriffTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySurvivorsTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWerewolvesTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayAccursedWolfFatherTargets).toHaveBeenCalledExactlyOnceWith([], game);\n expect(mocks.gamePlayValidatorService.validateGamePlayDefenderTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayPiedPiperTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWildChildTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScandalmongerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySeerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayFoxTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayCupidTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScapegoatTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayHunterTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWitchTargets).not.toHaveBeenCalled();\n });\n\n it(\"should call werewolves validator when game current play is for the big bad wolf.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayBigBadWolfEats() });\n await services.gamePlayValidator[\"validateGamePlaySourceTargets\"]([], game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlaySurvivorsTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySheriffTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWerewolvesTargets).toHaveBeenCalledExactlyOnceWith([], game);\n expect(mocks.gamePlayValidatorService.validateGamePlayDefenderTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayPiedPiperTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWildChildTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScandalmongerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySeerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayFoxTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayCupidTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScapegoatTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayHunterTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWitchTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayAccursedWolfFatherTargets).not.toHaveBeenCalled();\n });\n\n it(\"should call werewolves validator when game current play is for the white werewolf.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWhiteWerewolfEats() });\n await services.gamePlayValidator[\"validateGamePlaySourceTargets\"]([], game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlaySurvivorsTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySheriffTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWerewolvesTargets).toHaveBeenCalledExactlyOnceWith([], game);\n expect(mocks.gamePlayValidatorService.validateGamePlayDefenderTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayPiedPiperTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWildChildTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScandalmongerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySeerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayFoxTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayCupidTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScapegoatTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayHunterTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWitchTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayAccursedWolfFatherTargets).not.toHaveBeenCalled();\n });\n\n it(\"should call defender validator when game current play is for the defender.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayDefenderProtects() });\n await services.gamePlayValidator[\"validateGamePlaySourceTargets\"]([], game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlaySurvivorsTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySheriffTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWerewolvesTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayDefenderTargets).toHaveBeenCalledExactlyOnceWith([], game);\n expect(mocks.gamePlayValidatorService.validateGamePlayPiedPiperTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWildChildTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScandalmongerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySeerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayFoxTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayCupidTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScapegoatTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayHunterTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWitchTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayAccursedWolfFatherTargets).not.toHaveBeenCalled();\n });\n\n it(\"should call pied piper validator when game current play is for the pied piper.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayPiedPiperCharms() });\n await services.gamePlayValidator[\"validateGamePlaySourceTargets\"]([], game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlaySurvivorsTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySheriffTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWerewolvesTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayDefenderTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayPiedPiperTargets).toHaveBeenCalledExactlyOnceWith([], game);\n expect(mocks.gamePlayValidatorService.validateGamePlayWildChildTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScandalmongerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySeerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayFoxTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayCupidTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScapegoatTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayHunterTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWitchTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayAccursedWolfFatherTargets).not.toHaveBeenCalled();\n });\n\n it(\"should call wild child validator when game current play is for the wild child.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWildChildChoosesModel() });\n await services.gamePlayValidator[\"validateGamePlaySourceTargets\"]([], game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlaySurvivorsTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySheriffTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWerewolvesTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayDefenderTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayPiedPiperTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWildChildTargets).toHaveBeenCalledExactlyOnceWith([], game);\n expect(mocks.gamePlayValidatorService.validateGamePlayScandalmongerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySeerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayFoxTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayCupidTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScapegoatTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayHunterTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWitchTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayAccursedWolfFatherTargets).not.toHaveBeenCalled();\n });\n\n it(\"should call scandalmonger validator when game current play is for the scandalmonger.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayScandalmongerMarks() });\n await services.gamePlayValidator[\"validateGamePlaySourceTargets\"]([], game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlaySurvivorsTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySheriffTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWerewolvesTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayDefenderTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayPiedPiperTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWildChildTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScandalmongerTargets).toHaveBeenCalledExactlyOnceWith([], game);\n expect(mocks.gamePlayValidatorService.validateGamePlaySeerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayFoxTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayCupidTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScapegoatTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayHunterTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWitchTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayAccursedWolfFatherTargets).not.toHaveBeenCalled();\n });\n\n it(\"should call seer validator when game current play is for the seer.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySeerLooks() });\n await services.gamePlayValidator[\"validateGamePlaySourceTargets\"]([], game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlaySurvivorsTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySheriffTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWerewolvesTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayDefenderTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayPiedPiperTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWildChildTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScandalmongerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySeerTargets).toHaveBeenCalledExactlyOnceWith([], game);\n expect(mocks.gamePlayValidatorService.validateGamePlayFoxTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayCupidTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScapegoatTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayHunterTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWitchTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayAccursedWolfFatherTargets).not.toHaveBeenCalled();\n });\n\n it(\"should call fox validator when game current play is for the fox.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayFoxSniffs() });\n await services.gamePlayValidator[\"validateGamePlaySourceTargets\"]([], game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlaySurvivorsTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySheriffTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWerewolvesTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayDefenderTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayPiedPiperTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWildChildTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScandalmongerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySeerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayFoxTargets).toHaveBeenCalledExactlyOnceWith([], game);\n expect(mocks.gamePlayValidatorService.validateGamePlayCupidTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScapegoatTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayHunterTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWitchTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayAccursedWolfFatherTargets).not.toHaveBeenCalled();\n });\n\n it(\"should call cupid validator when game current play is for the cupid.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayCupidCharms() });\n await services.gamePlayValidator[\"validateGamePlaySourceTargets\"]([], game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlaySurvivorsTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySheriffTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWerewolvesTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayDefenderTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayPiedPiperTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWildChildTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScandalmongerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySeerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayFoxTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayCupidTargets).toHaveBeenCalledExactlyOnceWith([], game);\n expect(mocks.gamePlayValidatorService.validateGamePlayScapegoatTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayHunterTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWitchTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayAccursedWolfFatherTargets).not.toHaveBeenCalled();\n });\n\n it(\"should call scapegoat validator when game current play is for the scapegoat.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayScapegoatBansVoting() });\n await services.gamePlayValidator[\"validateGamePlaySourceTargets\"]([], game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlaySurvivorsTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySheriffTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWerewolvesTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayDefenderTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayPiedPiperTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWildChildTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScandalmongerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySeerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayFoxTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayCupidTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScapegoatTargets).toHaveBeenCalledExactlyOnceWith([], game);\n expect(mocks.gamePlayValidatorService.validateGamePlayHunterTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWitchTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayAccursedWolfFatherTargets).not.toHaveBeenCalled();\n });\n\n it(\"should call hunter validator when game current play is for the hunter.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayHunterShoots() });\n await services.gamePlayValidator[\"validateGamePlaySourceTargets\"]([], game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlaySurvivorsTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySheriffTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWerewolvesTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayDefenderTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayPiedPiperTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWildChildTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScandalmongerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySeerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayFoxTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayCupidTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScapegoatTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayHunterTargets).toHaveBeenCalledExactlyOnceWith([], game);\n expect(mocks.gamePlayValidatorService.validateGamePlayWitchTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayAccursedWolfFatherTargets).not.toHaveBeenCalled();\n });\n\n it(\"should call witch validator when game current play is for the witch.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWitchUsesPotions() });\n await services.gamePlayValidator[\"validateGamePlaySourceTargets\"]([], game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlaySurvivorsTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySheriffTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWerewolvesTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayDefenderTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayPiedPiperTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWildChildTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScandalmongerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySeerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayFoxTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayCupidTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScapegoatTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayHunterTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayAccursedWolfFatherTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWitchTargets).toHaveBeenCalledExactlyOnceWith([], game);\n });\n });\n\n describe(\"validateTargetsPotionUsage\", () => {\n it(\"should throw error when expected action is not use potions but targets drank potions.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWitchUsesPotions({ action: \"choose-card\" }) });\n const makeGamePlayTargetsWithRelationsDto = [\n createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"life\" }),\n createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"death\" }),\n createFakeMakeGamePlayTargetWithRelationsDto(),\n ];\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.UNEXPECTED_DRANK_POTION_TARGET);\n const error = await getError(() => services.gamePlayValidator[\"validateTargetsPotionUsage\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"`targets.drankPotion` can't be set on this current game's state\" });\n });\n\n it(\"should throw error when expected source is not witch but targets drank potions.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWitchUsesPotions({ source: createFakeGamePlaySource({ name: \"thief\" }) }) });\n const makeGamePlayTargetsWithRelationsDto = [\n createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"life\" }),\n createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"death\" }),\n createFakeMakeGamePlayTargetWithRelationsDto(),\n ];\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.UNEXPECTED_DRANK_POTION_TARGET);\n const error = await getError(() => services.gamePlayValidator[\"validateTargetsPotionUsage\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"`targets.drankPotion` can't be set on this current game's state\" });\n });\n\n it(\"should do nothing when expected some players drank potions and game play is valid.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWitchUsesPotions() });\n const makeGamePlayTargetsWithRelationsDto = [\n createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"life\" }),\n createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"death\" }),\n createFakeMakeGamePlayTargetWithRelationsDto(),\n ];\n\n expect(() => services.gamePlayValidator[\"validateTargetsPotionUsage\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n });\n\n describe(\"validateGamePlayTargetsWithRelationsDto\", () => {\n beforeEach(() => {\n mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayTargetsBoundaries }, \"validateGamePlayTargetsBoundaries\").mockImplementation();\n mocks.gamePlayValidatorService.validateTargetsPotionUsage = jest.spyOn(services.gamePlayValidator as unknown as { validateTargetsPotionUsage }, \"validateTargetsPotionUsage\").mockImplementation();\n mocks.gamePlayValidatorService.validateGamePlaySourceTargets = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlaySourceTargets }, \"validateGamePlaySourceTargets\").mockImplementation();\n });\n\n it(\"should do nothing when there are no targets defined and upcoming action doesn't require targets anyway.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsVote() });\n\n await expect(services.gamePlayValidator[\"validateGamePlayTargetsWithRelationsDto\"](undefined, game)).toResolve();\n expect(mocks.gamePlayValidatorService.validateTargetsPotionUsage).not.toHaveBeenCalled();\n });\n\n it(\"should do nothing when there are no targets and upcoming action can be skipped.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayFoxSniffs({ canBeSkipped: true }) });\n\n await expect(services.gamePlayValidator[\"validateGamePlayTargetsWithRelationsDto\"]([], game)).toResolve();\n expect(mocks.gamePlayValidatorService.validateTargetsPotionUsage).not.toHaveBeenCalled();\n });\n\n it(\"should throw error when there is no targets but they are required cause action can't be skipped.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySeerLooks({ canBeSkipped: false }) });\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.REQUIRED_TARGETS);\n const error = await getError(async() => services.gamePlayValidator[\"validateGamePlayTargetsWithRelationsDto\"]([], game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"`targets` is required on this current game's state\" });\n });\n\n it(\"should throw error when there are targets but they are not expected.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsVote() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto()];\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.UNEXPECTED_TARGETS);\n const error = await getError(async() => services.gamePlayValidator[\"validateGamePlayTargetsWithRelationsDto\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"`targets` can't be set on this current game's state\" });\n });\n\n it(\"should not validate game play targets boundaries when targets are expected but current play doesn't have eligible targets boundaries.\", async() => {\n const currentPlay = createFakeGamePlayWerewolvesEat();\n const game = createFakeGameWithCurrentPlay({ currentPlay });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto()];\n\n await expect(services.gamePlayValidator[\"validateGamePlayTargetsWithRelationsDto\"](makeGamePlayTargetsWithRelationsDto, game)).toResolve();\n expect(mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries).not.toHaveBeenCalled();\n });\n\n it(\"should call targets validators when targets data is valid.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWerewolvesEat() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto()];\n\n await expect(services.gamePlayValidator[\"validateGamePlayTargetsWithRelationsDto\"](makeGamePlayTargetsWithRelationsDto, game)).toResolve();\n expect(mocks.gamePlayValidatorService.validateGamePlaySourceTargets).toHaveBeenCalledOnce();\n expect(mocks.gamePlayValidatorService.validateTargetsPotionUsage).toHaveBeenCalledOnce();\n });\n });\n\n describe(\"validateGamePlayVotesTieBreakerWithRelationsDto\", () => {\n it(\"should throw error when action is vote and cause is previous votes were in tie but one voted player is not in the previous tie.\", async() => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeIdiotAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const source = createFakeGamePlaySource({ name: \"survivors\", players: [players[2]] });\n const currentPlay = createFakeGamePlaySurvivorsVote({ source, causes: [\"previous-votes-were-in-ties\"] });\n const game = createFakeGameWithCurrentPlay({ currentPlay, players });\n const makeGamePlayVotesWithRelationsDto = [\n createFakeMakeGamePlayVoteWithRelationsDto({ target: players[0] }),\n createFakeMakeGamePlayVoteWithRelationsDto({ target: players[1] }),\n createFakeMakeGamePlayVoteWithRelationsDto({ target: players[2] }),\n ];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValueOnce(false);\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_VOTE_TARGET_FOR_TIE_BREAKER);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayVotesTieBreakerWithRelationsDto\"](makeGamePlayVotesWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"One vote's target is not in the previous tie in votes\" });\n });\n\n it(\"should throw error when action is elect sheriff and cause is previous votes were in tie but one voted player is not in the previous tie.\", async() => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeIdiotAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const source = createFakeGamePlaySource({ name: \"survivors\", players: [players[2]] });\n const currentPlay = createFakeGamePlaySurvivorsElectSheriff({ source, causes: [\"previous-votes-were-in-ties\"] });\n const game = createFakeGameWithCurrentPlay({ currentPlay, players });\n const makeGamePlayVotesWithRelationsDto = [\n createFakeMakeGamePlayVoteWithRelationsDto({ target: players[0] }),\n createFakeMakeGamePlayVoteWithRelationsDto({ target: players[1] }),\n createFakeMakeGamePlayVoteWithRelationsDto({ target: players[2] }),\n ];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValueOnce(false);\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_VOTE_TARGET_FOR_TIE_BREAKER);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayVotesTieBreakerWithRelationsDto\"](makeGamePlayVotesWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"One vote's target is not in the previous tie in votes\" });\n });\n\n it(\"should call isPlayerInteractableWithInteractionTypeInCurrentGamePlay with vote interaction type when action is vote.\", () => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeIdiotAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const currentPlay = createFakeGamePlaySurvivorsVote({ causes: [\"previous-votes-were-in-ties\"] });\n const game = createFakeGameWithCurrentPlay({ currentPlay, players });\n const makeGamePlayVotesWithRelationsDto = [\n createFakeMakeGamePlayVoteWithRelationsDto({ target: players[0] }),\n createFakeMakeGamePlayVoteWithRelationsDto({ target: players[1] }),\n ];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n services.gamePlayValidator[\"validateGamePlayVotesTieBreakerWithRelationsDto\"](makeGamePlayVotesWithRelationsDto, game);\n\n expect(mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay).toHaveBeenNthCalledWith(1, players[0]._id, \"vote\", game);\n expect(mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay).toHaveBeenNthCalledWith(2, players[1]._id, \"vote\", game);\n });\n\n it(\"should call isPlayerInteractableWithInteractionTypeInCurrentGamePlay with choose as sheriff interaction type when action is elect sheriff.\", () => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeIdiotAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const currentPlay = createFakeGamePlaySurvivorsElectSheriff({ causes: [\"previous-votes-were-in-ties\"] });\n const game = createFakeGameWithCurrentPlay({ currentPlay, players });\n const makeGamePlayVotesWithRelationsDto = [\n createFakeMakeGamePlayVoteWithRelationsDto({ target: players[0] }),\n createFakeMakeGamePlayVoteWithRelationsDto({ target: players[1] }),\n ];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n services.gamePlayValidator[\"validateGamePlayVotesTieBreakerWithRelationsDto\"](makeGamePlayVotesWithRelationsDto, game);\n\n expect(mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay).toHaveBeenNthCalledWith(1, players[0]._id, \"choose-as-sheriff\", game);\n expect(mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay).toHaveBeenNthCalledWith(2, players[1]._id, \"choose-as-sheriff\", game);\n });\n\n it(\"should do nothing when cause is previous votes were in tie and all voted players were in previous tie.\", () => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeIdiotAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const currentPlay = createFakeGamePlaySurvivorsVote({ causes: [\"previous-votes-were-in-ties\"] });\n const game = createFakeGameWithCurrentPlay({ currentPlay, players });\n const makeGamePlayVotesWithRelationsDto = [\n createFakeMakeGamePlayVoteWithRelationsDto({ target: players[0] }),\n createFakeMakeGamePlayVoteWithRelationsDto({ target: players[1] }),\n ];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n\n expect(() => services.gamePlayValidator[\"validateGamePlayVotesTieBreakerWithRelationsDto\"](makeGamePlayVotesWithRelationsDto, game)).not.toThrow();\n });\n\n it(\"should do nothing when cause is not previous votes were in tie.\", () => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeIdiotAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const source = createFakeGamePlaySource({ name: \"survivors\", players: [players[2]] });\n const currentPlay = createFakeGamePlaySurvivorsVote({ source, causes: [\"angel-presence\"] });\n const game = createFakeGameWithCurrentPlay({ currentPlay, players });\n const makeGamePlayVotesWithRelationsDto = [\n createFakeMakeGamePlayVoteWithRelationsDto({ target: players[0] }),\n createFakeMakeGamePlayVoteWithRelationsDto({ target: players[1] }),\n createFakeMakeGamePlayVoteWithRelationsDto({ target: players[2] }),\n ];\n\n expect(() => services.gamePlayValidator[\"validateGamePlayVotesTieBreakerWithRelationsDto\"](makeGamePlayVotesWithRelationsDto, game)).not.toThrow();\n });\n });\n\n describe(\"validateGamePlayVotesWithRelationsDtoSourceAndTarget\", () => {\n it(\"should throw error when one vote source doesn't have the ability to vote.\", async() => {\n const players = [\n createFakeSeerAlivePlayer({ attributes: [createFakeCantVoteBySurvivorsPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer(),\n createFakeIdiotAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const source = createFakeGamePlaySource({ name: \"survivors\", players: [players[2]] });\n const currentPlay = createFakeGamePlaySurvivorsVote({ source });\n const game = createFakeGameWithCurrentPlay({ players, currentPlay });\n const makeGamePlayVotesWithRelationsDto = [\n createFakeMakeGamePlayVoteWithRelationsDto({ source: players[0], target: players[1] }),\n createFakeMakeGamePlayVoteWithRelationsDto({ source: players[2], target: players[1] }),\n ];\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_VOTE_SOURCE);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayVotesWithRelationsDtoSourceAndTarget\"](makeGamePlayVotesWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"One source is not able to vote because he's dead or doesn't have the ability to do so\" });\n });\n\n it(\"should throw error when one vote target can't be voted against.\", async() => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeIdiotAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const source = createFakeGamePlaySource({\n name: \"survivors\",\n players,\n interactions: [\n createFakeGamePlaySourceInteraction({\n type: \"vote\",\n source: \"survivors\",\n eligibleTargets: [players[1], players[2], players[3]],\n boundaries: { min: 1, max: 1 },\n }),\n ],\n });\n const currentPlay = createFakeGamePlaySurvivorsVote({ source });\n const game = createFakeGameWithCurrentPlay({ players, currentPlay });\n const makeGamePlayVotesWithRelationsDto = [\n createFakeMakeGamePlayVoteWithRelationsDto({ source: players[0], target: players[1] }),\n createFakeMakeGamePlayVoteWithRelationsDto({ source: players[2], target: players[1] }),\n createFakeMakeGamePlayVoteWithRelationsDto({ source: players[3], target: players[0] }),\n ];\n mocks.gamePlayHelper.isPlayerInteractableInCurrentGamePlay.mockReturnValueOnce(false);\n mocks.gamePlayHelper.isPlayerInteractableInCurrentGamePlay.mockReturnValueOnce(true);\n mocks.gamePlayHelper.isPlayerInteractableInCurrentGamePlay.mockReturnValueOnce(true);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_VOTE_TARGET);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayVotesWithRelationsDtoSourceAndTarget\"](makeGamePlayVotesWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"One target can't be voted because he's dead\" });\n });\n\n it(\"should throw error when there are votes with the same source and target.\", async() => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeIdiotAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const source = createFakeGamePlaySource({ name: \"survivors\", players });\n const currentPlay = createFakeGamePlaySurvivorsVote({ source });\n const game = createFakeGameWithCurrentPlay({ currentPlay, players });\n const makeGamePlayVotesWithRelationsDto = [\n createFakeMakeGamePlayVoteWithRelationsDto({ source: players[0], target: players[0] }),\n createFakeMakeGamePlayVoteWithRelationsDto({ source: players[2], target: players[1] }),\n ];\n mocks.gamePlayHelper.isPlayerInteractableInCurrentGamePlay.mockReturnValue(true);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.SAME_SOURCE_AND_TARGET_VOTE);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayVotesWithRelationsDtoSourceAndTarget\"](makeGamePlayVotesWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"One vote has the same source and target\" });\n });\n });\n\n describe(\"validateGamePlayVotesWithRelationsDto\", () => {\n beforeEach(() => {\n mocks.gamePlayValidatorService.validateGamePlayVotesTieBreakerWithRelationsDto = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayVotesTieBreakerWithRelationsDto }, \"validateGamePlayVotesTieBreakerWithRelationsDto\").mockImplementation();\n mocks.gamePlayValidatorService.validateGamePlayVotesWithRelationsDtoSourceAndTarget = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayVotesWithRelationsDtoSourceAndTarget }, \"validateGamePlayVotesWithRelationsDtoSourceAndTarget\").mockImplementation();\n });\n\n it(\"should do nothing when there are no votes defined but game play is not for votes anyway.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWerewolvesEat() });\n\n expect(() => services.gamePlayValidator[\"validateGamePlayVotesWithRelationsDto\"](undefined, game)).not.toThrow();\n });\n\n it(\"should throw error when there are empty votes but they are not expected.\", async() => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlayWerewolvesEat() });\n const makeGamePlayVotesWithRelationsDto = [];\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.UNEXPECTED_VOTES);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayVotesWithRelationsDto\"](makeGamePlayVotesWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"`votes` can't be set on this current game's state\" });\n });\n\n it(\"should throw error when there are votes but they are not expected.\", async() => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlayWerewolvesEat() });\n const makeGamePlayVotesWithRelationsDto = [createFakeMakeGamePlayVoteWithRelationsDto()];\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.UNEXPECTED_VOTES);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayVotesWithRelationsDto\"](makeGamePlayVotesWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"`votes` can't be set on this current game's state\" });\n });\n\n it(\"should do nothing when there are no votes defined but game play of votes can be skipped.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsVote({ canBeSkipped: true }) });\n\n expect(() => services.gamePlayValidator[\"validateGamePlayVotesWithRelationsDto\"](undefined, game)).not.toThrow();\n });\n\n it(\"should do nothing when there are no votes (empty array) but game play of votes can be skipped.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsVote({ canBeSkipped: true }) });\n\n expect(() => services.gamePlayValidator[\"validateGamePlayVotesWithRelationsDto\"]([], game)).not.toThrow();\n });\n\n it(\"should throw error when there are no votes (undefined) but game play of votes can't be skipped.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsVote({ canBeSkipped: false }) });\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.UNEXPECTED_VOTES);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayVotesWithRelationsDto\"](undefined, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"`votes` is required on this current game's state\" });\n });\n\n it(\"should throw error when there are no votes (empty array) but game play of votes can't be skipped.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsVote({ canBeSkipped: false }) });\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.UNEXPECTED_VOTES);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayVotesWithRelationsDto\"]([], game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"`votes` is required on this current game's state\" });\n });\n\n it(\"should call validateGamePlayVotesTieBreakerWithRelationsDto when current play is because of previous votes were in ties.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlaySurvivorsVote({ causes: [\"previous-votes-were-in-ties\"] }) });\n const makeGamePlayVotesWithRelationsDto = [createFakeMakeGamePlayVoteWithRelationsDto({ source: game.players[0], target: game.players[1] })];\n\n expect(() => services.gamePlayValidator[\"validateGamePlayVotesWithRelationsDto\"](makeGamePlayVotesWithRelationsDto, game)).not.toThrow();\n expect(mocks.gamePlayValidatorService.validateGamePlayVotesTieBreakerWithRelationsDto).toHaveBeenCalledExactlyOnceWith(makeGamePlayVotesWithRelationsDto, game);\n });\n\n it(\"should not call validateGamePlayVotesTieBreakerWithRelationsDto when current play is not because of previous votes were in ties.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlaySurvivorsVote({ causes: [\"angel-presence\"] }) });\n const makeGamePlayVotesWithRelationsDto = [createFakeMakeGamePlayVoteWithRelationsDto({ source: game.players[0], target: game.players[1] })];\n\n expect(() => services.gamePlayValidator[\"validateGamePlayVotesWithRelationsDto\"](makeGamePlayVotesWithRelationsDto, game)).not.toThrow();\n expect(mocks.gamePlayValidatorService.validateGamePlayVotesTieBreakerWithRelationsDto).not.toHaveBeenCalled();\n });\n\n it(\"should do nothing when votes are valid.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlaySurvivorsVote() });\n const makeGamePlayVotesWithRelationsDto = [createFakeMakeGamePlayVoteWithRelationsDto({ source: game.players[0], target: game.players[1] })];\n\n expect(() => services.gamePlayValidator[\"validateGamePlayVotesWithRelationsDto\"](makeGamePlayVotesWithRelationsDto, game)).not.toThrow();\n });\n });\n\n describe(\"validateGamePlayWithRelationsDtoChosenSide\", () => {\n it(\"should throw error when chosenSide is defined and game play action is not CHOOSE_SIDE.\", async() => {\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ wolfHound: createFakeWolfHoundGameOptions({ isSideRandomlyChosen: false }) }) });\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsVote(), options });\n const makeGamePlayWithRelationsDto = createFakeMakeGamePlayWithRelationsDto({ chosenSide: \"werewolves\" });\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.UNEXPECTED_CHOSEN_SIDE);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayWithRelationsDtoChosenSide\"](makeGamePlayWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"`chosenSide` can't be set on this current game's state\" });\n });\n\n it(\"should throw error when chosenSide is defined and game play action is CHOOSE_SIDE but game options say that it is randomly chosen.\", async() => {\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ wolfHound: createFakeWolfHoundGameOptions({ isSideRandomlyChosen: true }) }) });\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWolfHoundChoosesSide(), options });\n const makeGamePlayWithRelationsDto = createFakeMakeGamePlayWithRelationsDto({ chosenSide: \"werewolves\" });\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.UNEXPECTED_CHOSEN_SIDE);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayWithRelationsDtoChosenSide\"](makeGamePlayWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"`chosenSide` can't be set on this current game's state\" });\n });\n\n it(\"should throw error when chosenSide is not defined and game play action is CHOOSE_SIDE and game options say that side is not randomly chosen.\", async() => {\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ wolfHound: createFakeWolfHoundGameOptions({ isSideRandomlyChosen: false }) }) });\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWolfHoundChoosesSide(), options });\n const makeGamePlayWithRelationsDto = createFakeMakeGamePlayWithRelationsDto();\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.REQUIRED_CHOSEN_SIDE);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayWithRelationsDtoChosenSide\"](makeGamePlayWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"`chosenSide` is required on this current game's state\" });\n });\n\n it(\"should do nothing when chosenSide is defined and game play action is CHOOSE_SIDE and game options say that side is not randomly chosen.\", () => {\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ wolfHound: createFakeWolfHoundGameOptions({ isSideRandomlyChosen: false }) }) });\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWolfHoundChoosesSide(), options });\n const makeGamePlayWithRelationsDto = createFakeMakeGamePlayWithRelationsDto({ chosenSide: \"werewolves\" });\n\n expect(() => services.gamePlayValidator[\"validateGamePlayWithRelationsDtoChosenSide\"](makeGamePlayWithRelationsDto, game)).not.toThrow();\n });\n\n it(\"should do nothing when chosenSide is not defined and game play action is not CHOOSE_SIDE.\", () => {\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ wolfHound: createFakeWolfHoundGameOptions({ isSideRandomlyChosen: false }) }) });\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsVote(), options });\n const makeGamePlayWithRelationsDto = createFakeMakeGamePlayWithRelationsDto();\n\n expect(() => services.gamePlayValidator[\"validateGamePlayWithRelationsDtoChosenSide\"](makeGamePlayWithRelationsDto, game)).not.toThrow();\n });\n\n it(\"should do nothing when chosenSide is not defined and game play action CHOOSE_SIDE but game options say that side is randomly chosen.\", () => {\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ wolfHound: createFakeWolfHoundGameOptions({ isSideRandomlyChosen: true }) }) });\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsVote(), options });\n const makeGamePlayWithRelationsDto = createFakeMakeGamePlayWithRelationsDto();\n\n expect(() => services.gamePlayValidator[\"validateGamePlayWithRelationsDtoChosenSide\"](makeGamePlayWithRelationsDto, game)).not.toThrow();\n });\n });\n\n describe(\"validateGamePlayWithRelationsDtoJudgeRequest\", () => {\n beforeEach(() => {\n mocks.gameHistoryRecordService.didJudgeMakeHisSign.mockResolvedValue(true);\n });\n\n it(\"should throw error when doesJudgeRequestAnotherVote is defined and game play action is not request another vote.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsVote() });\n const makeGamePlayWithRelationsDto = createFakeMakeGamePlayWithRelationsDto({ doesJudgeRequestAnotherVote: true });\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.UNEXPECTED_STUTTERING_JUDGE_VOTE_REQUEST);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayWithRelationsDtoJudgeRequest\"](makeGamePlayWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"`doesJudgeRequestAnotherVote` can't be set on this current game's state\" });\n });\n\n it(\"should do nothing when doesJudgeRequestAnotherVote is undefined.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsVote() });\n const makeGamePlayWithRelationsDto = createFakeMakeGamePlayWithRelationsDto();\n\n expect(() => services.gamePlayValidator[\"validateGamePlayWithRelationsDtoJudgeRequest\"](makeGamePlayWithRelationsDto, game)).not.toThrow();\n });\n\n it(\"should do nothing when doesJudgeRequestAnotherVote defined and action is request another vote.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayStutteringJudgeRequestsAnotherVote() });\n const makeGamePlayWithRelationsDto = createFakeMakeGamePlayWithRelationsDto({ doesJudgeRequestAnotherVote: true });\n\n expect(() => services.gamePlayValidator[\"validateGamePlayWithRelationsDtoJudgeRequest\"](makeGamePlayWithRelationsDto, game)).not.toThrow();\n });\n });\n});" + "source": "import type { TestingModule } from \"@nestjs/testing\";\nimport { Test } from \"@nestjs/testing\";\nimport { when } from \"jest-when\";\n\nimport { GameHistoryRecordRepository } from \"@/modules/game/providers/repositories/game-history-record/game-history-record.repository\";\nimport * as GamePlayHelper from \"@/modules/game/helpers/game-play/game-play.helpers\";\nimport { GameRepository } from \"@/modules/game/providers/repositories/game.repository\";\nimport { GameHistoryRecordService } from \"@/modules/game/providers/services/game-history/game-history-record.service\";\nimport { GamePlayValidatorService } from \"@/modules/game/providers/services/game-play/game-play-validator.service\";\n\nimport { BadGamePlayPayloadReasons } from \"@/shared/exception/enums/bad-game-play-payload-error.enums\";\nimport { UnexpectedExceptionReasons } from \"@/shared/exception/enums/unexpected-exception.enums\";\nimport * as UnexpectedExceptionFactory from \"@/shared/exception/helpers/unexpected-exception.factory\";\nimport { BadGamePlayPayloadException } from \"@/shared/exception/types/bad-game-play-payload-exception.types\";\nimport { UnexpectedException } from \"@/shared/exception/types/unexpected-exception.types\";\n\nimport { createFakeMakeGamePlayTargetWithRelationsDto } from \"@tests/factories/game/dto/make-game-play/make-game-play-with-relations/make-game-play-target-with-relations.dto.factory\";\nimport { createFakeMakeGamePlayVoteWithRelationsDto } from \"@tests/factories/game/dto/make-game-play/make-game-play-with-relations/make-game-play-vote-with-relations.dto.factory\";\nimport { createFakeMakeGamePlayWithRelationsDto } from \"@tests/factories/game/dto/make-game-play/make-game-play-with-relations/make-game-play-with-relations.dto.factory\";\nimport { createFakeGameAdditionalCard } from \"@tests/factories/game/schemas/game-additional-card/game-additional-card.schema.factory\";\nimport { createFakeGameHistoryRecord, createFakeGameHistoryRecordSurvivorsVotePlay, createFakeGameHistoryRecordWitchUsePotionsPlay } from \"@tests/factories/game/schemas/game-history-record/game-history-record.schema.factory\";\nimport { createFakeGameOptions } from \"@tests/factories/game/schemas/game-options/game-options.schema.factory\";\nimport { createFakePiedPiperGameOptions, createFakeRolesGameOptions, createFakeWolfHoundGameOptions } from \"@tests/factories/game/schemas/game-options/game-roles-options/game-roles-options.schema.factory\";\nimport { createFakeGamePlaySourceInteractionBoundaries } from \"@tests/factories/game/schemas/game-play/game-play-source/game-play-source-interaction/game-play-source-interaction-boundaries/game-play-source-interaction-boundaries.schema.factory\";\nimport { createFakeGamePlaySourceInteraction } from \"@tests/factories/game/schemas/game-play/game-play-source/game-play-source-interaction/game-play-source-interaction.schema.factory\";\nimport { createFakeGamePlaySource } from \"@tests/factories/game/schemas/game-play/game-play-source/game-play-source.schema.factory\";\nimport { createFakeGamePlayAccursedWolfFatherInfects, createFakeGamePlayActorChoosesCard, createFakeGamePlayBigBadWolfEats, createFakeGamePlayCupidCharms, createFakeGamePlayDefenderProtects, createFakeGamePlayFoxSniffs, createFakeGamePlayHunterShoots, createFakeGamePlayPiedPiperCharms, createFakeGamePlayScandalmongerMarks, createFakeGamePlayScapegoatBansVoting, createFakeGamePlaySeerLooks, createFakeGamePlaySheriffDelegates, createFakeGamePlaySheriffSettlesVotes, createFakeGamePlayStutteringJudgeRequestsAnotherVote, createFakeGamePlaySurvivorsBuryDeadBodies, createFakeGamePlaySurvivorsElectSheriff, createFakeGamePlaySurvivorsVote, createFakeGamePlayThiefChoosesCard, createFakeGamePlayWerewolvesEat, createFakeGamePlayWhiteWerewolfEats, createFakeGamePlayWildChildChoosesModel, createFakeGamePlayWitchUsesPotions, createFakeGamePlayWolfHoundChoosesSide } from \"@tests/factories/game/schemas/game-play/game-play.schema.factory\";\nimport { createFakeGame, createFakeGameWithCurrentPlay } from \"@tests/factories/game/schemas/game.schema.factory\";\nimport { createFakeCantVoteBySurvivorsPlayerAttribute, createFakeEatenByWerewolvesPlayerAttribute, createFakeInLoveByCupidPlayerAttribute, createFakePowerlessByElderPlayerAttribute } from \"@tests/factories/game/schemas/player/player-attribute/player-attribute.schema.factory\";\nimport { createFakeDevotedServantAlivePlayer, createFakeIdiotAlivePlayer, createFakeSeerAlivePlayer, createFakeVillagerAlivePlayer, createFakeWerewolfAlivePlayer, createFakeWhiteWerewolfAlivePlayer, createFakeWildChildAlivePlayer, createFakeWitchAlivePlayer } from \"@tests/factories/game/schemas/player/player-with-role.schema.factory\";\nimport { createFakePlayer } from \"@tests/factories/game/schemas/player/player.schema.factory\";\nimport { getError } from \"@tests/helpers/exception/exception.helpers\";\n\ndescribe(\"Game Play Validator Service\", () => {\n let mocks: {\n gamePlayValidatorService: {\n validateGamePlayWithRelationsDtoJudgeRequest: jest.SpyInstance;\n validateGamePlayWithRelationsDtoChosenSide: jest.SpyInstance;\n validateGamePlayVotesWithRelationsDto: jest.SpyInstance;\n validateGamePlayTargetsWithRelationsDto: jest.SpyInstance;\n validateGamePlayWithRelationsDtoChosenCard: jest.SpyInstance;\n validateGamePlayActorChosenCard: jest.SpyInstance;\n validateGamePlayWitchTargets: jest.SpyInstance;\n validateGamePlayWithRelationsDto: jest.SpyInstance;\n validateGamePlayThiefChosenCard: jest.SpyInstance;\n validateDrankLifePotionTargets: jest.SpyInstance;\n validateDrankDeathPotionTargets: jest.SpyInstance;\n validateGamePlaySheriffTargets: jest.SpyInstance;\n validateGamePlayDefenderTargets: jest.SpyInstance;\n validateGamePlayPiedPiperTargets: jest.SpyInstance;\n validateGamePlayWildChildTargets: jest.SpyInstance;\n validateGamePlayScandalmongerTargets: jest.SpyInstance;\n validateGamePlaySeerTargets: jest.SpyInstance;\n validateGamePlayFoxTargets: jest.SpyInstance;\n validateGamePlayCupidTargets: jest.SpyInstance;\n validateGamePlayScapegoatTargets: jest.SpyInstance;\n validateGamePlayHunterTargets: jest.SpyInstance;\n validateGamePlayWerewolvesTargets: jest.SpyInstance;\n validateGamePlayAccursedWolfFatherTargets: jest.SpyInstance;\n validateGamePlayTargetsBoundaries: jest.SpyInstance;\n validateTargetsPotionUsage: jest.SpyInstance;\n validateGamePlaySourceTargets: jest.SpyInstance;\n validateGamePlayVotesTieBreakerWithRelationsDto: jest.SpyInstance;\n validateGamePlayVotesWithRelationsDtoSourceAndTarget: jest.SpyInstance;\n validateGamePlaySurvivorsTargets: jest.SpyInstance;\n };\n gameRepository: {\n find: jest.SpyInstance;\n findOne: jest.SpyInstance;\n create: jest.SpyInstance;\n updateOne: jest.SpyInstance;\n };\n gameHistoryRecordRepository: {\n find: jest.SpyInstance;\n create: jest.SpyInstance;\n };\n gameHistoryRecordService: {\n getLastGameHistoryDefenderProtectsRecord: jest.SpyInstance;\n getLastGameHistoryTieInVotesRecord: jest.SpyInstance;\n getGameHistoryWitchUsesSpecificPotionRecords: jest.SpyInstance;\n getLastGameHistoryAccursedWolfFatherInfectsRecord: jest.SpyInstance;\n getGameHistoryStutteringJudgeRequestsAnotherVoteRecords: jest.SpyInstance;\n didJudgeMakeHisSign: jest.SpyInstance;\n };\n gamePlayHelper: {\n isPlayerInteractableWithInteractionTypeInCurrentGamePlay: jest.SpyInstance;\n isPlayerInteractableInCurrentGamePlay: jest.SpyInstance;\n };\n unexpectedExceptionFactory: {\n createNoCurrentGamePlayUnexpectedException: jest.SpyInstance;\n createCantFindPlayerWithCurrentRoleUnexpectedException: jest.SpyInstance;\n };\n };\n let services: { gamePlayValidator: GamePlayValidatorService };\n\n beforeEach(async() => {\n mocks = {\n gamePlayValidatorService: {\n validateGamePlayWithRelationsDtoJudgeRequest: jest.fn(),\n validateGamePlayWithRelationsDtoChosenSide: jest.fn(),\n validateGamePlayVotesWithRelationsDto: jest.fn(),\n validateGamePlayTargetsWithRelationsDto: jest.fn(),\n validateGamePlayWithRelationsDtoChosenCard: jest.fn(),\n validateGamePlayActorChosenCard: jest.fn(),\n validateGamePlayWitchTargets: jest.fn(),\n validateGamePlayWithRelationsDto: jest.fn(),\n validateGamePlayThiefChosenCard: jest.fn(),\n validateDrankLifePotionTargets: jest.fn(),\n validateDrankDeathPotionTargets: jest.fn(),\n validateGamePlaySheriffTargets: jest.fn(),\n validateGamePlayDefenderTargets: jest.fn(),\n validateGamePlayPiedPiperTargets: jest.fn(),\n validateGamePlayWildChildTargets: jest.fn(),\n validateGamePlayScandalmongerTargets: jest.fn(),\n validateGamePlaySeerTargets: jest.fn(),\n validateGamePlayFoxTargets: jest.fn(),\n validateGamePlayCupidTargets: jest.fn(),\n validateGamePlayScapegoatTargets: jest.fn(),\n validateGamePlayHunterTargets: jest.fn(),\n validateGamePlayWerewolvesTargets: jest.fn(),\n validateGamePlayAccursedWolfFatherTargets: jest.fn(),\n validateGamePlayTargetsBoundaries: jest.fn(),\n validateTargetsPotionUsage: jest.fn(),\n validateGamePlaySourceTargets: jest.fn(),\n validateGamePlayVotesTieBreakerWithRelationsDto: jest.fn(),\n validateGamePlayVotesWithRelationsDtoSourceAndTarget: jest.fn(),\n validateGamePlaySurvivorsTargets: jest.fn(),\n },\n gameRepository: {\n find: jest.fn(),\n findOne: jest.fn(),\n create: jest.fn(),\n updateOne: jest.fn(),\n },\n gameHistoryRecordRepository: {\n find: jest.fn(),\n create: jest.fn(),\n },\n gameHistoryRecordService: {\n getLastGameHistoryDefenderProtectsRecord: jest.fn(),\n getLastGameHistoryTieInVotesRecord: jest.fn(),\n getGameHistoryWitchUsesSpecificPotionRecords: jest.fn(),\n getLastGameHistoryAccursedWolfFatherInfectsRecord: jest.fn(),\n getGameHistoryStutteringJudgeRequestsAnotherVoteRecords: jest.fn(),\n didJudgeMakeHisSign: jest.fn(),\n },\n gamePlayHelper: {\n isPlayerInteractableInCurrentGamePlay: jest.spyOn(GamePlayHelper, \"isPlayerInteractableInCurrentGamePlay\").mockImplementation(),\n isPlayerInteractableWithInteractionTypeInCurrentGamePlay: jest.spyOn(GamePlayHelper, \"isPlayerInteractableWithInteractionTypeInCurrentGamePlay\").mockImplementation(),\n },\n unexpectedExceptionFactory: {\n createNoCurrentGamePlayUnexpectedException: jest.spyOn(UnexpectedExceptionFactory, \"createNoCurrentGamePlayUnexpectedException\").mockImplementation(),\n createCantFindPlayerWithCurrentRoleUnexpectedException: jest.spyOn(UnexpectedExceptionFactory, \"createCantFindPlayerWithCurrentRoleUnexpectedException\").mockImplementation(),\n },\n };\n\n const module: TestingModule = await Test.createTestingModule({\n providers: [\n {\n provide: GameHistoryRecordService,\n useValue: mocks.gameHistoryRecordService,\n },\n {\n provide: GameRepository,\n useValue: mocks.gameRepository,\n },\n {\n provide: GameHistoryRecordRepository,\n useValue: mocks.gameHistoryRecordRepository,\n },\n GamePlayValidatorService,\n ],\n }).compile();\n\n services = { gamePlayValidator: module.get(GamePlayValidatorService) };\n });\n\n describe(\"validateGamePlayWithRelationsDto\", () => {\n beforeEach(() => {\n mocks.gamePlayValidatorService.validateGamePlayWithRelationsDtoJudgeRequest = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayWithRelationsDtoJudgeRequest }, \"validateGamePlayWithRelationsDtoJudgeRequest\").mockImplementation();\n mocks.gamePlayValidatorService.validateGamePlayWithRelationsDtoChosenSide = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayWithRelationsDtoChosenSide }, \"validateGamePlayWithRelationsDtoChosenSide\").mockImplementation();\n mocks.gamePlayValidatorService.validateGamePlayVotesWithRelationsDto = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayVotesWithRelationsDto }, \"validateGamePlayVotesWithRelationsDto\").mockImplementation();\n mocks.gamePlayValidatorService.validateGamePlayTargetsWithRelationsDto = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayTargetsWithRelationsDto }, \"validateGamePlayTargetsWithRelationsDto\").mockImplementation();\n mocks.gamePlayValidatorService.validateGamePlayWithRelationsDtoChosenCard = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayWithRelationsDtoChosenCard }, \"validateGamePlayWithRelationsDtoChosenCard\").mockImplementation();\n });\n\n it(\"should throw error when game's current play is not set.\", async() => {\n const game = createFakeGame();\n const makeGamePlayWithRelationsDto = createFakeMakeGamePlayWithRelationsDto({ doesJudgeRequestAnotherVote: true });\n const interpolations = { gameId: game._id };\n const mockedError = new UnexpectedException(\"validateGamePlayWithRelationsDto\", UnexpectedExceptionReasons.NO_CURRENT_GAME_PLAY, { gameId: game._id.toString() });\n mocks.unexpectedExceptionFactory.createNoCurrentGamePlayUnexpectedException.mockReturnValue(mockedError);\n\n await expect(services.gamePlayValidator.validateGamePlayWithRelationsDto(makeGamePlayWithRelationsDto, game)).rejects.toStrictEqual(mockedError);\n expect(mocks.unexpectedExceptionFactory.createNoCurrentGamePlayUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"validateGamePlayWithRelationsDto\", interpolations);\n });\n\n it(\"should call validators when called.\", async() => {\n const game = createFakeGame({ currentPlay: createFakeGamePlaySurvivorsVote() });\n const makeGamePlayWithRelationsDto = createFakeMakeGamePlayWithRelationsDto({ doesJudgeRequestAnotherVote: true });\n await services.gamePlayValidator.validateGamePlayWithRelationsDto(makeGamePlayWithRelationsDto, game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlayWithRelationsDtoJudgeRequest).toHaveBeenCalledOnce();\n expect(mocks.gamePlayValidatorService.validateGamePlayWithRelationsDtoChosenSide).toHaveBeenCalledOnce();\n expect(mocks.gamePlayValidatorService.validateGamePlayVotesWithRelationsDto).toHaveBeenCalledOnce();\n expect(mocks.gamePlayValidatorService.validateGamePlayTargetsWithRelationsDto).toHaveBeenCalledOnce();\n expect(mocks.gamePlayValidatorService.validateGamePlayWithRelationsDtoChosenCard).toHaveBeenCalledOnce();\n });\n });\n\n describe(\"validateGamePlayActorChosenCard\", () => {\n it(\"should do nothing when game additional cards are not set.\", () => {\n const chosenCard = createFakeGameAdditionalCard({ isUsed: true });\n const game = createFakeGameWithCurrentPlay();\n\n expect(() => services.gamePlayValidator[\"validateGamePlayActorChosenCard\"](chosenCard, game)).not.toThrow();\n });\n\n it(\"should do nothing when chosen card is not defined.\", () => {\n const chosenCard = undefined;\n const additionalCards = [\n createFakeGameAdditionalCard({ roleName: \"werewolf\", recipient: \"actor\", isUsed: false }),\n createFakeGameAdditionalCard({ roleName: \"white-werewolf\", recipient: \"actor\", isUsed: false }),\n ];\n const game = createFakeGameWithCurrentPlay({ additionalCards });\n\n expect(() => services.gamePlayValidator[\"validateGamePlayActorChosenCard\"](chosenCard, game)).not.toThrow();\n });\n\n it(\"should do nothing when chosen card is for actor.\", () => {\n const chosenCard = createFakeGameAdditionalCard({ roleName: \"white-werewolf\", recipient: \"actor\", isUsed: false });\n const additionalCards = [\n createFakeGameAdditionalCard({ roleName: \"werewolf\", recipient: \"actor\", isUsed: false }),\n createFakeGameAdditionalCard({ roleName: \"white-werewolf\", recipient: \"actor\", isUsed: false }),\n ];\n const game = createFakeGameWithCurrentPlay({ additionalCards });\n\n expect(() => services.gamePlayValidator[\"validateGamePlayActorChosenCard\"](chosenCard, game)).not.toThrow();\n });\n\n it(\"should throw an error when chosen card is not for the actor.\", async() => {\n const chosenCard = createFakeGameAdditionalCard({ roleName: \"werewolf\", recipient: \"thief\", isUsed: false });\n const additionalCards = [\n createFakeGameAdditionalCard({ roleName: \"werewolf\", recipient: \"actor\", isUsed: false }),\n createFakeGameAdditionalCard({ roleName: \"white-werewolf\", recipient: \"actor\", isUsed: false }),\n ];\n const game = createFakeGameWithCurrentPlay({ additionalCards });\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.CHOSEN_CARD_NOT_FOR_ACTOR);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayActorChosenCard\"](chosenCard, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Chosen card is not for actor\" });\n });\n\n it(\"should throw an error when chosen card is already used.\", async() => {\n const chosenCard = createFakeGameAdditionalCard({ roleName: \"werewolf\", recipient: \"actor\", isUsed: true });\n const additionalCards = [\n createFakeGameAdditionalCard({ roleName: \"werewolf\", recipient: \"actor\", isUsed: false }),\n createFakeGameAdditionalCard({ roleName: \"white-werewolf\", recipient: \"actor\", isUsed: false }),\n ];\n const game = createFakeGameWithCurrentPlay({ additionalCards });\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.CHOSEN_CARD_NOT_FOR_ACTOR);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayActorChosenCard\"](chosenCard, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Chosen card is already used\" });\n });\n });\n\n describe(\"validateGamePlayThiefChosenCard\", () => {\n it(\"should do nothing when game additional cards are not set.\", () => {\n const chosenCard = createFakeGameAdditionalCard({ recipient: \"actor\" });\n const currentPlay = createFakeGamePlayThiefChoosesCard({ canBeSkipped: false });\n const game = createFakeGameWithCurrentPlay({ currentPlay });\n\n expect(() => services.gamePlayValidator[\"validateGamePlayThiefChosenCard\"](chosenCard, game)).not.toThrow();\n });\n\n it(\"should do nothing when thief didn't choose a card but he can skip.\", () => {\n const chosenCard = undefined;\n const currentPlay = createFakeGamePlayThiefChoosesCard({ canBeSkipped: true });\n const additionalCards = [\n createFakeGameAdditionalCard({ roleName: \"werewolf\", recipient: \"thief\" }),\n createFakeGameAdditionalCard({ roleName: \"seer\", recipient: \"thief\" }),\n ];\n const game = createFakeGameWithCurrentPlay({ additionalCards, currentPlay });\n\n expect(() => services.gamePlayValidator[\"validateGamePlayThiefChosenCard\"](chosenCard, game)).not.toThrow();\n });\n\n it(\"should do nothing when thief chose a card for him.\", () => {\n const chosenCard = createFakeGameAdditionalCard({ recipient: \"thief\" });\n const currentPlay = createFakeGamePlayThiefChoosesCard({ canBeSkipped: false });\n const additionalCards = [\n createFakeGameAdditionalCard({ roleName: \"werewolf\", recipient: \"thief\" }),\n createFakeGameAdditionalCard({ roleName: \"white-werewolf\", recipient: \"thief\" }),\n ];\n const game = createFakeGameWithCurrentPlay({ additionalCards, currentPlay });\n\n expect(() => services.gamePlayValidator[\"validateGamePlayThiefChosenCard\"](chosenCard, game)).not.toThrow();\n });\n\n it(\"should throw error when thief can't skip and he didn't choose a card.\", async() => {\n const chosenCard = undefined;\n const additionalCards = [\n createFakeGameAdditionalCard({ roleName: \"werewolf\", recipient: \"thief\" }),\n createFakeGameAdditionalCard({ roleName: \"white-werewolf\", recipient: \"thief\" }),\n ];\n const currentPlay = createFakeGamePlayThiefChoosesCard({ canBeSkipped: false });\n const game = createFakeGameWithCurrentPlay({ additionalCards, currentPlay });\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.THIEF_MUST_CHOOSE_CARD);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayThiefChosenCard\"](chosenCard, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Thief must choose a card (`chosenCard`)\" });\n });\n\n it(\"should throw error when chosen card is not for thief.\", async() => {\n const chosenCard = createFakeGameAdditionalCard({ roleName: \"werewolf\", recipient: \"actor\" });\n const additionalCards = [\n createFakeGameAdditionalCard({ roleName: \"werewolf\", recipient: \"thief\" }),\n createFakeGameAdditionalCard({ roleName: \"white-werewolf\", recipient: \"thief\" }),\n ];\n const currentPlay = createFakeGamePlayThiefChoosesCard({ canBeSkipped: true });\n const game = createFakeGameWithCurrentPlay({ additionalCards, currentPlay });\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.CHOSEN_CARD_NOT_FOR_THIEF);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayThiefChosenCard\"](chosenCard, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Chosen card is not for thief\" });\n });\n });\n\n describe(\"validateGamePlayWithRelationsDtoChosenCard\", () => {\n beforeEach(() => {\n mocks.gamePlayValidatorService.validateGamePlayThiefChosenCard = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayThiefChosenCard }, \"validateGamePlayThiefChosenCard\").mockImplementation();\n mocks.gamePlayValidatorService.validateGamePlayActorChosenCard = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayActorChosenCard }, \"validateGamePlayActorChosenCard\").mockImplementation();\n });\n\n it(\"should do nothing when chosen card is not defined and not expected.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWolfHoundChoosesSide() });\n const makeGamePlayWithRelationsDto = createFakeMakeGamePlayWithRelationsDto();\n\n expect(() => services.gamePlayValidator[\"validateGamePlayWithRelationsDtoChosenCard\"](makeGamePlayWithRelationsDto, game)).not.toThrow();\n });\n\n it(\"should throw error when chosen card is defined but not expected.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWolfHoundChoosesSide() });\n const makeGamePlayWithRelationsDto = createFakeMakeGamePlayWithRelationsDto({ chosenCard: createFakeGameAdditionalCard() });\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.UNEXPECTED_CHOSEN_CARD);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayWithRelationsDtoChosenCard\"](makeGamePlayWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"`chosenCard` can't be set on this current game's state\" });\n });\n\n it(\"should call validateGamePlayThiefChosenCard method when action is choose card and source is thief.\", () => {\n const chosenCard = createFakeGameAdditionalCard();\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayThiefChoosesCard() });\n const makeGamePlayWithRelationsDto = createFakeMakeGamePlayWithRelationsDto({ chosenCard });\n services.gamePlayValidator[\"validateGamePlayWithRelationsDtoChosenCard\"](makeGamePlayWithRelationsDto, game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlayThiefChosenCard).toHaveBeenCalledExactlyOnceWith(chosenCard, game);\n });\n\n it(\"should call validateGamePlayActorChosenCard method when action is choose card and source is actor.\", () => {\n const chosenCard = createFakeGameAdditionalCard();\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayActorChoosesCard() });\n const makeGamePlayWithRelationsDto = createFakeMakeGamePlayWithRelationsDto({ chosenCard });\n services.gamePlayValidator[\"validateGamePlayWithRelationsDtoChosenCard\"](makeGamePlayWithRelationsDto, game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlayActorChosenCard).toHaveBeenCalledExactlyOnceWith(chosenCard, game);\n });\n\n it(\"should not call neither thief or actor validation methods when game source is any of them.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWolfHoundChoosesSide({ action: \"choose-card\" }) });\n const makeGamePlayWithRelationsDto = createFakeMakeGamePlayWithRelationsDto();\n services.gamePlayValidator[\"validateGamePlayWithRelationsDtoChosenCard\"](makeGamePlayWithRelationsDto, game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlayThiefChosenCard).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayActorChosenCard).not.toHaveBeenCalled();\n });\n });\n\n describe(\"validateGamePlaySurvivorsTargets\", () => {\n beforeEach(() => {\n mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayTargetsBoundaries }, \"validateGamePlayTargetsBoundaries\").mockImplementation();\n });\n\n it(\"should do nothing when game's current play action is not bury dead bodies.\", () => {\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer({ isAlive: false }) })];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsVote() });\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n\n expect(() => services.gamePlayValidator[\"validateGamePlaySurvivorsTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n\n it(\"should validate targets boundaries when game's current play action is bury dead bodies.\", () => {\n const players = [\n createFakeDevotedServantAlivePlayer(),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer(),\n ];\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer({ isAlive: false }) })];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsBuryDeadBodies(), players });\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n services.gamePlayValidator[\"validateGamePlaySurvivorsTargets\"](makeGamePlayTargetsWithRelationsDto, game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries).toHaveBeenCalledExactlyOnceWith(makeGamePlayTargetsWithRelationsDto, \"steal-role\", game);\n });\n\n it(\"should do nothing when there is no target.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsBuryDeadBodies() });\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n\n expect(() => services.gamePlayValidator[\"validateGamePlaySurvivorsTargets\"]([], game)).not.toThrow();\n });\n\n it(\"should throw error when there is a target but no devoted servant in the game.\", async() => {\n const players = [\n createFakeDevotedServantAlivePlayer({ isAlive: false }),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer(),\n ];\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer({ isAlive: false }) })];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsBuryDeadBodies(), players });\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.DEVOTED_SERVANT_CANT_STEAL_ROLE);\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlaySurvivorsTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Devoted servant can't steal the role of this target because she's not in the game or dead or powerless or in love with another player\" });\n });\n\n it(\"should throw error when there is a target but the devoted servant is dead.\", async() => {\n const players = [\n createFakeDevotedServantAlivePlayer({ isAlive: false }),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer(),\n ];\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer({ isAlive: false }) })];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsBuryDeadBodies(), players });\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.DEVOTED_SERVANT_CANT_STEAL_ROLE);\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlaySurvivorsTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Devoted servant can't steal the role of this target because she's not in the game or dead or powerless or in love with another player\" });\n });\n\n it(\"should throw error when there is a target but devoted servant is powerless.\", async() => {\n const players = [\n createFakeDevotedServantAlivePlayer({ attributes: [createFakePowerlessByElderPlayerAttribute()] }),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer(),\n ];\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer({ isAlive: false }) })];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsBuryDeadBodies(), players });\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.DEVOTED_SERVANT_CANT_STEAL_ROLE);\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlaySurvivorsTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Devoted servant can't steal the role of this target because she's not in the game or dead or powerless or in love with another player\" });\n });\n\n it(\"should throw error when there is a target but devoted servant is in-love.\", async() => {\n const players = [\n createFakeDevotedServantAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer(),\n ];\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer({ isAlive: false }) })];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsBuryDeadBodies(), players });\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.DEVOTED_SERVANT_CANT_STEAL_ROLE);\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlaySurvivorsTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Devoted servant can't steal the role of this target because she's not in the game or dead or powerless or in love with another player\" });\n });\n\n it(\"should throw error when there is a target but he can't be interacted with the devoted servant.\", async() => {\n const players = [\n createFakeDevotedServantAlivePlayer(),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer(),\n ];\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer({ isAlive: false }) })];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsBuryDeadBodies(), players });\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_DEVOTED_SERVANT_TARGET);\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlaySurvivorsTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Devoted servant can't steal the role of this target because he's not about to be buried\" });\n });\n\n it(\"should do nothing when target is valid for devoted servant.\", () => {\n const players = [\n createFakeDevotedServantAlivePlayer(),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer(),\n ];\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer({ isAlive: false }) })];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsBuryDeadBodies(), players });\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n\n expect(() => services.gamePlayValidator[\"validateGamePlaySurvivorsTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n });\n\n describe(\"validateDrankLifePotionTargets\", () => {\n it(\"should throw error when there are too much targets for life potion.\", async() => {\n const game = createFakeGameWithCurrentPlay();\n const drankLifePotionTargets = [\n createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"life\" }),\n createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"life\" }),\n ];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.TOO_MUCH_DRANK_LIFE_POTION_TARGETS);\n const error = await getError(() => services.gamePlayValidator[\"validateDrankLifePotionTargets\"](drankLifePotionTargets, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"There are too much targets which drank life potion (`targets.drankPotion`)\" });\n });\n\n it(\"should throw error when life potion target can't drink it.\", async() => {\n const game = createFakeGameWithCurrentPlay();\n const targetedPlayer = createFakePlayer({ isAlive: true, attributes: [] });\n const drankLifePotionTargets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: targetedPlayer, drankPotion: \"life\" })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_LIFE_POTION_TARGET);\n const error = await getError(() => services.gamePlayValidator[\"validateDrankLifePotionTargets\"](drankLifePotionTargets, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Life potion can't be applied to this target (`targets.drankPotion`)\" });\n });\n\n it(\"should do nothing when there is no life potion target.\", () => {\n const game = createFakeGameWithCurrentPlay();\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n\n expect(() => services.gamePlayValidator[\"validateDrankLifePotionTargets\"]([], game)).not.toThrow();\n });\n\n it(\"should do nothing when life potion target is applied on valid target.\", () => {\n const game = createFakeGameWithCurrentPlay();\n const targetedPlayer = createFakePlayer({ attributes: [createFakeEatenByWerewolvesPlayerAttribute()], isAlive: true });\n const drankLifePotionTargets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: targetedPlayer, drankPotion: \"life\" })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n\n expect(() => services.gamePlayValidator[\"validateDrankLifePotionTargets\"](drankLifePotionTargets, game)).not.toThrow();\n });\n });\n\n describe(\"validateDrankDeathPotionTargets\", () => {\n it(\"should throw error when there are too much targets for death potion.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWitchUsesPotions() });\n const drankDeathPotionTargets = [\n createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"death\" }),\n createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"death\" }),\n ];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.TOO_MUCH_DRANK_DEATH_POTION_TARGETS);\n const error = await getError(() => services.gamePlayValidator[\"validateDrankDeathPotionTargets\"](drankDeathPotionTargets, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"There are too much targets which drank death potion (`targets.drankPotion`)\" });\n });\n\n it(\"should throw error when death potion target can't drink it.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWitchUsesPotions() });\n const targetedPlayer = createFakePlayer({ isAlive: false });\n const drankDeathPotionTargets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: targetedPlayer, drankPotion: \"death\" })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_DEATH_POTION_TARGET);\n const error = await getError(() => services.gamePlayValidator[\"validateDrankDeathPotionTargets\"](drankDeathPotionTargets, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Death potion can't be applied to this target (`targets.drankPotion`)\" });\n });\n\n it(\"should do nothing when there is no death potion target.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWitchUsesPotions() });\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n\n expect(() => services.gamePlayValidator[\"validateDrankDeathPotionTargets\"]([], game)).not.toThrow();\n });\n\n it(\"should do nothing when death potion target is applied on valid target.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWitchUsesPotions() });\n const targetedPlayer = createFakePlayer({ isAlive: true });\n const drankDeathPotionTargets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: targetedPlayer, drankPotion: \"death\" })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n\n expect(() => services.gamePlayValidator[\"validateDrankDeathPotionTargets\"](drankDeathPotionTargets, game)).not.toThrow();\n });\n });\n\n describe(\"validateGamePlayWitchTargets\", () => {\n beforeEach(() => {\n mocks.gamePlayValidatorService.validateDrankLifePotionTargets = jest.spyOn(services.gamePlayValidator as unknown as { validateDrankLifePotionTargets }, \"validateDrankLifePotionTargets\").mockImplementation();\n mocks.gamePlayValidatorService.validateDrankDeathPotionTargets = jest.spyOn(services.gamePlayValidator as unknown as { validateDrankDeathPotionTargets }, \"validateDrankDeathPotionTargets\").mockImplementation();\n });\n\n it(\"should throw error when witch is not in the game.\", async() => {\n const players = [\n createFakeIdiotAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlayWitchUsesPotions() });\n const makeGamePlayTargetsWithRelationsDto = [\n createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"life\" }),\n createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"death\" }),\n ];\n const mockedError = new UnexpectedException(\"validateGamePlayWitchTargets\", UnexpectedExceptionReasons.CANT_FIND_PLAYER_WITH_CURRENT_ROLE_IN_GAME, { gameId: game._id.toString(), roleName: \"witch\" });\n mocks.unexpectedExceptionFactory.createCantFindPlayerWithCurrentRoleUnexpectedException.mockReturnValue(mockedError);\n\n await expect(services.gamePlayValidator[\"validateGamePlayWitchTargets\"](makeGamePlayTargetsWithRelationsDto, game)).rejects.toStrictEqual(mockedError);\n expect(mocks.unexpectedExceptionFactory.createCantFindPlayerWithCurrentRoleUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"validateGamePlayWitchTargets\", { gameId: game._id, roleName: \"witch\" });\n });\n\n it(\"should throw error when witch targeted someone with life potion but already used it with death potion before.\", async() => {\n const players = [\n createFakeWitchAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlayWitchUsesPotions() });\n const makeGamePlayTargetsWithRelationsDto = [\n createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"life\" }),\n createFakeMakeGamePlayTargetWithRelationsDto(),\n ];\n const gameHistoryRecordTargets = [\n createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"death\" }),\n createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"life\" }),\n ];\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ play: createFakeGameHistoryRecordSurvivorsVotePlay() }),\n createFakeGameHistoryRecord({ play: createFakeGameHistoryRecordWitchUsePotionsPlay({ targets: gameHistoryRecordTargets }) }),\n ];\n when(mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords).calledWith(game._id, players[0]._id, \"life\").mockResolvedValue(gameHistoryRecords);\n when(mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords).calledWith(game._id, players[0]._id, \"death\").mockResolvedValue(gameHistoryRecords);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.UNEXPECTED_DRANK_POTION_TARGET);\n const error = await getError(async() => services.gamePlayValidator[\"validateGamePlayWitchTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"`targets.drankPotion` can't be set on this current game's state\" });\n });\n\n it(\"should throw error when witch targeted someone with life potion but already used it alone before.\", async() => {\n const players = [\n createFakeWitchAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlayWitchUsesPotions() });\n const makeGamePlayTargetsWithRelationsDto = [\n createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"life\" }),\n createFakeMakeGamePlayTargetWithRelationsDto({}),\n ];\n const gameHistoryRecordTargets = [createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"life\" })];\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ play: createFakeGameHistoryRecordSurvivorsVotePlay() }),\n createFakeGameHistoryRecord({ play: createFakeGameHistoryRecordWitchUsePotionsPlay({ targets: gameHistoryRecordTargets }) }),\n ];\n when(mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords).calledWith(game._id, players[0]._id, \"life\").mockResolvedValue(gameHistoryRecords);\n when(mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords).calledWith(game._id, players[0]._id, \"death\").mockResolvedValue([]);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.UNEXPECTED_DRANK_POTION_TARGET);\n const error = await getError(async() => services.gamePlayValidator[\"validateGamePlayWitchTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"`targets.drankPotion` can't be set on this current game's state\" });\n });\n\n it(\"should throw error when witch targeted someone with death potion but already used it with life potion before.\", async() => {\n const players = [\n createFakeWitchAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlayWitchUsesPotions() });\n const makeGamePlayTargetsWithRelationsDto = [\n createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"death\" }),\n createFakeMakeGamePlayTargetWithRelationsDto(),\n ];\n const gameHistoryRecordTargets = [\n createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"death\" }),\n createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"life\" }),\n ];\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ play: createFakeGameHistoryRecordSurvivorsVotePlay() }),\n createFakeGameHistoryRecord({ play: createFakeGameHistoryRecordWitchUsePotionsPlay({ targets: gameHistoryRecordTargets }) }),\n ];\n when(mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords).calledWith(game._id, players[0]._id, \"life\").mockResolvedValue(gameHistoryRecords);\n when(mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords).calledWith(game._id, players[0]._id, \"death\").mockResolvedValue(gameHistoryRecords);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.UNEXPECTED_DRANK_POTION_TARGET);\n const error = await getError(async() => services.gamePlayValidator[\"validateGamePlayWitchTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"`targets.drankPotion` can't be set on this current game's state\" });\n });\n\n it(\"should throw error when witch targeted someone with death potion but already used it alone before.\", async() => {\n const players = [\n createFakeWitchAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlayWitchUsesPotions() });\n const makeGamePlayTargetsWithRelationsDto = [\n createFakeMakeGamePlayTargetWithRelationsDto({ player: game.players[1], drankPotion: \"death\" }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: game.players[2] }),\n ];\n const gameHistoryRecordTargets = [createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"death\" })];\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ play: createFakeGameHistoryRecordSurvivorsVotePlay() }),\n createFakeGameHistoryRecord({ play: createFakeGameHistoryRecordWitchUsePotionsPlay({ targets: gameHistoryRecordTargets }) }),\n ];\n when(mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords).calledWith(game._id, players[0]._id, \"life\").mockResolvedValue([]);\n when(mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords).calledWith(game._id, players[0]._id, \"death\").mockResolvedValue(gameHistoryRecords);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.UNEXPECTED_DRANK_POTION_TARGET);\n const error = await getError(async() => services.gamePlayValidator[\"validateGamePlayWitchTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"`targets.drankPotion` can't be set on this current game's state\" });\n });\n\n it(\"should call potions validators without players when called with valid data but no target drank potions.\", async() => {\n const players = [\n createFakeWitchAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlayWitchUsesPotions() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeSeerAlivePlayer() })];\n when(mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords).calledWith(game._id, players[0]._id, \"life\").mockResolvedValue([]);\n when(mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords).calledWith(game._id, players[0]._id, \"death\").mockResolvedValue([]);\n\n await expect(services.gamePlayValidator[\"validateGamePlayWitchTargets\"](makeGamePlayTargetsWithRelationsDto, game)).toResolve();\n expect(mocks.gamePlayValidatorService.validateDrankLifePotionTargets).toHaveBeenCalledExactlyOnceWith([], game);\n expect(mocks.gamePlayValidatorService.validateDrankDeathPotionTargets).toHaveBeenCalledExactlyOnceWith([], game);\n });\n\n it(\"should call potions validators with players when called without bad data and without witch history.\", async() => {\n const players = [\n createFakeWitchAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlayWitchUsesPotions() });\n const makeGamePlayTargetsWithRelationsDto = [\n createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"life\" }),\n createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"death\" }),\n ];\n when(mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords).calledWith(game._id, players[0]._id, \"life\").mockResolvedValue([]);\n when(mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords).calledWith(game._id, players[0]._id, \"death\").mockResolvedValue([]);\n\n await expect(services.gamePlayValidator[\"validateGamePlayWitchTargets\"](makeGamePlayTargetsWithRelationsDto, game)).toResolve();\n expect(mocks.gamePlayValidatorService.validateDrankLifePotionTargets).toHaveBeenCalledExactlyOnceWith([makeGamePlayTargetsWithRelationsDto[0]], game);\n expect(mocks.gamePlayValidatorService.validateDrankDeathPotionTargets).toHaveBeenCalledExactlyOnceWith([makeGamePlayTargetsWithRelationsDto[1]], game);\n });\n\n it(\"should call potions validators with players when called for valid life potion data and some witch history.\", async() => {\n const players = [\n createFakeWitchAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlayWitchUsesPotions() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"life\" })];\n const gameHistoryRecordTargets = [createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"death\" })];\n const gameHistoryRecords = [createFakeGameHistoryRecord({ play: createFakeGameHistoryRecordWitchUsePotionsPlay({ targets: gameHistoryRecordTargets }) })];\n when(mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords).calledWith(game._id, players[0]._id, \"life\").mockReturnValue([]);\n when(mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords).calledWith(game._id, players[0]._id, \"death\").mockResolvedValue(gameHistoryRecords);\n\n await expect(services.gamePlayValidator[\"validateGamePlayWitchTargets\"](makeGamePlayTargetsWithRelationsDto, game)).toResolve();\n expect(mocks.gamePlayValidatorService.validateDrankLifePotionTargets).toHaveBeenCalledExactlyOnceWith([makeGamePlayTargetsWithRelationsDto[0]], game);\n expect(mocks.gamePlayValidatorService.validateDrankDeathPotionTargets).toHaveBeenCalledExactlyOnceWith([], game);\n });\n\n it(\"should call potions validators with players when called for valid death potion data and some witch history.\", async() => {\n const players = [\n createFakeWitchAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlayWitchUsesPotions() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"death\" })];\n const gameHistoryRecordTargets = [createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"life\" })];\n const gameHistoryRecords = [createFakeGameHistoryRecord({ play: createFakeGameHistoryRecordWitchUsePotionsPlay({ targets: gameHistoryRecordTargets }) })];\n when(mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords).calledWith(game._id, players[0]._id, \"life\").mockResolvedValue(gameHistoryRecords);\n when(mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords).calledWith(game._id, players[0]._id, \"death\").mockResolvedValue([]);\n\n await expect(services.gamePlayValidator[\"validateGamePlayWitchTargets\"](makeGamePlayTargetsWithRelationsDto, game)).toResolve();\n expect(mocks.gamePlayValidatorService.validateDrankLifePotionTargets).toHaveBeenCalledExactlyOnceWith([], game);\n expect(mocks.gamePlayValidatorService.validateDrankDeathPotionTargets).toHaveBeenCalledExactlyOnceWith([makeGamePlayTargetsWithRelationsDto[0]], game);\n });\n });\n\n describe(\"validateGamePlayAccursedWolfFatherTargets\", () => {\n beforeEach(() => {\n mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayTargetsBoundaries }, \"validateGamePlayTargetsBoundaries\").mockImplementation();\n });\n\n it(\"should call validateGamePlayTargetsBoundaries when called.\", () => {\n const players = [\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWerewolvesEat(), players });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: game.players[0] })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n services.gamePlayValidator[\"validateGamePlayAccursedWolfFatherTargets\"](makeGamePlayTargetsWithRelationsDto, game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries).toHaveBeenCalledExactlyOnceWith(makeGamePlayTargetsWithRelationsDto, \"infect\", game);\n });\n\n it(\"should do nothing when there is no target.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayAccursedWolfFatherInfects() });\n const makeGamePlayTargetsWithRelationsDto = [];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n\n expect(() => services.gamePlayValidator[\"validateGamePlayAccursedWolfFatherTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n\n it(\"should throw error when there is a target but he can't be interacted with the accursed wolf father.\", async() => {\n const players = [\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWerewolvesEat(), players });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: game.players[1] })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_ACCURSED_WOLF_FATHER_TARGET);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayAccursedWolfFatherTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Accursed Wolf-father can't infect this target\" });\n });\n\n it(\"should do nothing when target is valid for accursed wolf father.\", () => {\n const players = [\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWerewolvesEat(), players });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: game.players[0] })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n\n expect(() => services.gamePlayValidator[\"validateGamePlayAccursedWolfFatherTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n });\n\n describe(\"validateGamePlayWerewolvesTargets\", () => {\n beforeEach(() => {\n mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayTargetsBoundaries }, \"validateGamePlayTargetsBoundaries\").mockImplementation();\n });\n\n it(\"should call validateGamePlayTargetsBoundaries when called.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayAccursedWolfFatherInfects() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto()];\n services.gamePlayValidator[\"validateGamePlayWerewolvesTargets\"](makeGamePlayTargetsWithRelationsDto, game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries).toHaveBeenCalledExactlyOnceWith(makeGamePlayTargetsWithRelationsDto, \"eat\", game);\n });\n\n it(\"should do nothing when there is no target.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWerewolvesEat() });\n const makeGamePlayTargetsWithRelationsDto = [];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n\n expect(() => services.gamePlayValidator[\"validateGamePlayWerewolvesTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n\n it(\"should do nothing when game's current play action is not werewolves eat.\", () => {\n const players = [\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySeerLooks(), players });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: game.players[1] })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n\n expect(() => services.gamePlayValidator[\"validateGamePlayWerewolvesTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n\n it(\"should throw error when source are werewolves and targeted player can't be eaten by them.\", async() => {\n const players = [\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWerewolvesEat(), players });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: game.players[1] })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_WEREWOLVES_TARGET);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayWerewolvesTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Werewolves can't eat this target\" });\n });\n\n it(\"should throw error when source is big bad wolf and targeted player can't be eaten by him.\", async() => {\n const players = [\n createFakeVillagerAlivePlayer({ attributes: [createFakeEatenByWerewolvesPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayBigBadWolfEats(), players });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: game.players[0] })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_BIG_BAD_WOLF_TARGET);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayWerewolvesTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Big bad wolf can't eat this target\" });\n });\n\n it(\"should throw error when source is white werewolf and targeted player can't be eaten by him.\", async() => {\n const whiteWerewolfPlayer = createFakeWhiteWerewolfAlivePlayer();\n const players = [\n whiteWerewolfPlayer,\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWhiteWerewolfEats(), players });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: whiteWerewolfPlayer })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_ACCURSED_WOLF_FATHER_TARGET);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayWerewolvesTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"White werewolf can't eat this target\" });\n });\n\n it(\"should do nothing when white werewolf eaten target is valid.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWhiteWerewolfEats(), players });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[0] })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n\n expect(() => services.gamePlayValidator[\"validateGamePlayWerewolvesTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n\n it(\"should do nothing when big bad wolf eaten target is valid.\", () => {\n const players = [createFakeVillagerAlivePlayer()];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayBigBadWolfEats(), players });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[0] })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n\n expect(() => services.gamePlayValidator[\"validateGamePlayWerewolvesTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n\n it(\"should do nothing when werewolves eaten target is valid.\", () => {\n const players = [createFakeVillagerAlivePlayer()];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWerewolvesEat(), players });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[0] })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n\n expect(() => services.gamePlayValidator[\"validateGamePlayWerewolvesTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n });\n\n describe(\"validateGamePlayHunterTargets\", () => {\n beforeEach(() => {\n mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayTargetsBoundaries }, \"validateGamePlayTargetsBoundaries\").mockImplementation();\n });\n\n it(\"should call validateGamePlayTargetsBoundaries when called.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayHunterShoots() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer() })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n services.gamePlayValidator[\"validateGamePlayHunterTargets\"](makeGamePlayTargetsWithRelationsDto, game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries).toHaveBeenCalledExactlyOnceWith(makeGamePlayTargetsWithRelationsDto, \"shoot\", game);\n });\n\n it(\"should throw error when targeted player can't be shot.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayHunterShoots() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer({ isAlive: false }) })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_HUNTER_TARGET);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayHunterTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Hunter can't shoot this target\" });\n });\n\n it(\"should do nothing when targeted player for hunter is valid.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayHunterShoots() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer() })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n\n expect(() => services.gamePlayValidator[\"validateGamePlayHunterTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n });\n\n describe(\"validateGamePlayScapeGoatTargets\", () => {\n beforeEach(() => {\n mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayTargetsBoundaries }, \"validateGamePlayTargetsBoundaries\").mockImplementation();\n });\n\n it(\"should call validateGamePlayTargetsBoundaries when called.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayScapegoatBansVoting() });\n const makeGamePlayTargetsWithRelationsDto = [\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer() }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer() }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeWerewolfAlivePlayer() }),\n ];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n services.gamePlayValidator[\"validateGamePlayScapegoatTargets\"](makeGamePlayTargetsWithRelationsDto, game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries).toHaveBeenCalledExactlyOnceWith(makeGamePlayTargetsWithRelationsDto, \"ban-voting\", game);\n });\n\n it(\"should throw error when one of the targeted player can't be banned from voting.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayScapegoatBansVoting() });\n const makeGamePlayTargetsWithRelationsDto = [\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer() }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer({ isAlive: false }) }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeWerewolfAlivePlayer() }),\n ];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValueOnce(true);\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValueOnce(false);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_SCAPEGOAT_TARGETS);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayScapegoatTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"At least one of the scapegoat targets can't be banned from voting\" });\n });\n\n it(\"should do nothing when all scapegoat's targets are valid.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayScapegoatBansVoting() });\n const makeGamePlayTargetsWithRelationsDto = [\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer() }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer() }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeWerewolfAlivePlayer() }),\n ];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n\n expect(() => services.gamePlayValidator[\"validateGamePlayScapegoatTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n });\n\n describe(\"validateGamePlayCupidTargets\", () => {\n beforeEach(() => {\n mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayTargetsBoundaries }, \"validateGamePlayTargetsBoundaries\").mockImplementation();\n });\n\n it(\"should call validateGamePlayTargetsBoundaries when called.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayCupidCharms() });\n const makeGamePlayTargetsWithRelationsDto = [\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer() }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer() }),\n ];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n services.gamePlayValidator[\"validateGamePlayCupidTargets\"](makeGamePlayTargetsWithRelationsDto, game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries).toHaveBeenCalledExactlyOnceWith(makeGamePlayTargetsWithRelationsDto, \"charm\", game);\n });\n\n it(\"should throw error when one of the targeted player can't be charmed.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayCupidCharms() });\n const makeGamePlayTargetsWithRelationsDto = [\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer() }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer({ isAlive: false }) }),\n ];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValueOnce(true);\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValueOnce(false);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_CUPID_TARGETS);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayCupidTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"At least one of the cupid targets can't be charmed\" });\n });\n\n it(\"should do nothing when all cupid's targets are valid.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayCupidCharms() });\n const makeGamePlayTargetsWithRelationsDto = [\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer() }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer() }),\n ];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n\n expect(() => services.gamePlayValidator[\"validateGamePlayCupidTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n });\n\n describe(\"validateGamePlayFoxTargets\", () => {\n beforeEach(() => {\n mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayTargetsBoundaries }, \"validateGamePlayTargetsBoundaries\").mockImplementation();\n });\n\n it(\"should call validateGamePlayTargetsBoundaries when called.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayFoxSniffs() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer() })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n services.gamePlayValidator[\"validateGamePlayFoxTargets\"](makeGamePlayTargetsWithRelationsDto, game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries).toHaveBeenCalledExactlyOnceWith(makeGamePlayTargetsWithRelationsDto, \"sniff\", game);\n });\n\n it(\"should do nothing when there are no targets.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayFoxSniffs() });\n const makeGamePlayTargetsWithRelationsDto = [];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n\n expect(() => services.gamePlayValidator[\"validateGamePlayFoxTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n\n it(\"should throw error when targeted player can't be sniffed.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayFoxSniffs() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer({ isAlive: false }) })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_FOX_TARGET);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayFoxTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Fox can't sniff this target\" });\n });\n\n it(\"should do nothing when targeted player for fox is valid.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayFoxSniffs() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer() })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n\n expect(() => services.gamePlayValidator[\"validateGamePlayFoxTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n });\n\n describe(\"validateGamePlaySeerTargets\", () => {\n beforeEach(() => {\n mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayTargetsBoundaries }, \"validateGamePlayTargetsBoundaries\").mockImplementation();\n });\n\n it(\"should call validateGamePlayTargetsBoundaries when called.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySeerLooks() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeWerewolfAlivePlayer() })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n services.gamePlayValidator[\"validateGamePlaySeerTargets\"](makeGamePlayTargetsWithRelationsDto, game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries).toHaveBeenCalledExactlyOnceWith(makeGamePlayTargetsWithRelationsDto, \"look\", game);\n });\n\n it(\"should throw error when targeted player can't be seen.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySeerLooks() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer({ isAlive: false }) })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_SEER_TARGET);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlaySeerTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Seer can't look at this target\" });\n });\n\n it(\"should do nothing when seer's targeted player is valid.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySeerLooks() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeWerewolfAlivePlayer() })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n\n expect(() => services.gamePlayValidator[\"validateGamePlaySeerTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n });\n\n describe(\"validateGamePlayScandalmongerTargets\", () => {\n beforeEach(() => {\n mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayTargetsBoundaries }, \"validateGamePlayTargetsBoundaries\").mockImplementation();\n });\n\n it(\"should call validateGamePlayTargetsBoundaries when called.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayScandalmongerMarks() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeWerewolfAlivePlayer() })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n services.gamePlayValidator[\"validateGamePlayScandalmongerTargets\"](makeGamePlayTargetsWithRelationsDto, game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries).toHaveBeenCalledExactlyOnceWith(makeGamePlayTargetsWithRelationsDto, \"mark\", game);\n });\n\n it(\"should throw error when targeted player can't be marked.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayScandalmongerMarks() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer({ isAlive: false }) })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_SCANDALMONGER_TARGET);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayScandalmongerTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Scandalmonger can't mark this target\" });\n });\n\n it(\"should do nothing when there are no targets.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayScandalmongerMarks() });\n const makeGamePlayTargetsWithRelationsDto = [];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n\n expect(() => services.gamePlayValidator[\"validateGamePlayScandalmongerTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n\n it(\"should do nothing when scandalmonger's target is valid.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayScandalmongerMarks() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeWerewolfAlivePlayer() })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n\n expect(() => services.gamePlayValidator[\"validateGamePlayScandalmongerTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n });\n\n describe(\"validateGamePlayWildChildTargets\", () => {\n beforeEach(() => {\n mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayTargetsBoundaries }, \"validateGamePlayTargetsBoundaries\").mockImplementation();\n });\n\n it(\"should call validateGamePlayTargetsBoundaries when called.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWildChildChoosesModel() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeWerewolfAlivePlayer() })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n services.gamePlayValidator[\"validateGamePlayWildChildTargets\"](makeGamePlayTargetsWithRelationsDto, game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries).toHaveBeenCalledExactlyOnceWith(makeGamePlayTargetsWithRelationsDto, \"choose-as-model\", game);\n });\n\n it(\"should throw error when targeted player can't be chosen as model.\", async() => {\n const wildChildPlayer = createFakeWildChildAlivePlayer();\n const players = [\n wildChildPlayer,\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWildChildChoosesModel(), players });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: wildChildPlayer })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_WILD_CHILD_TARGET);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayWildChildTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Wild child can't choose this target as a model\" });\n });\n\n it(\"should do nothing when wild child's targeted player is valid.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWildChildChoosesModel() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeWerewolfAlivePlayer() })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n\n expect(() => services.gamePlayValidator[\"validateGamePlayWildChildTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n });\n\n describe(\"validateGamePlayPiedPiperTargets\", () => {\n beforeEach(() => {\n mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayTargetsBoundaries }, \"validateGamePlayTargetsBoundaries\").mockImplementation();\n });\n\n it(\"should call validateGamePlayTargetsBoundaries when called.\", () => {\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ piedPiper: createFakePiedPiperGameOptions({ charmedPeopleCountPerNight: 5 }) }) });\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayPiedPiperCharms(), options });\n const leftToCharmPlayers = [createFakeWildChildAlivePlayer()];\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: leftToCharmPlayers[0] })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n services.gamePlayValidator[\"validateGamePlayPiedPiperTargets\"](makeGamePlayTargetsWithRelationsDto, game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries).toHaveBeenCalledExactlyOnceWith(makeGamePlayTargetsWithRelationsDto, \"charm\", game);\n });\n\n it(\"should throw error when one of the targeted player is not in the last to charm.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayPiedPiperCharms() });\n const leftToCharmPlayers = [\n createFakeWildChildAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const makeGamePlayTargetsWithRelationsDto = [\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer() }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: leftToCharmPlayers[0] }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: leftToCharmPlayers[1] }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: leftToCharmPlayers[2] }),\n ];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValueOnce(true);\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValueOnce(false);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_PIED_PIPER_TARGETS);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayPiedPiperTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"At least one of the pied piper targets can't be charmed\" });\n });\n\n it(\"should do nothing when pied piper targets are valid and limited to game options.\", () => {\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ piedPiper: createFakePiedPiperGameOptions({ charmedPeopleCountPerNight: 2 }) }) });\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayPiedPiperCharms(), options });\n const leftToCharmPlayers = [\n createFakeWildChildAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const makeGamePlayTargetsWithRelationsDto = [\n createFakeMakeGamePlayTargetWithRelationsDto({ player: leftToCharmPlayers[0] }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: leftToCharmPlayers[1] }),\n ];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n\n expect(() => services.gamePlayValidator[\"validateGamePlayPiedPiperTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n\n it(\"should do nothing when pied piper targets are valid and limited to left players to charm count.\", () => {\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ piedPiper: createFakePiedPiperGameOptions({ charmedPeopleCountPerNight: 5 }) }) });\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayPiedPiperCharms(), options });\n const leftToCharmPlayers = [createFakeWildChildAlivePlayer()];\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: leftToCharmPlayers[0] })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n\n expect(() => services.gamePlayValidator[\"validateGamePlayPiedPiperTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n });\n\n describe(\"validateGamePlayDefenderTargets\", () => {\n beforeEach(() => {\n mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayTargetsBoundaries }, \"validateGamePlayTargetsBoundaries\").mockImplementation();\n });\n\n it(\"should call validateGamePlayTargetsBoundaries when called.\", () => {\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ defender: { canProtectTwice: false } }) });\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayDefenderProtects(), options });\n const targetedPlayer = createFakeVillagerAlivePlayer();\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: targetedPlayer })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n services.gamePlayValidator[\"validateGamePlayDefenderTargets\"](makeGamePlayTargetsWithRelationsDto, game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries).toHaveBeenCalledExactlyOnceWith(makeGamePlayTargetsWithRelationsDto, \"protect\", game);\n });\n\n it(\"should throw error when targeted player can't be targeted.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayDefenderProtects() });\n const targetedPlayer = createFakeVillagerAlivePlayer({ isAlive: false });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: targetedPlayer })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_DEFENDER_TARGET);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayDefenderTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Defender can't protect this target\" });\n });\n\n it(\"should do nothing when targeted player can be protected.\", () => {\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ defender: { canProtectTwice: false } }) });\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayDefenderProtects(), options });\n const targetedPlayer = createFakeVillagerAlivePlayer();\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: targetedPlayer })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n\n expect(() => services.gamePlayValidator[\"validateGamePlayDefenderTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n });\n\n describe(\"validateGamePlaySheriffTargets\", () => {\n beforeEach(() => {\n mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayTargetsBoundaries }, \"validateGamePlayTargetsBoundaries\").mockImplementation();\n });\n\n it(\"should call validateGamePlayTargetsBoundaries when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlaySheriffDelegates() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: game.players[0] })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValueOnce(true);\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValueOnce(false);\n services.gamePlayValidator[\"validateGamePlaySheriffTargets\"](makeGamePlayTargetsWithRelationsDto, game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries).toHaveBeenNthCalledWith(1, makeGamePlayTargetsWithRelationsDto, \"transfer-sheriff-role\", game);\n expect(mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries).toHaveBeenNthCalledWith(2, makeGamePlayTargetsWithRelationsDto, \"sentence-to-death\", game);\n });\n\n it(\"should do nothing when game play action is not DELEGATE nor SETTLE_VOTES.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySheriffDelegates({ action: \"use-potions\" }) });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto()];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n\n expect(() => services.gamePlayValidator[\"validateGamePlaySheriffTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n\n it(\"should do nothing when targeted player for sheriff delegation is valid.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySheriffDelegates() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeSeerAlivePlayer() })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n\n expect(() => services.gamePlayValidator[\"validateGamePlaySheriffTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n\n it(\"should throw error when targeted player is not in last tie in votes and upcoming action is SETTLE_VOTES.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySheriffSettlesVotes() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer({ isAlive: false }) })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_SHERIFF_SETTLE_VOTES_TARGET);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlaySheriffTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Sheriff can't break the tie in votes with this target\" });\n });\n\n it(\"should throw error when targeted player is not in last tie in votes and upcoming action is DELEGATE.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySheriffDelegates() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer({ isAlive: false }) })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(false);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_SHERIFF_DELEGATE_TARGET);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlaySheriffTargets\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Sheriff can't delegate his role to this target\" });\n });\n\n it(\"should do nothing when targeted player for sheriff settling votes is valid for delegate.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlaySheriffDelegates() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: game.players[0] })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValueOnce(true);\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValueOnce(false);\n\n expect(() => services.gamePlayValidator[\"validateGamePlaySheriffTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n\n it(\"should do nothing when targeted player for sheriff settling votes is valid for settle votes.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlaySheriffSettlesVotes() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto({ player: game.players[0] })];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValueOnce(false);\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValueOnce(true);\n\n expect(() => services.gamePlayValidator[\"validateGamePlaySheriffTargets\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n });\n\n describe(\"validateGamePlayTargetsBoundaries\", () => {\n it(\"should do nothing when interaction is not found.\", () => {\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto()];\n const game = createFakeGameWithCurrentPlay({\n currentPlay: createFakeGamePlaySheriffDelegates({\n source: createFakeGamePlaySource({\n interactions: [\n createFakeGamePlaySourceInteraction({\n type: \"transfer-sheriff-role\",\n boundaries: createFakeGamePlaySourceInteractionBoundaries({ min: 4, max: 4 }),\n }),\n ],\n }),\n }),\n });\n\n expect(() => services.gamePlayValidator[\"validateGamePlayTargetsBoundaries\"](makeGamePlayTargetsWithRelationsDto, \"charm\", game)).not.toThrow();\n });\n\n it(\"should throw error when min boundary is not respected.\", async() => {\n const makeGamePlayTargetsWithRelationsDto = [\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeSeerAlivePlayer() }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer() }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeWerewolfAlivePlayer() }),\n ];\n const game = createFakeGameWithCurrentPlay({\n currentPlay: createFakeGamePlaySheriffDelegates({\n source: createFakeGamePlaySource({\n interactions: [\n createFakeGamePlaySourceInteraction({\n type: \"transfer-sheriff-role\",\n boundaries: createFakeGamePlaySourceInteractionBoundaries({ min: 4, max: 4 }),\n }),\n ],\n }),\n }),\n });\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.TOO_LESS_TARGETS);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayTargetsBoundaries\"](makeGamePlayTargetsWithRelationsDto, \"transfer-sheriff-role\", game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"There are too less targets for this current game's state\" });\n });\n\n it(\"should throw error when max boundary is not respected.\", async() => {\n const makeGamePlayTargetsWithRelationsDto = [\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeSeerAlivePlayer() }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer() }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeWerewolfAlivePlayer() }),\n ];\n const game = createFakeGameWithCurrentPlay({\n currentPlay: createFakeGamePlaySheriffDelegates({\n source: createFakeGamePlaySource({\n interactions: [\n createFakeGamePlaySourceInteraction({\n type: \"transfer-sheriff-role\",\n boundaries: createFakeGamePlaySourceInteractionBoundaries({ min: 1, max: 2 }),\n }),\n ],\n }),\n }),\n });\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.TOO_MUCH_TARGETS);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayTargetsBoundaries\"](makeGamePlayTargetsWithRelationsDto, \"transfer-sheriff-role\", game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"There are too much targets for this current game's state\" });\n });\n\n it(\"should do nothing when boundaries are respected, even equal to max.\", () => {\n const makeGamePlayTargetsWithRelationsDto = [\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeSeerAlivePlayer() }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer() }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeWerewolfAlivePlayer() }),\n ];\n const game = createFakeGameWithCurrentPlay({\n currentPlay: createFakeGamePlaySheriffDelegates({\n source: createFakeGamePlaySource({\n interactions: [\n createFakeGamePlaySourceInteraction({\n type: \"transfer-sheriff-role\",\n boundaries: createFakeGamePlaySourceInteractionBoundaries({ min: 3, max: 3 }),\n }),\n ],\n }),\n }),\n });\n\n expect(() => services.gamePlayValidator[\"validateGamePlayTargetsBoundaries\"](makeGamePlayTargetsWithRelationsDto, \"transfer-sheriff-role\", game)).not.toThrow();\n });\n\n it(\"should do nothing when boundaries are respected, even equal to min.\", () => {\n const makeGamePlayTargetsWithRelationsDto = [\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeSeerAlivePlayer() }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeVillagerAlivePlayer() }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: createFakeWerewolfAlivePlayer() }),\n ];\n const game = createFakeGameWithCurrentPlay({\n currentPlay: createFakeGamePlaySheriffDelegates({\n source: createFakeGamePlaySource({\n interactions: [\n createFakeGamePlaySourceInteraction({\n type: \"transfer-sheriff-role\",\n boundaries: createFakeGamePlaySourceInteractionBoundaries({ min: 3, max: 4 }),\n }),\n ],\n }),\n }),\n });\n\n expect(() => services.gamePlayValidator[\"validateGamePlayTargetsBoundaries\"](makeGamePlayTargetsWithRelationsDto, \"transfer-sheriff-role\", game)).not.toThrow();\n });\n });\n\n describe(\"validateGamePlaySourceTargets\", () => {\n beforeEach(() => {\n mocks.gamePlayValidatorService.validateGamePlaySheriffTargets = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlaySheriffTargets }, \"validateGamePlaySheriffTargets\").mockImplementation();\n mocks.gamePlayValidatorService.validateGamePlayDefenderTargets = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayDefenderTargets }, \"validateGamePlayDefenderTargets\").mockImplementation();\n mocks.gamePlayValidatorService.validateGamePlayPiedPiperTargets = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayPiedPiperTargets }, \"validateGamePlayPiedPiperTargets\").mockImplementation();\n mocks.gamePlayValidatorService.validateGamePlayWildChildTargets = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayWildChildTargets }, \"validateGamePlayWildChildTargets\").mockImplementation();\n mocks.gamePlayValidatorService.validateGamePlayScandalmongerTargets = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayScandalmongerTargets }, \"validateGamePlayScandalmongerTargets\").mockImplementation();\n mocks.gamePlayValidatorService.validateGamePlaySeerTargets = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlaySeerTargets }, \"validateGamePlaySeerTargets\").mockImplementation();\n mocks.gamePlayValidatorService.validateGamePlayFoxTargets = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayFoxTargets }, \"validateGamePlayFoxTargets\").mockImplementation();\n mocks.gamePlayValidatorService.validateGamePlayCupidTargets = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayCupidTargets }, \"validateGamePlayCupidTargets\").mockImplementation();\n mocks.gamePlayValidatorService.validateGamePlayScapegoatTargets = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayScapegoatTargets }, \"validateGamePlayScapegoatTargets\").mockImplementation();\n mocks.gamePlayValidatorService.validateGamePlayHunterTargets = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayHunterTargets }, \"validateGamePlayHunterTargets\").mockImplementation();\n mocks.gamePlayValidatorService.validateGamePlayWerewolvesTargets = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayWerewolvesTargets }, \"validateGamePlayWerewolvesTargets\").mockImplementation();\n mocks.gamePlayValidatorService.validateGamePlayAccursedWolfFatherTargets = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayAccursedWolfFatherTargets }, \"validateGamePlayAccursedWolfFatherTargets\").mockImplementation();\n mocks.gamePlayValidatorService.validateGamePlayWitchTargets = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayWitchTargets }, \"validateGamePlayWitchTargets\").mockImplementation();\n mocks.gamePlayValidatorService.validateGamePlaySurvivorsTargets = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlaySurvivorsTargets }, \"validateGamePlaySurvivorsTargets\").mockImplementation();\n });\n\n it(\"should call sheriff validator when game current play is for the sheriff.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySheriffSettlesVotes() });\n await services.gamePlayValidator[\"validateGamePlaySourceTargets\"]([], game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlaySheriffTargets).toHaveBeenCalledExactlyOnceWith([], game);\n expect(mocks.gamePlayValidatorService.validateGamePlaySurvivorsTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayDefenderTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayPiedPiperTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWildChildTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScandalmongerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySeerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayFoxTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayCupidTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScapegoatTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayHunterTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWitchTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayAccursedWolfFatherTargets).not.toHaveBeenCalled();\n });\n\n it(\"should call survivors validator when game current play is for the survivors.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsVote() });\n await services.gamePlayValidator[\"validateGamePlaySourceTargets\"]([], game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlaySheriffTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySurvivorsTargets).toHaveBeenCalledExactlyOnceWith([], game);\n expect(mocks.gamePlayValidatorService.validateGamePlayDefenderTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayPiedPiperTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWildChildTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScandalmongerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySeerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayFoxTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayCupidTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScapegoatTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayHunterTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWitchTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayAccursedWolfFatherTargets).not.toHaveBeenCalled();\n });\n\n it(\"should call werewolves validator when game current play is for the werewolves.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWerewolvesEat() });\n await services.gamePlayValidator[\"validateGamePlaySourceTargets\"]([], game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlaySheriffTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySurvivorsTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWerewolvesTargets).toHaveBeenCalledExactlyOnceWith([], game);\n expect(mocks.gamePlayValidatorService.validateGamePlayAccursedWolfFatherTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayDefenderTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayPiedPiperTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWildChildTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScandalmongerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySeerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayFoxTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayCupidTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScapegoatTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayHunterTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWitchTargets).not.toHaveBeenCalled();\n });\n\n it(\"should call accursed wolf-father validator when game current play is for the accursed wolf father.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayAccursedWolfFatherInfects() });\n await services.gamePlayValidator[\"validateGamePlaySourceTargets\"]([], game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlaySheriffTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySurvivorsTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWerewolvesTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayAccursedWolfFatherTargets).toHaveBeenCalledExactlyOnceWith([], game);\n expect(mocks.gamePlayValidatorService.validateGamePlayDefenderTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayPiedPiperTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWildChildTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScandalmongerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySeerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayFoxTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayCupidTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScapegoatTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayHunterTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWitchTargets).not.toHaveBeenCalled();\n });\n\n it(\"should call werewolves validator when game current play is for the big bad wolf.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayBigBadWolfEats() });\n await services.gamePlayValidator[\"validateGamePlaySourceTargets\"]([], game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlaySurvivorsTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySheriffTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWerewolvesTargets).toHaveBeenCalledExactlyOnceWith([], game);\n expect(mocks.gamePlayValidatorService.validateGamePlayDefenderTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayPiedPiperTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWildChildTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScandalmongerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySeerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayFoxTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayCupidTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScapegoatTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayHunterTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWitchTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayAccursedWolfFatherTargets).not.toHaveBeenCalled();\n });\n\n it(\"should call werewolves validator when game current play is for the white werewolf.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWhiteWerewolfEats() });\n await services.gamePlayValidator[\"validateGamePlaySourceTargets\"]([], game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlaySurvivorsTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySheriffTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWerewolvesTargets).toHaveBeenCalledExactlyOnceWith([], game);\n expect(mocks.gamePlayValidatorService.validateGamePlayDefenderTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayPiedPiperTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWildChildTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScandalmongerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySeerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayFoxTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayCupidTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScapegoatTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayHunterTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWitchTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayAccursedWolfFatherTargets).not.toHaveBeenCalled();\n });\n\n it(\"should call defender validator when game current play is for the defender.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayDefenderProtects() });\n await services.gamePlayValidator[\"validateGamePlaySourceTargets\"]([], game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlaySurvivorsTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySheriffTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWerewolvesTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayDefenderTargets).toHaveBeenCalledExactlyOnceWith([], game);\n expect(mocks.gamePlayValidatorService.validateGamePlayPiedPiperTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWildChildTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScandalmongerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySeerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayFoxTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayCupidTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScapegoatTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayHunterTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWitchTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayAccursedWolfFatherTargets).not.toHaveBeenCalled();\n });\n\n it(\"should call pied piper validator when game current play is for the pied piper.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayPiedPiperCharms() });\n await services.gamePlayValidator[\"validateGamePlaySourceTargets\"]([], game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlaySurvivorsTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySheriffTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWerewolvesTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayDefenderTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayPiedPiperTargets).toHaveBeenCalledExactlyOnceWith([], game);\n expect(mocks.gamePlayValidatorService.validateGamePlayWildChildTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScandalmongerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySeerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayFoxTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayCupidTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScapegoatTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayHunterTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWitchTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayAccursedWolfFatherTargets).not.toHaveBeenCalled();\n });\n\n it(\"should call wild child validator when game current play is for the wild child.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWildChildChoosesModel() });\n await services.gamePlayValidator[\"validateGamePlaySourceTargets\"]([], game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlaySurvivorsTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySheriffTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWerewolvesTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayDefenderTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayPiedPiperTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWildChildTargets).toHaveBeenCalledExactlyOnceWith([], game);\n expect(mocks.gamePlayValidatorService.validateGamePlayScandalmongerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySeerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayFoxTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayCupidTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScapegoatTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayHunterTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWitchTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayAccursedWolfFatherTargets).not.toHaveBeenCalled();\n });\n\n it(\"should call scandalmonger validator when game current play is for the scandalmonger.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayScandalmongerMarks() });\n await services.gamePlayValidator[\"validateGamePlaySourceTargets\"]([], game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlaySurvivorsTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySheriffTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWerewolvesTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayDefenderTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayPiedPiperTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWildChildTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScandalmongerTargets).toHaveBeenCalledExactlyOnceWith([], game);\n expect(mocks.gamePlayValidatorService.validateGamePlaySeerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayFoxTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayCupidTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScapegoatTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayHunterTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWitchTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayAccursedWolfFatherTargets).not.toHaveBeenCalled();\n });\n\n it(\"should call seer validator when game current play is for the seer.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySeerLooks() });\n await services.gamePlayValidator[\"validateGamePlaySourceTargets\"]([], game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlaySurvivorsTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySheriffTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWerewolvesTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayDefenderTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayPiedPiperTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWildChildTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScandalmongerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySeerTargets).toHaveBeenCalledExactlyOnceWith([], game);\n expect(mocks.gamePlayValidatorService.validateGamePlayFoxTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayCupidTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScapegoatTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayHunterTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWitchTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayAccursedWolfFatherTargets).not.toHaveBeenCalled();\n });\n\n it(\"should call fox validator when game current play is for the fox.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayFoxSniffs() });\n await services.gamePlayValidator[\"validateGamePlaySourceTargets\"]([], game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlaySurvivorsTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySheriffTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWerewolvesTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayDefenderTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayPiedPiperTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWildChildTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScandalmongerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySeerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayFoxTargets).toHaveBeenCalledExactlyOnceWith([], game);\n expect(mocks.gamePlayValidatorService.validateGamePlayCupidTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScapegoatTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayHunterTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWitchTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayAccursedWolfFatherTargets).not.toHaveBeenCalled();\n });\n\n it(\"should call cupid validator when game current play is for the cupid.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayCupidCharms() });\n await services.gamePlayValidator[\"validateGamePlaySourceTargets\"]([], game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlaySurvivorsTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySheriffTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWerewolvesTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayDefenderTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayPiedPiperTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWildChildTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScandalmongerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySeerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayFoxTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayCupidTargets).toHaveBeenCalledExactlyOnceWith([], game);\n expect(mocks.gamePlayValidatorService.validateGamePlayScapegoatTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayHunterTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWitchTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayAccursedWolfFatherTargets).not.toHaveBeenCalled();\n });\n\n it(\"should call scapegoat validator when game current play is for the scapegoat.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayScapegoatBansVoting() });\n await services.gamePlayValidator[\"validateGamePlaySourceTargets\"]([], game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlaySurvivorsTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySheriffTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWerewolvesTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayDefenderTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayPiedPiperTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWildChildTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScandalmongerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySeerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayFoxTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayCupidTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScapegoatTargets).toHaveBeenCalledExactlyOnceWith([], game);\n expect(mocks.gamePlayValidatorService.validateGamePlayHunterTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWitchTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayAccursedWolfFatherTargets).not.toHaveBeenCalled();\n });\n\n it(\"should call hunter validator when game current play is for the hunter.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayHunterShoots() });\n await services.gamePlayValidator[\"validateGamePlaySourceTargets\"]([], game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlaySurvivorsTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySheriffTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWerewolvesTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayDefenderTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayPiedPiperTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWildChildTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScandalmongerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySeerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayFoxTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayCupidTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScapegoatTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayHunterTargets).toHaveBeenCalledExactlyOnceWith([], game);\n expect(mocks.gamePlayValidatorService.validateGamePlayWitchTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayAccursedWolfFatherTargets).not.toHaveBeenCalled();\n });\n\n it(\"should call witch validator when game current play is for the witch.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWitchUsesPotions() });\n await services.gamePlayValidator[\"validateGamePlaySourceTargets\"]([], game);\n\n expect(mocks.gamePlayValidatorService.validateGamePlaySurvivorsTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySheriffTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWerewolvesTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayDefenderTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayPiedPiperTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWildChildTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScandalmongerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlaySeerTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayFoxTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayCupidTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayScapegoatTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayHunterTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayAccursedWolfFatherTargets).not.toHaveBeenCalled();\n expect(mocks.gamePlayValidatorService.validateGamePlayWitchTargets).toHaveBeenCalledExactlyOnceWith([], game);\n });\n });\n\n describe(\"validateTargetsPotionUsage\", () => {\n it(\"should throw error when expected action is not use potions but targets drank potions.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWitchUsesPotions({ action: \"choose-card\" }) });\n const makeGamePlayTargetsWithRelationsDto = [\n createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"life\" }),\n createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"death\" }),\n createFakeMakeGamePlayTargetWithRelationsDto(),\n ];\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.UNEXPECTED_DRANK_POTION_TARGET);\n const error = await getError(() => services.gamePlayValidator[\"validateTargetsPotionUsage\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"`targets.drankPotion` can't be set on this current game's state\" });\n });\n\n it(\"should throw error when expected source is not witch but targets drank potions.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWitchUsesPotions({ source: createFakeGamePlaySource({ name: \"thief\" }) }) });\n const makeGamePlayTargetsWithRelationsDto = [\n createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"life\" }),\n createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"death\" }),\n createFakeMakeGamePlayTargetWithRelationsDto(),\n ];\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.UNEXPECTED_DRANK_POTION_TARGET);\n const error = await getError(() => services.gamePlayValidator[\"validateTargetsPotionUsage\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"`targets.drankPotion` can't be set on this current game's state\" });\n });\n\n it(\"should do nothing when expected some players drank potions and game play is valid.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWitchUsesPotions() });\n const makeGamePlayTargetsWithRelationsDto = [\n createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"life\" }),\n createFakeMakeGamePlayTargetWithRelationsDto({ drankPotion: \"death\" }),\n createFakeMakeGamePlayTargetWithRelationsDto(),\n ];\n\n expect(() => services.gamePlayValidator[\"validateTargetsPotionUsage\"](makeGamePlayTargetsWithRelationsDto, game)).not.toThrow();\n });\n });\n\n describe(\"validateGamePlayTargetsWithRelationsDto\", () => {\n beforeEach(() => {\n mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayTargetsBoundaries }, \"validateGamePlayTargetsBoundaries\").mockImplementation();\n mocks.gamePlayValidatorService.validateTargetsPotionUsage = jest.spyOn(services.gamePlayValidator as unknown as { validateTargetsPotionUsage }, \"validateTargetsPotionUsage\").mockImplementation();\n mocks.gamePlayValidatorService.validateGamePlaySourceTargets = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlaySourceTargets }, \"validateGamePlaySourceTargets\").mockImplementation();\n });\n\n it(\"should do nothing when there are no targets defined and upcoming action doesn't require targets anyway.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsVote() });\n\n await expect(services.gamePlayValidator[\"validateGamePlayTargetsWithRelationsDto\"](undefined, game)).toResolve();\n expect(mocks.gamePlayValidatorService.validateTargetsPotionUsage).not.toHaveBeenCalled();\n });\n\n it(\"should do nothing when there are no targets and upcoming action can be skipped.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayFoxSniffs({ canBeSkipped: true }) });\n\n await expect(services.gamePlayValidator[\"validateGamePlayTargetsWithRelationsDto\"]([], game)).toResolve();\n expect(mocks.gamePlayValidatorService.validateTargetsPotionUsage).not.toHaveBeenCalled();\n });\n\n it(\"should throw error when there is no targets but they are required cause action can't be skipped.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySeerLooks({ canBeSkipped: false }) });\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.REQUIRED_TARGETS);\n const error = await getError(async() => services.gamePlayValidator[\"validateGamePlayTargetsWithRelationsDto\"]([], game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"`targets` is required on this current game's state\" });\n });\n\n it(\"should throw error when there are targets but they are not expected.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsVote() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto()];\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.UNEXPECTED_TARGETS);\n const error = await getError(async() => services.gamePlayValidator[\"validateGamePlayTargetsWithRelationsDto\"](makeGamePlayTargetsWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"`targets` can't be set on this current game's state\" });\n });\n\n it(\"should not validate game play targets boundaries when targets are expected but current play doesn't have eligible targets boundaries.\", async() => {\n const currentPlay = createFakeGamePlayWerewolvesEat();\n const game = createFakeGameWithCurrentPlay({ currentPlay });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto()];\n\n await expect(services.gamePlayValidator[\"validateGamePlayTargetsWithRelationsDto\"](makeGamePlayTargetsWithRelationsDto, game)).toResolve();\n expect(mocks.gamePlayValidatorService.validateGamePlayTargetsBoundaries).not.toHaveBeenCalled();\n });\n\n it(\"should call targets validators when targets data is valid.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWerewolvesEat() });\n const makeGamePlayTargetsWithRelationsDto = [createFakeMakeGamePlayTargetWithRelationsDto()];\n\n await expect(services.gamePlayValidator[\"validateGamePlayTargetsWithRelationsDto\"](makeGamePlayTargetsWithRelationsDto, game)).toResolve();\n expect(mocks.gamePlayValidatorService.validateGamePlaySourceTargets).toHaveBeenCalledOnce();\n expect(mocks.gamePlayValidatorService.validateTargetsPotionUsage).toHaveBeenCalledOnce();\n });\n });\n\n describe(\"validateGamePlayVotesTieBreakerWithRelationsDto\", () => {\n it(\"should throw error when action is vote and cause is previous votes were in tie but one voted player is not in the previous tie.\", async() => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeIdiotAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const source = createFakeGamePlaySource({ name: \"survivors\", players: [players[2]] });\n const currentPlay = createFakeGamePlaySurvivorsVote({ source, causes: [\"previous-votes-were-in-ties\"] });\n const game = createFakeGameWithCurrentPlay({ currentPlay, players });\n const makeGamePlayVotesWithRelationsDto = [\n createFakeMakeGamePlayVoteWithRelationsDto({ target: players[0] }),\n createFakeMakeGamePlayVoteWithRelationsDto({ target: players[1] }),\n createFakeMakeGamePlayVoteWithRelationsDto({ target: players[2] }),\n ];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValueOnce(false);\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_VOTE_TARGET_FOR_TIE_BREAKER);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayVotesTieBreakerWithRelationsDto\"](makeGamePlayVotesWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"One vote's target is not in the previous tie in votes\" });\n });\n\n it(\"should throw error when action is elect sheriff and cause is previous votes were in tie but one voted player is not in the previous tie.\", async() => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeIdiotAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const source = createFakeGamePlaySource({ name: \"survivors\", players: [players[2]] });\n const currentPlay = createFakeGamePlaySurvivorsElectSheriff({ source, causes: [\"previous-votes-were-in-ties\"] });\n const game = createFakeGameWithCurrentPlay({ currentPlay, players });\n const makeGamePlayVotesWithRelationsDto = [\n createFakeMakeGamePlayVoteWithRelationsDto({ target: players[0] }),\n createFakeMakeGamePlayVoteWithRelationsDto({ target: players[1] }),\n createFakeMakeGamePlayVoteWithRelationsDto({ target: players[2] }),\n ];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValueOnce(false);\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_VOTE_TARGET_FOR_TIE_BREAKER);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayVotesTieBreakerWithRelationsDto\"](makeGamePlayVotesWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"One vote's target is not in the previous tie in votes\" });\n });\n\n it(\"should call isPlayerInteractableWithInteractionTypeInCurrentGamePlay with vote interaction type when action is vote.\", () => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeIdiotAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const currentPlay = createFakeGamePlaySurvivorsVote({ causes: [\"previous-votes-were-in-ties\"] });\n const game = createFakeGameWithCurrentPlay({ currentPlay, players });\n const makeGamePlayVotesWithRelationsDto = [\n createFakeMakeGamePlayVoteWithRelationsDto({ target: players[0] }),\n createFakeMakeGamePlayVoteWithRelationsDto({ target: players[1] }),\n ];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n services.gamePlayValidator[\"validateGamePlayVotesTieBreakerWithRelationsDto\"](makeGamePlayVotesWithRelationsDto, game);\n\n expect(mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay).toHaveBeenNthCalledWith(1, players[0]._id, \"vote\", game);\n expect(mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay).toHaveBeenNthCalledWith(2, players[1]._id, \"vote\", game);\n });\n\n it(\"should call isPlayerInteractableWithInteractionTypeInCurrentGamePlay with choose as sheriff interaction type when action is elect sheriff.\", () => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeIdiotAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const currentPlay = createFakeGamePlaySurvivorsElectSheriff({ causes: [\"previous-votes-were-in-ties\"] });\n const game = createFakeGameWithCurrentPlay({ currentPlay, players });\n const makeGamePlayVotesWithRelationsDto = [\n createFakeMakeGamePlayVoteWithRelationsDto({ target: players[0] }),\n createFakeMakeGamePlayVoteWithRelationsDto({ target: players[1] }),\n ];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n services.gamePlayValidator[\"validateGamePlayVotesTieBreakerWithRelationsDto\"](makeGamePlayVotesWithRelationsDto, game);\n\n expect(mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay).toHaveBeenNthCalledWith(1, players[0]._id, \"choose-as-sheriff\", game);\n expect(mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay).toHaveBeenNthCalledWith(2, players[1]._id, \"choose-as-sheriff\", game);\n });\n\n it(\"should do nothing when cause is previous votes were in tie and all voted players were in previous tie.\", () => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeIdiotAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const currentPlay = createFakeGamePlaySurvivorsVote({ causes: [\"previous-votes-were-in-ties\"] });\n const game = createFakeGameWithCurrentPlay({ currentPlay, players });\n const makeGamePlayVotesWithRelationsDto = [\n createFakeMakeGamePlayVoteWithRelationsDto({ target: players[0] }),\n createFakeMakeGamePlayVoteWithRelationsDto({ target: players[1] }),\n ];\n mocks.gamePlayHelper.isPlayerInteractableWithInteractionTypeInCurrentGamePlay.mockReturnValue(true);\n\n expect(() => services.gamePlayValidator[\"validateGamePlayVotesTieBreakerWithRelationsDto\"](makeGamePlayVotesWithRelationsDto, game)).not.toThrow();\n });\n\n it(\"should do nothing when cause is not previous votes were in tie.\", () => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeIdiotAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const source = createFakeGamePlaySource({ name: \"survivors\", players: [players[2]] });\n const currentPlay = createFakeGamePlaySurvivorsVote({ source, causes: [\"angel-presence\"] });\n const game = createFakeGameWithCurrentPlay({ currentPlay, players });\n const makeGamePlayVotesWithRelationsDto = [\n createFakeMakeGamePlayVoteWithRelationsDto({ target: players[0] }),\n createFakeMakeGamePlayVoteWithRelationsDto({ target: players[1] }),\n createFakeMakeGamePlayVoteWithRelationsDto({ target: players[2] }),\n ];\n\n expect(() => services.gamePlayValidator[\"validateGamePlayVotesTieBreakerWithRelationsDto\"](makeGamePlayVotesWithRelationsDto, game)).not.toThrow();\n });\n });\n\n describe(\"validateGamePlayVotesWithRelationsDtoSourceAndTarget\", () => {\n it(\"should throw error when one vote source doesn't have the ability to vote.\", async() => {\n const players = [\n createFakeSeerAlivePlayer({ attributes: [createFakeCantVoteBySurvivorsPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer(),\n createFakeIdiotAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const source = createFakeGamePlaySource({ name: \"survivors\", players: [players[2]] });\n const currentPlay = createFakeGamePlaySurvivorsVote({ source });\n const game = createFakeGameWithCurrentPlay({ players, currentPlay });\n const makeGamePlayVotesWithRelationsDto = [\n createFakeMakeGamePlayVoteWithRelationsDto({ source: players[0], target: players[1] }),\n createFakeMakeGamePlayVoteWithRelationsDto({ source: players[2], target: players[1] }),\n ];\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_VOTE_SOURCE);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayVotesWithRelationsDtoSourceAndTarget\"](makeGamePlayVotesWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"One source is not able to vote because he's dead or doesn't have the ability to do so\" });\n });\n\n it(\"should throw error when one vote target can't be voted against.\", async() => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeIdiotAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const source = createFakeGamePlaySource({\n name: \"survivors\",\n players,\n interactions: [\n createFakeGamePlaySourceInteraction({\n type: \"vote\",\n source: \"survivors\",\n eligibleTargets: [players[1], players[2], players[3]],\n boundaries: { min: 1, max: 1 },\n }),\n ],\n });\n const currentPlay = createFakeGamePlaySurvivorsVote({ source });\n const game = createFakeGameWithCurrentPlay({ players, currentPlay });\n const makeGamePlayVotesWithRelationsDto = [\n createFakeMakeGamePlayVoteWithRelationsDto({ source: players[0], target: players[1] }),\n createFakeMakeGamePlayVoteWithRelationsDto({ source: players[2], target: players[1] }),\n createFakeMakeGamePlayVoteWithRelationsDto({ source: players[3], target: players[0] }),\n ];\n mocks.gamePlayHelper.isPlayerInteractableInCurrentGamePlay.mockReturnValueOnce(false);\n mocks.gamePlayHelper.isPlayerInteractableInCurrentGamePlay.mockReturnValueOnce(true);\n mocks.gamePlayHelper.isPlayerInteractableInCurrentGamePlay.mockReturnValueOnce(true);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.BAD_VOTE_TARGET);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayVotesWithRelationsDtoSourceAndTarget\"](makeGamePlayVotesWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"One target can't be voted because he's dead\" });\n });\n\n it(\"should throw error when there are votes with the same source and target.\", async() => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeIdiotAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const source = createFakeGamePlaySource({ name: \"survivors\", players });\n const currentPlay = createFakeGamePlaySurvivorsVote({ source });\n const game = createFakeGameWithCurrentPlay({ currentPlay, players });\n const makeGamePlayVotesWithRelationsDto = [\n createFakeMakeGamePlayVoteWithRelationsDto({ source: players[0], target: players[0] }),\n createFakeMakeGamePlayVoteWithRelationsDto({ source: players[2], target: players[1] }),\n ];\n mocks.gamePlayHelper.isPlayerInteractableInCurrentGamePlay.mockReturnValue(true);\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.SAME_SOURCE_AND_TARGET_VOTE);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayVotesWithRelationsDtoSourceAndTarget\"](makeGamePlayVotesWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"One vote has the same source and target\" });\n });\n });\n\n describe(\"validateGamePlayVotesWithRelationsDto\", () => {\n beforeEach(() => {\n mocks.gamePlayValidatorService.validateGamePlayVotesTieBreakerWithRelationsDto = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayVotesTieBreakerWithRelationsDto }, \"validateGamePlayVotesTieBreakerWithRelationsDto\").mockImplementation();\n mocks.gamePlayValidatorService.validateGamePlayVotesWithRelationsDtoSourceAndTarget = jest.spyOn(services.gamePlayValidator as unknown as { validateGamePlayVotesWithRelationsDtoSourceAndTarget }, \"validateGamePlayVotesWithRelationsDtoSourceAndTarget\").mockImplementation();\n });\n\n it(\"should do nothing when there are no votes defined but game play is not for votes anyway.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWerewolvesEat() });\n\n expect(() => services.gamePlayValidator[\"validateGamePlayVotesWithRelationsDto\"](undefined, game)).not.toThrow();\n });\n\n it(\"should throw error when there are empty votes but they are not expected.\", async() => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlayWerewolvesEat() });\n const makeGamePlayVotesWithRelationsDto = [];\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.UNEXPECTED_VOTES);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayVotesWithRelationsDto\"](makeGamePlayVotesWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"`votes` can't be set on this current game's state\" });\n });\n\n it(\"should throw error when there are votes but they are not expected.\", async() => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlayWerewolvesEat() });\n const makeGamePlayVotesWithRelationsDto = [createFakeMakeGamePlayVoteWithRelationsDto()];\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.UNEXPECTED_VOTES);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayVotesWithRelationsDto\"](makeGamePlayVotesWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"`votes` can't be set on this current game's state\" });\n });\n\n it(\"should do nothing when there are no votes defined but game play of votes can be skipped.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsVote({ canBeSkipped: true }) });\n\n expect(() => services.gamePlayValidator[\"validateGamePlayVotesWithRelationsDto\"](undefined, game)).not.toThrow();\n });\n\n it(\"should do nothing when there are no votes (empty array) but game play of votes can be skipped.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsVote({ canBeSkipped: true }) });\n\n expect(() => services.gamePlayValidator[\"validateGamePlayVotesWithRelationsDto\"]([], game)).not.toThrow();\n });\n\n it(\"should throw error when there are no votes (undefined) but game play of votes can't be skipped.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsVote({ canBeSkipped: false }) });\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.UNEXPECTED_VOTES);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayVotesWithRelationsDto\"](undefined, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"`votes` is required on this current game's state\" });\n });\n\n it(\"should throw error when there are no votes (empty array) but game play of votes can't be skipped.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsVote({ canBeSkipped: false }) });\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.UNEXPECTED_VOTES);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayVotesWithRelationsDto\"]([], game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"`votes` is required on this current game's state\" });\n });\n\n it(\"should call validateGamePlayVotesTieBreakerWithRelationsDto when current play is because of previous votes were in ties.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlaySurvivorsVote({ causes: [\"previous-votes-were-in-ties\"] }) });\n const makeGamePlayVotesWithRelationsDto = [createFakeMakeGamePlayVoteWithRelationsDto({ source: game.players[0], target: game.players[1] })];\n\n expect(() => services.gamePlayValidator[\"validateGamePlayVotesWithRelationsDto\"](makeGamePlayVotesWithRelationsDto, game)).not.toThrow();\n expect(mocks.gamePlayValidatorService.validateGamePlayVotesTieBreakerWithRelationsDto).toHaveBeenCalledExactlyOnceWith(makeGamePlayVotesWithRelationsDto, game);\n });\n\n it(\"should not call validateGamePlayVotesTieBreakerWithRelationsDto when current play is not because of previous votes were in ties.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlaySurvivorsVote({ causes: [\"angel-presence\"] }) });\n const makeGamePlayVotesWithRelationsDto = [createFakeMakeGamePlayVoteWithRelationsDto({ source: game.players[0], target: game.players[1] })];\n\n expect(() => services.gamePlayValidator[\"validateGamePlayVotesWithRelationsDto\"](makeGamePlayVotesWithRelationsDto, game)).not.toThrow();\n expect(mocks.gamePlayValidatorService.validateGamePlayVotesTieBreakerWithRelationsDto).not.toHaveBeenCalled();\n });\n\n it(\"should do nothing when votes are valid.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlaySurvivorsVote() });\n const makeGamePlayVotesWithRelationsDto = [createFakeMakeGamePlayVoteWithRelationsDto({ source: game.players[0], target: game.players[1] })];\n\n expect(() => services.gamePlayValidator[\"validateGamePlayVotesWithRelationsDto\"](makeGamePlayVotesWithRelationsDto, game)).not.toThrow();\n });\n });\n\n describe(\"validateGamePlayWithRelationsDtoChosenSide\", () => {\n it(\"should throw error when chosenSide is defined and game play action is not CHOOSE_SIDE.\", async() => {\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ wolfHound: createFakeWolfHoundGameOptions({ isSideRandomlyChosen: false }) }) });\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsVote(), options });\n const makeGamePlayWithRelationsDto = createFakeMakeGamePlayWithRelationsDto({ chosenSide: \"werewolves\" });\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.UNEXPECTED_CHOSEN_SIDE);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayWithRelationsDtoChosenSide\"](makeGamePlayWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"`chosenSide` can't be set on this current game's state\" });\n });\n\n it(\"should throw error when chosenSide is defined and game play action is CHOOSE_SIDE but game options say that it is randomly chosen.\", async() => {\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ wolfHound: createFakeWolfHoundGameOptions({ isSideRandomlyChosen: true }) }) });\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWolfHoundChoosesSide(), options });\n const makeGamePlayWithRelationsDto = createFakeMakeGamePlayWithRelationsDto({ chosenSide: \"werewolves\" });\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.UNEXPECTED_CHOSEN_SIDE);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayWithRelationsDtoChosenSide\"](makeGamePlayWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"`chosenSide` can't be set on this current game's state\" });\n });\n\n it(\"should throw error when chosenSide is not defined and game play action is CHOOSE_SIDE and game options say that side is not randomly chosen.\", async() => {\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ wolfHound: createFakeWolfHoundGameOptions({ isSideRandomlyChosen: false }) }) });\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWolfHoundChoosesSide(), options });\n const makeGamePlayWithRelationsDto = createFakeMakeGamePlayWithRelationsDto();\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.REQUIRED_CHOSEN_SIDE);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayWithRelationsDtoChosenSide\"](makeGamePlayWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"`chosenSide` is required on this current game's state\" });\n });\n\n it(\"should do nothing when chosenSide is defined and game play action is CHOOSE_SIDE and game options say that side is not randomly chosen.\", () => {\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ wolfHound: createFakeWolfHoundGameOptions({ isSideRandomlyChosen: false }) }) });\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWolfHoundChoosesSide(), options });\n const makeGamePlayWithRelationsDto = createFakeMakeGamePlayWithRelationsDto({ chosenSide: \"werewolves\" });\n\n expect(() => services.gamePlayValidator[\"validateGamePlayWithRelationsDtoChosenSide\"](makeGamePlayWithRelationsDto, game)).not.toThrow();\n });\n\n it(\"should do nothing when chosenSide is not defined and game play action is not CHOOSE_SIDE.\", () => {\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ wolfHound: createFakeWolfHoundGameOptions({ isSideRandomlyChosen: false }) }) });\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsVote(), options });\n const makeGamePlayWithRelationsDto = createFakeMakeGamePlayWithRelationsDto();\n\n expect(() => services.gamePlayValidator[\"validateGamePlayWithRelationsDtoChosenSide\"](makeGamePlayWithRelationsDto, game)).not.toThrow();\n });\n\n it(\"should do nothing when chosenSide is not defined and game play action CHOOSE_SIDE but game options say that side is randomly chosen.\", () => {\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ wolfHound: createFakeWolfHoundGameOptions({ isSideRandomlyChosen: true }) }) });\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsVote(), options });\n const makeGamePlayWithRelationsDto = createFakeMakeGamePlayWithRelationsDto();\n\n expect(() => services.gamePlayValidator[\"validateGamePlayWithRelationsDtoChosenSide\"](makeGamePlayWithRelationsDto, game)).not.toThrow();\n });\n });\n\n describe(\"validateGamePlayWithRelationsDtoJudgeRequest\", () => {\n beforeEach(() => {\n mocks.gameHistoryRecordService.didJudgeMakeHisSign.mockResolvedValue(true);\n });\n\n it(\"should throw error when doesJudgeRequestAnotherVote is defined and game play action is not request another vote.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsVote() });\n const makeGamePlayWithRelationsDto = createFakeMakeGamePlayWithRelationsDto({ doesJudgeRequestAnotherVote: true });\n const expectedError = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.UNEXPECTED_STUTTERING_JUDGE_VOTE_REQUEST);\n const error = await getError(() => services.gamePlayValidator[\"validateGamePlayWithRelationsDtoJudgeRequest\"](makeGamePlayWithRelationsDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"`doesJudgeRequestAnotherVote` can't be set on this current game's state\" });\n });\n\n it(\"should do nothing when doesJudgeRequestAnotherVote is undefined.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsVote() });\n const makeGamePlayWithRelationsDto = createFakeMakeGamePlayWithRelationsDto();\n\n expect(() => services.gamePlayValidator[\"validateGamePlayWithRelationsDtoJudgeRequest\"](makeGamePlayWithRelationsDto, game)).not.toThrow();\n });\n\n it(\"should do nothing when doesJudgeRequestAnotherVote defined and action is request another vote.\", () => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayStutteringJudgeRequestsAnotherVote() });\n const makeGamePlayWithRelationsDto = createFakeMakeGamePlayWithRelationsDto({ doesJudgeRequestAnotherVote: true });\n\n expect(() => services.gamePlayValidator[\"validateGamePlayWithRelationsDtoJudgeRequest\"](makeGamePlayWithRelationsDto, game)).not.toThrow();\n });\n });\n});" }, "tests/unit/specs/modules/game/providers/services/game-play/game-play.service.spec.ts": { "tests": [ @@ -189483,7 +189485,7 @@ } } ], - "source": "import type { TestingModule } from \"@nestjs/testing\";\nimport { Test } from \"@nestjs/testing\";\nimport lodash from \"lodash\";\n\nimport type { MakeGamePlayVoteWithRelationsDto } from \"@/modules/game/dto/make-game-play/make-game-play-vote/make-game-play-vote-with-relations.dto\";\nimport * as GameMutator from \"@/modules/game/helpers/game.mutators\";\nimport * as PlayerHelper from \"@/modules/game/helpers/player/player.helpers\";\nimport { GameHistoryRecordService } from \"@/modules/game/providers/services/game-history/game-history-record.service\";\nimport { DevotedServantGamePlayMakerService } from \"@/modules/game/providers/services/game-play/game-play-maker/devoted-servant-game-play-maker.service\";\nimport { GamePlayMakerService } from \"@/modules/game/providers/services/game-play/game-play-maker/game-play-maker.service\";\nimport { GamePlayVoteService } from \"@/modules/game/providers/services/game-play/game-play-vote/game-play-vote.service\";\nimport { PlayerKillerService } from \"@/modules/game/providers/services/player/player-killer.service\";\nimport type { Game } from \"@/modules/game/schemas/game.schema\";\nimport type { DeadPlayer } from \"@/modules/game/schemas/player/dead-player.schema\";\n\nimport { UnexpectedExceptionReasons } from \"@/shared/exception/enums/unexpected-exception.enum\";\nimport * as UnexpectedExceptionFactory from \"@/shared/exception/helpers/unexpected-exception.factory\";\nimport { UnexpectedException } from \"@/shared/exception/types/unexpected-exception.types\";\n\nimport { createFakeMakeGamePlayTargetWithRelationsDto } from \"@tests/factories/game/dto/make-game-play/make-game-play-with-relations/make-game-play-target-with-relations.dto.factory\";\nimport { createFakeMakeGamePlayVoteWithRelationsDto } from \"@tests/factories/game/dto/make-game-play/make-game-play-with-relations/make-game-play-vote-with-relations.dto.factory\";\nimport { createFakeMakeGamePlayWithRelationsDto } from \"@tests/factories/game/dto/make-game-play/make-game-play-with-relations/make-game-play-with-relations.dto.factory\";\nimport { createFakeGameAdditionalCard } from \"@tests/factories/game/schemas/game-additional-card/game-additional-card.schema.factory\";\nimport { createFakeGameHistoryRecord } from \"@tests/factories/game/schemas/game-history-record/game-history-record.schema.factory\";\nimport { createFakeGameOptions } from \"@tests/factories/game/schemas/game-options/game-options.schema.factory\";\nimport { createFakeActorGameOptions, createFakeFoxGameOptions, createFakeRolesGameOptions, createFakeSheriffGameOptions } from \"@tests/factories/game/schemas/game-options/game-roles-options/game-roles-options.schema.factory\";\nimport { createFakeGamePlayAccursedWolfFatherInfects, createFakeGamePlayActorChoosesCard, createFakeGamePlayBigBadWolfEats, createFakeGamePlayCharmedMeetEachOther, createFakeGamePlayCupidCharms, createFakeGamePlayDefenderProtects, createFakeGamePlayFoxSniffs, createFakeGamePlayHunterShoots, createFakeGamePlayLoversMeetEachOther, createFakeGamePlayPiedPiperCharms, createFakeGamePlayScandalmongerMarks, createFakeGamePlayScapegoatBansVoting, createFakeGamePlaySeerLooks, createFakeGamePlaySheriffDelegates, createFakeGamePlaySheriffSettlesVotes, createFakeGamePlayStutteringJudgeRequestsAnotherVote, createFakeGamePlaySurvivorsBuryDeadBodies, createFakeGamePlaySurvivorsElectSheriff, createFakeGamePlaySurvivorsVote, createFakeGamePlayThiefChoosesCard, createFakeGamePlayThreeBrothersMeetEachOther, createFakeGamePlayTwoSistersMeetEachOther, createFakeGamePlayWerewolvesEat, createFakeGamePlayWhiteWerewolfEats, createFakeGamePlayWildChildChoosesModel, createFakeGamePlayWitchUsesPotions, createFakeGamePlayWolfHoundChoosesSide } from \"@tests/factories/game/schemas/game-play/game-play.schema.factory\";\nimport { createFakeGame, createFakeGameWithCurrentPlay } from \"@tests/factories/game/schemas/game.schema.factory\";\nimport { createFakeActingByActorPlayerAttribute, createFakeCantVoteByScapegoatPlayerAttribute, createFakeCharmedByPiedPiperPlayerAttribute, createFakeDrankDeathPotionByWitchPlayerAttribute, createFakeDrankLifePotionByWitchPlayerAttribute, createFakeEatenByBigBadWolfPlayerAttribute, createFakeEatenByWerewolvesPlayerAttribute, createFakeEatenByWhiteWerewolfPlayerAttribute, createFakeInLoveByCupidPlayerAttribute, createFakePowerlessByAccursedWolfFatherPlayerAttribute, createFakePowerlessByActorPlayerAttribute, createFakePowerlessByElderPlayerAttribute, createFakePowerlessByFoxPlayerAttribute, createFakeProtectedByDefenderPlayerAttribute, createFakeScandalmongerMarkedByScandalmongerPlayerAttribute, createFakeSeenBySeerPlayerAttribute, createFakeSheriffBySheriffPlayerAttribute, createFakeSheriffBySurvivorsPlayerAttribute, createFakeWorshipedByWildChildPlayerAttribute } from \"@tests/factories/game/schemas/player/player-attribute/player-attribute.schema.factory\";\nimport { createFakePlayerShotByHunterDeath, createFakePlayerVoteBySheriffDeath, createFakePlayerVoteBySurvivorsDeath, createFakePlayerVoteScapegoatedBySurvivorsDeath } from \"@tests/factories/game/schemas/player/player-death/player-death.schema.factory\";\nimport { createFakeActorAlivePlayer, createFakeElderAlivePlayer, createFakeFoxAlivePlayer, createFakeScandalmongerAlivePlayer, createFakeScapegoatAlivePlayer, createFakeSeerAlivePlayer, createFakeStutteringJudgeAlivePlayer, createFakeThiefAlivePlayer, createFakeVillagerAlivePlayer, createFakeWerewolfAlivePlayer, createFakeWolfHoundAlivePlayer } from \"@tests/factories/game/schemas/player/player-with-role.schema.factory\";\nimport { createFakeDeadPlayer, createFakePlayer, createFakePlayerRole } from \"@tests/factories/game/schemas/player/player.schema.factory\";\n\ndescribe(\"Game Play Maker Service\", () => {\n let services: { gamePlayMaker: GamePlayMakerService };\n let mocks: {\n gamePlayMakerService: {\n accursedWolfFatherInfects: jest.SpyInstance;\n werewolvesEat: jest.SpyInstance;\n bigBadWolfEats: jest.SpyInstance;\n whiteWerewolfEats: jest.SpyInstance;\n seerLooks: jest.SpyInstance;\n cupidCharms: jest.SpyInstance;\n piedPiperCharms: jest.SpyInstance;\n witchUsesPotions: jest.SpyInstance;\n hunterShoots: jest.SpyInstance;\n defenderProtects: jest.SpyInstance;\n foxSniffs: jest.SpyInstance;\n wildChildChoosesModel: jest.SpyInstance;\n wolfHoundChoosesSide: jest.SpyInstance;\n scapegoatBansVoting: jest.SpyInstance;\n thiefChoosesCard: jest.SpyInstance;\n survivorsPlay: jest.SpyInstance;\n scandalmongerMarks: jest.SpyInstance;\n sheriffPlays: jest.SpyInstance;\n sheriffDelegates: jest.SpyInstance;\n sheriffSettlesVotes: jest.SpyInstance;\n killPlayerAmongNominatedPlayers: jest.SpyInstance;\n handleTieInVotes: jest.SpyInstance;\n handleTieInSheriffElection: jest.SpyInstance;\n survivorsElectSheriff: jest.SpyInstance;\n survivorsVote: jest.SpyInstance;\n survivorsBuryDeadBodies: jest.SpyInstance;\n actorChoosesCard: jest.SpyInstance;\n stutteringJudgeRequestsAnotherVote: jest.SpyInstance;\n };\n gameHistoryRecordService: {\n getPreviousGameHistoryRecord: jest.SpyInstance;\n };\n playerKillerService: {\n killOrRevealPlayer: jest.SpyInstance;\n applyPlayerDeathOutcomes: jest.SpyInstance;\n isElderKillable: jest.SpyInstance;\n getElderLivesCountAgainstWerewolves: jest.SpyInstance;\n revealPlayerRole: jest.SpyInstance;\n };\n devotedServantGamePlayMakerService: {\n devotedServantStealsRole: jest.SpyInstance;\n };\n gamePlayVoteService: { getNominatedPlayers: jest.SpyInstance };\n gameMutator: { prependUpcomingPlayInGame: jest.SpyInstance };\n playerHelper: { isPlayerPowerlessOnWerewolvesSide: jest.SpyInstance };\n unexpectedExceptionFactory: {\n createNoCurrentGamePlayUnexpectedException: jest.SpyInstance;\n createCantFindLastDeadPlayersUnexpectedException: jest.SpyInstance;\n };\n lodash: { sample: jest.SpyInstance };\n };\n\n beforeEach(async() => {\n mocks = {\n gamePlayMakerService: {\n accursedWolfFatherInfects: jest.fn(),\n werewolvesEat: jest.fn(),\n bigBadWolfEats: jest.fn(),\n whiteWerewolfEats: jest.fn(),\n seerLooks: jest.fn(),\n cupidCharms: jest.fn(),\n piedPiperCharms: jest.fn(),\n witchUsesPotions: jest.fn(),\n hunterShoots: jest.fn(),\n defenderProtects: jest.fn(),\n foxSniffs: jest.fn(),\n wildChildChoosesModel: jest.fn(),\n wolfHoundChoosesSide: jest.fn(),\n scapegoatBansVoting: jest.fn(),\n thiefChoosesCard: jest.fn(),\n survivorsPlay: jest.fn(),\n scandalmongerMarks: jest.fn(),\n sheriffPlays: jest.fn(),\n sheriffDelegates: jest.fn(),\n sheriffSettlesVotes: jest.fn(),\n killPlayerAmongNominatedPlayers: jest.fn(),\n handleTieInVotes: jest.fn(),\n handleTieInSheriffElection: jest.fn(),\n survivorsElectSheriff: jest.fn(),\n survivorsVote: jest.fn(),\n survivorsBuryDeadBodies: jest.fn(),\n actorChoosesCard: jest.fn(),\n stutteringJudgeRequestsAnotherVote: jest.fn(),\n },\n playerKillerService: {\n killOrRevealPlayer: jest.fn(),\n applyPlayerDeathOutcomes: jest.fn(),\n isElderKillable: jest.fn(),\n getElderLivesCountAgainstWerewolves: jest.fn(),\n revealPlayerRole: jest.fn(),\n },\n devotedServantGamePlayMakerService: { devotedServantStealsRole: jest.fn() },\n gameHistoryRecordService: { getPreviousGameHistoryRecord: jest.fn() },\n gamePlayVoteService: { getNominatedPlayers: jest.fn() },\n gameMutator: { prependUpcomingPlayInGame: jest.spyOn(GameMutator, \"prependUpcomingPlayInGame\").mockImplementation() },\n playerHelper: { isPlayerPowerlessOnWerewolvesSide: jest.spyOn(PlayerHelper, \"isPlayerPowerlessOnWerewolvesSide\").mockImplementation() },\n unexpectedExceptionFactory: {\n createNoCurrentGamePlayUnexpectedException: jest.spyOn(UnexpectedExceptionFactory, \"createNoCurrentGamePlayUnexpectedException\").mockImplementation(),\n createCantFindLastDeadPlayersUnexpectedException: jest.spyOn(UnexpectedExceptionFactory, \"createCantFindLastDeadPlayersUnexpectedException\").mockImplementation(),\n },\n lodash: { sample: jest.spyOn(lodash, \"sample\").mockImplementation() },\n };\n\n const module: TestingModule = await Test.createTestingModule({\n providers: [\n {\n provide: GamePlayVoteService,\n useValue: mocks.gamePlayVoteService,\n },\n {\n provide: PlayerKillerService,\n useValue: mocks.playerKillerService,\n },\n {\n provide: GameHistoryRecordService,\n useValue: mocks.gameHistoryRecordService,\n },\n {\n provide: DevotedServantGamePlayMakerService,\n useValue: mocks.devotedServantGamePlayMakerService,\n },\n GamePlayMakerService,\n ],\n }).compile();\n\n services = { gamePlayMaker: module.get(GamePlayMakerService) };\n });\n\n describe(\"makeGamePlay\", () => {\n beforeEach(() => {\n mocks.gamePlayMakerService.werewolvesEat = jest.spyOn(services.gamePlayMaker as unknown as { werewolvesEat }, \"werewolvesEat\").mockImplementation();\n mocks.gamePlayMakerService.bigBadWolfEats = jest.spyOn(services.gamePlayMaker as unknown as { bigBadWolfEats }, \"bigBadWolfEats\").mockImplementation();\n mocks.gamePlayMakerService.whiteWerewolfEats = jest.spyOn(services.gamePlayMaker as unknown as { whiteWerewolfEats }, \"whiteWerewolfEats\").mockImplementation();\n mocks.gamePlayMakerService.seerLooks = jest.spyOn(services.gamePlayMaker as unknown as { seerLooks }, \"seerLooks\").mockImplementation();\n mocks.gamePlayMakerService.cupidCharms = jest.spyOn(services.gamePlayMaker as unknown as { cupidCharms }, \"cupidCharms\").mockImplementation();\n mocks.gamePlayMakerService.piedPiperCharms = jest.spyOn(services.gamePlayMaker as unknown as { piedPiperCharms }, \"piedPiperCharms\").mockImplementation();\n mocks.gamePlayMakerService.witchUsesPotions = jest.spyOn(services.gamePlayMaker as unknown as { witchUsesPotions }, \"witchUsesPotions\").mockImplementation();\n mocks.gamePlayMakerService.hunterShoots = jest.spyOn(services.gamePlayMaker as unknown as { hunterShoots }, \"hunterShoots\").mockImplementation();\n mocks.gamePlayMakerService.defenderProtects = jest.spyOn(services.gamePlayMaker as unknown as { defenderProtects }, \"defenderProtects\").mockImplementation();\n mocks.gamePlayMakerService.foxSniffs = jest.spyOn(services.gamePlayMaker as unknown as { foxSniffs }, \"foxSniffs\").mockImplementation();\n mocks.gamePlayMakerService.wildChildChoosesModel = jest.spyOn(services.gamePlayMaker as unknown as { wildChildChoosesModel }, \"wildChildChoosesModel\").mockImplementation();\n mocks.gamePlayMakerService.wolfHoundChoosesSide = jest.spyOn(services.gamePlayMaker as unknown as { wolfHoundChoosesSide }, \"wolfHoundChoosesSide\").mockImplementation();\n mocks.gamePlayMakerService.scapegoatBansVoting = jest.spyOn(services.gamePlayMaker as unknown as { scapegoatBansVoting }, \"scapegoatBansVoting\").mockImplementation();\n mocks.gamePlayMakerService.thiefChoosesCard = jest.spyOn(services.gamePlayMaker as unknown as { thiefChoosesCard }, \"thiefChoosesCard\").mockImplementation();\n mocks.gamePlayMakerService.survivorsPlay = jest.spyOn(services.gamePlayMaker as unknown as { survivorsPlay }, \"survivorsPlay\").mockImplementation();\n mocks.gamePlayMakerService.scandalmongerMarks = jest.spyOn(services.gamePlayMaker as unknown as { scandalmongerMarks }, \"scandalmongerMarks\").mockImplementation();\n mocks.gamePlayMakerService.sheriffPlays = jest.spyOn(services.gamePlayMaker as unknown as { sheriffPlays }, \"sheriffPlays\").mockImplementation();\n mocks.gamePlayMakerService.actorChoosesCard = jest.spyOn(services.gamePlayMaker as unknown as { actorChoosesCard }, \"actorChoosesCard\").mockImplementation();\n mocks.gamePlayMakerService.accursedWolfFatherInfects = jest.spyOn(services.gamePlayMaker as unknown as { accursedWolfFatherInfects }, \"accursedWolfFatherInfects\").mockImplementation();\n mocks.gamePlayMakerService.stutteringJudgeRequestsAnotherVote = jest.spyOn(services.gamePlayMaker as unknown as { stutteringJudgeRequestsAnotherVote }, \"stutteringJudgeRequestsAnotherVote\").mockImplementation();\n });\n\n it(\"should throw error when game's current play is not set.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame();\n const interpolations = { gameId: game._id };\n const mockedError = new UnexpectedException(\"makeGamePlay\", UnexpectedExceptionReasons.NO_CURRENT_GAME_PLAY, { gameId: game._id.toString() });\n mocks.unexpectedExceptionFactory.createNoCurrentGamePlayUnexpectedException.mockReturnValueOnce(mockedError);\n\n await expect(services.gamePlayMaker.makeGamePlay(play, game)).rejects.toStrictEqual(mockedError);\n expect(mocks.unexpectedExceptionFactory.createNoCurrentGamePlayUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"makeGamePlay\", interpolations);\n });\n\n it(\"should call no play method when source is not in available methods.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlayTwoSistersMeetEachOther() });\n await services.gamePlayMaker.makeGamePlay(play, game);\n\n const gamePlayMakerServiceMockKeys = Object.keys(mocks.gamePlayMakerService);\n for (const gamePlayMakerServiceMockKey of gamePlayMakerServiceMockKeys) {\n expect(mocks.gamePlayMakerService[gamePlayMakerServiceMockKey]).not.toHaveBeenCalled();\n }\n });\n\n it(\"should return game as is when source is not in available methods.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlayTwoSistersMeetEachOther() });\n\n await expect(services.gamePlayMaker.makeGamePlay(play, game)).resolves.toStrictEqual(game);\n });\n\n it(\"should call werewolvesEat method when it's werewolves turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlayWerewolvesEat() });\n await services.gamePlayMaker.makeGamePlay(play, game);\n\n expect(mocks.gamePlayMakerService.werewolvesEat).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n\n it(\"should return game as is when it's lovers turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlayLoversMeetEachOther() });\n\n await expect(services.gamePlayMaker.makeGamePlay(play, game)).resolves.toStrictEqual(game);\n });\n\n it(\"should return game as is when it's charmed people turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlayCharmedMeetEachOther() });\n\n await expect(services.gamePlayMaker.makeGamePlay(play, game)).resolves.toStrictEqual(game);\n });\n\n it(\"should call sheriffPlays method when it's sheriff's turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlaySheriffDelegates() });\n await services.gamePlayMaker.makeGamePlay(play, game);\n\n expect(mocks.gamePlayMakerService.sheriffPlays).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n\n it(\"should call bigBadWolfEats method when it's big bad wolf's turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlayBigBadWolfEats() });\n await services.gamePlayMaker.makeGamePlay(play, game);\n\n expect(mocks.gamePlayMakerService.bigBadWolfEats).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n\n it(\"should call whiteWerewolfEats method when it's white werewolf's turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlayWhiteWerewolfEats() });\n await services.gamePlayMaker.makeGamePlay(play, game);\n\n expect(mocks.gamePlayMakerService.whiteWerewolfEats).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n\n it(\"should call seerLooks method when it's seer's turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlaySeerLooks() });\n await services.gamePlayMaker.makeGamePlay(play, game);\n\n expect(mocks.gamePlayMakerService.seerLooks).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n\n it(\"should call cupidCharms method when it's cupid's turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlayCupidCharms() });\n await services.gamePlayMaker.makeGamePlay(play, game);\n\n expect(mocks.gamePlayMakerService.cupidCharms).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n\n it(\"should call piedPiperCharms method when it's pied piper's turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlayPiedPiperCharms() });\n await services.gamePlayMaker.makeGamePlay(play, game);\n\n expect(mocks.gamePlayMakerService.piedPiperCharms).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n\n it(\"should call witchUsesPotions method when it's witch's turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlayWitchUsesPotions() });\n await services.gamePlayMaker.makeGamePlay(play, game);\n\n expect(mocks.gamePlayMakerService.witchUsesPotions).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n\n it(\"should call hunterShoots method when it's hunter's turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlayHunterShoots() });\n await services.gamePlayMaker.makeGamePlay(play, game);\n\n expect(mocks.gamePlayMakerService.hunterShoots).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n\n it(\"should call defenderProtects method when it's defender's turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlayDefenderProtects() });\n await services.gamePlayMaker.makeGamePlay(play, game);\n\n expect(mocks.gamePlayMakerService.defenderProtects).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n\n it(\"should call foxSniffs method when it's fox's turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlayFoxSniffs() });\n await services.gamePlayMaker.makeGamePlay(play, game);\n\n expect(mocks.gamePlayMakerService.foxSniffs).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n\n it(\"should call wildChildChoosesModel method when it's wild child's turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlayWildChildChoosesModel() });\n await services.gamePlayMaker.makeGamePlay(play, game);\n\n expect(mocks.gamePlayMakerService.wildChildChoosesModel).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n\n it(\"should call wolfHoundChoosesSide method when it's wolf-hound's turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlayWolfHoundChoosesSide() });\n await services.gamePlayMaker.makeGamePlay(play, game);\n\n expect(mocks.gamePlayMakerService.wolfHoundChoosesSide).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n\n it(\"should call scapegoatBansVoting method when it's scapegoat's turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlayScapegoatBansVoting() });\n await services.gamePlayMaker.makeGamePlay(play, game);\n\n expect(mocks.gamePlayMakerService.scapegoatBansVoting).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n\n it(\"should call thiefChoosesCard method when it's thief's turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlayThiefChoosesCard() });\n await services.gamePlayMaker.makeGamePlay(play, game);\n\n expect(mocks.gamePlayMakerService.thiefChoosesCard).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n\n it(\"should call survivorsPlay method when it's all's turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlaySurvivorsVote() });\n await services.gamePlayMaker.makeGamePlay(play, game);\n\n expect(mocks.gamePlayMakerService.survivorsPlay).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n\n it(\"should call scandalmongerMarks method when it's scandalmonger's turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlayScandalmongerMarks() });\n await services.gamePlayMaker.makeGamePlay(play, game);\n\n expect(mocks.gamePlayMakerService.scandalmongerMarks).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n\n it(\"should call actorChoosesCard method when it's actor's turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayActorChoosesCard() });\n await services.gamePlayMaker.makeGamePlay(play, game);\n\n expect(mocks.gamePlayMakerService.actorChoosesCard).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n\n it(\"should return game as is when it's two sisters turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlayTwoSistersMeetEachOther() });\n\n await expect(services.gamePlayMaker.makeGamePlay(play, game)).resolves.toStrictEqual(game);\n });\n\n it(\"should return game as is when it's three brothers turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlayThreeBrothersMeetEachOther() });\n\n await expect(services.gamePlayMaker.makeGamePlay(play, game)).resolves.toStrictEqual(game);\n });\n\n it(\"should call accursed wolf father infects method when it's accursed wolf father's turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlayAccursedWolfFatherInfects() });\n await services.gamePlayMaker.makeGamePlay(play, game);\n\n expect(mocks.gamePlayMakerService.accursedWolfFatherInfects).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n\n it(\"should call stuttering judge requests another vote method when it's stuttering judge's turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlayStutteringJudgeRequestsAnotherVote() });\n await services.gamePlayMaker.makeGamePlay(play, game);\n\n expect(mocks.gamePlayMakerService.stutteringJudgeRequestsAnotherVote).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n });\n\n describe(\"actorChoosesCard\", () => {\n it(\"should return game as is when actor is not in the game.\", () => {\n const additionalCards = [\n createFakeGameAdditionalCard({ isUsed: false }),\n createFakeGameAdditionalCard({ isUsed: false }),\n createFakeGameAdditionalCard({ isUsed: false }),\n createFakeGameAdditionalCard({ isUsed: false }),\n ];\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, additionalCards });\n const play = createFakeMakeGamePlayWithRelationsDto({ chosenCard: additionalCards[0] });\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"actorChoosesCard\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should return game as is when actor didn't choose a card.\", () => {\n const additionalCards = [\n createFakeGameAdditionalCard({ isUsed: false }),\n createFakeGameAdditionalCard({ isUsed: false }),\n createFakeGameAdditionalCard({ isUsed: false }),\n createFakeGameAdditionalCard({ isUsed: false }),\n ];\n const players = [\n createFakeActorAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, additionalCards });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"actorChoosesCard\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should return game as is when role from chosen card is not found.\", () => {\n const additionalCards = [\n createFakeGameAdditionalCard({ isUsed: false }),\n createFakeGameAdditionalCard({ isUsed: false }),\n createFakeGameAdditionalCard({ isUsed: false }),\n createFakeGameAdditionalCard({ isUsed: false }),\n ];\n const players = [\n createFakeActorAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, additionalCards });\n const play = createFakeMakeGamePlayWithRelationsDto({ chosenCard: createFakeGameAdditionalCard({}, { roleName: \"unknown\" }) });\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"actorChoosesCard\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should return game with actor having chosen card role, acting attribute and make it used when actor chose a card.\", () => {\n const additionalCards = [\n createFakeGameAdditionalCard({ isUsed: false }),\n createFakeGameAdditionalCard({ roleName: \"seer\", isUsed: false }),\n createFakeGameAdditionalCard({ isUsed: false }),\n createFakeGameAdditionalCard({ isUsed: false }),\n ];\n const players = [\n createFakeActorAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, additionalCards });\n const play = createFakeMakeGamePlayWithRelationsDto({ chosenCard: additionalCards[1] });\n const expectedActor = createFakePlayer({\n ...players[0],\n role: createFakePlayerRole({ ...players[0].role, current: additionalCards[1].roleName }),\n attributes: [createFakeActingByActorPlayerAttribute()],\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n expectedActor,\n players[1],\n players[2],\n players[3],\n ],\n additionalCards: [\n additionalCards[0],\n createFakeGameAdditionalCard({ ...additionalCards[1], isUsed: true }),\n additionalCards[2],\n additionalCards[3],\n ],\n });\n\n expect(services.gamePlayMaker[\"actorChoosesCard\"](play, game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"sheriffSettlesVotes\", () => {\n it(\"should return game as is when target count is not the one expected.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGameWithCurrentPlay();\n const expectedGame = createFakeGame(game);\n\n await expect(services.gamePlayMaker[\"sheriffSettlesVotes\"](play, game)).resolves.toStrictEqual(expectedGame);\n });\n\n it(\"should call killOrRevealPlayer method when sheriff delegates to a target.\", async() => {\n const targetedPlayer = createFakePlayer();\n const play = createFakeMakeGamePlayWithRelationsDto({ targets: [createFakeMakeGamePlayTargetWithRelationsDto({ player: targetedPlayer })] });\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySheriffDelegates() });\n await services.gamePlayMaker[\"sheriffSettlesVotes\"](play, game);\n\n expect(mocks.playerKillerService.killOrRevealPlayer).toHaveBeenCalledExactlyOnceWith(targetedPlayer._id, game, createFakePlayerVoteBySheriffDeath());\n });\n });\n\n describe(\"sheriffDelegates\", () => {\n it(\"should return game as is when target count is not the one expected.\", () => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGameWithCurrentPlay();\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"sheriffDelegates\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should remove previous sheriff attribute and add it to the target when called.\", () => {\n const players = [\n createFakePlayer({ attributes: [createFakeSheriffBySurvivorsPlayerAttribute()] }),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n ];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets: [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1] })] });\n const game = createFakeGameWithCurrentPlay({ players });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n createFakePlayer({ ...players[0], attributes: [] }),\n createFakePlayer({ ...players[1], attributes: [createFakeSheriffBySheriffPlayerAttribute()] }),\n players[2],\n players[3],\n ],\n });\n\n expect(services.gamePlayMaker[\"sheriffDelegates\"](play, game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"sheriffPlays\", () => {\n beforeEach(() => {\n mocks.gamePlayMakerService.sheriffDelegates = jest.spyOn(services.gamePlayMaker as unknown as { sheriffDelegates }, \"sheriffDelegates\").mockImplementation();\n mocks.gamePlayMakerService.sheriffSettlesVotes = jest.spyOn(services.gamePlayMaker as unknown as { sheriffSettlesVotes }, \"sheriffSettlesVotes\").mockImplementation();\n });\n\n it(\"should return game as is when upcoming play is not for sheriff.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayFoxSniffs() });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedGame = createFakeGame(game);\n\n await expect(services.gamePlayMaker[\"sheriffPlays\"](play, game)).resolves.toStrictEqual(expectedGame);\n });\n\n it(\"should call sheriffDelegates method when upcoming play is sheriff role delegation.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySheriffDelegates() });\n const play = createFakeMakeGamePlayWithRelationsDto();\n await services.gamePlayMaker[\"sheriffPlays\"](play, game);\n\n expect(mocks.gamePlayMakerService.sheriffDelegates).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n\n it(\"should call sheriffSettlesVotes method when upcoming play is sheriff settling vote.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySheriffSettlesVotes() });\n const play = createFakeMakeGamePlayWithRelationsDto();\n await services.gamePlayMaker[\"sheriffPlays\"](play, game);\n\n expect(mocks.gamePlayMakerService.sheriffSettlesVotes).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n });\n\n describe(\"survivorsBuryDeadBodies\", () => {\n it(\"should throw error when previous game history record is not found.\", async() => {\n const game = createFakeGameWithCurrentPlay();\n const play = createFakeMakeGamePlayWithRelationsDto();\n const mockedError = new UnexpectedException(\"survivorsBuryDeadBodies\", UnexpectedExceptionReasons.CANT_FIND_LAST_DEAD_PLAYERS, { gameId: game._id.toString() });\n mocks.gameHistoryRecordService.getPreviousGameHistoryRecord.mockReturnValueOnce(undefined);\n mocks.unexpectedExceptionFactory.createCantFindLastDeadPlayersUnexpectedException.mockReturnValueOnce(mockedError);\n\n await expect(services.gamePlayMaker[\"survivorsBuryDeadBodies\"](play, game)).rejects.toStrictEqual(mockedError);\n expect(mocks.unexpectedExceptionFactory.createCantFindLastDeadPlayersUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"survivorsBuryDeadBodies\", { gameId: game._id });\n });\n\n it(\"should throw error when previous game history record doesn't have dead players.\", async() => {\n const game = createFakeGameWithCurrentPlay();\n const play = createFakeMakeGamePlayWithRelationsDto();\n const mockedError = new UnexpectedException(\"survivorsBuryDeadBodies\", UnexpectedExceptionReasons.CANT_FIND_LAST_DEAD_PLAYERS, { gameId: game._id.toString() });\n mocks.gameHistoryRecordService.getPreviousGameHistoryRecord.mockReturnValueOnce(createFakeGameHistoryRecord({ deadPlayers: [] }));\n mocks.unexpectedExceptionFactory.createCantFindLastDeadPlayersUnexpectedException.mockReturnValueOnce(mockedError);\n\n await expect(services.gamePlayMaker[\"survivorsBuryDeadBodies\"](play, game)).rejects.toStrictEqual(mockedError);\n expect(mocks.unexpectedExceptionFactory.createCantFindLastDeadPlayersUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"survivorsBuryDeadBodies\", { gameId: game._id });\n });\n\n it(\"should make devoted servant steal role game play when there is one target.\", async() => {\n const game = createFakeGameWithCurrentPlay();\n const targets = [createFakeMakeGamePlayTargetWithRelationsDto()];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n mocks.gameHistoryRecordService.getPreviousGameHistoryRecord.mockReturnValueOnce(createFakeGameHistoryRecord({ deadPlayers: [createFakeDeadPlayer()] }));\n mocks.devotedServantGamePlayMakerService.devotedServantStealsRole.mockReturnValueOnce(game);\n mocks.playerKillerService.revealPlayerRole.mockReturnValue(game);\n mocks.playerKillerService.applyPlayerDeathOutcomes.mockReturnValue(game);\n await services.gamePlayMaker[\"survivorsBuryDeadBodies\"](play, game);\n\n expect(mocks.devotedServantGamePlayMakerService.devotedServantStealsRole).toHaveBeenCalledExactlyOnceWith(targets[0].player, game);\n });\n\n it(\"should not make devoted servant steal role game play when there is no target.\", async() => {\n const game = createFakeGameWithCurrentPlay();\n const play = createFakeMakeGamePlayWithRelationsDto();\n mocks.gameHistoryRecordService.getPreviousGameHistoryRecord.mockReturnValueOnce(createFakeGameHistoryRecord({ deadPlayers: [createFakeDeadPlayer()] }));\n mocks.devotedServantGamePlayMakerService.devotedServantStealsRole.mockReturnValueOnce(game);\n mocks.playerKillerService.revealPlayerRole.mockReturnValue(game);\n mocks.playerKillerService.applyPlayerDeathOutcomes.mockReturnValue(game);\n await services.gamePlayMaker[\"survivorsBuryDeadBodies\"](play, game);\n\n expect(mocks.devotedServantGamePlayMakerService.devotedServantStealsRole).not.toHaveBeenCalled();\n });\n\n it(\"should reveal role for each player when game options say that they must be revealed on death.\", async() => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ areRevealedOnDeath: true }) });\n const game = createFakeGameWithCurrentPlay({ players, options });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const deadPlayers = [createFakeDeadPlayer(players[1] as DeadPlayer), createFakeDeadPlayer(players[2] as DeadPlayer)];\n mocks.gameHistoryRecordService.getPreviousGameHistoryRecord.mockReturnValueOnce(createFakeGameHistoryRecord({ deadPlayers }));\n mocks.devotedServantGamePlayMakerService.devotedServantStealsRole.mockReturnValueOnce(game);\n mocks.playerKillerService.revealPlayerRole.mockReturnValue(game);\n mocks.playerKillerService.applyPlayerDeathOutcomes.mockReturnValue(game);\n await services.gamePlayMaker[\"survivorsBuryDeadBodies\"](play, game);\n\n expect(mocks.playerKillerService.revealPlayerRole).toHaveBeenCalledTimes(deadPlayers.length);\n expect(mocks.playerKillerService.revealPlayerRole).toHaveBeenCalledWith(players[1], game);\n expect(mocks.playerKillerService.revealPlayerRole).toHaveBeenCalledWith(players[2], game);\n });\n\n it(\"should not reveal role for each player when game options say that they must not be revealed on death.\", async() => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ areRevealedOnDeath: false }) });\n const game = createFakeGameWithCurrentPlay({ players, options });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const deadPlayers = [createFakeDeadPlayer(players[1] as DeadPlayer), createFakeDeadPlayer(players[2] as DeadPlayer)];\n mocks.gameHistoryRecordService.getPreviousGameHistoryRecord.mockReturnValueOnce(createFakeGameHistoryRecord({ deadPlayers }));\n mocks.devotedServantGamePlayMakerService.devotedServantStealsRole.mockReturnValueOnce(game);\n mocks.playerKillerService.revealPlayerRole.mockReturnValue(game);\n mocks.playerKillerService.applyPlayerDeathOutcomes.mockReturnValue(game);\n await services.gamePlayMaker[\"survivorsBuryDeadBodies\"](play, game);\n\n expect(mocks.playerKillerService.revealPlayerRole).not.toHaveBeenCalled();\n });\n\n it(\"should apply player death outcomes for each dead players from previous game history record when called.\", async() => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ areRevealedOnDeath: false }) });\n const game = createFakeGameWithCurrentPlay({ players, options });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const deadPlayers = [createFakeDeadPlayer(players[1] as DeadPlayer), createFakeDeadPlayer(players[2] as DeadPlayer)];\n mocks.gameHistoryRecordService.getPreviousGameHistoryRecord.mockReturnValueOnce(createFakeGameHistoryRecord({ deadPlayers }));\n mocks.devotedServantGamePlayMakerService.devotedServantStealsRole.mockReturnValueOnce(game);\n mocks.playerKillerService.revealPlayerRole.mockReturnValue(game);\n mocks.playerKillerService.applyPlayerDeathOutcomes.mockReturnValue(game);\n await services.gamePlayMaker[\"survivorsBuryDeadBodies\"](play, game);\n\n expect(mocks.playerKillerService.applyPlayerDeathOutcomes).toHaveBeenCalledTimes(deadPlayers.length);\n expect(mocks.playerKillerService.applyPlayerDeathOutcomes).toHaveBeenCalledWith(players[1], game);\n expect(mocks.playerKillerService.applyPlayerDeathOutcomes).toHaveBeenCalledWith(players[2], game);\n });\n });\n\n describe(\"killPlayerAmongNominatedPlayers\", () => {\n it(\"should return game as is when there is no nominated player.\", async() => {\n const game = createFakeGameWithCurrentPlay();\n const nominatedPlayers = [];\n const expectedGame = createFakeGame(game);\n\n await expect(services.gamePlayMaker[\"killPlayerAmongNominatedPlayers\"](game, nominatedPlayers)).resolves.toStrictEqual(expectedGame);\n });\n\n it(\"should kill nominated player when there is one nominated player in random way.\", async() => {\n const nominatedPlayers = [\n createFakePlayer(),\n createFakePlayer(),\n ];\n mocks.lodash.sample.mockReturnValue(nominatedPlayers[0]);\n const game = createFakeGameWithCurrentPlay();\n const expectedPlayerDeath = createFakePlayerVoteBySurvivorsDeath();\n await services.gamePlayMaker[\"killPlayerAmongNominatedPlayers\"](game, nominatedPlayers);\n\n expect(mocks.playerKillerService.killOrRevealPlayer).toHaveBeenCalledExactlyOnceWith(nominatedPlayers[0]._id, game, expectedPlayerDeath);\n });\n });\n\n describe(\"handleTieInVotes\", () => {\n beforeEach(() => {\n mocks.gamePlayMakerService.killPlayerAmongNominatedPlayers = jest.spyOn(services.gamePlayMaker as unknown as { killPlayerAmongNominatedPlayers }, \"killPlayerAmongNominatedPlayers\").mockImplementation();\n });\n\n it(\"should not kill scapegoat when he's not the game.\", async() => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n mocks.gameMutator.prependUpcomingPlayInGame.mockReturnValue(game);\n await services.gamePlayMaker[\"handleTieInVotes\"](game, players);\n\n expect(mocks.playerKillerService.killOrRevealPlayer).not.toHaveBeenCalled();\n });\n\n it(\"should not kill scapegoat when he's dead.\", async() => {\n const players = [\n createFakeScapegoatAlivePlayer({ isAlive: false }),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n mocks.gameMutator.prependUpcomingPlayInGame.mockReturnValue(game);\n await services.gamePlayMaker[\"handleTieInVotes\"](game, players);\n\n expect(mocks.playerKillerService.killOrRevealPlayer).not.toHaveBeenCalled();\n });\n\n it(\"should not kill scapegoat when he's powerless.\", async() => {\n const players = [\n createFakeScapegoatAlivePlayer({ attributes: [createFakePowerlessByElderPlayerAttribute()] }),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n mocks.gameMutator.prependUpcomingPlayInGame.mockReturnValue(game);\n await services.gamePlayMaker[\"handleTieInVotes\"](game, players);\n\n expect(mocks.playerKillerService.killOrRevealPlayer).not.toHaveBeenCalled();\n });\n\n it(\"should kill scapegoat when he's in the game and alive.\", async() => {\n const players = [\n createFakeScapegoatAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const playerDeath = createFakePlayerVoteScapegoatedBySurvivorsDeath();\n mocks.gameMutator.prependUpcomingPlayInGame.mockReturnValue(game);\n await services.gamePlayMaker[\"handleTieInVotes\"](game, players);\n\n expect(mocks.playerKillerService.killOrRevealPlayer).toHaveBeenCalledExactlyOnceWith(players[0]._id, game, playerDeath);\n });\n\n it(\"should not prepend sheriff settling tie in votes game play when sheriff is not in the game.\", async() => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ sheriff: createFakeSheriffGameOptions({ mustSettleTieInVotes: true }) }) });\n const game = createFakeGameWithCurrentPlay({ players, options });\n const gamePlaySheriffSettlesVotes = createFakeGamePlaySheriffSettlesVotes();\n mocks.gameMutator.prependUpcomingPlayInGame.mockReturnValue(game);\n await services.gamePlayMaker[\"handleTieInVotes\"](game, players);\n\n expect(mocks.gameMutator.prependUpcomingPlayInGame).not.toHaveBeenCalledExactlyOnceWith(gamePlaySheriffSettlesVotes, game);\n });\n\n it(\"should not prepend sheriff settling tie in votes game play when sheriff is dead.\", async() => {\n const players = [\n createFakeSeerAlivePlayer({ isAlive: false, attributes: [createFakeSheriffBySurvivorsPlayerAttribute()] }),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ sheriff: createFakeSheriffGameOptions({ mustSettleTieInVotes: true }) }) });\n const game = createFakeGameWithCurrentPlay({ players, options });\n const gamePlaySheriffSettlesVotes = createFakeGamePlaySheriffSettlesVotes();\n mocks.gameMutator.prependUpcomingPlayInGame.mockReturnValue(game);\n await services.gamePlayMaker[\"handleTieInVotes\"](game, players);\n\n expect(mocks.gameMutator.prependUpcomingPlayInGame).not.toHaveBeenCalledExactlyOnceWith(gamePlaySheriffSettlesVotes, game);\n });\n\n it(\"should not prepend sheriff settling tie in votes game play when game options don't allow it.\", async() => {\n const players = [\n createFakeSeerAlivePlayer({ isAlive: false, attributes: [createFakeSheriffBySurvivorsPlayerAttribute()] }),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ sheriff: createFakeSheriffGameOptions({ mustSettleTieInVotes: false }) }) });\n const game = createFakeGameWithCurrentPlay({ players, options });\n const gamePlaySheriffSettlesVotes = createFakeGamePlaySheriffSettlesVotes();\n mocks.gameMutator.prependUpcomingPlayInGame.mockReturnValue(game);\n await services.gamePlayMaker[\"handleTieInVotes\"](game, players);\n\n expect(mocks.gameMutator.prependUpcomingPlayInGame).not.toHaveBeenCalledExactlyOnceWith(gamePlaySheriffSettlesVotes, game);\n });\n\n it(\"should prepend sheriff delegation game play when sheriff is in the game.\", async() => {\n const players = [\n createFakeSeerAlivePlayer({ attributes: [createFakeSheriffBySurvivorsPlayerAttribute()] }),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ sheriff: createFakeSheriffGameOptions({ mustSettleTieInVotes: true }) }) });\n const game = createFakeGameWithCurrentPlay({ players, options });\n const gamePlaySheriffSettlesVotes = createFakeGamePlaySheriffSettlesVotes();\n mocks.gameMutator.prependUpcomingPlayInGame.mockReturnValue(game);\n await services.gamePlayMaker[\"handleTieInVotes\"](game, players);\n\n expect(mocks.gameMutator.prependUpcomingPlayInGame).toHaveBeenCalledExactlyOnceWith(gamePlaySheriffSettlesVotes, game);\n });\n\n it(\"should prepend vote game play with only tie cause when previous play is not a tie without cause.\", async() => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ sheriff: createFakeSheriffGameOptions({ mustSettleTieInVotes: true }) }) });\n const game = createFakeGameWithCurrentPlay({ players, options });\n const gamePlaySurvivorsVote = createFakeGamePlaySurvivorsVote({ causes: [\"previous-votes-were-in-ties\"] });\n mocks.gameMutator.prependUpcomingPlayInGame.mockReturnValue(game);\n await services.gamePlayMaker[\"handleTieInVotes\"](game, players);\n\n expect(mocks.gameMutator.prependUpcomingPlayInGame).toHaveBeenCalledExactlyOnceWith(gamePlaySurvivorsVote, game);\n });\n\n it(\"should prepend vote game play with tie and previous play causes when previous play is not a tie with causes.\", async() => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const currentPlay = createFakeGamePlaySurvivorsVote({ causes: [\"angel-presence\"] });\n const gamePlaySurvivorsVote = createFakeGamePlaySurvivorsVote({ causes: [\"previous-votes-were-in-ties\", \"angel-presence\"] });\n const game = createFakeGameWithCurrentPlay({ players, currentPlay });\n mocks.gameMutator.prependUpcomingPlayInGame.mockReturnValue(game);\n await services.gamePlayMaker[\"handleTieInVotes\"](game, players);\n\n expect(mocks.gameMutator.prependUpcomingPlayInGame).toHaveBeenCalledWith(gamePlaySurvivorsVote, game);\n });\n\n it(\"should prepend vote game play when there is no game history records.\", async() => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ sheriff: createFakeSheriffGameOptions({ mustSettleTieInVotes: true }) }) });\n const game = createFakeGameWithCurrentPlay({ players, options });\n mocks.gameMutator.prependUpcomingPlayInGame.mockReturnValue(game);\n const gamePlaySurvivorsVote = createFakeGamePlaySurvivorsVote({ causes: [\"previous-votes-were-in-ties\"], occurrence: \"consequential\" });\n await services.gamePlayMaker[\"handleTieInVotes\"](game, players);\n\n expect(mocks.gameMutator.prependUpcomingPlayInGame).toHaveBeenCalledExactlyOnceWith(gamePlaySurvivorsVote, game);\n });\n\n it(\"should not prepend vote game play when current play is due to a tie and cause is not angel presence.\", async() => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const currentPlay = createFakeGamePlaySurvivorsVote({ causes: [\"previous-votes-were-in-ties\"] });\n const gamePlaySurvivorsVote = createFakeGamePlaySurvivorsVote({ causes: [\"previous-votes-were-in-ties\"], occurrence: \"consequential\" });\n const game = createFakeGameWithCurrentPlay({ players, currentPlay });\n mocks.gameMutator.prependUpcomingPlayInGame.mockReturnValue(game);\n await services.gamePlayMaker[\"handleTieInVotes\"](game, players);\n\n expect(mocks.gameMutator.prependUpcomingPlayInGame).not.toHaveBeenCalledExactlyOnceWith(gamePlaySurvivorsVote, game);\n expect(mocks.gamePlayMakerService.killPlayerAmongNominatedPlayers).not.toHaveBeenCalled();\n });\n\n it(\"should kill player among nominated players when current play is due to a tie and cause is angel presence.\", async() => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const currentPlay = createFakeGamePlaySurvivorsVote({ causes: [\"angel-presence\", \"previous-votes-were-in-ties\"] });\n const game = createFakeGameWithCurrentPlay({ players, currentPlay });\n const nominatedPlayers = [createFakePlayer()];\n mocks.gameMutator.prependUpcomingPlayInGame.mockReturnValue(game);\n await services.gamePlayMaker[\"handleTieInVotes\"](game, nominatedPlayers);\n\n expect(mocks.gamePlayMakerService.killPlayerAmongNominatedPlayers).toHaveBeenCalledExactlyOnceWith(game, nominatedPlayers);\n });\n });\n\n describe(\"survivorsVote\", () => {\n beforeEach(() => {\n mocks.gamePlayMakerService.handleTieInVotes = jest.spyOn(services.gamePlayMaker as unknown as { handleTieInVotes }, \"handleTieInVotes\").mockImplementation();\n });\n\n it(\"should return game as is when there is no vote.\", async() => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsVote({ causes: [\"stuttering-judge-request\"] }), players });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedGame = createFakeGame(game);\n mocks.gamePlayVoteService.getNominatedPlayers.mockReturnValue([]);\n\n await expect(services.gamePlayMaker[\"survivorsVote\"](play, game)).resolves.toStrictEqual(expectedGame);\n });\n\n it(\"should return game as is when there is no nominated players.\", async() => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsVote({ causes: [\"stuttering-judge-request\"] }), players });\n const votes: MakeGamePlayVoteWithRelationsDto[] = [\n createFakeMakeGamePlayVoteWithRelationsDto({ source: players[0], target: players[1] }),\n createFakeMakeGamePlayVoteWithRelationsDto({ source: players[2], target: players[0] }),\n ];\n const play = createFakeMakeGamePlayWithRelationsDto({ votes, doesJudgeRequestAnotherVote: false });\n const nominatedPlayers = [];\n mocks.gamePlayVoteService.getNominatedPlayers.mockReturnValue(nominatedPlayers);\n const expectedGame = createFakeGame(game);\n\n await expect(services.gamePlayMaker[\"survivorsVote\"](play, game)).resolves.toStrictEqual(expectedGame);\n });\n\n it(\"should call handleTieInVotes method when there are several nominated players.\", async() => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsVote({ causes: [\"stuttering-judge-request\"] }), players });\n const votes: MakeGamePlayVoteWithRelationsDto[] = [\n createFakeMakeGamePlayVoteWithRelationsDto({ source: players[0], target: players[1] }),\n createFakeMakeGamePlayVoteWithRelationsDto({ source: players[2], target: players[0] }),\n ];\n const play = createFakeMakeGamePlayWithRelationsDto({ votes, doesJudgeRequestAnotherVote: false });\n const nominatedPlayers = [players[1], players[2]];\n mocks.gamePlayVoteService.getNominatedPlayers.mockReturnValue(nominatedPlayers);\n await services.gamePlayMaker[\"survivorsVote\"](play, game);\n\n expect(mocks.gamePlayMakerService.handleTieInVotes).toHaveBeenCalledExactlyOnceWith(game, nominatedPlayers);\n });\n\n it(\"should remove scandalmonger mark when there is this attribute among players.\", async() => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeScandalmongerMarkedByScandalmongerPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsVote({ causes: [\"stuttering-judge-request\"] }), players });\n const votes: MakeGamePlayVoteWithRelationsDto[] = [\n createFakeMakeGamePlayVoteWithRelationsDto({ source: players[0], target: players[1] }),\n createFakeMakeGamePlayVoteWithRelationsDto({ source: players[2], target: players[0] }),\n ];\n const play = createFakeMakeGamePlayWithRelationsDto({ votes, doesJudgeRequestAnotherVote: false });\n const nominatedPlayers = [players[1], players[2]];\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n players[1],\n createFakeWerewolfAlivePlayer({\n ...players[2],\n attributes: [],\n }),\n players[3],\n ],\n });\n mocks.gamePlayVoteService.getNominatedPlayers.mockReturnValue(nominatedPlayers);\n await services.gamePlayMaker[\"survivorsVote\"](play, game);\n\n expect(mocks.gamePlayMakerService.handleTieInVotes).toHaveBeenCalledExactlyOnceWith(expectedGame, nominatedPlayers);\n });\n\n it(\"should prepend stuttering judge request another vote game play when current play cause is undefined.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsVote() });\n const votes: MakeGamePlayVoteWithRelationsDto[] = [\n createFakeMakeGamePlayVoteWithRelationsDto(),\n createFakeMakeGamePlayVoteWithRelationsDto(),\n ];\n const play = createFakeMakeGamePlayWithRelationsDto({ votes });\n const nominatedPlayers = [createFakePlayer()];\n const gamePlayStutteringJudgeRequestsAnotherVote = createFakeGamePlayStutteringJudgeRequestsAnotherVote();\n mocks.gamePlayVoteService.getNominatedPlayers.mockReturnValue(nominatedPlayers);\n mocks.gameMutator.prependUpcomingPlayInGame.mockReturnValue(game);\n await services.gamePlayMaker[\"survivorsVote\"](play, game);\n\n expect(mocks.gameMutator.prependUpcomingPlayInGame).toHaveBeenCalledExactlyOnceWith(gamePlayStutteringJudgeRequestsAnotherVote, game);\n });\n\n it(\"should prepend stuttering judge request another vote game play when current play cause is angel presence and there is no tie in votes.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsVote({ causes: [\"angel-presence\"] }) });\n const votes: MakeGamePlayVoteWithRelationsDto[] = [\n createFakeMakeGamePlayVoteWithRelationsDto(),\n createFakeMakeGamePlayVoteWithRelationsDto(),\n ];\n const play = createFakeMakeGamePlayWithRelationsDto({ votes });\n const nominatedPlayers = [createFakePlayer()];\n const gamePlayStutteringJudgeRequestsAnotherVote = createFakeGamePlayStutteringJudgeRequestsAnotherVote();\n mocks.gamePlayVoteService.getNominatedPlayers.mockReturnValue(nominatedPlayers);\n mocks.gameMutator.prependUpcomingPlayInGame.mockReturnValue(game);\n await services.gamePlayMaker[\"survivorsVote\"](play, game);\n\n expect(mocks.gameMutator.prependUpcomingPlayInGame).toHaveBeenCalledExactlyOnceWith(gamePlayStutteringJudgeRequestsAnotherVote, game);\n });\n\n it(\"should not prepend stuttering judge request another vote game play when current play cause is angel presence and there is a tie in votes.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsVote({ causes: [\"angel-presence\", \"previous-votes-were-in-ties\"] }) });\n const votes: MakeGamePlayVoteWithRelationsDto[] = [\n createFakeMakeGamePlayVoteWithRelationsDto(),\n createFakeMakeGamePlayVoteWithRelationsDto(),\n ];\n const play = createFakeMakeGamePlayWithRelationsDto({ votes, doesJudgeRequestAnotherVote: false });\n const nominatedPlayers = [createFakePlayer()];\n mocks.gamePlayVoteService.getNominatedPlayers.mockReturnValue(nominatedPlayers);\n await services.gamePlayMaker[\"survivorsVote\"](play, game);\n\n expect(mocks.gameMutator.prependUpcomingPlayInGame).not.toHaveBeenCalled();\n });\n\n it(\"should call killOrRevealPlayer method when there is one nominated player.\", async() => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsVote({ causes: [\"stuttering-judge-request\"] }), players });\n const votes: MakeGamePlayVoteWithRelationsDto[] = [\n createFakeMakeGamePlayVoteWithRelationsDto({ source: players[0], target: players[1] }),\n createFakeMakeGamePlayVoteWithRelationsDto({ source: players[2], target: players[0] }),\n ];\n const play = createFakeMakeGamePlayWithRelationsDto({ votes, doesJudgeRequestAnotherVote: false });\n const nominatedPlayers = [players[1]];\n const playerVoteBySurvivorsDeath = createFakePlayerVoteBySurvivorsDeath();\n mocks.gamePlayVoteService.getNominatedPlayers.mockReturnValue(nominatedPlayers);\n await services.gamePlayMaker[\"survivorsVote\"](play, game);\n\n expect(mocks.playerKillerService.killOrRevealPlayer).toHaveBeenCalledExactlyOnceWith(players[1]._id, game, playerVoteBySurvivorsDeath);\n });\n });\n\n describe(\"handleTieInSheriffElection\", () => {\n it(\"should prepend survivors elect sheriff game play when current play is not due to a tie.\", () => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const currentPlay = createFakeGamePlaySurvivorsElectSheriff({ causes: [\"stuttering-judge-request\"] });\n const upcomingPlays = [createFakeGamePlayHunterShoots()];\n const game = createFakeGameWithCurrentPlay({ currentPlay, players, upcomingPlays });\n const nominatedPlayers = [players[0], players[1]];\n const prependedGamePlay = createFakeGamePlaySurvivorsElectSheriff({ causes: [\"previous-votes-were-in-ties\"] });\n services.gamePlayMaker[\"handleTieInSheriffElection\"](nominatedPlayers, game);\n\n expect(mocks.gameMutator.prependUpcomingPlayInGame).toHaveBeenCalledExactlyOnceWith(prependedGamePlay, game);\n });\n\n it(\"should add sheriff attribute to a random nominated player when current play is due to a tie.\", () => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n mocks.lodash.sample.mockReturnValue(players[0]);\n const currentPlay = createFakeGamePlaySurvivorsElectSheriff({ causes: [\"previous-votes-were-in-ties\"] });\n const upcomingPlays = [createFakeGamePlayHunterShoots()];\n const game = createFakeGameWithCurrentPlay({ currentPlay, players, upcomingPlays });\n const nominatedPlayers = [players[0], players[1]];\n const expectedGame = createFakeGame({\n ...game,\n players: [\n createFakePlayer({\n ...players[0],\n attributes: [createFakeSheriffBySurvivorsPlayerAttribute()],\n }),\n players[1],\n players[2],\n players[3],\n ],\n });\n\n expect(services.gamePlayMaker[\"handleTieInSheriffElection\"](nominatedPlayers, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should return game as is when it's not possible to choose a random nominated player.\", () => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n mocks.lodash.sample.mockReturnValue(undefined);\n const currentPlay = createFakeGamePlaySurvivorsElectSheriff({ causes: [\"previous-votes-were-in-ties\"] });\n const upcomingPlays = [createFakeGamePlayHunterShoots()];\n const game = createFakeGameWithCurrentPlay({ currentPlay, players, upcomingPlays });\n const nominatedPlayers = [players[0], players[1]];\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"handleTieInSheriffElection\"](nominatedPlayers, game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"survivorsElectSheriff\", () => {\n beforeEach(() => {\n mocks.gamePlayMakerService.handleTieInSheriffElection = jest.spyOn(services.gamePlayMaker as unknown as { handleTieInSheriffElection }, \"handleTieInSheriffElection\").mockImplementation();\n });\n\n it(\"should return game as is when there is no vote.\", () => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedGame = createFakeGame(game);\n mocks.gamePlayVoteService.getNominatedPlayers.mockReturnValue([]);\n\n expect(services.gamePlayMaker[\"survivorsElectSheriff\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should return game as is when there is no nominated players.\", () => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const votes: MakeGamePlayVoteWithRelationsDto[] = [\n createFakeMakeGamePlayVoteWithRelationsDto({ source: players[0], target: players[1] }),\n createFakeMakeGamePlayVoteWithRelationsDto({ source: players[2], target: players[0] }),\n ];\n const play = createFakeMakeGamePlayWithRelationsDto({ votes });\n mocks.gamePlayVoteService.getNominatedPlayers.mockReturnValue([]);\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"survivorsElectSheriff\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should call handleTieInSheriffElection method when there is a tie in votes.\", () => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const votes: MakeGamePlayVoteWithRelationsDto[] = [\n createFakeMakeGamePlayVoteWithRelationsDto({ source: players[0], target: players[1] }),\n createFakeMakeGamePlayVoteWithRelationsDto({ source: players[2], target: players[0] }),\n ];\n const play = createFakeMakeGamePlayWithRelationsDto({ votes });\n const nominatedPlayers = [players[0], players[1]];\n mocks.gamePlayVoteService.getNominatedPlayers.mockReturnValue(nominatedPlayers);\n services.gamePlayMaker[\"survivorsElectSheriff\"](play, game);\n\n expect(mocks.gamePlayMakerService.handleTieInSheriffElection).toHaveBeenCalledExactlyOnceWith(nominatedPlayers, game);\n });\n\n it(\"should add sheriff attribute to nominated player when called.\", () => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const votes: MakeGamePlayVoteWithRelationsDto[] = [\n createFakeMakeGamePlayVoteWithRelationsDto({ source: players[0], target: players[1] }),\n createFakeMakeGamePlayVoteWithRelationsDto({ source: players[2], target: players[0] }),\n ];\n const play = createFakeMakeGamePlayWithRelationsDto({ votes });\n mocks.gamePlayVoteService.getNominatedPlayers.mockReturnValue([players[1]]);\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n createFakePlayer({ ...players[1], attributes: [createFakeSheriffBySurvivorsPlayerAttribute()] }),\n players[2],\n players[3],\n ],\n });\n\n expect(services.gamePlayMaker[\"survivorsElectSheriff\"](play, game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"survivorsPlay\", () => {\n beforeEach(() => {\n mocks.gamePlayMakerService.survivorsElectSheriff = jest.spyOn(services.gamePlayMaker as unknown as { survivorsElectSheriff }, \"survivorsElectSheriff\").mockImplementation();\n mocks.gamePlayMakerService.survivorsVote = jest.spyOn(services.gamePlayMaker as unknown as { survivorsVote }, \"survivorsVote\").mockImplementation();\n mocks.gamePlayMakerService.survivorsBuryDeadBodies = jest.spyOn(services.gamePlayMaker as unknown as { survivorsBuryDeadBodies }, \"survivorsBuryDeadBodies\").mockImplementation();\n });\n\n it(\"should return game as is when upcoming play is not for all.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayFoxSniffs() });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedGame = createFakeGame(game);\n\n await expect(services.gamePlayMaker[\"survivorsPlay\"](play, game)).resolves.toStrictEqual(expectedGame);\n });\n\n it(\"should call survivorsElectSheriff method when upcoming play is sheriff role delegation.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsElectSheriff() });\n const play = createFakeMakeGamePlayWithRelationsDto();\n await services.gamePlayMaker[\"survivorsPlay\"](play, game);\n\n expect(mocks.gamePlayMakerService.survivorsElectSheriff).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n\n it(\"should call survivorsVote method when upcoming play is sheriff settling vote.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsVote() });\n const play = createFakeMakeGamePlayWithRelationsDto();\n await services.gamePlayMaker[\"survivorsPlay\"](play, game);\n\n expect(mocks.gamePlayMakerService.survivorsVote).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n\n it(\"should call survivorsBuryDeadBodies method when upcoming play is burying dead bodies.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsBuryDeadBodies() });\n const play = createFakeMakeGamePlayWithRelationsDto();\n await services.gamePlayMaker[\"survivorsPlay\"](play, game);\n\n expect(mocks.gamePlayMakerService.survivorsBuryDeadBodies).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n });\n\n describe(\"thiefChoosesCard\", () => {\n it(\"should return game as is when there is no thief player in game.\", () => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const additionalCards = [\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, additionalCards });\n const play = createFakeMakeGamePlayWithRelationsDto({ chosenCard: additionalCards[0] });\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"thiefChoosesCard\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should return game as is when there is no chosen card.\", () => {\n const players = [\n createFakeThiefAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const additionalCards = [\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, additionalCards });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"thiefChoosesCard\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should return game as is when chosen card role is unknown.\", () => {\n const players = [\n createFakeThiefAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const additionalCards = [\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, additionalCards });\n const play = createFakeMakeGamePlayWithRelationsDto({ chosenCard: createFakeGameAdditionalCard({}, { roleName: \"Toto\" }) });\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"thiefChoosesCard\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should update thief role and side and make his card used when called.\", () => {\n const players = [\n createFakeThiefAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const additionalCards = [\n createFakeGameAdditionalCard({ roleName: \"werewolf\", isUsed: false }),\n createFakeGameAdditionalCard({ isUsed: false }),\n createFakeGameAdditionalCard({ isUsed: false }),\n createFakeGameAdditionalCard({ isUsed: false }),\n ];\n const game = createFakeGameWithCurrentPlay({ players, additionalCards });\n const play = createFakeMakeGamePlayWithRelationsDto({ chosenCard: additionalCards[0] });\n const expectedThiefPlayer = createFakePlayer({\n ...players[0],\n role: { ...players[0].role, current: \"werewolf\" },\n side: { ...players[0].side, current: \"werewolves\" },\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n expectedThiefPlayer,\n players[1],\n players[2],\n players[3],\n ],\n additionalCards: [\n createFakeGameAdditionalCard({ ...additionalCards[0], isUsed: true }),\n additionalCards[1],\n additionalCards[2],\n additionalCards[3],\n ],\n });\n\n expect(services.gamePlayMaker[\"thiefChoosesCard\"](play, game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"scapegoatBansVoting\", () => {\n it(\"should return game as is when there are no targets.\", () => {\n const players = [\n createFakeThiefAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"scapegoatBansVoting\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should add scapegoat ban voting attributes to targets when called.\", () => {\n const players = [\n createFakeThiefAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const targets = [\n createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1] }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: players[2] }),\n ];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n createFakePlayer({ ...players[1], attributes: [createFakeCantVoteByScapegoatPlayerAttribute(game)] }),\n createFakePlayer({ ...players[2], attributes: [createFakeCantVoteByScapegoatPlayerAttribute(game)] }),\n players[3],\n ],\n });\n\n expect(services.gamePlayMaker[\"scapegoatBansVoting\"](play, game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"wolfHoundChoosesSide\", () => {\n it(\"should return game as is when there is no wolf-hound in the game.\", () => {\n const players = [\n createFakeThiefAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const play = createFakeMakeGamePlayWithRelationsDto({ chosenSide: \"werewolves\" });\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"wolfHoundChoosesSide\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should return wolf-hound on random side when chosen side is not set.\", () => {\n const players = [\n createFakeScandalmongerAlivePlayer(),\n createFakeWolfHoundAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedWolfHoundPlayer = createFakePlayer({\n ...players[1],\n side: { ...players[1].side, current: \"villagers\" },\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n expectedWolfHoundPlayer,\n players[2],\n players[3],\n ],\n });\n mocks.lodash.sample.mockReturnValue(\"villagers\");\n\n expect(services.gamePlayMaker[\"wolfHoundChoosesSide\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should get a random side when chosen side is not set.\", () => {\n const players = [\n createFakeScandalmongerAlivePlayer(),\n createFakeWolfHoundAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const play = createFakeMakeGamePlayWithRelationsDto();\n services.gamePlayMaker[\"wolfHoundChoosesSide\"](play, game);\n\n expect(mocks.lodash.sample).toHaveBeenCalledExactlyOnceWith([\"villagers\", \"werewolves\"]);\n });\n\n it(\"should return wolf-hound on the werewolves side when chosen side is werewolves.\", () => {\n const players = [\n createFakeScandalmongerAlivePlayer(),\n createFakeWolfHoundAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ actor: createFakeActorGameOptions({ isPowerlessOnWerewolvesSide: true }) }) });\n const game = createFakeGameWithCurrentPlay({ players, options });\n const play = createFakeMakeGamePlayWithRelationsDto({ chosenSide: \"werewolves\" });\n const expectedWolfHoundPlayer = createFakePlayer({\n ...players[1],\n side: { ...players[1].side, current: \"werewolves\" },\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n expectedWolfHoundPlayer,\n players[2],\n players[3],\n ],\n });\n\n expect(services.gamePlayMaker[\"wolfHoundChoosesSide\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should return wolf-hound on the werewolves side and add powerless attribute when chosen side is werewolves and wolf-hound is actor in disguise.\", () => {\n const players = [\n createFakeScandalmongerAlivePlayer(),\n createFakeWolfHoundAlivePlayer({ role: createFakePlayerRole({ original: \"actor\", current: \"wolf-hound\" }) }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ actor: createFakeActorGameOptions({ isPowerlessOnWerewolvesSide: true }) }) });\n const game = createFakeGameWithCurrentPlay({ players, options });\n const play = createFakeMakeGamePlayWithRelationsDto({ chosenSide: \"werewolves\" });\n const expectedWolfHoundPlayer = createFakePlayer({\n ...players[1],\n side: { ...players[1].side, current: \"werewolves\" },\n attributes: [createFakePowerlessByActorPlayerAttribute()],\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n expectedWolfHoundPlayer,\n players[2],\n players[3],\n ],\n });\n\n expect(services.gamePlayMaker[\"wolfHoundChoosesSide\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should return wolf-hound on the werewolves side but without powerless attribute when chosen side is werewolves and wolf-hound is actor in disguise but game options are changed.\", () => {\n const players = [\n createFakeScandalmongerAlivePlayer(),\n createFakeWolfHoundAlivePlayer({ role: createFakePlayerRole({ original: \"actor\", current: \"wolf-hound\" }) }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ actor: createFakeActorGameOptions({ isPowerlessOnWerewolvesSide: false }) }) });\n const game = createFakeGameWithCurrentPlay({ players, options });\n const play = createFakeMakeGamePlayWithRelationsDto({ chosenSide: \"werewolves\" });\n const expectedWolfHoundPlayer = createFakePlayer({\n ...players[1],\n side: { ...players[1].side, current: \"werewolves\" },\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n expectedWolfHoundPlayer,\n players[2],\n players[3],\n ],\n });\n\n expect(services.gamePlayMaker[\"wolfHoundChoosesSide\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should return wolf-hound on the villagers side when chosen side is villagers.\", () => {\n const players = [\n createFakeScandalmongerAlivePlayer(),\n createFakeWolfHoundAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const play = createFakeMakeGamePlayWithRelationsDto({ chosenSide: \"villagers\" });\n const expectedWolfHoundPlayer = createFakePlayer({\n ...players[1],\n side: { ...players[1].side, current: \"villagers\" },\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n expectedWolfHoundPlayer,\n players[2],\n players[3],\n ],\n });\n\n expect(services.gamePlayMaker[\"wolfHoundChoosesSide\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should return wolf-hound on the villagers side but without powerless attribute when chosen side is villagers and wolf-hound is actor in disguise.\", () => {\n const players = [\n createFakeScandalmongerAlivePlayer(),\n createFakeWolfHoundAlivePlayer({ role: createFakePlayerRole({ original: \"actor\", current: \"wolf-hound\" }) }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ actor: createFakeActorGameOptions({ isPowerlessOnWerewolvesSide: true }) }) });\n const game = createFakeGameWithCurrentPlay({ players, options });\n const play = createFakeMakeGamePlayWithRelationsDto({ chosenSide: \"villagers\" });\n const expectedWolfHoundPlayer = createFakePlayer({\n ...players[1],\n side: { ...players[1].side, current: \"villagers\" },\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n expectedWolfHoundPlayer,\n players[2],\n players[3],\n ],\n });\n\n expect(services.gamePlayMaker[\"wolfHoundChoosesSide\"](play, game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"wildChildChoosesModel\", () => {\n it(\"should return game as is when expected target count is not reached.\", () => {\n const players = [\n createFakeWolfHoundAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"wildChildChoosesModel\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should add worshiped attribute to target when called.\", () => {\n const players = [\n createFakeWolfHoundAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const targets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1] })];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n const expectedTargetedPlayer = createFakePlayer({\n ...players[1],\n attributes: [createFakeWorshipedByWildChildPlayerAttribute()],\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n expectedTargetedPlayer,\n players[2],\n players[3],\n ],\n });\n\n expect(services.gamePlayMaker[\"wildChildChoosesModel\"](play, game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"foxSniffs\", () => {\n it(\"should return game as is when expected target count is not reached.\", () => {\n const players = [\n createFakeFoxAlivePlayer({ position: 0 }),\n createFakeScandalmongerAlivePlayer({ position: 1 }),\n createFakeWerewolfAlivePlayer({ position: 2 }),\n createFakeWerewolfAlivePlayer({ position: 3 }),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"foxSniffs\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should return game as is when there is no fox in the game.\", () => {\n const players = [\n createFakeSeerAlivePlayer({ position: 0 }),\n createFakeScandalmongerAlivePlayer({ position: 1 }),\n createFakeWerewolfAlivePlayer({ position: 2 }),\n createFakeWerewolfAlivePlayer({ position: 3 }),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const targets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1] })];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"foxSniffs\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should return game as is when fox is not powerless if misses werewolves by game options.\", () => {\n const players = [\n createFakeFoxAlivePlayer({ position: 0 }),\n createFakeScandalmongerAlivePlayer({ position: 1 }),\n createFakeWerewolfAlivePlayer({ position: 2 }),\n createFakeWerewolfAlivePlayer({ position: 3 }),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ fox: createFakeFoxGameOptions({ isPowerlessIfMissesWerewolf: false }) }) });\n const game = createFakeGameWithCurrentPlay({ players, options });\n const targets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1] })];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"foxSniffs\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should return game as is when fox sniffes a werewolf in the group.\", () => {\n const players = [\n createFakeFoxAlivePlayer({ position: 0 }),\n createFakeScandalmongerAlivePlayer({ position: 1 }),\n createFakeWerewolfAlivePlayer({ position: 2 }),\n createFakeWerewolfAlivePlayer({ position: 3 }),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ fox: createFakeFoxGameOptions({ isPowerlessIfMissesWerewolf: true }) }) });\n const game = createFakeGameWithCurrentPlay({ players, options });\n const targets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1] })];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"foxSniffs\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should make fox powerless when there is no werewolf in the group.\", () => {\n const players = [\n createFakeFoxAlivePlayer({ position: 0 }),\n createFakeScandalmongerAlivePlayer({ position: 1 }),\n createFakeVillagerAlivePlayer({ position: 2 }),\n createFakeWerewolfAlivePlayer({ position: 3 }),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ fox: createFakeFoxGameOptions({ isPowerlessIfMissesWerewolf: true }) }) });\n const game = createFakeGameWithCurrentPlay({ players, options });\n const targets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1] })];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n const expectedTargetedPlayer = createFakePlayer({\n ...players[0],\n attributes: [createFakePowerlessByFoxPlayerAttribute({ doesRemainAfterDeath: true })],\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n expectedTargetedPlayer,\n players[1],\n players[2],\n players[3],\n ],\n });\n\n expect(services.gamePlayMaker[\"foxSniffs\"](play, game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"scandalmongerMarks\", () => {\n it(\"should return game as is when expected target count is not reached.\", () => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"scandalmongerMarks\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should add scandalmonger marked attribute to target when called.\", () => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const targets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1] })];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n const expectedTargetedPlayer = createFakePlayer({\n ...players[1],\n attributes: [createFakeScandalmongerMarkedByScandalmongerPlayerAttribute()],\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n expectedTargetedPlayer,\n players[2],\n players[3],\n ],\n });\n\n expect(services.gamePlayMaker[\"scandalmongerMarks\"](play, game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"defenderProtects\", () => {\n it(\"should return game as is when expected target count is not reached.\", () => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"defenderProtects\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should add protected attribute to target when called.\", () => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const targets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1] })];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n const expectedTargetedPlayer = createFakePlayer({\n ...players[1],\n attributes: [createFakeProtectedByDefenderPlayerAttribute()],\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n expectedTargetedPlayer,\n players[2],\n players[3],\n ],\n });\n\n expect(services.gamePlayMaker[\"defenderProtects\"](play, game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"hunterShoots\", () => {\n it(\"should return game as is when expected target count is not reached.\", async() => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedGame = createFakeGame(game);\n\n await expect(services.gamePlayMaker[\"hunterShoots\"](play, game)).resolves.toStrictEqual(expectedGame);\n });\n\n it(\"should call killOrRevealPlayer method when called.\", async() => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const targets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1] })];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n const playerDeath = createFakePlayerShotByHunterDeath();\n await services.gamePlayMaker[\"hunterShoots\"](play, game);\n\n expect(mocks.playerKillerService.killOrRevealPlayer).toHaveBeenCalledExactlyOnceWith(players[1]._id, game, playerDeath);\n });\n });\n\n describe(\"witchUsesPotions\", () => {\n it(\"should return game as is when expected target count is not reached.\", () => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"witchUsesPotions\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should add only one potion attributes to targets when called.\", () => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const targets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1], drankPotion: \"life\" })];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n const expectedTargetedPlayer = createFakePlayer({\n ...players[1],\n attributes: [createFakeDrankLifePotionByWitchPlayerAttribute()],\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n expectedTargetedPlayer,\n players[2],\n players[3],\n ],\n });\n\n expect(services.gamePlayMaker[\"witchUsesPotions\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should add both potion attributes to targets when called.\", () => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const targets = [\n createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1], drankPotion: \"life\" }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: players[2], drankPotion: \"death\" }),\n ];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n const expectedFirstTargetedPlayer = createFakePlayer({\n ...players[1],\n attributes: [createFakeDrankLifePotionByWitchPlayerAttribute()],\n });\n const expectedSecondTargetedPlayer = createFakePlayer({\n ...players[2],\n attributes: [createFakeDrankDeathPotionByWitchPlayerAttribute()],\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n expectedFirstTargetedPlayer,\n expectedSecondTargetedPlayer,\n players[3],\n ],\n });\n\n expect(services.gamePlayMaker[\"witchUsesPotions\"](play, game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"piedPiperCharms\", () => {\n it(\"should return game as is when targets are undefined.\", () => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"piedPiperCharms\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should return game as is when targets are empty.\", () => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const play = createFakeMakeGamePlayWithRelationsDto({ targets: [] });\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"piedPiperCharms\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should add pied piper charmed attributes to targets when called.\", () => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const targets = [\n createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1] }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: players[2] }),\n ];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n const expectedFirstTargetedPlayer = createFakePlayer({\n ...players[1],\n attributes: [createFakeCharmedByPiedPiperPlayerAttribute()],\n });\n const expectedSecondTargetedPlayer = createFakePlayer({\n ...players[2],\n attributes: [createFakeCharmedByPiedPiperPlayerAttribute()],\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n expectedFirstTargetedPlayer,\n expectedSecondTargetedPlayer,\n players[3],\n ],\n });\n\n expect(services.gamePlayMaker[\"piedPiperCharms\"](play, game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"cupidCharms\", () => {\n it(\"should return game as is when expected target count is not reached.\", () => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"cupidCharms\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should add in-love attribute to targets when called.\", () => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const targets = [\n createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1] }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: players[2] }),\n ];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n const expectedFirstTargetedPlayer = createFakePlayer({\n ...players[1],\n attributes: [createFakeInLoveByCupidPlayerAttribute()],\n });\n const expectedSecondTargetedPlayer = createFakePlayer({\n ...players[2],\n attributes: [createFakeInLoveByCupidPlayerAttribute()],\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n expectedFirstTargetedPlayer,\n expectedSecondTargetedPlayer,\n players[3],\n ],\n });\n\n expect(services.gamePlayMaker[\"cupidCharms\"](play, game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"seerLooks\", () => {\n it(\"should return game as is when expected target count is not reached.\", () => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"seerLooks\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should add seen attribute to target when called.\", () => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const targets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1] })];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n const expectedTargetedPlayer = createFakePlayer({\n ...players[1],\n attributes: [createFakeSeenBySeerPlayerAttribute()],\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n expectedTargetedPlayer,\n players[2],\n players[3],\n ],\n });\n\n expect(services.gamePlayMaker[\"seerLooks\"](play, game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"whiteWerewolfEats\", () => {\n it(\"should return game as is when expected target count is not reached.\", () => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"whiteWerewolfEats\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should add eaten attribute by white werewolf to target when called.\", () => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const targets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1] })];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n const expectedTargetedPlayer = createFakePlayer({\n ...players[1],\n attributes: [createFakeEatenByWhiteWerewolfPlayerAttribute()],\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n expectedTargetedPlayer,\n players[2],\n players[3],\n ],\n });\n\n expect(services.gamePlayMaker[\"whiteWerewolfEats\"](play, game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"bigBadWolfEats\", () => {\n it(\"should return game as is when expected target count is not reached.\", () => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"bigBadWolfEats\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should add eaten attribute by big bad wolf to target when called.\", () => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const targets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1] })];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n const expectedTargetedPlayer = createFakePlayer({\n ...players[1],\n attributes: [createFakeEatenByBigBadWolfPlayerAttribute()],\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n expectedTargetedPlayer,\n players[2],\n players[3],\n ],\n });\n\n expect(services.gamePlayMaker[\"bigBadWolfEats\"](play, game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"accursedWolfFatherInfects\", () => {\n it(\"should return game as is when target count is not reached.\", async() => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const targets = [];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n const expectedGame = createFakeGame(game);\n mocks.playerKillerService.isElderKillable.mockResolvedValueOnce(true);\n mocks.playerHelper.isPlayerPowerlessOnWerewolvesSide.mockReturnValue(true);\n\n await expect(services.gamePlayMaker[\"accursedWolfFatherInfects\"](play, game)).resolves.toStrictEqual(expectedGame);\n });\n\n it(\"should return game as is when target is elder and is not killable.\", async() => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeElderAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const targets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1] })];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n const expectedGame = createFakeGame(game);\n mocks.playerKillerService.isElderKillable.mockResolvedValueOnce(false);\n mocks.playerHelper.isPlayerPowerlessOnWerewolvesSide.mockReturnValue(true);\n\n await expect(services.gamePlayMaker[\"accursedWolfFatherInfects\"](play, game)).resolves.toStrictEqual(expectedGame);\n });\n\n it(\"should change target's side to werewolves and remove eaten by werewolves attribute when elder is killable.\", async() => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeElderAlivePlayer({\n attributes: [\n createFakeEatenByWerewolvesPlayerAttribute(),\n createFakeEatenByWerewolvesPlayerAttribute({ source: \"seer\" }),\n createFakeEatenByWhiteWerewolfPlayerAttribute(),\n ],\n }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const targets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1] })];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n const expectedTargetedPlayer = createFakePlayer({\n ...players[1],\n side: { ...players[1].side, current: \"werewolves\" },\n attributes: [\n createFakeEatenByWerewolvesPlayerAttribute({ source: \"seer\" }),\n createFakeEatenByWhiteWerewolfPlayerAttribute(),\n ],\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n expectedTargetedPlayer,\n players[2],\n players[3],\n ],\n });\n mocks.playerKillerService.isElderKillable.mockResolvedValueOnce(true);\n mocks.playerHelper.isPlayerPowerlessOnWerewolvesSide.mockReturnValue(false);\n\n await expect(services.gamePlayMaker[\"accursedWolfFatherInfects\"](play, game)).resolves.toStrictEqual(expectedGame);\n });\n\n it(\"should change target's side to werewolves and remove eaten by werewolves attribute when player is not elder.\", async() => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer({\n attributes: [\n createFakeEatenByWerewolvesPlayerAttribute(),\n createFakeSeenBySeerPlayerAttribute(),\n createFakeWorshipedByWildChildPlayerAttribute({ source: \"werewolves\" }),\n createFakeEatenByWhiteWerewolfPlayerAttribute(),\n ],\n }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const targets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1] })];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n const expectedTargetedPlayer = createFakePlayer({\n ...players[1],\n side: { ...players[1].side, current: \"werewolves\" },\n attributes: [\n createFakeSeenBySeerPlayerAttribute(),\n createFakeWorshipedByWildChildPlayerAttribute({ source: \"werewolves\" }),\n createFakeEatenByWhiteWerewolfPlayerAttribute(),\n ],\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n expectedTargetedPlayer,\n players[2],\n players[3],\n ],\n });\n mocks.playerKillerService.getElderLivesCountAgainstWerewolves.mockResolvedValueOnce(2);\n mocks.playerHelper.isPlayerPowerlessOnWerewolvesSide.mockReturnValue(false);\n\n await expect(services.gamePlayMaker[\"accursedWolfFatherInfects\"](play, game)).resolves.toStrictEqual(expectedGame);\n });\n\n it(\"should change target's side to werewolves, remove eaten by werewolves attribute and add powerless by accursed wolf-father attribute when target is powerless on joining the werewolves side.\", async() => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer({ attributes: [createFakeEatenByWerewolvesPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const targets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1] })];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n const expectedTargetedPlayer = createFakePlayer({\n ...players[1],\n side: { ...players[1].side, current: \"werewolves\" },\n attributes: [createFakePowerlessByAccursedWolfFatherPlayerAttribute()],\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n expectedTargetedPlayer,\n players[2],\n players[3],\n ],\n });\n mocks.playerKillerService.getElderLivesCountAgainstWerewolves.mockResolvedValueOnce(1);\n mocks.playerHelper.isPlayerPowerlessOnWerewolvesSide.mockReturnValue(true);\n\n await expect(services.gamePlayMaker[\"accursedWolfFatherInfects\"](play, game)).resolves.toStrictEqual(expectedGame);\n });\n });\n\n describe(\"werewolvesEat\", () => {\n it(\"should return game as is when expected target count is not reached.\", () => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedGame = createFakeGame(game);\n mocks.gamePlayMakerService.accursedWolfFatherInfects.mockReturnValue(expectedGame);\n\n expect(services.gamePlayMaker[\"werewolvesEat\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should add eaten attribute by werewolves to the target when called.\", () => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const targets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1] })];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n const expectedTargetedPlayer = createFakePlayer({\n ...players[1],\n attributes: [createFakeEatenByWerewolvesPlayerAttribute()],\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n expectedTargetedPlayer,\n players[2],\n players[3],\n ],\n });\n mocks.playerKillerService.getElderLivesCountAgainstWerewolves.mockReturnValue(2);\n mocks.gamePlayMakerService.accursedWolfFatherInfects.mockReturnValue(expectedGame);\n\n expect(services.gamePlayMaker[\"werewolvesEat\"](play, game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"stutteringJudgeRequestsAnotherVote\", () => {\n it(\"should return game as is when stuttering judge does not request another vote.\", () => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeStutteringJudgeAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const play = createFakeMakeGamePlayWithRelationsDto({ doesJudgeRequestAnotherVote: false });\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"stutteringJudgeRequestsAnotherVote\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should return game with prepended vote of cause stuttering judge request when stuttering judge does request another vote.\", () => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeStutteringJudgeAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const play = createFakeMakeGamePlayWithRelationsDto({ doesJudgeRequestAnotherVote: true });\n services.gamePlayMaker[\"stutteringJudgeRequestsAnotherVote\"](play, game);\n\n expect(mocks.gameMutator.prependUpcomingPlayInGame).toHaveBeenCalledExactlyOnceWith(createFakeGamePlaySurvivorsVote({ causes: [\"stuttering-judge-request\"] }), game);\n });\n });\n});" + "source": "import type { TestingModule } from \"@nestjs/testing\";\nimport { Test } from \"@nestjs/testing\";\nimport lodash from \"lodash\";\n\nimport type { MakeGamePlayVoteWithRelationsDto } from \"@/modules/game/dto/make-game-play/make-game-play-vote/make-game-play-vote-with-relations.dto\";\nimport * as GameMutator from \"@/modules/game/helpers/game.mutators\";\nimport * as PlayerHelper from \"@/modules/game/helpers/player/player.helpers\";\nimport { GameHistoryRecordService } from \"@/modules/game/providers/services/game-history/game-history-record.service\";\nimport { DevotedServantGamePlayMakerService } from \"@/modules/game/providers/services/game-play/game-play-maker/devoted-servant-game-play-maker.service\";\nimport { GamePlayMakerService } from \"@/modules/game/providers/services/game-play/game-play-maker/game-play-maker.service\";\nimport { GamePlayVoteService } from \"@/modules/game/providers/services/game-play/game-play-vote/game-play-vote.service\";\nimport { PlayerKillerService } from \"@/modules/game/providers/services/player/player-killer.service\";\nimport type { Game } from \"@/modules/game/schemas/game.schema\";\nimport type { DeadPlayer } from \"@/modules/game/schemas/player/dead-player.schema\";\n\nimport { UnexpectedExceptionReasons } from \"@/shared/exception/enums/unexpected-exception.enums\";\nimport * as UnexpectedExceptionFactory from \"@/shared/exception/helpers/unexpected-exception.factory\";\nimport { UnexpectedException } from \"@/shared/exception/types/unexpected-exception.types\";\n\nimport { createFakeMakeGamePlayTargetWithRelationsDto } from \"@tests/factories/game/dto/make-game-play/make-game-play-with-relations/make-game-play-target-with-relations.dto.factory\";\nimport { createFakeMakeGamePlayVoteWithRelationsDto } from \"@tests/factories/game/dto/make-game-play/make-game-play-with-relations/make-game-play-vote-with-relations.dto.factory\";\nimport { createFakeMakeGamePlayWithRelationsDto } from \"@tests/factories/game/dto/make-game-play/make-game-play-with-relations/make-game-play-with-relations.dto.factory\";\nimport { createFakeGameAdditionalCard } from \"@tests/factories/game/schemas/game-additional-card/game-additional-card.schema.factory\";\nimport { createFakeGameHistoryRecord } from \"@tests/factories/game/schemas/game-history-record/game-history-record.schema.factory\";\nimport { createFakeGameOptions } from \"@tests/factories/game/schemas/game-options/game-options.schema.factory\";\nimport { createFakeActorGameOptions, createFakeFoxGameOptions, createFakeRolesGameOptions, createFakeSheriffGameOptions } from \"@tests/factories/game/schemas/game-options/game-roles-options/game-roles-options.schema.factory\";\nimport { createFakeGamePlayAccursedWolfFatherInfects, createFakeGamePlayActorChoosesCard, createFakeGamePlayBigBadWolfEats, createFakeGamePlayCharmedMeetEachOther, createFakeGamePlayCupidCharms, createFakeGamePlayDefenderProtects, createFakeGamePlayFoxSniffs, createFakeGamePlayHunterShoots, createFakeGamePlayLoversMeetEachOther, createFakeGamePlayPiedPiperCharms, createFakeGamePlayScandalmongerMarks, createFakeGamePlayScapegoatBansVoting, createFakeGamePlaySeerLooks, createFakeGamePlaySheriffDelegates, createFakeGamePlaySheriffSettlesVotes, createFakeGamePlayStutteringJudgeRequestsAnotherVote, createFakeGamePlaySurvivorsBuryDeadBodies, createFakeGamePlaySurvivorsElectSheriff, createFakeGamePlaySurvivorsVote, createFakeGamePlayThiefChoosesCard, createFakeGamePlayThreeBrothersMeetEachOther, createFakeGamePlayTwoSistersMeetEachOther, createFakeGamePlayWerewolvesEat, createFakeGamePlayWhiteWerewolfEats, createFakeGamePlayWildChildChoosesModel, createFakeGamePlayWitchUsesPotions, createFakeGamePlayWolfHoundChoosesSide } from \"@tests/factories/game/schemas/game-play/game-play.schema.factory\";\nimport { createFakeGame, createFakeGameWithCurrentPlay } from \"@tests/factories/game/schemas/game.schema.factory\";\nimport { createFakeActingByActorPlayerAttribute, createFakeCantVoteByScapegoatPlayerAttribute, createFakeCharmedByPiedPiperPlayerAttribute, createFakeDrankDeathPotionByWitchPlayerAttribute, createFakeDrankLifePotionByWitchPlayerAttribute, createFakeEatenByBigBadWolfPlayerAttribute, createFakeEatenByWerewolvesPlayerAttribute, createFakeEatenByWhiteWerewolfPlayerAttribute, createFakeInLoveByCupidPlayerAttribute, createFakePowerlessByAccursedWolfFatherPlayerAttribute, createFakePowerlessByActorPlayerAttribute, createFakePowerlessByElderPlayerAttribute, createFakePowerlessByFoxPlayerAttribute, createFakeProtectedByDefenderPlayerAttribute, createFakeScandalmongerMarkedByScandalmongerPlayerAttribute, createFakeSeenBySeerPlayerAttribute, createFakeSheriffBySheriffPlayerAttribute, createFakeSheriffBySurvivorsPlayerAttribute, createFakeWorshipedByWildChildPlayerAttribute } from \"@tests/factories/game/schemas/player/player-attribute/player-attribute.schema.factory\";\nimport { createFakePlayerShotByHunterDeath, createFakePlayerVoteBySheriffDeath, createFakePlayerVoteBySurvivorsDeath, createFakePlayerVoteScapegoatedBySurvivorsDeath } from \"@tests/factories/game/schemas/player/player-death/player-death.schema.factory\";\nimport { createFakeActorAlivePlayer, createFakeElderAlivePlayer, createFakeFoxAlivePlayer, createFakeScandalmongerAlivePlayer, createFakeScapegoatAlivePlayer, createFakeSeerAlivePlayer, createFakeStutteringJudgeAlivePlayer, createFakeThiefAlivePlayer, createFakeVillagerAlivePlayer, createFakeWerewolfAlivePlayer, createFakeWolfHoundAlivePlayer } from \"@tests/factories/game/schemas/player/player-with-role.schema.factory\";\nimport { createFakeDeadPlayer, createFakePlayer, createFakePlayerRole } from \"@tests/factories/game/schemas/player/player.schema.factory\";\n\ndescribe(\"Game Play Maker Service\", () => {\n let services: { gamePlayMaker: GamePlayMakerService };\n let mocks: {\n gamePlayMakerService: {\n accursedWolfFatherInfects: jest.SpyInstance;\n werewolvesEat: jest.SpyInstance;\n bigBadWolfEats: jest.SpyInstance;\n whiteWerewolfEats: jest.SpyInstance;\n seerLooks: jest.SpyInstance;\n cupidCharms: jest.SpyInstance;\n piedPiperCharms: jest.SpyInstance;\n witchUsesPotions: jest.SpyInstance;\n hunterShoots: jest.SpyInstance;\n defenderProtects: jest.SpyInstance;\n foxSniffs: jest.SpyInstance;\n wildChildChoosesModel: jest.SpyInstance;\n wolfHoundChoosesSide: jest.SpyInstance;\n scapegoatBansVoting: jest.SpyInstance;\n thiefChoosesCard: jest.SpyInstance;\n survivorsPlay: jest.SpyInstance;\n scandalmongerMarks: jest.SpyInstance;\n sheriffPlays: jest.SpyInstance;\n sheriffDelegates: jest.SpyInstance;\n sheriffSettlesVotes: jest.SpyInstance;\n killPlayerAmongNominatedPlayers: jest.SpyInstance;\n handleTieInVotes: jest.SpyInstance;\n handleTieInSheriffElection: jest.SpyInstance;\n survivorsElectSheriff: jest.SpyInstance;\n survivorsVote: jest.SpyInstance;\n survivorsBuryDeadBodies: jest.SpyInstance;\n actorChoosesCard: jest.SpyInstance;\n stutteringJudgeRequestsAnotherVote: jest.SpyInstance;\n };\n gameHistoryRecordService: {\n getPreviousGameHistoryRecord: jest.SpyInstance;\n };\n playerKillerService: {\n killOrRevealPlayer: jest.SpyInstance;\n applyPlayerDeathOutcomes: jest.SpyInstance;\n isElderKillable: jest.SpyInstance;\n getElderLivesCountAgainstWerewolves: jest.SpyInstance;\n revealPlayerRole: jest.SpyInstance;\n };\n devotedServantGamePlayMakerService: {\n devotedServantStealsRole: jest.SpyInstance;\n };\n gamePlayVoteService: { getNominatedPlayers: jest.SpyInstance };\n gameMutator: { prependUpcomingPlayInGame: jest.SpyInstance };\n playerHelper: { isPlayerPowerlessOnWerewolvesSide: jest.SpyInstance };\n unexpectedExceptionFactory: {\n createNoCurrentGamePlayUnexpectedException: jest.SpyInstance;\n createCantFindLastDeadPlayersUnexpectedException: jest.SpyInstance;\n };\n lodash: { sample: jest.SpyInstance };\n };\n\n beforeEach(async() => {\n mocks = {\n gamePlayMakerService: {\n accursedWolfFatherInfects: jest.fn(),\n werewolvesEat: jest.fn(),\n bigBadWolfEats: jest.fn(),\n whiteWerewolfEats: jest.fn(),\n seerLooks: jest.fn(),\n cupidCharms: jest.fn(),\n piedPiperCharms: jest.fn(),\n witchUsesPotions: jest.fn(),\n hunterShoots: jest.fn(),\n defenderProtects: jest.fn(),\n foxSniffs: jest.fn(),\n wildChildChoosesModel: jest.fn(),\n wolfHoundChoosesSide: jest.fn(),\n scapegoatBansVoting: jest.fn(),\n thiefChoosesCard: jest.fn(),\n survivorsPlay: jest.fn(),\n scandalmongerMarks: jest.fn(),\n sheriffPlays: jest.fn(),\n sheriffDelegates: jest.fn(),\n sheriffSettlesVotes: jest.fn(),\n killPlayerAmongNominatedPlayers: jest.fn(),\n handleTieInVotes: jest.fn(),\n handleTieInSheriffElection: jest.fn(),\n survivorsElectSheriff: jest.fn(),\n survivorsVote: jest.fn(),\n survivorsBuryDeadBodies: jest.fn(),\n actorChoosesCard: jest.fn(),\n stutteringJudgeRequestsAnotherVote: jest.fn(),\n },\n playerKillerService: {\n killOrRevealPlayer: jest.fn(),\n applyPlayerDeathOutcomes: jest.fn(),\n isElderKillable: jest.fn(),\n getElderLivesCountAgainstWerewolves: jest.fn(),\n revealPlayerRole: jest.fn(),\n },\n devotedServantGamePlayMakerService: { devotedServantStealsRole: jest.fn() },\n gameHistoryRecordService: { getPreviousGameHistoryRecord: jest.fn() },\n gamePlayVoteService: { getNominatedPlayers: jest.fn() },\n gameMutator: { prependUpcomingPlayInGame: jest.spyOn(GameMutator, \"prependUpcomingPlayInGame\").mockImplementation() },\n playerHelper: { isPlayerPowerlessOnWerewolvesSide: jest.spyOn(PlayerHelper, \"isPlayerPowerlessOnWerewolvesSide\").mockImplementation() },\n unexpectedExceptionFactory: {\n createNoCurrentGamePlayUnexpectedException: jest.spyOn(UnexpectedExceptionFactory, \"createNoCurrentGamePlayUnexpectedException\").mockImplementation(),\n createCantFindLastDeadPlayersUnexpectedException: jest.spyOn(UnexpectedExceptionFactory, \"createCantFindLastDeadPlayersUnexpectedException\").mockImplementation(),\n },\n lodash: { sample: jest.spyOn(lodash, \"sample\").mockImplementation() },\n };\n\n const module: TestingModule = await Test.createTestingModule({\n providers: [\n {\n provide: GamePlayVoteService,\n useValue: mocks.gamePlayVoteService,\n },\n {\n provide: PlayerKillerService,\n useValue: mocks.playerKillerService,\n },\n {\n provide: GameHistoryRecordService,\n useValue: mocks.gameHistoryRecordService,\n },\n {\n provide: DevotedServantGamePlayMakerService,\n useValue: mocks.devotedServantGamePlayMakerService,\n },\n GamePlayMakerService,\n ],\n }).compile();\n\n services = { gamePlayMaker: module.get(GamePlayMakerService) };\n });\n\n describe(\"makeGamePlay\", () => {\n beforeEach(() => {\n mocks.gamePlayMakerService.werewolvesEat = jest.spyOn(services.gamePlayMaker as unknown as { werewolvesEat }, \"werewolvesEat\").mockImplementation();\n mocks.gamePlayMakerService.bigBadWolfEats = jest.spyOn(services.gamePlayMaker as unknown as { bigBadWolfEats }, \"bigBadWolfEats\").mockImplementation();\n mocks.gamePlayMakerService.whiteWerewolfEats = jest.spyOn(services.gamePlayMaker as unknown as { whiteWerewolfEats }, \"whiteWerewolfEats\").mockImplementation();\n mocks.gamePlayMakerService.seerLooks = jest.spyOn(services.gamePlayMaker as unknown as { seerLooks }, \"seerLooks\").mockImplementation();\n mocks.gamePlayMakerService.cupidCharms = jest.spyOn(services.gamePlayMaker as unknown as { cupidCharms }, \"cupidCharms\").mockImplementation();\n mocks.gamePlayMakerService.piedPiperCharms = jest.spyOn(services.gamePlayMaker as unknown as { piedPiperCharms }, \"piedPiperCharms\").mockImplementation();\n mocks.gamePlayMakerService.witchUsesPotions = jest.spyOn(services.gamePlayMaker as unknown as { witchUsesPotions }, \"witchUsesPotions\").mockImplementation();\n mocks.gamePlayMakerService.hunterShoots = jest.spyOn(services.gamePlayMaker as unknown as { hunterShoots }, \"hunterShoots\").mockImplementation();\n mocks.gamePlayMakerService.defenderProtects = jest.spyOn(services.gamePlayMaker as unknown as { defenderProtects }, \"defenderProtects\").mockImplementation();\n mocks.gamePlayMakerService.foxSniffs = jest.spyOn(services.gamePlayMaker as unknown as { foxSniffs }, \"foxSniffs\").mockImplementation();\n mocks.gamePlayMakerService.wildChildChoosesModel = jest.spyOn(services.gamePlayMaker as unknown as { wildChildChoosesModel }, \"wildChildChoosesModel\").mockImplementation();\n mocks.gamePlayMakerService.wolfHoundChoosesSide = jest.spyOn(services.gamePlayMaker as unknown as { wolfHoundChoosesSide }, \"wolfHoundChoosesSide\").mockImplementation();\n mocks.gamePlayMakerService.scapegoatBansVoting = jest.spyOn(services.gamePlayMaker as unknown as { scapegoatBansVoting }, \"scapegoatBansVoting\").mockImplementation();\n mocks.gamePlayMakerService.thiefChoosesCard = jest.spyOn(services.gamePlayMaker as unknown as { thiefChoosesCard }, \"thiefChoosesCard\").mockImplementation();\n mocks.gamePlayMakerService.survivorsPlay = jest.spyOn(services.gamePlayMaker as unknown as { survivorsPlay }, \"survivorsPlay\").mockImplementation();\n mocks.gamePlayMakerService.scandalmongerMarks = jest.spyOn(services.gamePlayMaker as unknown as { scandalmongerMarks }, \"scandalmongerMarks\").mockImplementation();\n mocks.gamePlayMakerService.sheriffPlays = jest.spyOn(services.gamePlayMaker as unknown as { sheriffPlays }, \"sheriffPlays\").mockImplementation();\n mocks.gamePlayMakerService.actorChoosesCard = jest.spyOn(services.gamePlayMaker as unknown as { actorChoosesCard }, \"actorChoosesCard\").mockImplementation();\n mocks.gamePlayMakerService.accursedWolfFatherInfects = jest.spyOn(services.gamePlayMaker as unknown as { accursedWolfFatherInfects }, \"accursedWolfFatherInfects\").mockImplementation();\n mocks.gamePlayMakerService.stutteringJudgeRequestsAnotherVote = jest.spyOn(services.gamePlayMaker as unknown as { stutteringJudgeRequestsAnotherVote }, \"stutteringJudgeRequestsAnotherVote\").mockImplementation();\n });\n\n it(\"should throw error when game's current play is not set.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame();\n const interpolations = { gameId: game._id };\n const mockedError = new UnexpectedException(\"makeGamePlay\", UnexpectedExceptionReasons.NO_CURRENT_GAME_PLAY, { gameId: game._id.toString() });\n mocks.unexpectedExceptionFactory.createNoCurrentGamePlayUnexpectedException.mockReturnValueOnce(mockedError);\n\n await expect(services.gamePlayMaker.makeGamePlay(play, game)).rejects.toStrictEqual(mockedError);\n expect(mocks.unexpectedExceptionFactory.createNoCurrentGamePlayUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"makeGamePlay\", interpolations);\n });\n\n it(\"should call no play method when source is not in available methods.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlayTwoSistersMeetEachOther() });\n await services.gamePlayMaker.makeGamePlay(play, game);\n\n const gamePlayMakerServiceMockKeys = Object.keys(mocks.gamePlayMakerService);\n for (const gamePlayMakerServiceMockKey of gamePlayMakerServiceMockKeys) {\n expect(mocks.gamePlayMakerService[gamePlayMakerServiceMockKey]).not.toHaveBeenCalled();\n }\n });\n\n it(\"should return game as is when source is not in available methods.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlayTwoSistersMeetEachOther() });\n\n await expect(services.gamePlayMaker.makeGamePlay(play, game)).resolves.toStrictEqual(game);\n });\n\n it(\"should call werewolvesEat method when it's werewolves turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlayWerewolvesEat() });\n await services.gamePlayMaker.makeGamePlay(play, game);\n\n expect(mocks.gamePlayMakerService.werewolvesEat).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n\n it(\"should return game as is when it's lovers turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlayLoversMeetEachOther() });\n\n await expect(services.gamePlayMaker.makeGamePlay(play, game)).resolves.toStrictEqual(game);\n });\n\n it(\"should return game as is when it's charmed people turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlayCharmedMeetEachOther() });\n\n await expect(services.gamePlayMaker.makeGamePlay(play, game)).resolves.toStrictEqual(game);\n });\n\n it(\"should call sheriffPlays method when it's sheriff's turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlaySheriffDelegates() });\n await services.gamePlayMaker.makeGamePlay(play, game);\n\n expect(mocks.gamePlayMakerService.sheriffPlays).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n\n it(\"should call bigBadWolfEats method when it's big bad wolf's turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlayBigBadWolfEats() });\n await services.gamePlayMaker.makeGamePlay(play, game);\n\n expect(mocks.gamePlayMakerService.bigBadWolfEats).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n\n it(\"should call whiteWerewolfEats method when it's white werewolf's turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlayWhiteWerewolfEats() });\n await services.gamePlayMaker.makeGamePlay(play, game);\n\n expect(mocks.gamePlayMakerService.whiteWerewolfEats).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n\n it(\"should call seerLooks method when it's seer's turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlaySeerLooks() });\n await services.gamePlayMaker.makeGamePlay(play, game);\n\n expect(mocks.gamePlayMakerService.seerLooks).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n\n it(\"should call cupidCharms method when it's cupid's turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlayCupidCharms() });\n await services.gamePlayMaker.makeGamePlay(play, game);\n\n expect(mocks.gamePlayMakerService.cupidCharms).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n\n it(\"should call piedPiperCharms method when it's pied piper's turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlayPiedPiperCharms() });\n await services.gamePlayMaker.makeGamePlay(play, game);\n\n expect(mocks.gamePlayMakerService.piedPiperCharms).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n\n it(\"should call witchUsesPotions method when it's witch's turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlayWitchUsesPotions() });\n await services.gamePlayMaker.makeGamePlay(play, game);\n\n expect(mocks.gamePlayMakerService.witchUsesPotions).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n\n it(\"should call hunterShoots method when it's hunter's turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlayHunterShoots() });\n await services.gamePlayMaker.makeGamePlay(play, game);\n\n expect(mocks.gamePlayMakerService.hunterShoots).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n\n it(\"should call defenderProtects method when it's defender's turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlayDefenderProtects() });\n await services.gamePlayMaker.makeGamePlay(play, game);\n\n expect(mocks.gamePlayMakerService.defenderProtects).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n\n it(\"should call foxSniffs method when it's fox's turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlayFoxSniffs() });\n await services.gamePlayMaker.makeGamePlay(play, game);\n\n expect(mocks.gamePlayMakerService.foxSniffs).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n\n it(\"should call wildChildChoosesModel method when it's wild child's turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlayWildChildChoosesModel() });\n await services.gamePlayMaker.makeGamePlay(play, game);\n\n expect(mocks.gamePlayMakerService.wildChildChoosesModel).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n\n it(\"should call wolfHoundChoosesSide method when it's wolf-hound's turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlayWolfHoundChoosesSide() });\n await services.gamePlayMaker.makeGamePlay(play, game);\n\n expect(mocks.gamePlayMakerService.wolfHoundChoosesSide).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n\n it(\"should call scapegoatBansVoting method when it's scapegoat's turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlayScapegoatBansVoting() });\n await services.gamePlayMaker.makeGamePlay(play, game);\n\n expect(mocks.gamePlayMakerService.scapegoatBansVoting).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n\n it(\"should call thiefChoosesCard method when it's thief's turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlayThiefChoosesCard() });\n await services.gamePlayMaker.makeGamePlay(play, game);\n\n expect(mocks.gamePlayMakerService.thiefChoosesCard).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n\n it(\"should call survivorsPlay method when it's all's turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlaySurvivorsVote() });\n await services.gamePlayMaker.makeGamePlay(play, game);\n\n expect(mocks.gamePlayMakerService.survivorsPlay).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n\n it(\"should call scandalmongerMarks method when it's scandalmonger's turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlayScandalmongerMarks() });\n await services.gamePlayMaker.makeGamePlay(play, game);\n\n expect(mocks.gamePlayMakerService.scandalmongerMarks).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n\n it(\"should call actorChoosesCard method when it's actor's turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayActorChoosesCard() });\n await services.gamePlayMaker.makeGamePlay(play, game);\n\n expect(mocks.gamePlayMakerService.actorChoosesCard).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n\n it(\"should return game as is when it's two sisters turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlayTwoSistersMeetEachOther() });\n\n await expect(services.gamePlayMaker.makeGamePlay(play, game)).resolves.toStrictEqual(game);\n });\n\n it(\"should return game as is when it's three brothers turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlayThreeBrothersMeetEachOther() });\n\n await expect(services.gamePlayMaker.makeGamePlay(play, game)).resolves.toStrictEqual(game);\n });\n\n it(\"should call accursed wolf father infects method when it's accursed wolf father's turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlayAccursedWolfFatherInfects() });\n await services.gamePlayMaker.makeGamePlay(play, game);\n\n expect(mocks.gamePlayMakerService.accursedWolfFatherInfects).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n\n it(\"should call stuttering judge requests another vote method when it's stuttering judge's turn.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGame({ currentPlay: createFakeGamePlayStutteringJudgeRequestsAnotherVote() });\n await services.gamePlayMaker.makeGamePlay(play, game);\n\n expect(mocks.gamePlayMakerService.stutteringJudgeRequestsAnotherVote).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n });\n\n describe(\"actorChoosesCard\", () => {\n it(\"should return game as is when actor is not in the game.\", () => {\n const additionalCards = [\n createFakeGameAdditionalCard({ isUsed: false }),\n createFakeGameAdditionalCard({ isUsed: false }),\n createFakeGameAdditionalCard({ isUsed: false }),\n createFakeGameAdditionalCard({ isUsed: false }),\n ];\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, additionalCards });\n const play = createFakeMakeGamePlayWithRelationsDto({ chosenCard: additionalCards[0] });\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"actorChoosesCard\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should return game as is when actor didn't choose a card.\", () => {\n const additionalCards = [\n createFakeGameAdditionalCard({ isUsed: false }),\n createFakeGameAdditionalCard({ isUsed: false }),\n createFakeGameAdditionalCard({ isUsed: false }),\n createFakeGameAdditionalCard({ isUsed: false }),\n ];\n const players = [\n createFakeActorAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, additionalCards });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"actorChoosesCard\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should return game as is when role from chosen card is not found.\", () => {\n const additionalCards = [\n createFakeGameAdditionalCard({ isUsed: false }),\n createFakeGameAdditionalCard({ isUsed: false }),\n createFakeGameAdditionalCard({ isUsed: false }),\n createFakeGameAdditionalCard({ isUsed: false }),\n ];\n const players = [\n createFakeActorAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, additionalCards });\n const play = createFakeMakeGamePlayWithRelationsDto({ chosenCard: createFakeGameAdditionalCard({}, { roleName: \"unknown\" }) });\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"actorChoosesCard\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should return game with actor having chosen card role, acting attribute and make it used when actor chose a card.\", () => {\n const additionalCards = [\n createFakeGameAdditionalCard({ isUsed: false }),\n createFakeGameAdditionalCard({ roleName: \"seer\", isUsed: false }),\n createFakeGameAdditionalCard({ isUsed: false }),\n createFakeGameAdditionalCard({ isUsed: false }),\n ];\n const players = [\n createFakeActorAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, additionalCards });\n const play = createFakeMakeGamePlayWithRelationsDto({ chosenCard: additionalCards[1] });\n const expectedActor = createFakePlayer({\n ...players[0],\n role: createFakePlayerRole({ ...players[0].role, current: additionalCards[1].roleName }),\n attributes: [createFakeActingByActorPlayerAttribute()],\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n expectedActor,\n players[1],\n players[2],\n players[3],\n ],\n additionalCards: [\n additionalCards[0],\n createFakeGameAdditionalCard({ ...additionalCards[1], isUsed: true }),\n additionalCards[2],\n additionalCards[3],\n ],\n });\n\n expect(services.gamePlayMaker[\"actorChoosesCard\"](play, game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"sheriffSettlesVotes\", () => {\n it(\"should return game as is when target count is not the one expected.\", async() => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGameWithCurrentPlay();\n const expectedGame = createFakeGame(game);\n\n await expect(services.gamePlayMaker[\"sheriffSettlesVotes\"](play, game)).resolves.toStrictEqual(expectedGame);\n });\n\n it(\"should call killOrRevealPlayer method when sheriff delegates to a target.\", async() => {\n const targetedPlayer = createFakePlayer();\n const play = createFakeMakeGamePlayWithRelationsDto({ targets: [createFakeMakeGamePlayTargetWithRelationsDto({ player: targetedPlayer })] });\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySheriffDelegates() });\n await services.gamePlayMaker[\"sheriffSettlesVotes\"](play, game);\n\n expect(mocks.playerKillerService.killOrRevealPlayer).toHaveBeenCalledExactlyOnceWith(targetedPlayer._id, game, createFakePlayerVoteBySheriffDeath());\n });\n });\n\n describe(\"sheriffDelegates\", () => {\n it(\"should return game as is when target count is not the one expected.\", () => {\n const play = createFakeMakeGamePlayWithRelationsDto();\n const game = createFakeGameWithCurrentPlay();\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"sheriffDelegates\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should remove previous sheriff attribute and add it to the target when called.\", () => {\n const players = [\n createFakePlayer({ attributes: [createFakeSheriffBySurvivorsPlayerAttribute()] }),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n ];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets: [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1] })] });\n const game = createFakeGameWithCurrentPlay({ players });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n createFakePlayer({ ...players[0], attributes: [] }),\n createFakePlayer({ ...players[1], attributes: [createFakeSheriffBySheriffPlayerAttribute()] }),\n players[2],\n players[3],\n ],\n });\n\n expect(services.gamePlayMaker[\"sheriffDelegates\"](play, game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"sheriffPlays\", () => {\n beforeEach(() => {\n mocks.gamePlayMakerService.sheriffDelegates = jest.spyOn(services.gamePlayMaker as unknown as { sheriffDelegates }, \"sheriffDelegates\").mockImplementation();\n mocks.gamePlayMakerService.sheriffSettlesVotes = jest.spyOn(services.gamePlayMaker as unknown as { sheriffSettlesVotes }, \"sheriffSettlesVotes\").mockImplementation();\n });\n\n it(\"should return game as is when upcoming play is not for sheriff.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayFoxSniffs() });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedGame = createFakeGame(game);\n\n await expect(services.gamePlayMaker[\"sheriffPlays\"](play, game)).resolves.toStrictEqual(expectedGame);\n });\n\n it(\"should call sheriffDelegates method when upcoming play is sheriff role delegation.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySheriffDelegates() });\n const play = createFakeMakeGamePlayWithRelationsDto();\n await services.gamePlayMaker[\"sheriffPlays\"](play, game);\n\n expect(mocks.gamePlayMakerService.sheriffDelegates).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n\n it(\"should call sheriffSettlesVotes method when upcoming play is sheriff settling vote.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySheriffSettlesVotes() });\n const play = createFakeMakeGamePlayWithRelationsDto();\n await services.gamePlayMaker[\"sheriffPlays\"](play, game);\n\n expect(mocks.gamePlayMakerService.sheriffSettlesVotes).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n });\n\n describe(\"survivorsBuryDeadBodies\", () => {\n it(\"should throw error when previous game history record is not found.\", async() => {\n const game = createFakeGameWithCurrentPlay();\n const play = createFakeMakeGamePlayWithRelationsDto();\n const mockedError = new UnexpectedException(\"survivorsBuryDeadBodies\", UnexpectedExceptionReasons.CANT_FIND_LAST_DEAD_PLAYERS, { gameId: game._id.toString() });\n mocks.gameHistoryRecordService.getPreviousGameHistoryRecord.mockReturnValueOnce(undefined);\n mocks.unexpectedExceptionFactory.createCantFindLastDeadPlayersUnexpectedException.mockReturnValueOnce(mockedError);\n\n await expect(services.gamePlayMaker[\"survivorsBuryDeadBodies\"](play, game)).rejects.toStrictEqual(mockedError);\n expect(mocks.unexpectedExceptionFactory.createCantFindLastDeadPlayersUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"survivorsBuryDeadBodies\", { gameId: game._id });\n });\n\n it(\"should throw error when previous game history record doesn't have dead players.\", async() => {\n const game = createFakeGameWithCurrentPlay();\n const play = createFakeMakeGamePlayWithRelationsDto();\n const mockedError = new UnexpectedException(\"survivorsBuryDeadBodies\", UnexpectedExceptionReasons.CANT_FIND_LAST_DEAD_PLAYERS, { gameId: game._id.toString() });\n mocks.gameHistoryRecordService.getPreviousGameHistoryRecord.mockReturnValueOnce(createFakeGameHistoryRecord({ deadPlayers: [] }));\n mocks.unexpectedExceptionFactory.createCantFindLastDeadPlayersUnexpectedException.mockReturnValueOnce(mockedError);\n\n await expect(services.gamePlayMaker[\"survivorsBuryDeadBodies\"](play, game)).rejects.toStrictEqual(mockedError);\n expect(mocks.unexpectedExceptionFactory.createCantFindLastDeadPlayersUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"survivorsBuryDeadBodies\", { gameId: game._id });\n });\n\n it(\"should make devoted servant steal role game play when there is one target.\", async() => {\n const game = createFakeGameWithCurrentPlay();\n const targets = [createFakeMakeGamePlayTargetWithRelationsDto()];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n mocks.gameHistoryRecordService.getPreviousGameHistoryRecord.mockReturnValueOnce(createFakeGameHistoryRecord({ deadPlayers: [createFakeDeadPlayer()] }));\n mocks.devotedServantGamePlayMakerService.devotedServantStealsRole.mockReturnValueOnce(game);\n mocks.playerKillerService.revealPlayerRole.mockReturnValue(game);\n mocks.playerKillerService.applyPlayerDeathOutcomes.mockReturnValue(game);\n await services.gamePlayMaker[\"survivorsBuryDeadBodies\"](play, game);\n\n expect(mocks.devotedServantGamePlayMakerService.devotedServantStealsRole).toHaveBeenCalledExactlyOnceWith(targets[0].player, game);\n });\n\n it(\"should not make devoted servant steal role game play when there is no target.\", async() => {\n const game = createFakeGameWithCurrentPlay();\n const play = createFakeMakeGamePlayWithRelationsDto();\n mocks.gameHistoryRecordService.getPreviousGameHistoryRecord.mockReturnValueOnce(createFakeGameHistoryRecord({ deadPlayers: [createFakeDeadPlayer()] }));\n mocks.devotedServantGamePlayMakerService.devotedServantStealsRole.mockReturnValueOnce(game);\n mocks.playerKillerService.revealPlayerRole.mockReturnValue(game);\n mocks.playerKillerService.applyPlayerDeathOutcomes.mockReturnValue(game);\n await services.gamePlayMaker[\"survivorsBuryDeadBodies\"](play, game);\n\n expect(mocks.devotedServantGamePlayMakerService.devotedServantStealsRole).not.toHaveBeenCalled();\n });\n\n it(\"should reveal role for each player when game options say that they must be revealed on death.\", async() => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ areRevealedOnDeath: true }) });\n const game = createFakeGameWithCurrentPlay({ players, options });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const deadPlayers = [createFakeDeadPlayer(players[1] as DeadPlayer), createFakeDeadPlayer(players[2] as DeadPlayer)];\n mocks.gameHistoryRecordService.getPreviousGameHistoryRecord.mockReturnValueOnce(createFakeGameHistoryRecord({ deadPlayers }));\n mocks.devotedServantGamePlayMakerService.devotedServantStealsRole.mockReturnValueOnce(game);\n mocks.playerKillerService.revealPlayerRole.mockReturnValue(game);\n mocks.playerKillerService.applyPlayerDeathOutcomes.mockReturnValue(game);\n await services.gamePlayMaker[\"survivorsBuryDeadBodies\"](play, game);\n\n expect(mocks.playerKillerService.revealPlayerRole).toHaveBeenCalledTimes(deadPlayers.length);\n expect(mocks.playerKillerService.revealPlayerRole).toHaveBeenCalledWith(players[1], game);\n expect(mocks.playerKillerService.revealPlayerRole).toHaveBeenCalledWith(players[2], game);\n });\n\n it(\"should not reveal role for each player when game options say that they must not be revealed on death.\", async() => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ areRevealedOnDeath: false }) });\n const game = createFakeGameWithCurrentPlay({ players, options });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const deadPlayers = [createFakeDeadPlayer(players[1] as DeadPlayer), createFakeDeadPlayer(players[2] as DeadPlayer)];\n mocks.gameHistoryRecordService.getPreviousGameHistoryRecord.mockReturnValueOnce(createFakeGameHistoryRecord({ deadPlayers }));\n mocks.devotedServantGamePlayMakerService.devotedServantStealsRole.mockReturnValueOnce(game);\n mocks.playerKillerService.revealPlayerRole.mockReturnValue(game);\n mocks.playerKillerService.applyPlayerDeathOutcomes.mockReturnValue(game);\n await services.gamePlayMaker[\"survivorsBuryDeadBodies\"](play, game);\n\n expect(mocks.playerKillerService.revealPlayerRole).not.toHaveBeenCalled();\n });\n\n it(\"should apply player death outcomes for each dead players from previous game history record when called.\", async() => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ areRevealedOnDeath: false }) });\n const game = createFakeGameWithCurrentPlay({ players, options });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const deadPlayers = [createFakeDeadPlayer(players[1] as DeadPlayer), createFakeDeadPlayer(players[2] as DeadPlayer)];\n mocks.gameHistoryRecordService.getPreviousGameHistoryRecord.mockReturnValueOnce(createFakeGameHistoryRecord({ deadPlayers }));\n mocks.devotedServantGamePlayMakerService.devotedServantStealsRole.mockReturnValueOnce(game);\n mocks.playerKillerService.revealPlayerRole.mockReturnValue(game);\n mocks.playerKillerService.applyPlayerDeathOutcomes.mockReturnValue(game);\n await services.gamePlayMaker[\"survivorsBuryDeadBodies\"](play, game);\n\n expect(mocks.playerKillerService.applyPlayerDeathOutcomes).toHaveBeenCalledTimes(deadPlayers.length);\n expect(mocks.playerKillerService.applyPlayerDeathOutcomes).toHaveBeenCalledWith(players[1], game);\n expect(mocks.playerKillerService.applyPlayerDeathOutcomes).toHaveBeenCalledWith(players[2], game);\n });\n });\n\n describe(\"killPlayerAmongNominatedPlayers\", () => {\n it(\"should return game as is when there is no nominated player.\", async() => {\n const game = createFakeGameWithCurrentPlay();\n const nominatedPlayers = [];\n const expectedGame = createFakeGame(game);\n\n await expect(services.gamePlayMaker[\"killPlayerAmongNominatedPlayers\"](game, nominatedPlayers)).resolves.toStrictEqual(expectedGame);\n });\n\n it(\"should kill nominated player when there is one nominated player in random way.\", async() => {\n const nominatedPlayers = [\n createFakePlayer(),\n createFakePlayer(),\n ];\n mocks.lodash.sample.mockReturnValue(nominatedPlayers[0]);\n const game = createFakeGameWithCurrentPlay();\n const expectedPlayerDeath = createFakePlayerVoteBySurvivorsDeath();\n await services.gamePlayMaker[\"killPlayerAmongNominatedPlayers\"](game, nominatedPlayers);\n\n expect(mocks.playerKillerService.killOrRevealPlayer).toHaveBeenCalledExactlyOnceWith(nominatedPlayers[0]._id, game, expectedPlayerDeath);\n });\n });\n\n describe(\"handleTieInVotes\", () => {\n beforeEach(() => {\n mocks.gamePlayMakerService.killPlayerAmongNominatedPlayers = jest.spyOn(services.gamePlayMaker as unknown as { killPlayerAmongNominatedPlayers }, \"killPlayerAmongNominatedPlayers\").mockImplementation();\n });\n\n it(\"should not kill scapegoat when he's not the game.\", async() => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n mocks.gameMutator.prependUpcomingPlayInGame.mockReturnValue(game);\n await services.gamePlayMaker[\"handleTieInVotes\"](game, players);\n\n expect(mocks.playerKillerService.killOrRevealPlayer).not.toHaveBeenCalled();\n });\n\n it(\"should not kill scapegoat when he's dead.\", async() => {\n const players = [\n createFakeScapegoatAlivePlayer({ isAlive: false }),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n mocks.gameMutator.prependUpcomingPlayInGame.mockReturnValue(game);\n await services.gamePlayMaker[\"handleTieInVotes\"](game, players);\n\n expect(mocks.playerKillerService.killOrRevealPlayer).not.toHaveBeenCalled();\n });\n\n it(\"should not kill scapegoat when he's powerless.\", async() => {\n const players = [\n createFakeScapegoatAlivePlayer({ attributes: [createFakePowerlessByElderPlayerAttribute()] }),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n mocks.gameMutator.prependUpcomingPlayInGame.mockReturnValue(game);\n await services.gamePlayMaker[\"handleTieInVotes\"](game, players);\n\n expect(mocks.playerKillerService.killOrRevealPlayer).not.toHaveBeenCalled();\n });\n\n it(\"should kill scapegoat when he's in the game and alive.\", async() => {\n const players = [\n createFakeScapegoatAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const playerDeath = createFakePlayerVoteScapegoatedBySurvivorsDeath();\n mocks.gameMutator.prependUpcomingPlayInGame.mockReturnValue(game);\n await services.gamePlayMaker[\"handleTieInVotes\"](game, players);\n\n expect(mocks.playerKillerService.killOrRevealPlayer).toHaveBeenCalledExactlyOnceWith(players[0]._id, game, playerDeath);\n });\n\n it(\"should not prepend sheriff settling tie in votes game play when sheriff is not in the game.\", async() => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ sheriff: createFakeSheriffGameOptions({ mustSettleTieInVotes: true }) }) });\n const game = createFakeGameWithCurrentPlay({ players, options });\n const gamePlaySheriffSettlesVotes = createFakeGamePlaySheriffSettlesVotes();\n mocks.gameMutator.prependUpcomingPlayInGame.mockReturnValue(game);\n await services.gamePlayMaker[\"handleTieInVotes\"](game, players);\n\n expect(mocks.gameMutator.prependUpcomingPlayInGame).not.toHaveBeenCalledExactlyOnceWith(gamePlaySheriffSettlesVotes, game);\n });\n\n it(\"should not prepend sheriff settling tie in votes game play when sheriff is dead.\", async() => {\n const players = [\n createFakeSeerAlivePlayer({ isAlive: false, attributes: [createFakeSheriffBySurvivorsPlayerAttribute()] }),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ sheriff: createFakeSheriffGameOptions({ mustSettleTieInVotes: true }) }) });\n const game = createFakeGameWithCurrentPlay({ players, options });\n const gamePlaySheriffSettlesVotes = createFakeGamePlaySheriffSettlesVotes();\n mocks.gameMutator.prependUpcomingPlayInGame.mockReturnValue(game);\n await services.gamePlayMaker[\"handleTieInVotes\"](game, players);\n\n expect(mocks.gameMutator.prependUpcomingPlayInGame).not.toHaveBeenCalledExactlyOnceWith(gamePlaySheriffSettlesVotes, game);\n });\n\n it(\"should not prepend sheriff settling tie in votes game play when game options don't allow it.\", async() => {\n const players = [\n createFakeSeerAlivePlayer({ isAlive: false, attributes: [createFakeSheriffBySurvivorsPlayerAttribute()] }),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ sheriff: createFakeSheriffGameOptions({ mustSettleTieInVotes: false }) }) });\n const game = createFakeGameWithCurrentPlay({ players, options });\n const gamePlaySheriffSettlesVotes = createFakeGamePlaySheriffSettlesVotes();\n mocks.gameMutator.prependUpcomingPlayInGame.mockReturnValue(game);\n await services.gamePlayMaker[\"handleTieInVotes\"](game, players);\n\n expect(mocks.gameMutator.prependUpcomingPlayInGame).not.toHaveBeenCalledExactlyOnceWith(gamePlaySheriffSettlesVotes, game);\n });\n\n it(\"should prepend sheriff delegation game play when sheriff is in the game.\", async() => {\n const players = [\n createFakeSeerAlivePlayer({ attributes: [createFakeSheriffBySurvivorsPlayerAttribute()] }),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ sheriff: createFakeSheriffGameOptions({ mustSettleTieInVotes: true }) }) });\n const game = createFakeGameWithCurrentPlay({ players, options });\n const gamePlaySheriffSettlesVotes = createFakeGamePlaySheriffSettlesVotes();\n mocks.gameMutator.prependUpcomingPlayInGame.mockReturnValue(game);\n await services.gamePlayMaker[\"handleTieInVotes\"](game, players);\n\n expect(mocks.gameMutator.prependUpcomingPlayInGame).toHaveBeenCalledExactlyOnceWith(gamePlaySheriffSettlesVotes, game);\n });\n\n it(\"should prepend vote game play with only tie cause when previous play is not a tie without cause.\", async() => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ sheriff: createFakeSheriffGameOptions({ mustSettleTieInVotes: true }) }) });\n const game = createFakeGameWithCurrentPlay({ players, options });\n const gamePlaySurvivorsVote = createFakeGamePlaySurvivorsVote({ causes: [\"previous-votes-were-in-ties\"] });\n mocks.gameMutator.prependUpcomingPlayInGame.mockReturnValue(game);\n await services.gamePlayMaker[\"handleTieInVotes\"](game, players);\n\n expect(mocks.gameMutator.prependUpcomingPlayInGame).toHaveBeenCalledExactlyOnceWith(gamePlaySurvivorsVote, game);\n });\n\n it(\"should prepend vote game play with tie and previous play causes when previous play is not a tie with causes.\", async() => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const currentPlay = createFakeGamePlaySurvivorsVote({ causes: [\"angel-presence\"] });\n const gamePlaySurvivorsVote = createFakeGamePlaySurvivorsVote({ causes: [\"previous-votes-were-in-ties\", \"angel-presence\"] });\n const game = createFakeGameWithCurrentPlay({ players, currentPlay });\n mocks.gameMutator.prependUpcomingPlayInGame.mockReturnValue(game);\n await services.gamePlayMaker[\"handleTieInVotes\"](game, players);\n\n expect(mocks.gameMutator.prependUpcomingPlayInGame).toHaveBeenCalledWith(gamePlaySurvivorsVote, game);\n });\n\n it(\"should prepend vote game play when there is no game history records.\", async() => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ sheriff: createFakeSheriffGameOptions({ mustSettleTieInVotes: true }) }) });\n const game = createFakeGameWithCurrentPlay({ players, options });\n mocks.gameMutator.prependUpcomingPlayInGame.mockReturnValue(game);\n const gamePlaySurvivorsVote = createFakeGamePlaySurvivorsVote({ causes: [\"previous-votes-were-in-ties\"], occurrence: \"consequential\" });\n await services.gamePlayMaker[\"handleTieInVotes\"](game, players);\n\n expect(mocks.gameMutator.prependUpcomingPlayInGame).toHaveBeenCalledExactlyOnceWith(gamePlaySurvivorsVote, game);\n });\n\n it(\"should not prepend vote game play when current play is due to a tie and cause is not angel presence.\", async() => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const currentPlay = createFakeGamePlaySurvivorsVote({ causes: [\"previous-votes-were-in-ties\"] });\n const gamePlaySurvivorsVote = createFakeGamePlaySurvivorsVote({ causes: [\"previous-votes-were-in-ties\"], occurrence: \"consequential\" });\n const game = createFakeGameWithCurrentPlay({ players, currentPlay });\n mocks.gameMutator.prependUpcomingPlayInGame.mockReturnValue(game);\n await services.gamePlayMaker[\"handleTieInVotes\"](game, players);\n\n expect(mocks.gameMutator.prependUpcomingPlayInGame).not.toHaveBeenCalledExactlyOnceWith(gamePlaySurvivorsVote, game);\n expect(mocks.gamePlayMakerService.killPlayerAmongNominatedPlayers).not.toHaveBeenCalled();\n });\n\n it(\"should kill player among nominated players when current play is due to a tie and cause is angel presence.\", async() => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const currentPlay = createFakeGamePlaySurvivorsVote({ causes: [\"angel-presence\", \"previous-votes-were-in-ties\"] });\n const game = createFakeGameWithCurrentPlay({ players, currentPlay });\n const nominatedPlayers = [createFakePlayer()];\n mocks.gameMutator.prependUpcomingPlayInGame.mockReturnValue(game);\n await services.gamePlayMaker[\"handleTieInVotes\"](game, nominatedPlayers);\n\n expect(mocks.gamePlayMakerService.killPlayerAmongNominatedPlayers).toHaveBeenCalledExactlyOnceWith(game, nominatedPlayers);\n });\n });\n\n describe(\"survivorsVote\", () => {\n beforeEach(() => {\n mocks.gamePlayMakerService.handleTieInVotes = jest.spyOn(services.gamePlayMaker as unknown as { handleTieInVotes }, \"handleTieInVotes\").mockImplementation();\n });\n\n it(\"should return game as is when there is no vote.\", async() => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsVote({ causes: [\"stuttering-judge-request\"] }), players });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedGame = createFakeGame(game);\n mocks.gamePlayVoteService.getNominatedPlayers.mockReturnValue([]);\n\n await expect(services.gamePlayMaker[\"survivorsVote\"](play, game)).resolves.toStrictEqual(expectedGame);\n });\n\n it(\"should return game as is when there is no nominated players.\", async() => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsVote({ causes: [\"stuttering-judge-request\"] }), players });\n const votes: MakeGamePlayVoteWithRelationsDto[] = [\n createFakeMakeGamePlayVoteWithRelationsDto({ source: players[0], target: players[1] }),\n createFakeMakeGamePlayVoteWithRelationsDto({ source: players[2], target: players[0] }),\n ];\n const play = createFakeMakeGamePlayWithRelationsDto({ votes, doesJudgeRequestAnotherVote: false });\n const nominatedPlayers = [];\n mocks.gamePlayVoteService.getNominatedPlayers.mockReturnValue(nominatedPlayers);\n const expectedGame = createFakeGame(game);\n\n await expect(services.gamePlayMaker[\"survivorsVote\"](play, game)).resolves.toStrictEqual(expectedGame);\n });\n\n it(\"should call handleTieInVotes method when there are several nominated players.\", async() => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsVote({ causes: [\"stuttering-judge-request\"] }), players });\n const votes: MakeGamePlayVoteWithRelationsDto[] = [\n createFakeMakeGamePlayVoteWithRelationsDto({ source: players[0], target: players[1] }),\n createFakeMakeGamePlayVoteWithRelationsDto({ source: players[2], target: players[0] }),\n ];\n const play = createFakeMakeGamePlayWithRelationsDto({ votes, doesJudgeRequestAnotherVote: false });\n const nominatedPlayers = [players[1], players[2]];\n mocks.gamePlayVoteService.getNominatedPlayers.mockReturnValue(nominatedPlayers);\n await services.gamePlayMaker[\"survivorsVote\"](play, game);\n\n expect(mocks.gamePlayMakerService.handleTieInVotes).toHaveBeenCalledExactlyOnceWith(game, nominatedPlayers);\n });\n\n it(\"should remove scandalmonger mark when there is this attribute among players.\", async() => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeScandalmongerMarkedByScandalmongerPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsVote({ causes: [\"stuttering-judge-request\"] }), players });\n const votes: MakeGamePlayVoteWithRelationsDto[] = [\n createFakeMakeGamePlayVoteWithRelationsDto({ source: players[0], target: players[1] }),\n createFakeMakeGamePlayVoteWithRelationsDto({ source: players[2], target: players[0] }),\n ];\n const play = createFakeMakeGamePlayWithRelationsDto({ votes, doesJudgeRequestAnotherVote: false });\n const nominatedPlayers = [players[1], players[2]];\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n players[1],\n createFakeWerewolfAlivePlayer({\n ...players[2],\n attributes: [],\n }),\n players[3],\n ],\n });\n mocks.gamePlayVoteService.getNominatedPlayers.mockReturnValue(nominatedPlayers);\n await services.gamePlayMaker[\"survivorsVote\"](play, game);\n\n expect(mocks.gamePlayMakerService.handleTieInVotes).toHaveBeenCalledExactlyOnceWith(expectedGame, nominatedPlayers);\n });\n\n it(\"should prepend stuttering judge request another vote game play when current play cause is undefined.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsVote() });\n const votes: MakeGamePlayVoteWithRelationsDto[] = [\n createFakeMakeGamePlayVoteWithRelationsDto(),\n createFakeMakeGamePlayVoteWithRelationsDto(),\n ];\n const play = createFakeMakeGamePlayWithRelationsDto({ votes });\n const nominatedPlayers = [createFakePlayer()];\n const gamePlayStutteringJudgeRequestsAnotherVote = createFakeGamePlayStutteringJudgeRequestsAnotherVote();\n mocks.gamePlayVoteService.getNominatedPlayers.mockReturnValue(nominatedPlayers);\n mocks.gameMutator.prependUpcomingPlayInGame.mockReturnValue(game);\n await services.gamePlayMaker[\"survivorsVote\"](play, game);\n\n expect(mocks.gameMutator.prependUpcomingPlayInGame).toHaveBeenCalledExactlyOnceWith(gamePlayStutteringJudgeRequestsAnotherVote, game);\n });\n\n it(\"should prepend stuttering judge request another vote game play when current play cause is angel presence and there is no tie in votes.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsVote({ causes: [\"angel-presence\"] }) });\n const votes: MakeGamePlayVoteWithRelationsDto[] = [\n createFakeMakeGamePlayVoteWithRelationsDto(),\n createFakeMakeGamePlayVoteWithRelationsDto(),\n ];\n const play = createFakeMakeGamePlayWithRelationsDto({ votes });\n const nominatedPlayers = [createFakePlayer()];\n const gamePlayStutteringJudgeRequestsAnotherVote = createFakeGamePlayStutteringJudgeRequestsAnotherVote();\n mocks.gamePlayVoteService.getNominatedPlayers.mockReturnValue(nominatedPlayers);\n mocks.gameMutator.prependUpcomingPlayInGame.mockReturnValue(game);\n await services.gamePlayMaker[\"survivorsVote\"](play, game);\n\n expect(mocks.gameMutator.prependUpcomingPlayInGame).toHaveBeenCalledExactlyOnceWith(gamePlayStutteringJudgeRequestsAnotherVote, game);\n });\n\n it(\"should not prepend stuttering judge request another vote game play when current play cause is angel presence and there is a tie in votes.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsVote({ causes: [\"angel-presence\", \"previous-votes-were-in-ties\"] }) });\n const votes: MakeGamePlayVoteWithRelationsDto[] = [\n createFakeMakeGamePlayVoteWithRelationsDto(),\n createFakeMakeGamePlayVoteWithRelationsDto(),\n ];\n const play = createFakeMakeGamePlayWithRelationsDto({ votes, doesJudgeRequestAnotherVote: false });\n const nominatedPlayers = [createFakePlayer()];\n mocks.gamePlayVoteService.getNominatedPlayers.mockReturnValue(nominatedPlayers);\n await services.gamePlayMaker[\"survivorsVote\"](play, game);\n\n expect(mocks.gameMutator.prependUpcomingPlayInGame).not.toHaveBeenCalled();\n });\n\n it(\"should call killOrRevealPlayer method when there is one nominated player.\", async() => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsVote({ causes: [\"stuttering-judge-request\"] }), players });\n const votes: MakeGamePlayVoteWithRelationsDto[] = [\n createFakeMakeGamePlayVoteWithRelationsDto({ source: players[0], target: players[1] }),\n createFakeMakeGamePlayVoteWithRelationsDto({ source: players[2], target: players[0] }),\n ];\n const play = createFakeMakeGamePlayWithRelationsDto({ votes, doesJudgeRequestAnotherVote: false });\n const nominatedPlayers = [players[1]];\n const playerVoteBySurvivorsDeath = createFakePlayerVoteBySurvivorsDeath();\n mocks.gamePlayVoteService.getNominatedPlayers.mockReturnValue(nominatedPlayers);\n await services.gamePlayMaker[\"survivorsVote\"](play, game);\n\n expect(mocks.playerKillerService.killOrRevealPlayer).toHaveBeenCalledExactlyOnceWith(players[1]._id, game, playerVoteBySurvivorsDeath);\n });\n });\n\n describe(\"handleTieInSheriffElection\", () => {\n it(\"should prepend survivors elect sheriff game play when current play is not due to a tie.\", () => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const currentPlay = createFakeGamePlaySurvivorsElectSheriff({ causes: [\"stuttering-judge-request\"] });\n const upcomingPlays = [createFakeGamePlayHunterShoots()];\n const game = createFakeGameWithCurrentPlay({ currentPlay, players, upcomingPlays });\n const nominatedPlayers = [players[0], players[1]];\n const prependedGamePlay = createFakeGamePlaySurvivorsElectSheriff({ causes: [\"previous-votes-were-in-ties\"] });\n services.gamePlayMaker[\"handleTieInSheriffElection\"](nominatedPlayers, game);\n\n expect(mocks.gameMutator.prependUpcomingPlayInGame).toHaveBeenCalledExactlyOnceWith(prependedGamePlay, game);\n });\n\n it(\"should add sheriff attribute to a random nominated player when current play is due to a tie.\", () => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n mocks.lodash.sample.mockReturnValue(players[0]);\n const currentPlay = createFakeGamePlaySurvivorsElectSheriff({ causes: [\"previous-votes-were-in-ties\"] });\n const upcomingPlays = [createFakeGamePlayHunterShoots()];\n const game = createFakeGameWithCurrentPlay({ currentPlay, players, upcomingPlays });\n const nominatedPlayers = [players[0], players[1]];\n const expectedGame = createFakeGame({\n ...game,\n players: [\n createFakePlayer({\n ...players[0],\n attributes: [createFakeSheriffBySurvivorsPlayerAttribute()],\n }),\n players[1],\n players[2],\n players[3],\n ],\n });\n\n expect(services.gamePlayMaker[\"handleTieInSheriffElection\"](nominatedPlayers, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should return game as is when it's not possible to choose a random nominated player.\", () => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n mocks.lodash.sample.mockReturnValue(undefined);\n const currentPlay = createFakeGamePlaySurvivorsElectSheriff({ causes: [\"previous-votes-were-in-ties\"] });\n const upcomingPlays = [createFakeGamePlayHunterShoots()];\n const game = createFakeGameWithCurrentPlay({ currentPlay, players, upcomingPlays });\n const nominatedPlayers = [players[0], players[1]];\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"handleTieInSheriffElection\"](nominatedPlayers, game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"survivorsElectSheriff\", () => {\n beforeEach(() => {\n mocks.gamePlayMakerService.handleTieInSheriffElection = jest.spyOn(services.gamePlayMaker as unknown as { handleTieInSheriffElection }, \"handleTieInSheriffElection\").mockImplementation();\n });\n\n it(\"should return game as is when there is no vote.\", () => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedGame = createFakeGame(game);\n mocks.gamePlayVoteService.getNominatedPlayers.mockReturnValue([]);\n\n expect(services.gamePlayMaker[\"survivorsElectSheriff\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should return game as is when there is no nominated players.\", () => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const votes: MakeGamePlayVoteWithRelationsDto[] = [\n createFakeMakeGamePlayVoteWithRelationsDto({ source: players[0], target: players[1] }),\n createFakeMakeGamePlayVoteWithRelationsDto({ source: players[2], target: players[0] }),\n ];\n const play = createFakeMakeGamePlayWithRelationsDto({ votes });\n mocks.gamePlayVoteService.getNominatedPlayers.mockReturnValue([]);\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"survivorsElectSheriff\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should call handleTieInSheriffElection method when there is a tie in votes.\", () => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const votes: MakeGamePlayVoteWithRelationsDto[] = [\n createFakeMakeGamePlayVoteWithRelationsDto({ source: players[0], target: players[1] }),\n createFakeMakeGamePlayVoteWithRelationsDto({ source: players[2], target: players[0] }),\n ];\n const play = createFakeMakeGamePlayWithRelationsDto({ votes });\n const nominatedPlayers = [players[0], players[1]];\n mocks.gamePlayVoteService.getNominatedPlayers.mockReturnValue(nominatedPlayers);\n services.gamePlayMaker[\"survivorsElectSheriff\"](play, game);\n\n expect(mocks.gamePlayMakerService.handleTieInSheriffElection).toHaveBeenCalledExactlyOnceWith(nominatedPlayers, game);\n });\n\n it(\"should add sheriff attribute to nominated player when called.\", () => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const votes: MakeGamePlayVoteWithRelationsDto[] = [\n createFakeMakeGamePlayVoteWithRelationsDto({ source: players[0], target: players[1] }),\n createFakeMakeGamePlayVoteWithRelationsDto({ source: players[2], target: players[0] }),\n ];\n const play = createFakeMakeGamePlayWithRelationsDto({ votes });\n mocks.gamePlayVoteService.getNominatedPlayers.mockReturnValue([players[1]]);\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n createFakePlayer({ ...players[1], attributes: [createFakeSheriffBySurvivorsPlayerAttribute()] }),\n players[2],\n players[3],\n ],\n });\n\n expect(services.gamePlayMaker[\"survivorsElectSheriff\"](play, game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"survivorsPlay\", () => {\n beforeEach(() => {\n mocks.gamePlayMakerService.survivorsElectSheriff = jest.spyOn(services.gamePlayMaker as unknown as { survivorsElectSheriff }, \"survivorsElectSheriff\").mockImplementation();\n mocks.gamePlayMakerService.survivorsVote = jest.spyOn(services.gamePlayMaker as unknown as { survivorsVote }, \"survivorsVote\").mockImplementation();\n mocks.gamePlayMakerService.survivorsBuryDeadBodies = jest.spyOn(services.gamePlayMaker as unknown as { survivorsBuryDeadBodies }, \"survivorsBuryDeadBodies\").mockImplementation();\n });\n\n it(\"should return game as is when upcoming play is not for all.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayFoxSniffs() });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedGame = createFakeGame(game);\n\n await expect(services.gamePlayMaker[\"survivorsPlay\"](play, game)).resolves.toStrictEqual(expectedGame);\n });\n\n it(\"should call survivorsElectSheriff method when upcoming play is sheriff role delegation.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsElectSheriff() });\n const play = createFakeMakeGamePlayWithRelationsDto();\n await services.gamePlayMaker[\"survivorsPlay\"](play, game);\n\n expect(mocks.gamePlayMakerService.survivorsElectSheriff).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n\n it(\"should call survivorsVote method when upcoming play is sheriff settling vote.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsVote() });\n const play = createFakeMakeGamePlayWithRelationsDto();\n await services.gamePlayMaker[\"survivorsPlay\"](play, game);\n\n expect(mocks.gamePlayMakerService.survivorsVote).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n\n it(\"should call survivorsBuryDeadBodies method when upcoming play is burying dead bodies.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlaySurvivorsBuryDeadBodies() });\n const play = createFakeMakeGamePlayWithRelationsDto();\n await services.gamePlayMaker[\"survivorsPlay\"](play, game);\n\n expect(mocks.gamePlayMakerService.survivorsBuryDeadBodies).toHaveBeenCalledExactlyOnceWith(play, game);\n });\n });\n\n describe(\"thiefChoosesCard\", () => {\n it(\"should return game as is when there is no thief player in game.\", () => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const additionalCards = [\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, additionalCards });\n const play = createFakeMakeGamePlayWithRelationsDto({ chosenCard: additionalCards[0] });\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"thiefChoosesCard\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should return game as is when there is no chosen card.\", () => {\n const players = [\n createFakeThiefAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const additionalCards = [\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, additionalCards });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"thiefChoosesCard\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should return game as is when chosen card role is unknown.\", () => {\n const players = [\n createFakeThiefAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const additionalCards = [\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n ];\n const game = createFakeGameWithCurrentPlay({ players, additionalCards });\n const play = createFakeMakeGamePlayWithRelationsDto({ chosenCard: createFakeGameAdditionalCard({}, { roleName: \"Toto\" }) });\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"thiefChoosesCard\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should update thief role and side and make his card used when called.\", () => {\n const players = [\n createFakeThiefAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const additionalCards = [\n createFakeGameAdditionalCard({ roleName: \"werewolf\", isUsed: false }),\n createFakeGameAdditionalCard({ isUsed: false }),\n createFakeGameAdditionalCard({ isUsed: false }),\n createFakeGameAdditionalCard({ isUsed: false }),\n ];\n const game = createFakeGameWithCurrentPlay({ players, additionalCards });\n const play = createFakeMakeGamePlayWithRelationsDto({ chosenCard: additionalCards[0] });\n const expectedThiefPlayer = createFakePlayer({\n ...players[0],\n role: { ...players[0].role, current: \"werewolf\" },\n side: { ...players[0].side, current: \"werewolves\" },\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n expectedThiefPlayer,\n players[1],\n players[2],\n players[3],\n ],\n additionalCards: [\n createFakeGameAdditionalCard({ ...additionalCards[0], isUsed: true }),\n additionalCards[1],\n additionalCards[2],\n additionalCards[3],\n ],\n });\n\n expect(services.gamePlayMaker[\"thiefChoosesCard\"](play, game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"scapegoatBansVoting\", () => {\n it(\"should return game as is when there are no targets.\", () => {\n const players = [\n createFakeThiefAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"scapegoatBansVoting\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should add scapegoat ban voting attributes to targets when called.\", () => {\n const players = [\n createFakeThiefAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const targets = [\n createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1] }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: players[2] }),\n ];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n createFakePlayer({ ...players[1], attributes: [createFakeCantVoteByScapegoatPlayerAttribute(game)] }),\n createFakePlayer({ ...players[2], attributes: [createFakeCantVoteByScapegoatPlayerAttribute(game)] }),\n players[3],\n ],\n });\n\n expect(services.gamePlayMaker[\"scapegoatBansVoting\"](play, game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"wolfHoundChoosesSide\", () => {\n it(\"should return game as is when there is no wolf-hound in the game.\", () => {\n const players = [\n createFakeThiefAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const play = createFakeMakeGamePlayWithRelationsDto({ chosenSide: \"werewolves\" });\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"wolfHoundChoosesSide\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should return wolf-hound on random side when chosen side is not set.\", () => {\n const players = [\n createFakeScandalmongerAlivePlayer(),\n createFakeWolfHoundAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedWolfHoundPlayer = createFakePlayer({\n ...players[1],\n side: { ...players[1].side, current: \"villagers\" },\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n expectedWolfHoundPlayer,\n players[2],\n players[3],\n ],\n });\n mocks.lodash.sample.mockReturnValue(\"villagers\");\n\n expect(services.gamePlayMaker[\"wolfHoundChoosesSide\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should get a random side when chosen side is not set.\", () => {\n const players = [\n createFakeScandalmongerAlivePlayer(),\n createFakeWolfHoundAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const play = createFakeMakeGamePlayWithRelationsDto();\n services.gamePlayMaker[\"wolfHoundChoosesSide\"](play, game);\n\n expect(mocks.lodash.sample).toHaveBeenCalledExactlyOnceWith([\"villagers\", \"werewolves\"]);\n });\n\n it(\"should return wolf-hound on the werewolves side when chosen side is werewolves.\", () => {\n const players = [\n createFakeScandalmongerAlivePlayer(),\n createFakeWolfHoundAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ actor: createFakeActorGameOptions({ isPowerlessOnWerewolvesSide: true }) }) });\n const game = createFakeGameWithCurrentPlay({ players, options });\n const play = createFakeMakeGamePlayWithRelationsDto({ chosenSide: \"werewolves\" });\n const expectedWolfHoundPlayer = createFakePlayer({\n ...players[1],\n side: { ...players[1].side, current: \"werewolves\" },\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n expectedWolfHoundPlayer,\n players[2],\n players[3],\n ],\n });\n\n expect(services.gamePlayMaker[\"wolfHoundChoosesSide\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should return wolf-hound on the werewolves side and add powerless attribute when chosen side is werewolves and wolf-hound is actor in disguise.\", () => {\n const players = [\n createFakeScandalmongerAlivePlayer(),\n createFakeWolfHoundAlivePlayer({ role: createFakePlayerRole({ original: \"actor\", current: \"wolf-hound\" }) }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ actor: createFakeActorGameOptions({ isPowerlessOnWerewolvesSide: true }) }) });\n const game = createFakeGameWithCurrentPlay({ players, options });\n const play = createFakeMakeGamePlayWithRelationsDto({ chosenSide: \"werewolves\" });\n const expectedWolfHoundPlayer = createFakePlayer({\n ...players[1],\n side: { ...players[1].side, current: \"werewolves\" },\n attributes: [createFakePowerlessByActorPlayerAttribute()],\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n expectedWolfHoundPlayer,\n players[2],\n players[3],\n ],\n });\n\n expect(services.gamePlayMaker[\"wolfHoundChoosesSide\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should return wolf-hound on the werewolves side but without powerless attribute when chosen side is werewolves and wolf-hound is actor in disguise but game options are changed.\", () => {\n const players = [\n createFakeScandalmongerAlivePlayer(),\n createFakeWolfHoundAlivePlayer({ role: createFakePlayerRole({ original: \"actor\", current: \"wolf-hound\" }) }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ actor: createFakeActorGameOptions({ isPowerlessOnWerewolvesSide: false }) }) });\n const game = createFakeGameWithCurrentPlay({ players, options });\n const play = createFakeMakeGamePlayWithRelationsDto({ chosenSide: \"werewolves\" });\n const expectedWolfHoundPlayer = createFakePlayer({\n ...players[1],\n side: { ...players[1].side, current: \"werewolves\" },\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n expectedWolfHoundPlayer,\n players[2],\n players[3],\n ],\n });\n\n expect(services.gamePlayMaker[\"wolfHoundChoosesSide\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should return wolf-hound on the villagers side when chosen side is villagers.\", () => {\n const players = [\n createFakeScandalmongerAlivePlayer(),\n createFakeWolfHoundAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const play = createFakeMakeGamePlayWithRelationsDto({ chosenSide: \"villagers\" });\n const expectedWolfHoundPlayer = createFakePlayer({\n ...players[1],\n side: { ...players[1].side, current: \"villagers\" },\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n expectedWolfHoundPlayer,\n players[2],\n players[3],\n ],\n });\n\n expect(services.gamePlayMaker[\"wolfHoundChoosesSide\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should return wolf-hound on the villagers side but without powerless attribute when chosen side is villagers and wolf-hound is actor in disguise.\", () => {\n const players = [\n createFakeScandalmongerAlivePlayer(),\n createFakeWolfHoundAlivePlayer({ role: createFakePlayerRole({ original: \"actor\", current: \"wolf-hound\" }) }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ actor: createFakeActorGameOptions({ isPowerlessOnWerewolvesSide: true }) }) });\n const game = createFakeGameWithCurrentPlay({ players, options });\n const play = createFakeMakeGamePlayWithRelationsDto({ chosenSide: \"villagers\" });\n const expectedWolfHoundPlayer = createFakePlayer({\n ...players[1],\n side: { ...players[1].side, current: \"villagers\" },\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n expectedWolfHoundPlayer,\n players[2],\n players[3],\n ],\n });\n\n expect(services.gamePlayMaker[\"wolfHoundChoosesSide\"](play, game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"wildChildChoosesModel\", () => {\n it(\"should return game as is when expected target count is not reached.\", () => {\n const players = [\n createFakeWolfHoundAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"wildChildChoosesModel\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should add worshiped attribute to target when called.\", () => {\n const players = [\n createFakeWolfHoundAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const targets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1] })];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n const expectedTargetedPlayer = createFakePlayer({\n ...players[1],\n attributes: [createFakeWorshipedByWildChildPlayerAttribute()],\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n expectedTargetedPlayer,\n players[2],\n players[3],\n ],\n });\n\n expect(services.gamePlayMaker[\"wildChildChoosesModel\"](play, game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"foxSniffs\", () => {\n it(\"should return game as is when expected target count is not reached.\", () => {\n const players = [\n createFakeFoxAlivePlayer({ position: 0 }),\n createFakeScandalmongerAlivePlayer({ position: 1 }),\n createFakeWerewolfAlivePlayer({ position: 2 }),\n createFakeWerewolfAlivePlayer({ position: 3 }),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"foxSniffs\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should return game as is when there is no fox in the game.\", () => {\n const players = [\n createFakeSeerAlivePlayer({ position: 0 }),\n createFakeScandalmongerAlivePlayer({ position: 1 }),\n createFakeWerewolfAlivePlayer({ position: 2 }),\n createFakeWerewolfAlivePlayer({ position: 3 }),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const targets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1] })];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"foxSniffs\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should return game as is when fox is not powerless if misses werewolves by game options.\", () => {\n const players = [\n createFakeFoxAlivePlayer({ position: 0 }),\n createFakeScandalmongerAlivePlayer({ position: 1 }),\n createFakeWerewolfAlivePlayer({ position: 2 }),\n createFakeWerewolfAlivePlayer({ position: 3 }),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ fox: createFakeFoxGameOptions({ isPowerlessIfMissesWerewolf: false }) }) });\n const game = createFakeGameWithCurrentPlay({ players, options });\n const targets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1] })];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"foxSniffs\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should return game as is when fox sniffes a werewolf in the group.\", () => {\n const players = [\n createFakeFoxAlivePlayer({ position: 0 }),\n createFakeScandalmongerAlivePlayer({ position: 1 }),\n createFakeWerewolfAlivePlayer({ position: 2 }),\n createFakeWerewolfAlivePlayer({ position: 3 }),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ fox: createFakeFoxGameOptions({ isPowerlessIfMissesWerewolf: true }) }) });\n const game = createFakeGameWithCurrentPlay({ players, options });\n const targets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1] })];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"foxSniffs\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should make fox powerless when there is no werewolf in the group.\", () => {\n const players = [\n createFakeFoxAlivePlayer({ position: 0 }),\n createFakeScandalmongerAlivePlayer({ position: 1 }),\n createFakeVillagerAlivePlayer({ position: 2 }),\n createFakeWerewolfAlivePlayer({ position: 3 }),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ fox: createFakeFoxGameOptions({ isPowerlessIfMissesWerewolf: true }) }) });\n const game = createFakeGameWithCurrentPlay({ players, options });\n const targets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1] })];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n const expectedTargetedPlayer = createFakePlayer({\n ...players[0],\n attributes: [createFakePowerlessByFoxPlayerAttribute({ doesRemainAfterDeath: true })],\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n expectedTargetedPlayer,\n players[1],\n players[2],\n players[3],\n ],\n });\n\n expect(services.gamePlayMaker[\"foxSniffs\"](play, game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"scandalmongerMarks\", () => {\n it(\"should return game as is when expected target count is not reached.\", () => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"scandalmongerMarks\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should add scandalmonger marked attribute to target when called.\", () => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const targets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1] })];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n const expectedTargetedPlayer = createFakePlayer({\n ...players[1],\n attributes: [createFakeScandalmongerMarkedByScandalmongerPlayerAttribute()],\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n expectedTargetedPlayer,\n players[2],\n players[3],\n ],\n });\n\n expect(services.gamePlayMaker[\"scandalmongerMarks\"](play, game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"defenderProtects\", () => {\n it(\"should return game as is when expected target count is not reached.\", () => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"defenderProtects\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should add protected attribute to target when called.\", () => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const targets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1] })];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n const expectedTargetedPlayer = createFakePlayer({\n ...players[1],\n attributes: [createFakeProtectedByDefenderPlayerAttribute()],\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n expectedTargetedPlayer,\n players[2],\n players[3],\n ],\n });\n\n expect(services.gamePlayMaker[\"defenderProtects\"](play, game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"hunterShoots\", () => {\n it(\"should return game as is when expected target count is not reached.\", async() => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedGame = createFakeGame(game);\n\n await expect(services.gamePlayMaker[\"hunterShoots\"](play, game)).resolves.toStrictEqual(expectedGame);\n });\n\n it(\"should call killOrRevealPlayer method when called.\", async() => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const targets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1] })];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n const playerDeath = createFakePlayerShotByHunterDeath();\n await services.gamePlayMaker[\"hunterShoots\"](play, game);\n\n expect(mocks.playerKillerService.killOrRevealPlayer).toHaveBeenCalledExactlyOnceWith(players[1]._id, game, playerDeath);\n });\n });\n\n describe(\"witchUsesPotions\", () => {\n it(\"should return game as is when expected target count is not reached.\", () => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"witchUsesPotions\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should add only one potion attributes to targets when called.\", () => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const targets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1], drankPotion: \"life\" })];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n const expectedTargetedPlayer = createFakePlayer({\n ...players[1],\n attributes: [createFakeDrankLifePotionByWitchPlayerAttribute()],\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n expectedTargetedPlayer,\n players[2],\n players[3],\n ],\n });\n\n expect(services.gamePlayMaker[\"witchUsesPotions\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should add both potion attributes to targets when called.\", () => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const targets = [\n createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1], drankPotion: \"life\" }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: players[2], drankPotion: \"death\" }),\n ];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n const expectedFirstTargetedPlayer = createFakePlayer({\n ...players[1],\n attributes: [createFakeDrankLifePotionByWitchPlayerAttribute()],\n });\n const expectedSecondTargetedPlayer = createFakePlayer({\n ...players[2],\n attributes: [createFakeDrankDeathPotionByWitchPlayerAttribute()],\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n expectedFirstTargetedPlayer,\n expectedSecondTargetedPlayer,\n players[3],\n ],\n });\n\n expect(services.gamePlayMaker[\"witchUsesPotions\"](play, game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"piedPiperCharms\", () => {\n it(\"should return game as is when targets are undefined.\", () => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"piedPiperCharms\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should return game as is when targets are empty.\", () => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const play = createFakeMakeGamePlayWithRelationsDto({ targets: [] });\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"piedPiperCharms\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should add pied piper charmed attributes to targets when called.\", () => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const targets = [\n createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1] }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: players[2] }),\n ];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n const expectedFirstTargetedPlayer = createFakePlayer({\n ...players[1],\n attributes: [createFakeCharmedByPiedPiperPlayerAttribute()],\n });\n const expectedSecondTargetedPlayer = createFakePlayer({\n ...players[2],\n attributes: [createFakeCharmedByPiedPiperPlayerAttribute()],\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n expectedFirstTargetedPlayer,\n expectedSecondTargetedPlayer,\n players[3],\n ],\n });\n\n expect(services.gamePlayMaker[\"piedPiperCharms\"](play, game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"cupidCharms\", () => {\n it(\"should return game as is when expected target count is not reached.\", () => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"cupidCharms\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should add in-love attribute to targets when called.\", () => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const targets = [\n createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1] }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: players[2] }),\n ];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n const expectedFirstTargetedPlayer = createFakePlayer({\n ...players[1],\n attributes: [createFakeInLoveByCupidPlayerAttribute()],\n });\n const expectedSecondTargetedPlayer = createFakePlayer({\n ...players[2],\n attributes: [createFakeInLoveByCupidPlayerAttribute()],\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n expectedFirstTargetedPlayer,\n expectedSecondTargetedPlayer,\n players[3],\n ],\n });\n\n expect(services.gamePlayMaker[\"cupidCharms\"](play, game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"seerLooks\", () => {\n it(\"should return game as is when expected target count is not reached.\", () => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"seerLooks\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should add seen attribute to target when called.\", () => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const targets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1] })];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n const expectedTargetedPlayer = createFakePlayer({\n ...players[1],\n attributes: [createFakeSeenBySeerPlayerAttribute()],\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n expectedTargetedPlayer,\n players[2],\n players[3],\n ],\n });\n\n expect(services.gamePlayMaker[\"seerLooks\"](play, game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"whiteWerewolfEats\", () => {\n it(\"should return game as is when expected target count is not reached.\", () => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"whiteWerewolfEats\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should add eaten attribute by white werewolf to target when called.\", () => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const targets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1] })];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n const expectedTargetedPlayer = createFakePlayer({\n ...players[1],\n attributes: [createFakeEatenByWhiteWerewolfPlayerAttribute()],\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n expectedTargetedPlayer,\n players[2],\n players[3],\n ],\n });\n\n expect(services.gamePlayMaker[\"whiteWerewolfEats\"](play, game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"bigBadWolfEats\", () => {\n it(\"should return game as is when expected target count is not reached.\", () => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"bigBadWolfEats\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should add eaten attribute by big bad wolf to target when called.\", () => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const targets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1] })];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n const expectedTargetedPlayer = createFakePlayer({\n ...players[1],\n attributes: [createFakeEatenByBigBadWolfPlayerAttribute()],\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n expectedTargetedPlayer,\n players[2],\n players[3],\n ],\n });\n\n expect(services.gamePlayMaker[\"bigBadWolfEats\"](play, game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"accursedWolfFatherInfects\", () => {\n it(\"should return game as is when target count is not reached.\", async() => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const targets = [];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n const expectedGame = createFakeGame(game);\n mocks.playerKillerService.isElderKillable.mockResolvedValueOnce(true);\n mocks.playerHelper.isPlayerPowerlessOnWerewolvesSide.mockReturnValue(true);\n\n await expect(services.gamePlayMaker[\"accursedWolfFatherInfects\"](play, game)).resolves.toStrictEqual(expectedGame);\n });\n\n it(\"should return game as is when target is elder and is not killable.\", async() => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeElderAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const targets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1] })];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n const expectedGame = createFakeGame(game);\n mocks.playerKillerService.isElderKillable.mockResolvedValueOnce(false);\n mocks.playerHelper.isPlayerPowerlessOnWerewolvesSide.mockReturnValue(true);\n\n await expect(services.gamePlayMaker[\"accursedWolfFatherInfects\"](play, game)).resolves.toStrictEqual(expectedGame);\n });\n\n it(\"should change target's side to werewolves and remove eaten by werewolves attribute when elder is killable.\", async() => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeElderAlivePlayer({\n attributes: [\n createFakeEatenByWerewolvesPlayerAttribute(),\n createFakeEatenByWerewolvesPlayerAttribute({ source: \"seer\" }),\n createFakeEatenByWhiteWerewolfPlayerAttribute(),\n ],\n }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const targets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1] })];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n const expectedTargetedPlayer = createFakePlayer({\n ...players[1],\n side: { ...players[1].side, current: \"werewolves\" },\n attributes: [\n createFakeEatenByWerewolvesPlayerAttribute({ source: \"seer\" }),\n createFakeEatenByWhiteWerewolfPlayerAttribute(),\n ],\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n expectedTargetedPlayer,\n players[2],\n players[3],\n ],\n });\n mocks.playerKillerService.isElderKillable.mockResolvedValueOnce(true);\n mocks.playerHelper.isPlayerPowerlessOnWerewolvesSide.mockReturnValue(false);\n\n await expect(services.gamePlayMaker[\"accursedWolfFatherInfects\"](play, game)).resolves.toStrictEqual(expectedGame);\n });\n\n it(\"should change target's side to werewolves and remove eaten by werewolves attribute when player is not elder.\", async() => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer({\n attributes: [\n createFakeEatenByWerewolvesPlayerAttribute(),\n createFakeSeenBySeerPlayerAttribute(),\n createFakeWorshipedByWildChildPlayerAttribute({ source: \"werewolves\" }),\n createFakeEatenByWhiteWerewolfPlayerAttribute(),\n ],\n }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const targets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1] })];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n const expectedTargetedPlayer = createFakePlayer({\n ...players[1],\n side: { ...players[1].side, current: \"werewolves\" },\n attributes: [\n createFakeSeenBySeerPlayerAttribute(),\n createFakeWorshipedByWildChildPlayerAttribute({ source: \"werewolves\" }),\n createFakeEatenByWhiteWerewolfPlayerAttribute(),\n ],\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n expectedTargetedPlayer,\n players[2],\n players[3],\n ],\n });\n mocks.playerKillerService.getElderLivesCountAgainstWerewolves.mockResolvedValueOnce(2);\n mocks.playerHelper.isPlayerPowerlessOnWerewolvesSide.mockReturnValue(false);\n\n await expect(services.gamePlayMaker[\"accursedWolfFatherInfects\"](play, game)).resolves.toStrictEqual(expectedGame);\n });\n\n it(\"should change target's side to werewolves, remove eaten by werewolves attribute and add powerless by accursed wolf-father attribute when target is powerless on joining the werewolves side.\", async() => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer({ attributes: [createFakeEatenByWerewolvesPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const targets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1] })];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n const expectedTargetedPlayer = createFakePlayer({\n ...players[1],\n side: { ...players[1].side, current: \"werewolves\" },\n attributes: [createFakePowerlessByAccursedWolfFatherPlayerAttribute()],\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n expectedTargetedPlayer,\n players[2],\n players[3],\n ],\n });\n mocks.playerKillerService.getElderLivesCountAgainstWerewolves.mockResolvedValueOnce(1);\n mocks.playerHelper.isPlayerPowerlessOnWerewolvesSide.mockReturnValue(true);\n\n await expect(services.gamePlayMaker[\"accursedWolfFatherInfects\"](play, game)).resolves.toStrictEqual(expectedGame);\n });\n });\n\n describe(\"werewolvesEat\", () => {\n it(\"should return game as is when expected target count is not reached.\", () => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedGame = createFakeGame(game);\n mocks.gamePlayMakerService.accursedWolfFatherInfects.mockReturnValue(expectedGame);\n\n expect(services.gamePlayMaker[\"werewolvesEat\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should add eaten attribute by werewolves to the target when called.\", () => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const targets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1] })];\n const play = createFakeMakeGamePlayWithRelationsDto({ targets });\n const expectedTargetedPlayer = createFakePlayer({\n ...players[1],\n attributes: [createFakeEatenByWerewolvesPlayerAttribute()],\n });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n expectedTargetedPlayer,\n players[2],\n players[3],\n ],\n });\n mocks.playerKillerService.getElderLivesCountAgainstWerewolves.mockReturnValue(2);\n mocks.gamePlayMakerService.accursedWolfFatherInfects.mockReturnValue(expectedGame);\n\n expect(services.gamePlayMaker[\"werewolvesEat\"](play, game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"stutteringJudgeRequestsAnotherVote\", () => {\n it(\"should return game as is when stuttering judge does not request another vote.\", () => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeStutteringJudgeAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const play = createFakeMakeGamePlayWithRelationsDto({ doesJudgeRequestAnotherVote: false });\n const expectedGame = createFakeGame(game);\n\n expect(services.gamePlayMaker[\"stutteringJudgeRequestsAnotherVote\"](play, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should return game with prepended vote of cause stuttering judge request when stuttering judge does request another vote.\", () => {\n const players = [\n createFakeFoxAlivePlayer(),\n createFakeStutteringJudgeAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const play = createFakeMakeGamePlayWithRelationsDto({ doesJudgeRequestAnotherVote: true });\n services.gamePlayMaker[\"stutteringJudgeRequestsAnotherVote\"](play, game);\n\n expect(mocks.gameMutator.prependUpcomingPlayInGame).toHaveBeenCalledExactlyOnceWith(createFakeGamePlaySurvivorsVote({ causes: [\"stuttering-judge-request\"] }), game);\n });\n });\n});" }, "tests/unit/specs/modules/game/providers/services/game-play/game-play-augmenter.service.spec.ts": { "tests": [ @@ -190718,7 +190720,7 @@ } } ], - "source": "import { DEFAULT_GAME_OPTIONS } from \"@/modules/game/constants/game-options/game-options.constants\";\nimport type { TestingModule } from \"@nestjs/testing\";\nimport { Test } from \"@nestjs/testing\";\n\nimport * as GameHelper from \"@/modules/game/helpers/game.helpers\";\nimport { GameHistoryRecordService } from \"@/modules/game/providers/services/game-history/game-history-record.service\";\nimport { GamePlayAugmenterService } from \"@/modules/game/providers/services/game-play/game-play-augmenter.service\";\nimport type { GamePlaySourceInteraction } from \"@/modules/game/schemas/game-play/game-play-source/game-play-source-interaction/game-play-source-interaction.schema\";\nimport type { GamePlay } from \"@/modules/game/schemas/game-play/game-play.schema\";\nimport type { Game } from \"@/modules/game/schemas/game.schema\";\nimport type { Player } from \"@/modules/game/schemas/player/player.schema\";\n\nimport { UnexpectedExceptionReasons } from \"@/shared/exception/enums/unexpected-exception.enum\";\nimport * as UnexpectedExceptionFactory from \"@/shared/exception/helpers/unexpected-exception.factory\";\nimport { UnexpectedException } from \"@/shared/exception/types/unexpected-exception.types\";\n\nimport { createFakeGameAdditionalCard } from \"@tests/factories/game/schemas/game-additional-card/game-additional-card.schema.factory\";\nimport { createFakeGameHistoryRecord, createFakeGameHistoryRecordPlay, createFakeGameHistoryRecordPlayVoting } from \"@tests/factories/game/schemas/game-history-record/game-history-record.schema.factory\";\nimport { createFakeGameOptions } from \"@tests/factories/game/schemas/game-options/game-options.schema.factory\";\nimport { createFakeCupidGameOptions, createFakeDefenderGameOptions, createFakePiedPiperGameOptions, createFakeRolesGameOptions, createFakeThiefGameOptions } from \"@tests/factories/game/schemas/game-options/game-roles-options/game-roles-options.schema.factory\";\nimport { createFakeVotesGameOptions } from \"@tests/factories/game/schemas/game-options/votes-game-options.schema.factory\";\nimport { createFakeGamePlaySourceInteraction } from \"@tests/factories/game/schemas/game-play/game-play-source/game-play-source-interaction/game-play-source-interaction.schema.factory\";\nimport { createFakeGamePlaySource } from \"@tests/factories/game/schemas/game-play/game-play-source/game-play-source.schema.factory\";\nimport { createFakeGamePlay, createFakeGamePlayAccursedWolfFatherInfects, createFakeGamePlayActorChoosesCard, createFakeGamePlayBigBadWolfEats, createFakeGamePlayCharmedMeetEachOther, createFakeGamePlayCupidCharms, createFakeGamePlayDefenderProtects, createFakeGamePlayFoxSniffs, createFakeGamePlayHunterShoots, createFakeGamePlayLoversMeetEachOther, createFakeGamePlayPiedPiperCharms, createFakeGamePlayScandalmongerMarks, createFakeGamePlayScapegoatBansVoting, createFakeGamePlaySeerLooks, createFakeGamePlaySheriffDelegates, createFakeGamePlaySheriffSettlesVotes, createFakeGamePlayStutteringJudgeRequestsAnotherVote, createFakeGamePlaySurvivorsBuryDeadBodies, createFakeGamePlaySurvivorsElectSheriff, createFakeGamePlaySurvivorsVote, createFakeGamePlayThiefChoosesCard, createFakeGamePlayThreeBrothersMeetEachOther, createFakeGamePlayTwoSistersMeetEachOther, createFakeGamePlayWerewolvesEat, createFakeGamePlayWhiteWerewolfEats, createFakeGamePlayWildChildChoosesModel, createFakeGamePlayWitchUsesPotions } from \"@tests/factories/game/schemas/game-play/game-play.schema.factory\";\nimport { createFakeGame } from \"@tests/factories/game/schemas/game.schema.factory\";\nimport { createFakeCantVoteBySurvivorsPlayerAttribute, createFakeEatenByBigBadWolfPlayerAttribute, createFakeEatenByWerewolvesPlayerAttribute, createFakeInLoveByCupidPlayerAttribute, createFakePowerlessByElderPlayerAttribute, createFakeSheriffBySurvivorsPlayerAttribute } from \"@tests/factories/game/schemas/player/player-attribute/player-attribute.schema.factory\";\nimport { createFakePlayerDeath } from \"@tests/factories/game/schemas/player/player-death/player-death.schema.factory\";\nimport { createFakeAccursedWolfFatherAlivePlayer, createFakeAngelAlivePlayer, createFakeCupidAlivePlayer, createFakeDefenderAlivePlayer, createFakeDevotedServantAlivePlayer, createFakeHunterAlivePlayer, createFakeScapegoatAlivePlayer, createFakeSeerAlivePlayer, createFakeTwoSistersAlivePlayer, createFakeVillagerAlivePlayer, createFakeWerewolfAlivePlayer, createFakeWhiteWerewolfAlivePlayer, createFakeWildChildAlivePlayer, createFakeWitchAlivePlayer } from \"@tests/factories/game/schemas/player/player-with-role.schema.factory\";\nimport { createFakeDeadPlayer, createFakePlayer } from \"@tests/factories/game/schemas/player/player.schema.factory\";\n\ndescribe(\"Game Play Augmenter Service\", () => {\n let services: { gamePlayAugmenter: GamePlayAugmenterService };\n let mocks: {\n gamePlayAugmenterService: {\n canGamePlayBeSkipped: jest.SpyInstance;\n getGamePlaySourceInteractions: jest.SpyInstance;\n getExpectedPlayersToPlay: jest.SpyInstance;\n getSheriffSettlesVotesGamePlaySourceInteractions: jest.SpyInstance;\n getSheriffDelegatesGamePlaySourceInteractions: jest.SpyInstance;\n getSheriffGamePlaySourceInteractions: jest.SpyInstance;\n getSurvivorsVoteGamePlaySourceInteractionEligibleTargets: jest.SpyInstance;\n getSurvivorsVoteGamePlaySourceInteractions: jest.SpyInstance;\n getSurvivorsElectSheriffGamePlaySourceInteractions: jest.SpyInstance;\n getSurvivorsGamePlaySourceInteractions: jest.SpyInstance;\n getWerewolvesEatGamePlaySourceInteractions: jest.SpyInstance;\n getWerewolvesGamePlaySourceInteractions: jest.SpyInstance;\n getWhiteWerewolfEatGamePlaySourceInteractions: jest.SpyInstance;\n getWhiteWerewolfGamePlaySourceInteractions: jest.SpyInstance;\n getWitchUsesPotionsGamePlaySourceInteractions: jest.SpyInstance;\n getWitchGamePlaySourceInteractions: jest.SpyInstance;\n getBigBadWolfEatGamePlaySourceInteractions: jest.SpyInstance;\n getBigBadWolfGamePlaySourceInteractions: jest.SpyInstance;\n getFoxSniffsGamePlaySourceInteractions: jest.SpyInstance;\n getFoxGamePlaySourceInteractions: jest.SpyInstance;\n getDefenderProtectsGamePlaySourceInteractions: jest.SpyInstance;\n getDefenderGamePlaySourceInteractions: jest.SpyInstance;\n getHunterShootsGamePlaySourceInteractions: jest.SpyInstance;\n getHunterGamePlaySourceInteractions: jest.SpyInstance;\n getLoversMeetEachOtherGamePlaySourceInteractions: jest.SpyInstance;\n getLoversGamePlaySourceInteractions: jest.SpyInstance;\n getPiedPiperCharmsGamePlaySourceInteractions: jest.SpyInstance;\n getPiedPiperGamePlaySourceInteractions: jest.SpyInstance;\n getScandalmongerMarksGamePlaySourceInteractions: jest.SpyInstance;\n getScandalmongerGamePlaySourceInteractions: jest.SpyInstance;\n getScapegoatBansVotingGamePlaySourceInteractions: jest.SpyInstance;\n getScapegoatGamePlaySourceInteractions: jest.SpyInstance;\n getSeerLooksGamePlaySourceInteractions: jest.SpyInstance;\n getSeerGamePlaySourceInteractions: jest.SpyInstance;\n getThiefChoosesCardGamePlaySourceInteractions: jest.SpyInstance;\n getThiefGamePlaySourceInteractions: jest.SpyInstance;\n getThreeBrothersMeetEachOtherGamePlaySourceInteractions: jest.SpyInstance;\n getThreeBrothersGamePlaySourceInteractions: jest.SpyInstance;\n getTwoSistersMeetEachOtherGamePlaySourceInteractions: jest.SpyInstance;\n getTwoSistersGamePlaySourceInteractions: jest.SpyInstance;\n getWildChildChoosesModelGamePlaySourceInteractions: jest.SpyInstance;\n getWildChildGamePlaySourceInteractions: jest.SpyInstance;\n getCharmedMeetEachOtherGamePlaySourceInteractions: jest.SpyInstance;\n getCharmedGamePlaySourceInteractions: jest.SpyInstance;\n canSurvivorsSkipGamePlay: jest.SpyInstance;\n getSurvivorsBuryDeadBodiesGamePlaySourceDevotedServantInteraction: jest.SpyInstance;\n getSurvivorsBuryDeadBodiesGamePlaySourceInteractions: jest.SpyInstance;\n getWitchGamePlaySourceGiveLifePotionInteraction: jest.SpyInstance;\n getWitchGamePlaySourceGiveDeathPotionInteraction: jest.SpyInstance;\n getCupidGamePlaySourceInteractions: jest.SpyInstance;\n getAccursedWolfFatherGamePlaySourceInteractions: jest.SpyInstance;\n canBigBadWolfSkipGamePlay: jest.SpyInstance;\n canThiefSkipGamePlay: jest.SpyInstance;\n canCupidSkipGamePlay: jest.SpyInstance;\n };\n gameHelper: {\n getEligibleWerewolvesTargets: jest.SpyInstance;\n getEligibleBigBadWolfTargets: jest.SpyInstance;\n getEligibleWhiteWerewolfTargets: jest.SpyInstance;\n getEligiblePiedPiperTargets: jest.SpyInstance;\n getEligibleCupidTargets: jest.SpyInstance;\n getAllowedToVotePlayers: jest.SpyInstance;\n };\n gameHistoryRecordService: {\n getLastGameHistoryTieInVotesRecord: jest.SpyInstance;\n getLastGameHistoryDefenderProtectsRecord: jest.SpyInstance;\n getGameHistoryWitchUsesSpecificPotionRecords: jest.SpyInstance;\n getPreviousGameHistoryRecord: jest.SpyInstance;\n getGameHistoryAccursedWolfFatherInfectsWithTargetRecords: jest.SpyInstance;\n };\n unexpectedExceptionFactory: {\n createCantFindPlayerWithCurrentRoleUnexpectedException: jest.SpyInstance;\n createCantFindLastNominatedPlayersUnexpectedException: jest.SpyInstance;\n createMalformedCurrentGamePlayUnexpectedException: jest.SpyInstance;\n createNoCurrentGamePlayUnexpectedException: jest.SpyInstance;\n createCantFindLastDeadPlayersUnexpectedException: jest.SpyInstance;\n };\n };\n\n beforeEach(async() => {\n mocks = {\n gamePlayAugmenterService: {\n canGamePlayBeSkipped: jest.fn(),\n getGamePlaySourceInteractions: jest.fn(),\n getExpectedPlayersToPlay: jest.fn(),\n getSheriffSettlesVotesGamePlaySourceInteractions: jest.fn(),\n getSheriffDelegatesGamePlaySourceInteractions: jest.fn(),\n getSheriffGamePlaySourceInteractions: jest.fn(),\n getSurvivorsVoteGamePlaySourceInteractionEligibleTargets: jest.fn(),\n getSurvivorsBuryDeadBodiesGamePlaySourceDevotedServantInteraction: jest.fn(),\n getSurvivorsVoteGamePlaySourceInteractions: jest.fn(),\n getSurvivorsElectSheriffGamePlaySourceInteractions: jest.fn(),\n getSurvivorsGamePlaySourceInteractions: jest.fn(),\n getWerewolvesEatGamePlaySourceInteractions: jest.fn(),\n getWerewolvesGamePlaySourceInteractions: jest.fn(),\n getWhiteWerewolfEatGamePlaySourceInteractions: jest.fn(),\n getWhiteWerewolfGamePlaySourceInteractions: jest.fn(),\n getWitchUsesPotionsGamePlaySourceInteractions: jest.fn(),\n getWitchGamePlaySourceInteractions: jest.fn(),\n getBigBadWolfEatGamePlaySourceInteractions: jest.fn(),\n getBigBadWolfGamePlaySourceInteractions: jest.fn(),\n getFoxSniffsGamePlaySourceInteractions: jest.fn(),\n getFoxGamePlaySourceInteractions: jest.fn(),\n getDefenderProtectsGamePlaySourceInteractions: jest.fn(),\n getDefenderGamePlaySourceInteractions: jest.fn(),\n getHunterShootsGamePlaySourceInteractions: jest.fn(),\n getHunterGamePlaySourceInteractions: jest.fn(),\n getLoversMeetEachOtherGamePlaySourceInteractions: jest.fn(),\n getLoversGamePlaySourceInteractions: jest.fn(),\n getPiedPiperCharmsGamePlaySourceInteractions: jest.fn(),\n getPiedPiperGamePlaySourceInteractions: jest.fn(),\n getScandalmongerMarksGamePlaySourceInteractions: jest.fn(),\n getScandalmongerGamePlaySourceInteractions: jest.fn(),\n getScapegoatBansVotingGamePlaySourceInteractions: jest.fn(),\n getScapegoatGamePlaySourceInteractions: jest.fn(),\n getSeerLooksGamePlaySourceInteractions: jest.fn(),\n getSeerGamePlaySourceInteractions: jest.fn(),\n getThiefChoosesCardGamePlaySourceInteractions: jest.fn(),\n getThiefGamePlaySourceInteractions: jest.fn(),\n getThreeBrothersMeetEachOtherGamePlaySourceInteractions: jest.fn(),\n getThreeBrothersGamePlaySourceInteractions: jest.fn(),\n getTwoSistersMeetEachOtherGamePlaySourceInteractions: jest.fn(),\n getTwoSistersGamePlaySourceInteractions: jest.fn(),\n getWildChildChoosesModelGamePlaySourceInteractions: jest.fn(),\n getWildChildGamePlaySourceInteractions: jest.fn(),\n getCharmedMeetEachOtherGamePlaySourceInteractions: jest.fn(),\n getCharmedGamePlaySourceInteractions: jest.fn(),\n getSurvivorsBuryDeadBodiesGamePlaySourceInteractions: jest.fn(),\n canSurvivorsSkipGamePlay: jest.fn(),\n getWitchGamePlaySourceGiveDeathPotionInteraction: jest.fn(),\n getWitchGamePlaySourceGiveLifePotionInteraction: jest.fn(),\n getAccursedWolfFatherGamePlaySourceInteractions: jest.fn(),\n getCupidGamePlaySourceInteractions: jest.fn(),\n canBigBadWolfSkipGamePlay: jest.fn(),\n canThiefSkipGamePlay: jest.fn(),\n canCupidSkipGamePlay: jest.fn(),\n },\n gameHelper: {\n getEligibleWerewolvesTargets: jest.spyOn(GameHelper, \"getEligibleWerewolvesTargets\"),\n getEligibleBigBadWolfTargets: jest.spyOn(GameHelper, \"getEligibleBigBadWolfTargets\"),\n getEligibleWhiteWerewolfTargets: jest.spyOn(GameHelper, \"getEligibleWhiteWerewolfTargets\"),\n getEligiblePiedPiperTargets: jest.spyOn(GameHelper, \"getEligiblePiedPiperTargets\"),\n getEligibleCupidTargets: jest.spyOn(GameHelper, \"getEligibleCupidTargets\"),\n getAllowedToVotePlayers: jest.spyOn(GameHelper, \"getAllowedToVotePlayers\"),\n },\n gameHistoryRecordService: {\n getLastGameHistoryTieInVotesRecord: jest.fn(),\n getLastGameHistoryDefenderProtectsRecord: jest.fn(),\n getGameHistoryWitchUsesSpecificPotionRecords: jest.fn(),\n getPreviousGameHistoryRecord: jest.fn(),\n getGameHistoryAccursedWolfFatherInfectsWithTargetRecords: jest.fn(),\n },\n unexpectedExceptionFactory: {\n createCantFindPlayerWithCurrentRoleUnexpectedException: jest.spyOn(UnexpectedExceptionFactory, \"createCantFindPlayerWithCurrentRoleUnexpectedException\"),\n createCantFindLastNominatedPlayersUnexpectedException: jest.spyOn(UnexpectedExceptionFactory, \"createCantFindLastNominatedPlayersUnexpectedException\"),\n createMalformedCurrentGamePlayUnexpectedException: jest.spyOn(UnexpectedExceptionFactory, \"createMalformedCurrentGamePlayUnexpectedException\"),\n createNoCurrentGamePlayUnexpectedException: jest.spyOn(UnexpectedExceptionFactory, \"createNoCurrentGamePlayUnexpectedException\"),\n createCantFindLastDeadPlayersUnexpectedException: jest.spyOn(UnexpectedExceptionFactory, \"createCantFindLastDeadPlayersUnexpectedException\"),\n },\n };\n const module: TestingModule = await Test.createTestingModule({\n providers: [\n {\n provide: GameHistoryRecordService,\n useValue: mocks.gameHistoryRecordService,\n },\n GamePlayAugmenterService,\n ],\n }).compile();\n\n services = { gamePlayAugmenter: module.get(GamePlayAugmenterService) };\n });\n\n describe(\"setGamePlayCanBeSkipped\", () => {\n beforeEach(() => {\n mocks.gamePlayAugmenterService.canGamePlayBeSkipped = jest.spyOn(services.gamePlayAugmenter as unknown as { canGamePlayBeSkipped }, \"canGamePlayBeSkipped\");\n });\n\n it(\"should return game play with canBeSkipped when called.\", () => {\n const gamePlay = createFakeGamePlay();\n const game = createFakeGame();\n mocks.gamePlayAugmenterService.canGamePlayBeSkipped.mockReturnValueOnce(true);\n const expectedGamePlay = createFakeGamePlay({\n ...gamePlay,\n canBeSkipped: true,\n });\n\n expect(services.gamePlayAugmenter.setGamePlayCanBeSkipped(gamePlay, game)).toStrictEqual(expectedGamePlay);\n });\n });\n\n describe(\"setGamePlaySourceInteractions\", () => {\n beforeEach(() => {\n mocks.gamePlayAugmenterService.getGamePlaySourceInteractions = jest.spyOn(services.gamePlayAugmenter as unknown as { getGamePlaySourceInteractions }, \"getGamePlaySourceInteractions\");\n });\n\n it(\"should return game play with source interactions when called.\", async() => {\n const gamePlay = createFakeGamePlay();\n const game = createFakeGame();\n const expectedInteractions = [\n createFakeGamePlaySourceInteraction(),\n createFakeGamePlaySourceInteraction(),\n createFakeGamePlaySourceInteraction(),\n ];\n const expectedGamePlay = createFakeGamePlay({\n ...gamePlay,\n source: createFakeGamePlaySource({\n ...gamePlay.source,\n interactions: expectedInteractions,\n }),\n });\n mocks.gamePlayAugmenterService.getGamePlaySourceInteractions.mockResolvedValueOnce(expectedInteractions);\n\n await expect(services.gamePlayAugmenter.setGamePlaySourceInteractions(gamePlay, game)).resolves.toStrictEqual(expectedGamePlay);\n });\n });\n\n describe(\"setGamePlaySourcePlayers\", () => {\n beforeEach(() => {\n mocks.gamePlayAugmenterService.getExpectedPlayersToPlay = jest.spyOn(services.gamePlayAugmenter as unknown as { getExpectedPlayersToPlay }, \"getExpectedPlayersToPlay\");\n });\n\n it(\"should return game play with source players when called.\", () => {\n const gamePlay = createFakeGamePlay();\n const game = createFakeGame();\n const expectedGamePlaySourcePlayers = [createFakePlayer()];\n const expectedGamePlay = createFakeGamePlay({\n ...gamePlay,\n source: createFakeGamePlaySource({\n ...gamePlay.source,\n players: expectedGamePlaySourcePlayers,\n }),\n });\n mocks.gamePlayAugmenterService.getExpectedPlayersToPlay.mockReturnValue(expectedGamePlaySourcePlayers);\n\n expect(services.gamePlayAugmenter.setGamePlaySourcePlayers(gamePlay, game)).toStrictEqual(expectedGamePlay);\n });\n });\n\n describe(\"getSheriffSettlesVotesGamePlaySourceInteractions\", () => {\n beforeEach(() => {\n mocks.gameHistoryRecordService.getLastGameHistoryTieInVotesRecord.mockResolvedValue([]);\n });\n\n it(\"should throw error when there is no last tie in votes record.\", async() => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const mockedError = new UnexpectedException(\"error\", UnexpectedExceptionReasons.CANT_FIND_LAST_NOMINATED_PLAYERS, { gameId: game._id.toString() });\n mocks.gameHistoryRecordService.getLastGameHistoryTieInVotesRecord.mockResolvedValueOnce(null);\n mocks.unexpectedExceptionFactory.createCantFindLastNominatedPlayersUnexpectedException.mockReturnValue(mockedError);\n\n await expect(services.gamePlayAugmenter[\"getSheriffSettlesVotesGamePlaySourceInteractions\"](game)).rejects.toStrictEqual(mockedError);\n expect(mocks.unexpectedExceptionFactory.createCantFindLastNominatedPlayersUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"getSheriffSettlesVotesGamePlaySourceInteractions\", { gameId: game._id });\n });\n\n it(\"should throw error when there are not nominated players in last tie in votes record.\", async() => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const gameHistoryRecordPlayVoting = createFakeGameHistoryRecordPlayVoting({ nominatedPlayers: [] });\n const gameHistoryRecord = createFakeGameHistoryRecord({ play: createFakeGameHistoryRecordPlay({ voting: gameHistoryRecordPlayVoting }) });\n const mockedError = new UnexpectedException(\"error\", UnexpectedExceptionReasons.CANT_FIND_LAST_NOMINATED_PLAYERS, { gameId: game._id.toString() });\n mocks.gameHistoryRecordService.getLastGameHistoryTieInVotesRecord.mockResolvedValueOnce(gameHistoryRecord);\n mocks.unexpectedExceptionFactory.createCantFindLastNominatedPlayersUnexpectedException.mockReturnValue(mockedError);\n\n await expect(services.gamePlayAugmenter[\"getSheriffSettlesVotesGamePlaySourceInteractions\"](game)).rejects.toStrictEqual(mockedError);\n expect(mocks.unexpectedExceptionFactory.createCantFindLastNominatedPlayersUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"getSheriffSettlesVotesGamePlaySourceInteractions\", { gameId: game._id });\n });\n\n it(\"should return all nominated players with 1 to 1 boundaries when there are nominated players in last tie in votes record.\", async() => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const gameHistoryRecord = createFakeGameHistoryRecord({\n play: createFakeGameHistoryRecordPlay({\n voting: createFakeGameHistoryRecordPlayVoting({\n nominatedPlayers: [\n players[0],\n players[1],\n ],\n }),\n }),\n });\n mocks.gameHistoryRecordService.getLastGameHistoryTieInVotesRecord.mockResolvedValueOnce(gameHistoryRecord);\n const expectedInteraction = createFakeGamePlaySourceInteraction({\n source: \"sheriff\",\n type: \"sentence-to-death\",\n eligibleTargets: [players[0], players[1]],\n boundaries: {\n min: 1,\n max: 1,\n },\n });\n\n await expect(services.gamePlayAugmenter[\"getSheriffSettlesVotesGamePlaySourceInteractions\"](game)).resolves.toStrictEqual([expectedInteraction]);\n });\n });\n\n describe(\"getSheriffDelegatesGamePlaySourceInteractions\", () => {\n it(\"should return all alive and not sheriff players as eligible targets with 1 to 1 targets boundaries when called.\", () => {\n const players = [\n createFakeAngelAlivePlayer(),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeSheriffBySurvivorsPlayerAttribute()] }),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWitchAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"sheriff\",\n type: \"transfer-sheriff-role\",\n eligibleTargets: [players[0], players[3]],\n boundaries: {\n min: 1,\n max: 1,\n },\n });\n\n expect(services.gamePlayAugmenter[\"getSheriffDelegatesGamePlaySourceInteractions\"](game)).toStrictEqual([expectedGamePlaySourceInteraction]);\n });\n });\n\n describe(\"getSheriffGamePlaySourceInteractions\", () => {\n beforeEach(() => {\n mocks.gamePlayAugmenterService.getSheriffSettlesVotesGamePlaySourceInteractions = jest.spyOn(services.gamePlayAugmenter as unknown as { getSheriffSettlesVotesGamePlaySourceInteractions }, \"getSheriffSettlesVotesGamePlaySourceInteractions\").mockImplementation();\n mocks.gamePlayAugmenterService.getSheriffDelegatesGamePlaySourceInteractions = jest.spyOn(services.gamePlayAugmenter as unknown as { getSheriffDelegatesGamePlaySourceInteractions }, \"getSheriffDelegatesGamePlaySourceInteractions\").mockImplementation();\n });\n\n it(\"should call get sheriff delegates game play source interactions when game play action is delegate.\", async() => {\n const gamePlay = createFakeGamePlaySheriffDelegates();\n const game = createFakeGame();\n await services.gamePlayAugmenter[\"getSheriffGamePlaySourceInteractions\"](game, gamePlay);\n\n expect(mocks.gamePlayAugmenterService.getSheriffDelegatesGamePlaySourceInteractions).toHaveBeenCalledExactlyOnceWith(game);\n expect(mocks.gamePlayAugmenterService.getSheriffSettlesVotesGamePlaySourceInteractions).not.toHaveBeenCalled();\n });\n\n it(\"should call get sheriff settles votes game play source interactions when game play action is settles votes.\", async() => {\n const gamePlay = createFakeGamePlaySheriffSettlesVotes();\n const game = createFakeGame();\n await services.gamePlayAugmenter[\"getSheriffGamePlaySourceInteractions\"](game, gamePlay);\n\n expect(mocks.gamePlayAugmenterService.getSheriffSettlesVotesGamePlaySourceInteractions).toHaveBeenCalledExactlyOnceWith(game);\n expect(mocks.gamePlayAugmenterService.getSheriffDelegatesGamePlaySourceInteractions).not.toHaveBeenCalled();\n });\n\n it(\"should throw error when game play action is not delegate nor settles votes.\", async() => {\n const gamePlay = createFakeGamePlayScandalmongerMarks();\n const game = createFakeGame();\n const mockedError = new UnexpectedException(\"error\", UnexpectedExceptionReasons.MALFORMED_CURRENT_GAME_PLAY, { gamePlayAction: gamePlay.action });\n mocks.unexpectedExceptionFactory.createMalformedCurrentGamePlayUnexpectedException.mockReturnValue(mockedError);\n\n await expect(services.gamePlayAugmenter[\"getSheriffGamePlaySourceInteractions\"](game, gamePlay)).rejects.toThrow(mockedError);\n expect(mocks.unexpectedExceptionFactory.createMalformedCurrentGamePlayUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"getSheriffGamePlaySourceInteractions\", gamePlay, game._id);\n });\n });\n\n describe(\"getSurvivorsVoteGamePlaySourceInteractionEligibleTargets\", () => {\n it(\"should return all alive players when votes are not cause of previous tie in votes.\", async() => {\n const players = [\n createFakeAngelAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWitchAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const gamePlay = createFakeGamePlaySurvivorsVote({ causes: [\"angel-presence\"] });\n const expectedPlayers = [\n createFakePlayer(players[0]),\n createFakePlayer(players[1]),\n createFakePlayer(players[3]),\n ];\n\n await expect(services.gamePlayAugmenter[\"getSurvivorsVoteGamePlaySourceInteractionEligibleTargets\"](game, gamePlay)).resolves.toStrictEqual(expectedPlayers);\n });\n\n it(\"should return nominated players when votes are cause of previous tie in votes.\", async() => {\n const players = [\n createFakeAngelAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWitchAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const gamePlay = createFakeGamePlaySurvivorsVote({ causes: [\"previous-votes-were-in-ties\"] });\n const gameHistoryRecordPlayVoting = createFakeGameHistoryRecordPlayVoting({ nominatedPlayers: [players[0], players[1]] });\n const gameHistoryRecord = createFakeGameHistoryRecord({ play: createFakeGameHistoryRecordPlay({ voting: gameHistoryRecordPlayVoting }) });\n mocks.gameHistoryRecordService.getLastGameHistoryTieInVotesRecord.mockResolvedValueOnce(gameHistoryRecord);\n const expectedPlayers = [\n createFakePlayer(players[0]),\n createFakePlayer(players[1]),\n ];\n\n await expect(services.gamePlayAugmenter[\"getSurvivorsVoteGamePlaySourceInteractionEligibleTargets\"](game, gamePlay)).resolves.toStrictEqual(expectedPlayers);\n });\n\n it(\"should throw error when there is no last tie in votes record.\", async() => {\n const players = [\n createFakeAngelAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWitchAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const gamePlay = createFakeGamePlaySurvivorsVote({ causes: [\"previous-votes-were-in-ties\"] });\n const mockedError = new UnexpectedException(\"error\", UnexpectedExceptionReasons.CANT_FIND_LAST_NOMINATED_PLAYERS, { gameId: game._id.toString() });\n mocks.gameHistoryRecordService.getLastGameHistoryTieInVotesRecord.mockResolvedValueOnce(null);\n mocks.unexpectedExceptionFactory.createCantFindLastNominatedPlayersUnexpectedException.mockReturnValue(mockedError);\n\n await expect(async() => services.gamePlayAugmenter[\"getSurvivorsVoteGamePlaySourceInteractionEligibleTargets\"](game, gamePlay)).rejects.toStrictEqual(mockedError);\n expect(mocks.unexpectedExceptionFactory.createCantFindLastNominatedPlayersUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"getSurvivorsVoteGamePlaySourceInteractionEligibleTargets\", { gameId: game._id });\n });\n\n it(\"should throw error when there is no nominated players in last tie in votes record.\", async() => {\n const players = [\n createFakeAngelAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWitchAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const gamePlay = createFakeGamePlaySurvivorsVote({ causes: [\"previous-votes-were-in-ties\"] });\n const gameRecordPlayVoting = createFakeGameHistoryRecordPlayVoting({ nominatedPlayers: [] });\n const mockedError = new UnexpectedException(\"error\", UnexpectedExceptionReasons.CANT_FIND_LAST_NOMINATED_PLAYERS, { gameId: game._id.toString() });\n mocks.gameHistoryRecordService.getLastGameHistoryTieInVotesRecord.mockResolvedValueOnce(createFakeGameHistoryRecord({ play: createFakeGameHistoryRecordPlay({ voting: gameRecordPlayVoting }) }));\n mocks.unexpectedExceptionFactory.createCantFindLastNominatedPlayersUnexpectedException.mockReturnValue(mockedError);\n\n await expect(async() => services.gamePlayAugmenter[\"getSurvivorsVoteGamePlaySourceInteractionEligibleTargets\"](game, gamePlay)).rejects.toStrictEqual(mockedError);\n expect(mocks.unexpectedExceptionFactory.createCantFindLastNominatedPlayersUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"getSurvivorsVoteGamePlaySourceInteractionEligibleTargets\", { gameId: game._id });\n });\n });\n\n describe(\"getSurvivorsVoteGamePlaySourceInteractions\", () => {\n beforeEach(() => {\n mocks.gameHelper.getAllowedToVotePlayers.mockReturnValue([]);\n mocks.gamePlayAugmenterService.canSurvivorsSkipGamePlay = jest.spyOn(services.gamePlayAugmenter as unknown as { canSurvivorsSkipGamePlay }, \"canSurvivorsSkipGamePlay\").mockImplementation();\n mocks.gamePlayAugmenterService.getSurvivorsVoteGamePlaySourceInteractionEligibleTargets = jest.spyOn(services.gamePlayAugmenter as unknown as { getSurvivorsVoteGamePlaySourceInteractionEligibleTargets }, \"getSurvivorsVoteGamePlaySourceInteractionEligibleTargets\").mockImplementation();\n });\n\n it(\"should return no players as eligible targets with 1 to alive players length when votes can't be skipped.\", async() => {\n const players = [\n createFakeAngelAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWitchAlivePlayer(),\n ];\n const gamePlay = createFakeGamePlaySurvivorsVote({ canBeSkipped: false });\n const game = createFakeGame({ players });\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"survivors\",\n type: \"vote\",\n eligibleTargets: [],\n boundaries: {\n min: 1,\n max: 3,\n },\n });\n mocks.gameHelper.getAllowedToVotePlayers.mockReturnValueOnce([players[0], players[1], players[3]]);\n mocks.gamePlayAugmenterService.canSurvivorsSkipGamePlay.mockReturnValueOnce(false);\n mocks.gamePlayAugmenterService.getSurvivorsVoteGamePlaySourceInteractionEligibleTargets.mockResolvedValueOnce([]);\n\n await expect(services.gamePlayAugmenter[\"getSurvivorsVoteGamePlaySourceInteractions\"](game, gamePlay)).resolves.toStrictEqual([expectedGamePlaySourceInteraction]);\n });\n\n it(\"should return alive players as eligible targets with boundaries from 0 to alive players length when votes can be skipped.\", async() => {\n const players = [\n createFakeAngelAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWitchAlivePlayer(),\n ];\n const gamePlay = createFakeGamePlaySurvivorsVote({ canBeSkipped: true });\n const game = createFakeGame({ players });\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"survivors\",\n type: \"vote\",\n eligibleTargets: [],\n boundaries: {\n min: 0,\n max: 3,\n },\n });\n mocks.gameHelper.getAllowedToVotePlayers.mockReturnValueOnce([players[0], players[1], players[3]]);\n mocks.gamePlayAugmenterService.canSurvivorsSkipGamePlay.mockReturnValueOnce(true);\n mocks.gamePlayAugmenterService.getSurvivorsVoteGamePlaySourceInteractionEligibleTargets.mockResolvedValueOnce([]);\n\n await expect(services.gamePlayAugmenter[\"getSurvivorsVoteGamePlaySourceInteractions\"](game, gamePlay)).resolves.toStrictEqual([expectedGamePlaySourceInteraction]);\n });\n });\n\n describe(\"getSurvivorsElectSheriffGamePlaySourceInteractions\", () => {\n it(\"should return alive players as eligible targets with boundaries from 1 to 1 when called.\", async() => {\n const players = [\n createFakeAngelAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWitchAlivePlayer(),\n ];\n const gamePlay = createFakeGamePlaySurvivorsElectSheriff();\n const game = createFakeGame({ players });\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"survivors\",\n type: \"choose-as-sheriff\",\n eligibleTargets: [players[0], players[1], players[3]],\n boundaries: {\n min: 1,\n max: 3,\n },\n });\n\n await expect(services.gamePlayAugmenter[\"getSurvivorsElectSheriffGamePlaySourceInteractions\"](game, gamePlay)).resolves.toStrictEqual([expectedGamePlaySourceInteraction]);\n });\n });\n\n describe(\"getSurvivorsBuryDeadBodiesGamePlaySourceDevotedServantInteraction\", () => {\n it(\"should return undefined when there is no devoted servant in the game.\", () => {\n const players = [\n createFakeAngelAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWitchAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const deadPlayers = [\n createFakeDeadPlayer({ ...players[0], isAlive: false, death: createFakePlayerDeath() }),\n createFakeDeadPlayer({ ...players[1], isAlive: false, death: createFakePlayerDeath() }),\n ];\n\n expect(services.gamePlayAugmenter[\"getSurvivorsBuryDeadBodiesGamePlaySourceDevotedServantInteraction\"](game, deadPlayers)).toBeUndefined();\n });\n\n it(\"should return undefined when devoted servant is dead.\", () => {\n const players = [\n createFakeAngelAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeDevotedServantAlivePlayer({ isAlive: false }),\n ];\n const game = createFakeGame({ players });\n const deadPlayers = [\n createFakeDeadPlayer({ ...players[0], isAlive: false, death: createFakePlayerDeath() }),\n createFakeDeadPlayer({ ...players[1], isAlive: false, death: createFakePlayerDeath() }),\n ];\n\n expect(services.gamePlayAugmenter[\"getSurvivorsBuryDeadBodiesGamePlaySourceDevotedServantInteraction\"](game, deadPlayers)).toBeUndefined();\n });\n\n it(\"should return undefined when devoted servant is powerless.\", () => {\n const players = [\n createFakeAngelAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeDevotedServantAlivePlayer({ attributes: [createFakePowerlessByElderPlayerAttribute()] }),\n ];\n const game = createFakeGame({ players });\n const deadPlayers = [\n createFakeDeadPlayer({ ...players[0], isAlive: false, death: createFakePlayerDeath() }),\n createFakeDeadPlayer({ ...players[1], isAlive: false, death: createFakePlayerDeath() }),\n ];\n\n expect(services.gamePlayAugmenter[\"getSurvivorsBuryDeadBodiesGamePlaySourceDevotedServantInteraction\"](game, deadPlayers)).toBeUndefined();\n });\n\n it(\"should return undefined when devoted servant is in love.\", () => {\n const players = [\n createFakeAngelAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeDevotedServantAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n ];\n const game = createFakeGame({ players });\n const deadPlayers = [\n createFakeDeadPlayer({ ...players[0], isAlive: false, death: createFakePlayerDeath() }),\n createFakeDeadPlayer({ ...players[1], isAlive: false, death: createFakePlayerDeath() }),\n ];\n\n expect(services.gamePlayAugmenter[\"getSurvivorsBuryDeadBodiesGamePlaySourceDevotedServantInteraction\"](game, deadPlayers)).toBeUndefined();\n });\n\n it(\"should return interaction for devoted servant with dead players as eligible targets with boundaries from 0 to 1 when called.\", () => {\n const players = [\n createFakeAngelAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeDevotedServantAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const deadPlayers = [\n createFakeDeadPlayer({ ...players[0], isAlive: false, death: createFakePlayerDeath() }),\n createFakeDeadPlayer({ ...players[1], isAlive: false, death: createFakePlayerDeath() }),\n ];\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"devoted-servant\",\n type: \"steal-role\",\n eligibleTargets: [deadPlayers[0], deadPlayers[1]],\n boundaries: {\n min: 0,\n max: 1,\n },\n });\n\n expect(services.gamePlayAugmenter[\"getSurvivorsBuryDeadBodiesGamePlaySourceDevotedServantInteraction\"](game, deadPlayers)).toStrictEqual(expectedGamePlaySourceInteraction);\n });\n });\n\n describe(\"getSurvivorsBuryDeadBodiesGamePlaySourceInteractions\", () => {\n beforeEach(() => {\n mocks.gamePlayAugmenterService.getSurvivorsBuryDeadBodiesGamePlaySourceDevotedServantInteraction = jest.spyOn(services.gamePlayAugmenter as unknown as { getSurvivorsBuryDeadBodiesGamePlaySourceDevotedServantInteraction }, \"getSurvivorsBuryDeadBodiesGamePlaySourceDevotedServantInteraction\").mockImplementation();\n });\n\n it(\"should throw error when there is no previous game history record.\", async() => {\n const players = [\n createFakeAngelAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeDevotedServantAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const mockedError = new UnexpectedException(\"error\", UnexpectedExceptionReasons.CANT_FIND_LAST_DEAD_PLAYERS, { gameId: game._id.toString() });\n mocks.gameHistoryRecordService.getPreviousGameHistoryRecord.mockResolvedValueOnce(null);\n mocks.unexpectedExceptionFactory.createCantFindLastDeadPlayersUnexpectedException.mockReturnValue(mockedError);\n\n await expect(services.gamePlayAugmenter[\"getSurvivorsBuryDeadBodiesGamePlaySourceInteractions\"](game)).rejects.toStrictEqual(mockedError);\n expect(mocks.unexpectedExceptionFactory.createCantFindLastDeadPlayersUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"getSurvivorsBuryDeadBodiesGamePlaySourceInteractions\", { gameId: game._id });\n });\n\n it(\"should throw error when dead players are undefined in previous game history record.\", async() => {\n const players = [\n createFakeAngelAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeDevotedServantAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const gameHistoryRecord = createFakeGameHistoryRecord({ deadPlayers: undefined });\n const mockedError = new UnexpectedException(\"error\", UnexpectedExceptionReasons.CANT_FIND_LAST_DEAD_PLAYERS, { gameId: game._id.toString() });\n mocks.gameHistoryRecordService.getPreviousGameHistoryRecord.mockResolvedValueOnce(gameHistoryRecord);\n mocks.unexpectedExceptionFactory.createCantFindLastDeadPlayersUnexpectedException.mockReturnValue(mockedError);\n\n await expect(services.gamePlayAugmenter[\"getSurvivorsBuryDeadBodiesGamePlaySourceInteractions\"](game)).rejects.toStrictEqual(mockedError);\n expect(mocks.unexpectedExceptionFactory.createCantFindLastDeadPlayersUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"getSurvivorsBuryDeadBodiesGamePlaySourceInteractions\", { gameId: game._id });\n });\n\n it(\"should throw error when dead players are empty in previous game history record.\", async() => {\n const players = [\n createFakeAngelAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeDevotedServantAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const gameHistoryRecord = createFakeGameHistoryRecord({ deadPlayers: [] });\n const mockedError = new UnexpectedException(\"error\", UnexpectedExceptionReasons.CANT_FIND_LAST_DEAD_PLAYERS, { gameId: game._id.toString() });\n mocks.gameHistoryRecordService.getPreviousGameHistoryRecord.mockResolvedValueOnce(gameHistoryRecord);\n mocks.unexpectedExceptionFactory.createCantFindLastDeadPlayersUnexpectedException.mockReturnValue(mockedError);\n\n await expect(services.gamePlayAugmenter[\"getSurvivorsBuryDeadBodiesGamePlaySourceInteractions\"](game)).rejects.toStrictEqual(mockedError);\n expect(mocks.unexpectedExceptionFactory.createCantFindLastDeadPlayersUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"getSurvivorsBuryDeadBodiesGamePlaySourceInteractions\", { gameId: game._id });\n });\n\n it(\"should return inconsequential survivors bury dead bodies game play source interaction when called.\", async() => {\n const players = [\n createFakeAngelAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeDevotedServantAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const deadPlayers = [\n createFakeDeadPlayer({ ...players[0], isAlive: false, death: createFakePlayerDeath() }),\n createFakeDeadPlayer({ ...players[1], isAlive: false, death: createFakePlayerDeath() }),\n ];\n const gameHistoryRecord = createFakeGameHistoryRecord({ deadPlayers });\n mocks.gameHistoryRecordService.getPreviousGameHistoryRecord.mockResolvedValueOnce(gameHistoryRecord);\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"survivors\",\n type: \"bury\",\n eligibleTargets: deadPlayers,\n boundaries: {\n min: 0,\n max: 2,\n },\n isInconsequential: true,\n });\n\n await expect(services.gamePlayAugmenter[\"getSurvivorsBuryDeadBodiesGamePlaySourceInteractions\"](game)).resolves.toStrictEqual([expectedGamePlaySourceInteraction]);\n });\n\n it(\"should return devoted servant steals role game play source interaction plus bury interactions when there is devoted servant interaction.\", async() => {\n const players = [\n createFakeAngelAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeDevotedServantAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const deadPlayers = [\n createFakeDeadPlayer({ ...players[0], isAlive: false, death: createFakePlayerDeath() }),\n createFakeDeadPlayer({ ...players[1], isAlive: false, death: createFakePlayerDeath() }),\n ];\n const gameHistoryRecord = createFakeGameHistoryRecord({ deadPlayers });\n mocks.gameHistoryRecordService.getPreviousGameHistoryRecord.mockResolvedValueOnce(gameHistoryRecord);\n const expectedGamePlaySourceInteractionStealRole = createFakeGamePlaySourceInteraction({\n source: \"devoted-servant\",\n type: \"steal-role\",\n eligibleTargets: deadPlayers,\n boundaries: {\n min: 0,\n max: 1,\n },\n });\n mocks.gamePlayAugmenterService.getSurvivorsBuryDeadBodiesGamePlaySourceDevotedServantInteraction.mockReturnValueOnce(expectedGamePlaySourceInteractionStealRole);\n const expectedGamePlaySourceInteractionBury = createFakeGamePlaySourceInteraction({\n source: \"survivors\",\n type: \"bury\",\n eligibleTargets: deadPlayers,\n boundaries: {\n min: 0,\n max: 2,\n },\n isInconsequential: true,\n });\n const expectedInteractions = [expectedGamePlaySourceInteractionBury, expectedGamePlaySourceInteractionStealRole];\n\n await expect(services.gamePlayAugmenter[\"getSurvivorsBuryDeadBodiesGamePlaySourceInteractions\"](game)).resolves.toStrictEqual(expectedInteractions);\n });\n });\n\n describe(\"getSurvivorsGamePlaySourceInteractions\", () => {\n beforeEach(() => {\n mocks.gamePlayAugmenterService.getSurvivorsElectSheriffGamePlaySourceInteractions = jest.spyOn(services.gamePlayAugmenter as unknown as { getSurvivorsElectSheriffGamePlaySourceInteractions }, \"getSurvivorsElectSheriffGamePlaySourceInteractions\").mockImplementation();\n mocks.gamePlayAugmenterService.getSurvivorsVoteGamePlaySourceInteractions = jest.spyOn(services.gamePlayAugmenter as unknown as { getSurvivorsVoteGamePlaySourceInteractions }, \"getSurvivorsVoteGamePlaySourceInteractions\").mockImplementation();\n mocks.gamePlayAugmenterService.getSurvivorsBuryDeadBodiesGamePlaySourceInteractions = jest.spyOn(services.gamePlayAugmenter as unknown as { getSurvivorsBuryDeadBodiesGamePlaySourceInteractions }, \"getSurvivorsBuryDeadBodiesGamePlaySourceInteractions\").mockImplementation();\n });\n\n it(\"should call get survivors bury dead bodies game play eligible targets when game play action is bury dead bodies.\", async() => {\n const gamePlay = createFakeGamePlaySurvivorsBuryDeadBodies();\n const game = createFakeGame();\n await services.gamePlayAugmenter[\"getSurvivorsGamePlaySourceInteractions\"](game, gamePlay);\n\n expect(mocks.gamePlayAugmenterService.getSurvivorsBuryDeadBodiesGamePlaySourceInteractions).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call get survivors elect sheriff game play eligible targets when game play action is elect sheriff.\", async() => {\n const gamePlay = createFakeGamePlaySurvivorsElectSheriff();\n const game = createFakeGame();\n await services.gamePlayAugmenter[\"getSurvivorsGamePlaySourceInteractions\"](game, gamePlay);\n\n expect(mocks.gamePlayAugmenterService.getSurvivorsElectSheriffGamePlaySourceInteractions).toHaveBeenCalledExactlyOnceWith(game, gamePlay);\n expect(mocks.gamePlayAugmenterService.getSurvivorsVoteGamePlaySourceInteractions).not.toHaveBeenCalled();\n });\n\n it(\"should call get survivors vote game play eligible targets when game play action is vote.\", async() => {\n const gamePlay = createFakeGamePlaySurvivorsVote();\n const game = createFakeGame();\n await services.gamePlayAugmenter[\"getSurvivorsGamePlaySourceInteractions\"](game, gamePlay);\n\n expect(mocks.gamePlayAugmenterService.getSurvivorsVoteGamePlaySourceInteractions).toHaveBeenCalledExactlyOnceWith(game, gamePlay);\n expect(mocks.gamePlayAugmenterService.getSurvivorsElectSheriffGamePlaySourceInteractions).not.toHaveBeenCalled();\n });\n\n it(\"should throw error when game play action is not elect sheriff nor vote.\", async() => {\n const gamePlay = createFakeGamePlayWildChildChoosesModel();\n const game = createFakeGame();\n const mockedError = new UnexpectedException(\"error\", UnexpectedExceptionReasons.MALFORMED_CURRENT_GAME_PLAY, { gamePlayAction: gamePlay.action });\n mocks.unexpectedExceptionFactory.createMalformedCurrentGamePlayUnexpectedException.mockReturnValue(mockedError);\n\n await expect(services.gamePlayAugmenter[\"getSurvivorsGamePlaySourceInteractions\"](game, gamePlay)).rejects.toStrictEqual(mockedError);\n expect(mocks.unexpectedExceptionFactory.createMalformedCurrentGamePlayUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"getSurvivorsGamePlaySourceInteractions\", gamePlay, game._id);\n });\n });\n\n describe(\"getWerewolvesGamePlaySourceInteractions\", () => {\n it(\"should return alive villagers sided players as eligible targets with boundaries from 1 to 1 when called.\", () => {\n const players = [\n createFakeAngelAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWitchAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"werewolves\",\n type: \"eat\",\n eligibleTargets: [players[0], players[3]],\n boundaries: {\n min: 1,\n max: 1,\n },\n });\n\n expect(services.gamePlayAugmenter[\"getWerewolvesGamePlaySourceInteractions\"](game)).toStrictEqual([expectedGamePlaySourceInteraction]);\n });\n });\n\n describe(\"getBigBadWolfGamePlaySourceInteractions\", () => {\n it(\"should return alive villagers as eligible targets with boundaries from 1 to 1 when there are still left to eat targets.\", () => {\n const players = [\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n mocks.gameHelper.getEligibleBigBadWolfTargets.mockReturnValueOnce([\n players[0],\n players[1],\n ]);\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"big-bad-wolf\",\n type: \"eat\",\n eligibleTargets: [players[0], players[1]],\n boundaries: {\n min: 1,\n max: 1,\n },\n });\n\n expect(services.gamePlayAugmenter[\"getBigBadWolfGamePlaySourceInteractions\"](game)).toStrictEqual([expectedGamePlaySourceInteraction]);\n });\n\n it(\"should return no eligible targets with target boundaries from 0 to 0 when there are no left to eat targets.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({\n players,\n options: DEFAULT_GAME_OPTIONS,\n });\n mocks.gameHelper.getEligibleBigBadWolfTargets.mockReturnValueOnce([]);\n\n expect(services.gamePlayAugmenter[\"getBigBadWolfGamePlaySourceInteractions\"](game)).toStrictEqual([]);\n });\n });\n\n describe(\"getCupidGamePlaySourceInteractions\", () => {\n it(\"should return all alive eligible targets with 2 to 2 targets boundaries when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeCupidAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ cupid: createFakeCupidGameOptions({ mustWinWithLovers: false }) }) });\n const game = createFakeGame({ players, options });\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"cupid\",\n type: \"charm\",\n eligibleTargets: [players[0], players[3]],\n boundaries: {\n min: 2,\n max: 2,\n },\n });\n\n expect(services.gamePlayAugmenter[\"getCupidGamePlaySourceInteractions\"](game)).toStrictEqual([expectedGamePlaySourceInteraction]);\n });\n\n it(\"should return all alive and not cupid eligible targets with 2 to 2 targets boundaries when game options says that cupid must win with lovers.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeCupidAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ cupid: createFakeCupidGameOptions({ mustWinWithLovers: true }) }) });\n const game = createFakeGame({ players, options });\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"cupid\",\n type: \"charm\",\n eligibleTargets: [players[0], players[1]],\n boundaries: {\n min: 2,\n max: 2,\n },\n });\n\n expect(services.gamePlayAugmenter[\"getCupidGamePlaySourceInteractions\"](game)).toStrictEqual([expectedGamePlaySourceInteraction]);\n });\n\n it(\"should return empty array when there is not enough targets for cupid.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeCupidAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ cupid: createFakeCupidGameOptions({ mustWinWithLovers: true }) }) });\n const game = createFakeGame({ players, options });\n\n expect(services.gamePlayAugmenter[\"getCupidGamePlaySourceInteractions\"](game)).toStrictEqual([]);\n });\n });\n\n describe(\"getFoxGamePlaySourceInteractions\", () => {\n it(\"should return all alive eligible targets with 0 to 1 boundaries when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"fox\",\n type: \"sniff\",\n eligibleTargets: [players[0], players[3]],\n boundaries: {\n min: 0,\n max: 1,\n },\n });\n\n expect(services.gamePlayAugmenter[\"getFoxGamePlaySourceInteractions\"](game)).toStrictEqual([expectedGamePlaySourceInteraction]);\n });\n });\n\n describe(\"getDefenderGamePlaySourceInteractions\", () => {\n it(\"should throw error when there is no defender in the game.\", async() => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const mockedError = new UnexpectedException(\"error\", UnexpectedExceptionReasons.CANT_FIND_PLAYER_WITH_CURRENT_ROLE_IN_GAME, { gameId: game._id.toString(), roleName: \"defender\" });\n mocks.unexpectedExceptionFactory.createCantFindPlayerWithCurrentRoleUnexpectedException.mockReturnValue(mockedError);\n\n await expect(services.gamePlayAugmenter[\"getDefenderGamePlaySourceInteractions\"](game)).rejects.toStrictEqual(mockedError);\n expect(mocks.unexpectedExceptionFactory.createCantFindPlayerWithCurrentRoleUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"getDefenderGamePlaySourceInteractions\", { gameId: game._id, roleName: \"defender\" });\n });\n\n it(\"should return all alive players as eligible targets with boundaries from 1 to 1 when there is no last protected players.\", async() => {\n const players = [\n createFakeDefenderAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n mocks.gameHistoryRecordService.getLastGameHistoryDefenderProtectsRecord.mockResolvedValueOnce(null);\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"defender\",\n type: \"protect\",\n eligibleTargets: [players[0], players[1], players[2], players[3]],\n boundaries: { min: 1, max: 1 },\n });\n\n await expect(services.gamePlayAugmenter[\"getDefenderGamePlaySourceInteractions\"](game)).resolves.toStrictEqual([expectedGamePlaySourceInteraction]);\n });\n\n it(\"should return all alive players as eligible targets with boundaries from 1 to 1 when there is last protected players but defender can protect twice in a row.\", async() => {\n const players = [\n createFakeDefenderAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ defender: createFakeDefenderGameOptions({ canProtectTwice: true }) }) });\n const game = createFakeGame({ players, options });\n const gameHistoryRecord = createFakeGameHistoryRecord({ play: createFakeGameHistoryRecordPlay({ targets: [{ player: players[2] }] }) });\n mocks.gameHistoryRecordService.getLastGameHistoryDefenderProtectsRecord.mockResolvedValueOnce(gameHistoryRecord);\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"defender\",\n type: \"protect\",\n eligibleTargets: [players[0], players[2], players[3]],\n boundaries: { min: 1, max: 1 },\n });\n\n await expect(services.gamePlayAugmenter[\"getDefenderGamePlaySourceInteractions\"](game)).resolves.toStrictEqual([expectedGamePlaySourceInteraction]);\n });\n\n it(\"should return all alive players but last protected player as eligible targets with boundaries from 1 to 1 when there is last protected players but defender can't protect twice in a row.\", async() => {\n const players = [\n createFakeDefenderAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ defender: createFakeDefenderGameOptions({ canProtectTwice: false }) }) });\n const game = createFakeGame({ players, options });\n const gameHistoryRecord = createFakeGameHistoryRecord({ play: createFakeGameHistoryRecordPlay({ targets: [{ player: players[2] }] }) });\n mocks.gameHistoryRecordService.getLastGameHistoryDefenderProtectsRecord.mockResolvedValueOnce(gameHistoryRecord);\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"defender\",\n type: \"protect\",\n eligibleTargets: [players[0], players[3]],\n boundaries: { min: 1, max: 1 },\n });\n\n await expect(services.gamePlayAugmenter[\"getDefenderGamePlaySourceInteractions\"](game)).resolves.toStrictEqual([expectedGamePlaySourceInteraction]);\n });\n });\n\n describe(\"getHunterGamePlaySourceInteractions\", () => {\n it(\"should return all alive players as eligible targets with boundaries from 1 to 1 when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"hunter\",\n type: \"shoot\",\n eligibleTargets: [players[0], players[1], players[3]],\n boundaries: { min: 1, max: 1 },\n });\n\n expect(services.gamePlayAugmenter[\"getHunterGamePlaySourceInteractions\"](game)).toStrictEqual([expectedGamePlaySourceInteraction]);\n });\n });\n\n describe(\"getPiedPiperGamePlaySourceInteractions\", () => {\n it(\"should return 2 eligible targets with 2 to 2 targets boundaries when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ piedPiper: createFakePiedPiperGameOptions({ charmedPeopleCountPerNight: 4 }) }) });\n const game = createFakeGame({\n players,\n options,\n });\n mocks.gameHelper.getEligiblePiedPiperTargets.mockReturnValueOnce([\n players[0],\n players[1],\n ]);\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"pied-piper\",\n type: \"charm\",\n eligibleTargets: [players[0], players[1]],\n boundaries: {\n min: 2,\n max: 2,\n },\n });\n\n expect(services.gamePlayAugmenter[\"getPiedPiperGamePlaySourceInteractions\"](game)).toStrictEqual([expectedGamePlaySourceInteraction]);\n });\n\n it(\"should return 2 eligible targets with 1 to 1 targets boundaries when game options charm count is lower than left to charm players.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ piedPiper: createFakePiedPiperGameOptions({ charmedPeopleCountPerNight: 1 }) }) });\n const game = createFakeGame({\n players,\n options,\n });\n mocks.gameHelper.getEligiblePiedPiperTargets.mockReturnValueOnce([\n players[0],\n players[1],\n ]);\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"pied-piper\",\n type: \"charm\",\n eligibleTargets: [players[0], players[1]],\n boundaries: {\n min: 1,\n max: 1,\n },\n });\n\n expect(services.gamePlayAugmenter[\"getPiedPiperGamePlaySourceInteractions\"](game)).toStrictEqual([expectedGamePlaySourceInteraction]);\n });\n });\n\n describe(\"getScandalmongerGamePlaySourceInteractions\", () => {\n it(\"should return all alive eligible targets with 0 to 1 targets boundaries when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"scandalmonger\",\n type: \"mark\",\n eligibleTargets: [players[0], players[3]],\n boundaries: {\n min: 0,\n max: 1,\n },\n });\n\n expect(services.gamePlayAugmenter[\"getScandalmongerGamePlaySourceInteractions\"](game)).toStrictEqual([expectedGamePlaySourceInteraction]);\n });\n });\n\n describe(\"getScapegoatGamePlaySourceInteractions\", () => {\n it(\"should return all alive eligible targets with 0 to alive length target boundaries when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"scapegoat\",\n type: \"ban-voting\",\n eligibleTargets: [players[0], players[3]],\n boundaries: {\n min: 0,\n max: 2,\n },\n });\n\n expect(services.gamePlayAugmenter[\"getScapegoatGamePlaySourceInteractions\"](game)).toStrictEqual([expectedGamePlaySourceInteraction]);\n });\n });\n\n describe(\"getSeerGamePlaySourceInteractions\", () => {\n it(\"should return alive players but seer as eligible targets with boundaries from 1 to 1 when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeSeerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"seer\",\n type: \"look\",\n eligibleTargets: [players[0], players[3]],\n boundaries: { min: 1, max: 1 },\n });\n\n expect(services.gamePlayAugmenter[\"getSeerGamePlaySourceInteractions\"](game)).toStrictEqual([expectedGamePlaySourceInteraction]);\n });\n });\n\n describe(\"getWhiteWerewolfGamePlaySourceInteractions\", () => {\n it(\"should return two eligible targets with 0 to 1 boundaries when there are still wolves to eat.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n mocks.gameHelper.getEligibleWhiteWerewolfTargets.mockReturnValueOnce([\n players[0],\n players[1],\n ]);\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"white-werewolf\",\n type: \"eat\",\n eligibleTargets: [players[0], players[1]],\n boundaries: {\n min: 0,\n max: 1,\n },\n });\n\n expect(services.gamePlayAugmenter[\"getWhiteWerewolfGamePlaySourceInteractions\"](game)).toStrictEqual([expectedGamePlaySourceInteraction]);\n });\n\n it(\"should return no eligible player with 0 to 0 boundaries when there are no wolves to eat.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n mocks.gameHelper.getEligibleWhiteWerewolfTargets.mockReturnValueOnce([]);\n\n expect(services.gamePlayAugmenter[\"getWhiteWerewolfGamePlaySourceInteractions\"](game)).toStrictEqual([]);\n });\n });\n\n describe(\"getWildChildGamePlaySourceInteractions\", () => {\n it(\"should return alive players without wild child as eligible targets with 1 to 1 boundaries when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeWildChildAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"wild-child\",\n type: \"choose-as-model\",\n eligibleTargets: [players[0], players[3]],\n boundaries: { min: 1, max: 1 },\n });\n\n expect(services.gamePlayAugmenter[\"getWildChildGamePlaySourceInteractions\"](game)).toStrictEqual([expectedGamePlaySourceInteraction]);\n });\n });\n\n describe(\"getWitchGamePlaySourceGiveDeathPotionInteraction\", () => {\n it(\"should return undefined when witch used death potion before.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeEatenByBigBadWolfPlayerAttribute()] }),\n createFakeWitchAlivePlayer(),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n ];\n const game = createFakeGame({ players });\n\n expect(services.gamePlayAugmenter[\"getWitchGamePlaySourceGiveDeathPotionInteraction\"](game, true)).toBeUndefined();\n });\n\n it(\"should return interaction with alive not eaten eligible targets when witch didn't use her death potion before.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeEatenByBigBadWolfPlayerAttribute()] }),\n createFakeWitchAlivePlayer(),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n ];\n const game = createFakeGame({ players });\n const expectedDeathPotionInteraction = createFakeGamePlaySourceInteraction({\n source: \"witch\",\n type: \"give-death-potion\",\n eligibleTargets: [players[0], players[2]],\n boundaries: { min: 0, max: 1 },\n });\n\n expect(services.gamePlayAugmenter[\"getWitchGamePlaySourceGiveDeathPotionInteraction\"](game, false)).toStrictEqual(expectedDeathPotionInteraction);\n });\n });\n\n describe(\"getWitchGamePlaySourceGiveLifePotionInteraction\", () => {\n it(\"should return undefined when witch used life potion before.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeEatenByBigBadWolfPlayerAttribute()] }),\n createFakeWitchAlivePlayer(),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n ];\n const game = createFakeGame({ players });\n\n expect(services.gamePlayAugmenter[\"getWitchGamePlaySourceGiveLifePotionInteraction\"](game, true)).toBeUndefined();\n });\n\n it(\"should return interaction with alive eaten eligible targets when witch didn't use her life potion before.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeEatenByBigBadWolfPlayerAttribute()] }),\n createFakeWitchAlivePlayer(),\n createFakeVillagerAlivePlayer({ isAlive: false, attributes: [createFakeEatenByBigBadWolfPlayerAttribute()] }),\n ];\n const game = createFakeGame({ players });\n const expectedLifePotionInteraction = createFakeGamePlaySourceInteraction({\n source: \"witch\",\n type: \"give-life-potion\",\n eligibleTargets: [players[1]],\n boundaries: { min: 0, max: 1 },\n });\n\n expect(services.gamePlayAugmenter[\"getWitchGamePlaySourceGiveLifePotionInteraction\"](game, false)).toStrictEqual(expectedLifePotionInteraction);\n });\n });\n\n describe(\"getWitchGamePlaySourceInteractions\", () => {\n beforeEach(() => {\n mocks.gamePlayAugmenterService.getWitchGamePlaySourceGiveDeathPotionInteraction = jest.spyOn(services.gamePlayAugmenter as unknown as { getWitchGamePlaySourceGiveDeathPotionInteraction }, \"getWitchGamePlaySourceGiveDeathPotionInteraction\").mockImplementation();\n mocks.gamePlayAugmenterService.getWitchGamePlaySourceGiveLifePotionInteraction = jest.spyOn(services.gamePlayAugmenter as unknown as { getWitchGamePlaySourceGiveLifePotionInteraction }, \"getWitchGamePlaySourceGiveLifePotionInteraction\").mockImplementation();\n });\n\n it(\"should throw error when witch is not in the game.\", async() => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const mockedError = new UnexpectedException(\"getWitchGamePlaySourceInteractions\", UnexpectedExceptionReasons.CANT_FIND_PLAYER_WITH_CURRENT_ROLE_IN_GAME, { gameId: game._id.toString(), roleName: \"witch\" });\n mocks.unexpectedExceptionFactory.createCantFindPlayerWithCurrentRoleUnexpectedException.mockReturnValue(mockedError);\n\n await expect(services.gamePlayAugmenter[\"getWitchGamePlaySourceInteractions\"](game)).rejects.toStrictEqual(mockedError);\n expect(mocks.unexpectedExceptionFactory.createCantFindPlayerWithCurrentRoleUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"getWitchGamePlaySourceInteractions\", { gameId: game._id, roleName: \"witch\" });\n });\n\n it(\"should get eligible targets from game when called and there is no history for life potion and death potion.\", async() => {\n const players = [\n createFakeWitchAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords.mockResolvedValueOnce([]);\n mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords.mockResolvedValueOnce([]);\n await services.gamePlayAugmenter[\"getWitchGamePlaySourceInteractions\"](game);\n\n expect(mocks.gamePlayAugmenterService.getWitchGamePlaySourceGiveLifePotionInteraction).toHaveBeenCalledExactlyOnceWith(game, false);\n expect(mocks.gamePlayAugmenterService.getWitchGamePlaySourceGiveDeathPotionInteraction).toHaveBeenCalledExactlyOnceWith(game, false);\n });\n\n it(\"should get eligible targets from game with life potion used when called and there is history for life potion.\", async() => {\n const players = [\n createFakeWitchAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords.mockResolvedValueOnce([createFakeGameHistoryRecord()]);\n mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords.mockResolvedValueOnce([]);\n await services.gamePlayAugmenter[\"getWitchGamePlaySourceInteractions\"](game);\n\n expect(mocks.gamePlayAugmenterService.getWitchGamePlaySourceGiveLifePotionInteraction).toHaveBeenCalledExactlyOnceWith(game, true);\n expect(mocks.gamePlayAugmenterService.getWitchGamePlaySourceGiveDeathPotionInteraction).toHaveBeenCalledExactlyOnceWith(game, false);\n });\n\n it(\"should get eligible targets from game with death potion used when called and there is history for death potion.\", async() => {\n const players = [\n createFakeWitchAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords.mockResolvedValueOnce([]);\n mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords.mockResolvedValueOnce([createFakeGameHistoryRecord()]);\n await services.gamePlayAugmenter[\"getWitchGamePlaySourceInteractions\"](game);\n\n expect(mocks.gamePlayAugmenterService.getWitchGamePlaySourceGiveLifePotionInteraction).toHaveBeenCalledExactlyOnceWith(game, false);\n expect(mocks.gamePlayAugmenterService.getWitchGamePlaySourceGiveDeathPotionInteraction).toHaveBeenCalledExactlyOnceWith(game, true);\n });\n\n it(\"should return eligible targets for both life and death potions interactions when called.\", async() => {\n const players = [\n createFakeWitchAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const expectedLifePotionInteraction = createFakeGamePlaySourceInteraction({\n source: \"witch\",\n type: \"give-life-potion\",\n eligibleTargets: [players[1]],\n boundaries: { min: 0, max: 1 },\n });\n mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords.mockResolvedValue([]);\n mocks.gamePlayAugmenterService.getWitchGamePlaySourceGiveLifePotionInteraction.mockReturnValueOnce(expectedLifePotionInteraction);\n mocks.gamePlayAugmenterService.getWitchGamePlaySourceGiveDeathPotionInteraction.mockReturnValueOnce(undefined);\n\n await expect(services.gamePlayAugmenter[\"getWitchGamePlaySourceInteractions\"](game)).resolves.toStrictEqual([expectedLifePotionInteraction]);\n });\n });\n\n describe(\"getAccursedWolfFatherGamePlaySourceInteractions\", () => {\n beforeEach(() => {\n mocks.gameHistoryRecordService.getGameHistoryAccursedWolfFatherInfectsWithTargetRecords.mockResolvedValue([]);\n });\n\n it(\"should throw error when there is no accursed wolf father in the game.\", async() => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const mockedError = new UnexpectedException(\"getAccursedWolfFatherGamePlaySourceInteractions\", UnexpectedExceptionReasons.CANT_FIND_PLAYER_WITH_CURRENT_ROLE_IN_GAME, { gameId: game._id.toString(), roleName: \"accursed-wolf-father\" });\n mocks.unexpectedExceptionFactory.createCantFindPlayerWithCurrentRoleUnexpectedException.mockReturnValue(mockedError);\n\n await expect(services.gamePlayAugmenter[\"getAccursedWolfFatherGamePlaySourceInteractions\"](game)).rejects.toStrictEqual(mockedError);\n expect(mocks.unexpectedExceptionFactory.createCantFindPlayerWithCurrentRoleUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"getAccursedWolfFatherGamePlaySourceInteractions\", { gameId: game._id, roleName: \"accursed-wolf-father\" });\n });\n\n it(\"should return empty array when there is a record for accursed wolf father infects with target.\", async() => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeAccursedWolfFatherAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const gameHistoryRecord = createFakeGameHistoryRecord({ play: createFakeGameHistoryRecordPlay({ targets: [{ player: players[3] }] }) });\n mocks.gameHistoryRecordService.getGameHistoryAccursedWolfFatherInfectsWithTargetRecords.mockResolvedValueOnce([gameHistoryRecord]);\n\n await expect(services.gamePlayAugmenter[\"getAccursedWolfFatherGamePlaySourceInteractions\"](game)).resolves.toStrictEqual([]);\n });\n\n it(\"should return all eaten by werewolves players as eligible targets with boundaries from 0 to 1 when called.\", async() => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeAccursedWolfFatherAlivePlayer(),\n createFakeVillagerAlivePlayer({ attributes: [createFakeEatenByWerewolvesPlayerAttribute()] }),\n ];\n const game = createFakeGame({ players });\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"accursed-wolf-father\",\n type: \"infect\",\n eligibleTargets: [players[3]],\n boundaries: { min: 0, max: 1 },\n });\n\n await expect(services.gamePlayAugmenter[\"getAccursedWolfFatherGamePlaySourceInteractions\"](game)).resolves.toStrictEqual([expectedGamePlaySourceInteraction]);\n });\n });\n\n describe(\"getGamePlaySourceInteractions\", () => {\n beforeEach(() => {\n mocks.gamePlayAugmenterService.getSheriffGamePlaySourceInteractions = jest.spyOn(services.gamePlayAugmenter as unknown as {\n getSheriffGamePlaySourceInteractions;\n }, \"getSheriffGamePlaySourceInteractions\").mockImplementation().mockReturnValue([]);\n mocks.gamePlayAugmenterService.getSurvivorsGamePlaySourceInteractions = jest.spyOn(services.gamePlayAugmenter as unknown as {\n getSurvivorsGamePlaySourceInteractions;\n }, \"getSurvivorsGamePlaySourceInteractions\").mockImplementation().mockReturnValue([]);\n mocks.gamePlayAugmenterService.getWerewolvesGamePlaySourceInteractions = jest.spyOn(services.gamePlayAugmenter as unknown as {\n getWerewolvesGamePlaySourceInteractions;\n }, \"getWerewolvesGamePlaySourceInteractions\").mockImplementation().mockReturnValue([]);\n mocks.gamePlayAugmenterService.getBigBadWolfGamePlaySourceInteractions = jest.spyOn(services.gamePlayAugmenter as unknown as {\n getBigBadWolfGamePlaySourceInteractions;\n }, \"getBigBadWolfGamePlaySourceInteractions\").mockImplementation().mockReturnValue([]);\n mocks.gamePlayAugmenterService.getCupidGamePlaySourceInteractions = jest.spyOn(services.gamePlayAugmenter as unknown as {\n getCupidGamePlaySourceInteractions;\n }, \"getCupidGamePlaySourceInteractions\").mockImplementation().mockReturnValue([]);\n mocks.gamePlayAugmenterService.getFoxGamePlaySourceInteractions = jest.spyOn(services.gamePlayAugmenter as unknown as {\n getFoxGamePlaySourceInteractions;\n }, \"getFoxGamePlaySourceInteractions\").mockImplementation().mockReturnValue([]);\n mocks.gamePlayAugmenterService.getDefenderGamePlaySourceInteractions = jest.spyOn(services.gamePlayAugmenter as unknown as {\n getDefenderGamePlaySourceInteractions;\n }, \"getDefenderGamePlaySourceInteractions\").mockImplementation().mockReturnValue([]);\n mocks.gamePlayAugmenterService.getHunterGamePlaySourceInteractions = jest.spyOn(services.gamePlayAugmenter as unknown as {\n getHunterGamePlaySourceInteractions;\n }, \"getHunterGamePlaySourceInteractions\").mockImplementation().mockReturnValue([]);\n mocks.gamePlayAugmenterService.getPiedPiperGamePlaySourceInteractions = jest.spyOn(services.gamePlayAugmenter as unknown as {\n getPiedPiperGamePlaySourceInteractions;\n }, \"getPiedPiperGamePlaySourceInteractions\").mockImplementation().mockReturnValue([]);\n mocks.gamePlayAugmenterService.getScandalmongerGamePlaySourceInteractions = jest.spyOn(services.gamePlayAugmenter as unknown as {\n getScandalmongerGamePlaySourceInteractions;\n }, \"getScandalmongerGamePlaySourceInteractions\").mockImplementation().mockReturnValue([]);\n mocks.gamePlayAugmenterService.getScapegoatGamePlaySourceInteractions = jest.spyOn(services.gamePlayAugmenter as unknown as {\n getScapegoatGamePlaySourceInteractions;\n }, \"getScapegoatGamePlaySourceInteractions\").mockImplementation().mockReturnValue([]);\n mocks.gamePlayAugmenterService.getSeerGamePlaySourceInteractions = jest.spyOn(services.gamePlayAugmenter as unknown as {\n getSeerGamePlaySourceInteractions;\n }, \"getSeerGamePlaySourceInteractions\").mockImplementation().mockReturnValue([]);\n mocks.gamePlayAugmenterService.getWhiteWerewolfGamePlaySourceInteractions = jest.spyOn(services.gamePlayAugmenter as unknown as {\n getWhiteWerewolfGamePlaySourceInteractions;\n }, \"getWhiteWerewolfGamePlaySourceInteractions\").mockImplementation().mockReturnValue([]);\n mocks.gamePlayAugmenterService.getWildChildGamePlaySourceInteractions = jest.spyOn(services.gamePlayAugmenter as unknown as {\n getWildChildGamePlaySourceInteractions;\n }, \"getWildChildGamePlaySourceInteractions\").mockImplementation().mockReturnValue([]);\n mocks.gamePlayAugmenterService.getWitchGamePlaySourceInteractions = jest.spyOn(services.gamePlayAugmenter as unknown as {\n getWitchGamePlaySourceInteractions;\n }, \"getWitchGamePlaySourceInteractions\").mockImplementation().mockReturnValue([]);\n mocks.gamePlayAugmenterService.getAccursedWolfFatherGamePlaySourceInteractions = jest.spyOn(services.gamePlayAugmenter as unknown as {\n getAccursedWolfFatherGamePlaySourceInteractions;\n }, \"getAccursedWolfFatherGamePlaySourceInteractions\").mockImplementation().mockReturnValue([]);\n });\n\n it(\"should return undefined when game play source name is not in getGamePlaySourceInteractionsMethods.\", async() => {\n const gamePlay = createFakeGamePlayThreeBrothersMeetEachOther();\n const game = createFakeGame();\n\n await expect(services.gamePlayAugmenter[\"getGamePlaySourceInteractions\"](gamePlay, game)).resolves.toBeUndefined();\n });\n\n it(\"should return undefined when eligible targets are empty array.\", async() => {\n const gamePlay = createFakeGamePlaySheriffDelegates();\n const game = createFakeGame();\n mocks.gamePlayAugmenterService.getSheriffGamePlaySourceInteractions.mockReturnValueOnce([]);\n\n await expect(services.gamePlayAugmenter[\"getGamePlaySourceInteractions\"](gamePlay, game)).resolves.toBeUndefined();\n });\n\n it(\"should return game play eligible targets when game play method returns eligible targets.\", async() => {\n const gamePlay = createFakeGamePlaySheriffDelegates();\n const game = createFakeGame();\n const expectedInteractions = [\n createFakeGamePlaySourceInteraction(),\n createFakeGamePlaySourceInteraction(),\n ];\n mocks.gamePlayAugmenterService.getSheriffGamePlaySourceInteractions.mockReturnValueOnce(expectedInteractions);\n\n await expect(services.gamePlayAugmenter[\"getGamePlaySourceInteractions\"](gamePlay, game)).resolves.toStrictEqual(expectedInteractions);\n });\n\n it(\"should call get game play eligible targets for sheriff when game play source name is sheriff.\", async() => {\n const gamePlay = createFakeGamePlaySheriffDelegates();\n const game = createFakeGame();\n await services.gamePlayAugmenter[\"getGamePlaySourceInteractions\"](gamePlay, game);\n\n expect(mocks.gamePlayAugmenterService.getSheriffGamePlaySourceInteractions).toHaveBeenCalledExactlyOnceWith(game, gamePlay);\n });\n\n it(\"should call get game play eligible targets for survivors when game play source name is survivors.\", async() => {\n const gamePlay = createFakeGamePlaySurvivorsVote();\n const game = createFakeGame();\n await services.gamePlayAugmenter[\"getGamePlaySourceInteractions\"](gamePlay, game);\n\n expect(mocks.gamePlayAugmenterService.getSurvivorsGamePlaySourceInteractions).toHaveBeenCalledExactlyOnceWith(game, gamePlay);\n });\n\n it(\"should call get game play eligible targets for werewolves when game play source name is werewolves.\", async() => {\n const gamePlay = createFakeGamePlayWerewolvesEat();\n const game = createFakeGame();\n await services.gamePlayAugmenter[\"getGamePlaySourceInteractions\"](gamePlay, game);\n\n expect(mocks.gamePlayAugmenterService.getWerewolvesGamePlaySourceInteractions).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call get game play eligible targets for big bad wolf when game play source name is big bad wolf.\", async() => {\n const gamePlay = createFakeGamePlayBigBadWolfEats();\n const game = createFakeGame();\n await services.gamePlayAugmenter[\"getGamePlaySourceInteractions\"](gamePlay, game);\n\n expect(mocks.gamePlayAugmenterService.getBigBadWolfGamePlaySourceInteractions).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call get game play eligible targets for cupid when game play source name is cupid.\", async() => {\n const gamePlay = createFakeGamePlayCupidCharms();\n const game = createFakeGame();\n await services.gamePlayAugmenter[\"getGamePlaySourceInteractions\"](gamePlay, game);\n\n expect(mocks.gamePlayAugmenterService.getCupidGamePlaySourceInteractions).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call get game play eligible targets for fox when game play source name is fox.\", async() => {\n const gamePlay = createFakeGamePlayFoxSniffs();\n const game = createFakeGame();\n await services.gamePlayAugmenter[\"getGamePlaySourceInteractions\"](gamePlay, game);\n\n expect(mocks.gamePlayAugmenterService.getFoxGamePlaySourceInteractions).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call get game play eligible targets for defender when game play source name is defender.\", async() => {\n const gamePlay = createFakeGamePlayDefenderProtects();\n const game = createFakeGame();\n await services.gamePlayAugmenter[\"getGamePlaySourceInteractions\"](gamePlay, game);\n\n expect(mocks.gamePlayAugmenterService.getDefenderGamePlaySourceInteractions).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call get game play eligible targets for hunter when game play source name is hunter.\", async() => {\n const gamePlay = createFakeGamePlayHunterShoots();\n const game = createFakeGame();\n await services.gamePlayAugmenter[\"getGamePlaySourceInteractions\"](gamePlay, game);\n\n expect(mocks.gamePlayAugmenterService.getHunterGamePlaySourceInteractions).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call get game play eligible targets for pied piper when game play source name is pied piper.\", async() => {\n const gamePlay = createFakeGamePlayPiedPiperCharms();\n const game = createFakeGame();\n await services.gamePlayAugmenter[\"getGamePlaySourceInteractions\"](gamePlay, game);\n\n expect(mocks.gamePlayAugmenterService.getPiedPiperGamePlaySourceInteractions).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call get game play eligible targets for scandalmonger when game play source name is scandalmonger.\", async() => {\n const gamePlay = createFakeGamePlayScandalmongerMarks();\n const game = createFakeGame();\n await services.gamePlayAugmenter[\"getGamePlaySourceInteractions\"](gamePlay, game);\n\n expect(mocks.gamePlayAugmenterService.getScandalmongerGamePlaySourceInteractions).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call get game play eligible targets for scapegoat when game play source name is scapegoat.\", async() => {\n const gamePlay = createFakeGamePlayScapegoatBansVoting();\n const game = createFakeGame();\n await services.gamePlayAugmenter[\"getGamePlaySourceInteractions\"](gamePlay, game);\n\n expect(mocks.gamePlayAugmenterService.getScapegoatGamePlaySourceInteractions).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call get game play eligible targets for see when game play source name is see.\", async() => {\n const gamePlay = createFakeGamePlaySeerLooks();\n const game = createFakeGame();\n await services.gamePlayAugmenter[\"getGamePlaySourceInteractions\"](gamePlay, game);\n\n expect(mocks.gamePlayAugmenterService.getSeerGamePlaySourceInteractions).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call get game play eligible targets for white werewolf when game play source name is white werewolf.\", async() => {\n const gamePlay = createFakeGamePlayWhiteWerewolfEats();\n const game = createFakeGame();\n await services.gamePlayAugmenter[\"getGamePlaySourceInteractions\"](gamePlay, game);\n\n expect(mocks.gamePlayAugmenterService.getWhiteWerewolfGamePlaySourceInteractions).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call get game play eligible targets for wild child when game play source name is wild child.\", async() => {\n const gamePlay = createFakeGamePlayWildChildChoosesModel();\n const game = createFakeGame();\n await services.gamePlayAugmenter[\"getGamePlaySourceInteractions\"](gamePlay, game);\n\n expect(mocks.gamePlayAugmenterService.getWildChildGamePlaySourceInteractions).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call get game play eligible targets for witch when game play source name is witch.\", async() => {\n const gamePlay = createFakeGamePlayWitchUsesPotions();\n const game = createFakeGame();\n await services.gamePlayAugmenter[\"getGamePlaySourceInteractions\"](gamePlay, game);\n\n expect(mocks.gamePlayAugmenterService.getWitchGamePlaySourceInteractions).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call get game play eligible targets for accursed wolf-father when game play source name is accursed wolf-father.\", async() => {\n const gamePlay = createFakeGamePlayAccursedWolfFatherInfects();\n const game = createFakeGame();\n await services.gamePlayAugmenter[\"getGamePlaySourceInteractions\"](gamePlay, game);\n\n expect(mocks.gamePlayAugmenterService.getAccursedWolfFatherGamePlaySourceInteractions).toHaveBeenCalledExactlyOnceWith(game);\n });\n });\n\n describe(\"canSurvivorsSkipGamePlay\", () => {\n it.each<{\n test: string;\n gamePlay: GamePlay;\n game: Game;\n expected: boolean;\n }>([\n {\n test: \"should return false when game play action is elect sheriff.\",\n gamePlay: createFakeGamePlay({ action: \"elect-sheriff\" }),\n game: createFakeGame(),\n expected: false,\n },\n {\n test: \"should return false when game play action is vote and game play cause is angel presence.\",\n gamePlay: createFakeGamePlaySurvivorsVote({ causes: [\"angel-presence\"] }),\n game: createFakeGame({ options: createFakeGameOptions({ votes: createFakeVotesGameOptions({ canBeSkipped: true }) }) }),\n expected: false,\n },\n {\n test: \"should return true when game play action is bury dead bodies.\",\n gamePlay: createFakeGamePlay({ action: \"bury-dead-bodies\" }),\n game: createFakeGame({ options: createFakeGameOptions({ votes: createFakeVotesGameOptions({ canBeSkipped: false }) }) }),\n expected: true,\n },\n {\n test: \"should return true when game play action is not elect sheriff and game options say that votes can be skipped.\",\n gamePlay: createFakeGamePlay({ action: \"vote\" }),\n game: createFakeGame({ options: createFakeGameOptions({ votes: createFakeVotesGameOptions({ canBeSkipped: true }) }) }),\n expected: true,\n },\n {\n test: \"should return true when game play action is not vote but because angel presence.\",\n gamePlay: createFakeGamePlayScandalmongerMarks({ causes: [\"angel-presence\"] }),\n game: createFakeGame({ options: createFakeGameOptions({ votes: createFakeVotesGameOptions({ canBeSkipped: true }) }) }),\n expected: true,\n },\n {\n test: \"should return false when game play action is not elect sheriff and game options say that votes can't be skipped.\",\n gamePlay: createFakeGamePlay({ action: \"vote\" }),\n game: createFakeGame({\n options: createFakeGameOptions({ votes: createFakeVotesGameOptions({ canBeSkipped: false }) }),\n players: [\n createFakeWhiteWerewolfAlivePlayer({ attributes: [createFakeCantVoteBySurvivorsPlayerAttribute()] }),\n createFakeAngelAlivePlayer(),\n createFakeWitchAlivePlayer({ isAlive: false }),\n ],\n }),\n expected: false,\n },\n ])(\"$test\", ({ gamePlay, game, expected }) => {\n expect(services.gamePlayAugmenter[\"canSurvivorsSkipGamePlay\"](game, gamePlay)).toBe(expected);\n });\n });\n\n describe(\"canCupidSkipGamePlay\", () => {\n it.each<{\n test: string;\n game: Game;\n expected: boolean;\n }>([\n {\n test: \"should return false when expected there are at least 2 targets for cupid.\",\n game: createFakeGame({\n players: [\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ],\n }),\n expected: false,\n },\n {\n test: \"should return true when expected there are less than 2 targets for cupid.\",\n game: createFakeGame({ players: [createFakeVillagerAlivePlayer()] }),\n expected: true,\n },\n ])(\"$test\", ({ game, expected }) => {\n expect(services.gamePlayAugmenter[\"canCupidSkipGamePlay\"](game)).toBe(expected);\n });\n });\n\n describe(\"canBigBadWolfSkipGamePlay\", () => {\n it.each<{\n test: string;\n game: Game;\n expected: boolean;\n }>([\n {\n test: \"should return true when there are no players left to eat by werewolves.\",\n game: createFakeGame({ players: [createFakeWerewolfAlivePlayer()] }),\n expected: true,\n },\n {\n test: \"should return false when there are players left to eat by werewolves.\",\n game: createFakeGame({ players: [createFakeVillagerAlivePlayer()] }),\n expected: false,\n },\n ])(\"$test\", ({ game, expected }) => {\n expect(services.gamePlayAugmenter[\"canBigBadWolfSkipGamePlay\"](game)).toBe(expected);\n });\n });\n\n describe(\"canThiefSkipGamePlay\", () => {\n it.each<{\n test: string;\n game: Game;\n expected: boolean;\n }>([\n {\n test: \"should return true when game has undefined additional cards.\",\n game: createFakeGame(),\n expected: true,\n },\n {\n test: \"should return true when game has no additional cards.\",\n game: createFakeGame({ additionalCards: [], options: createFakeGameOptions({ roles: createFakeRolesGameOptions({ thief: createFakeThiefGameOptions({ mustChooseBetweenWerewolves: false }) }) }) }),\n expected: true,\n },\n {\n test: \"should return true when thief doesn't have to choose between werewolves cards.\",\n game: createFakeGame({\n additionalCards: [\n createFakeGameAdditionalCard({ roleName: \"seer\" }),\n createFakeGameAdditionalCard({ roleName: \"werewolf\" }),\n ],\n options: createFakeGameOptions({ roles: createFakeRolesGameOptions({ thief: createFakeThiefGameOptions({ mustChooseBetweenWerewolves: true }) }) }),\n }),\n expected: true,\n },\n {\n test: \"should return true when thief has to choose between werewolves cards but game options allow to skip.\",\n game: createFakeGame({\n additionalCards: [\n createFakeGameAdditionalCard({ roleName: \"werewolf\" }),\n createFakeGameAdditionalCard({ roleName: \"werewolf\" }),\n ],\n options: createFakeGameOptions({ roles: createFakeRolesGameOptions({ thief: createFakeThiefGameOptions({ mustChooseBetweenWerewolves: false }) }) }),\n }),\n expected: true,\n },\n {\n test: \"should return false when thief has to choose between werewolves cards and game options don't allow to skip.\",\n game: createFakeGame({\n additionalCards: [\n createFakeGameAdditionalCard({ roleName: \"werewolf\" }),\n createFakeGameAdditionalCard({ roleName: \"werewolf\" }),\n ],\n options: createFakeGameOptions({ roles: createFakeRolesGameOptions({ thief: createFakeThiefGameOptions({ mustChooseBetweenWerewolves: true }) }) }),\n }),\n expected: false,\n },\n ])(\"$test\", ({ game, expected }) => {\n expect(services.gamePlayAugmenter[\"canThiefSkipGamePlay\"](game)).toBe(expected);\n });\n });\n\n describe(\"canGamePlayBeSkipped\", () => {\n beforeEach(() => {\n mocks.gamePlayAugmenterService.canSurvivorsSkipGamePlay = jest.spyOn(services.gamePlayAugmenter as unknown as { canSurvivorsSkipGamePlay }, \"canSurvivorsSkipGamePlay\").mockImplementation();\n mocks.gamePlayAugmenterService.canBigBadWolfSkipGamePlay = jest.spyOn(services.gamePlayAugmenter as unknown as { canBigBadWolfSkipGamePlay }, \"canBigBadWolfSkipGamePlay\").mockImplementation();\n mocks.gamePlayAugmenterService.canThiefSkipGamePlay = jest.spyOn(services.gamePlayAugmenter as unknown as { canThiefSkipGamePlay }, \"canThiefSkipGamePlay\").mockImplementation();\n mocks.gamePlayAugmenterService.canCupidSkipGamePlay = jest.spyOn(services.gamePlayAugmenter as unknown as { canCupidSkipGamePlay }, \"canCupidSkipGamePlay\").mockImplementation();\n });\n\n it(\"should return false when game play source name is not in canBeSkippedPlayMethods.\", () => {\n const gamePlay = createFakeGamePlayWildChildChoosesModel();\n const game = createFakeGame();\n\n expect(services.gamePlayAugmenter[\"canGamePlayBeSkipped\"](game, gamePlay)).toBe(false);\n });\n\n it.each<{\n test: string;\n gamePlay: GamePlay;\n }>([\n {\n gamePlay: createFakeGamePlayLoversMeetEachOther(),\n test: \"should return true when game play source name are lovers.\",\n },\n {\n gamePlay: createFakeGamePlayCharmedMeetEachOther(),\n test: \"should return true when game play source name are charmed.\",\n },\n {\n gamePlay: createFakeGamePlayFoxSniffs(),\n test: \"should return true when game play source name is fox.\",\n },\n {\n gamePlay: createFakeGamePlayScandalmongerMarks(),\n test: \"should return true when game play source name is scandalmonger.\",\n },\n {\n gamePlay: createFakeGamePlayScapegoatBansVoting(),\n test: \"should return true when game play source name is scapegoat.\",\n },\n {\n gamePlay: createFakeGamePlayTwoSistersMeetEachOther(),\n test: \"should return true when game play source name are two sisters.\",\n },\n {\n gamePlay: createFakeGamePlayThreeBrothersMeetEachOther(),\n test: \"should return true when game play source name are three brothers.\",\n },\n {\n gamePlay: createFakeGamePlayWhiteWerewolfEats(),\n test: \"should return true when game play source name is white werewolf.\",\n },\n {\n gamePlay: createFakeGamePlayWitchUsesPotions(),\n test: \"should return true when game play source name is witch.\",\n },\n {\n gamePlay: createFakeGamePlayActorChoosesCard(),\n test: \"should return true when game play source name is actor.\",\n },\n {\n gamePlay: createFakeGamePlayAccursedWolfFatherInfects(),\n test: \"should return true when game play source name is accursed wolf-father.\",\n },\n {\n gamePlay: createFakeGamePlayStutteringJudgeRequestsAnotherVote(),\n test: \"should return true when game play source name is stuttering judge.\",\n },\n ])(\"$test\", ({ gamePlay }) => {\n const game = createFakeGame();\n\n expect(services.gamePlayAugmenter[\"canGamePlayBeSkipped\"](game, gamePlay)).toBe(true);\n });\n\n it(\"should call canSurvivorsSkipGamePlay method when game play source name is survivors.\", () => {\n const gamePlay = createFakeGamePlaySurvivorsVote();\n const game = createFakeGame();\n services.gamePlayAugmenter[\"canGamePlayBeSkipped\"](game, gamePlay);\n\n expect(mocks.gamePlayAugmenterService.canSurvivorsSkipGamePlay).toHaveBeenCalledExactlyOnceWith(game, gamePlay);\n });\n\n it(\"should call canBigBadWolfSkipGamePlay method when game play source name is big bad wolf.\", () => {\n const gamePlay = createFakeGamePlayBigBadWolfEats();\n const game = createFakeGame();\n services.gamePlayAugmenter[\"canGamePlayBeSkipped\"](game, gamePlay);\n\n expect(mocks.gamePlayAugmenterService.canBigBadWolfSkipGamePlay).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call canThiefSkipGamePlay method when game play source name is thief.\", () => {\n const gamePlay = createFakeGamePlayThiefChoosesCard();\n const game = createFakeGame();\n services.gamePlayAugmenter[\"canGamePlayBeSkipped\"](game, gamePlay);\n\n expect(mocks.gamePlayAugmenterService.canThiefSkipGamePlay).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call canCupidSkipGamePlay method when game play source name is cupid.\", () => {\n const gamePlay = createFakeGamePlayCupidCharms();\n const game = createFakeGame();\n services.gamePlayAugmenter[\"canGamePlayBeSkipped\"](game, gamePlay);\n\n expect(mocks.gamePlayAugmenterService.canCupidSkipGamePlay).toHaveBeenCalledExactlyOnceWith(game);\n });\n });\n\n describe(\"getExpectedPlayersToPlay\", () => {\n it(\"should throw error when there is no current play.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeWhiteWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer({ attributes: [createFakeSheriffBySurvivorsPlayerAttribute()] }),\n ];\n const game = createFakeGame({ players });\n const interpolations = { gameId: game._id };\n const mockedError = new UnexpectedException(\"getExpectedPlayersToPlay\", UnexpectedExceptionReasons.NO_CURRENT_GAME_PLAY, { gameId: game._id.toString() });\n mocks.unexpectedExceptionFactory.createNoCurrentGamePlayUnexpectedException.mockReturnValueOnce(mockedError);\n\n expect(() => services.gamePlayAugmenter[\"getExpectedPlayersToPlay\"](game)).toThrow(mockedError);\n expect(mocks.unexpectedExceptionFactory.createNoCurrentGamePlayUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"getExpectedPlayersToPlay\", interpolations);\n });\n\n it(\"should return alive werewolves when source is group of werewolves.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeWhiteWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer({ attributes: [createFakeSheriffBySurvivorsPlayerAttribute()] }),\n ];\n const game = createFakeGame({ players, currentPlay: createFakeGamePlayWerewolvesEat() });\n\n expect(services.gamePlayAugmenter[\"getExpectedPlayersToPlay\"](game)).toStrictEqual([\n players[0],\n players[2],\n ]);\n });\n\n it(\"should return alive two sisters when source is specific role.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeWhiteWerewolfAlivePlayer(),\n createFakeTwoSistersAlivePlayer(),\n createFakeTwoSistersAlivePlayer({ isAlive: false }),\n createFakeVillagerAlivePlayer({ attributes: [createFakeSheriffBySurvivorsPlayerAttribute()] }),\n ];\n const game = createFakeGame({ players, currentPlay: createFakeGamePlayTwoSistersMeetEachOther() });\n\n expect(services.gamePlayAugmenter[\"getExpectedPlayersToPlay\"](game)).toStrictEqual([players[3]]);\n });\n\n it(\"should not return sheriff when source is sheriff but action is not DELEGATE and sheriff is dead.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeWhiteWerewolfAlivePlayer(),\n createFakeTwoSistersAlivePlayer(),\n createFakeTwoSistersAlivePlayer({ isAlive: false }),\n createFakeVillagerAlivePlayer({ attributes: [createFakeSheriffBySurvivorsPlayerAttribute()], isAlive: false }),\n ];\n const game = createFakeGame({ players, currentPlay: createFakeGamePlaySheriffSettlesVotes() });\n\n expect(services.gamePlayAugmenter[\"getExpectedPlayersToPlay\"](game)).toStrictEqual([]);\n });\n\n it(\"should return sheriff when source is sheriff and action is DELEGATE even if he is dying.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeWhiteWerewolfAlivePlayer(),\n createFakeTwoSistersAlivePlayer(),\n createFakeTwoSistersAlivePlayer({ isAlive: false }),\n createFakeVillagerAlivePlayer({ attributes: [createFakeSheriffBySurvivorsPlayerAttribute()], isAlive: false }),\n ];\n const game = createFakeGame({ players, currentPlay: createFakeGamePlaySheriffDelegates() });\n\n expect(services.gamePlayAugmenter[\"getExpectedPlayersToPlay\"](game)).toStrictEqual([players[5]]);\n });\n\n it(\"should return hunter when source is hunter and action is SHOOT even if he is dying.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeWhiteWerewolfAlivePlayer(),\n createFakeTwoSistersAlivePlayer(),\n createFakeTwoSistersAlivePlayer({ isAlive: false }),\n createFakeHunterAlivePlayer({ attributes: [createFakeSheriffBySurvivorsPlayerAttribute()], isAlive: false }),\n ];\n const game = createFakeGame({ players, currentPlay: createFakeGamePlayHunterShoots() });\n\n expect(services.gamePlayAugmenter[\"getExpectedPlayersToPlay\"](game)).toStrictEqual([players[5]]);\n });\n\n it(\"should return scapegoat when source is scapegoat and action is BAN_VOTING even if he is dying.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeWhiteWerewolfAlivePlayer(),\n createFakeTwoSistersAlivePlayer({}),\n createFakeTwoSistersAlivePlayer({ isAlive: false }),\n createFakeScapegoatAlivePlayer({ attributes: [createFakeSheriffBySurvivorsPlayerAttribute(), createFakeCantVoteBySurvivorsPlayerAttribute()], isAlive: false }),\n ];\n const game = createFakeGame({ players, currentPlay: createFakeGamePlayScapegoatBansVoting() });\n\n expect(services.gamePlayAugmenter[\"getExpectedPlayersToPlay\"](game)).toStrictEqual([players[5]]);\n });\n\n it(\"should return alive players capable of vote when action is vote.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeWhiteWerewolfAlivePlayer(),\n createFakeTwoSistersAlivePlayer({ attributes: [createFakeCantVoteBySurvivorsPlayerAttribute()] }),\n createFakeTwoSistersAlivePlayer({ isAlive: false }),\n createFakeVillagerAlivePlayer({ attributes: [createFakeSheriffBySurvivorsPlayerAttribute()], isAlive: false }),\n ];\n const game = createFakeGame({ players, currentPlay: createFakeGamePlaySurvivorsVote() });\n\n expect(services.gamePlayAugmenter[\"getExpectedPlayersToPlay\"](game)).toStrictEqual([players[0], players[2]]);\n });\n });\n});" + "source": "import type { TestingModule } from \"@nestjs/testing\";\nimport { Test } from \"@nestjs/testing\";\n\nimport { DEFAULT_GAME_OPTIONS } from \"@/modules/game/constants/game-options/game-options.constants\";\nimport * as GameHelper from \"@/modules/game/helpers/game.helpers\";\nimport { GameHistoryRecordService } from \"@/modules/game/providers/services/game-history/game-history-record.service\";\nimport { GamePlayAugmenterService } from \"@/modules/game/providers/services/game-play/game-play-augmenter.service\";\nimport type { GamePlaySourceInteraction } from \"@/modules/game/schemas/game-play/game-play-source/game-play-source-interaction/game-play-source-interaction.schema\";\nimport type { GamePlay } from \"@/modules/game/schemas/game-play/game-play.schema\";\nimport type { Game } from \"@/modules/game/schemas/game.schema\";\nimport type { Player } from \"@/modules/game/schemas/player/player.schema\";\n\nimport { UnexpectedExceptionReasons } from \"@/shared/exception/enums/unexpected-exception.enums\";\nimport * as UnexpectedExceptionFactory from \"@/shared/exception/helpers/unexpected-exception.factory\";\nimport { UnexpectedException } from \"@/shared/exception/types/unexpected-exception.types\";\n\nimport { createFakeGameAdditionalCard } from \"@tests/factories/game/schemas/game-additional-card/game-additional-card.schema.factory\";\nimport { createFakeGameHistoryRecord, createFakeGameHistoryRecordPlay, createFakeGameHistoryRecordPlayVoting } from \"@tests/factories/game/schemas/game-history-record/game-history-record.schema.factory\";\nimport { createFakeGameOptions } from \"@tests/factories/game/schemas/game-options/game-options.schema.factory\";\nimport { createFakeCupidGameOptions, createFakeDefenderGameOptions, createFakePiedPiperGameOptions, createFakeRolesGameOptions, createFakeThiefGameOptions } from \"@tests/factories/game/schemas/game-options/game-roles-options/game-roles-options.schema.factory\";\nimport { createFakeVotesGameOptions } from \"@tests/factories/game/schemas/game-options/votes-game-options.schema.factory\";\nimport { createFakeGamePlaySourceInteraction } from \"@tests/factories/game/schemas/game-play/game-play-source/game-play-source-interaction/game-play-source-interaction.schema.factory\";\nimport { createFakeGamePlaySource } from \"@tests/factories/game/schemas/game-play/game-play-source/game-play-source.schema.factory\";\nimport { createFakeGamePlay, createFakeGamePlayAccursedWolfFatherInfects, createFakeGamePlayActorChoosesCard, createFakeGamePlayBigBadWolfEats, createFakeGamePlayCharmedMeetEachOther, createFakeGamePlayCupidCharms, createFakeGamePlayDefenderProtects, createFakeGamePlayFoxSniffs, createFakeGamePlayHunterShoots, createFakeGamePlayLoversMeetEachOther, createFakeGamePlayPiedPiperCharms, createFakeGamePlayScandalmongerMarks, createFakeGamePlayScapegoatBansVoting, createFakeGamePlaySeerLooks, createFakeGamePlaySheriffDelegates, createFakeGamePlaySheriffSettlesVotes, createFakeGamePlayStutteringJudgeRequestsAnotherVote, createFakeGamePlaySurvivorsBuryDeadBodies, createFakeGamePlaySurvivorsElectSheriff, createFakeGamePlaySurvivorsVote, createFakeGamePlayThiefChoosesCard, createFakeGamePlayThreeBrothersMeetEachOther, createFakeGamePlayTwoSistersMeetEachOther, createFakeGamePlayWerewolvesEat, createFakeGamePlayWhiteWerewolfEats, createFakeGamePlayWildChildChoosesModel, createFakeGamePlayWitchUsesPotions } from \"@tests/factories/game/schemas/game-play/game-play.schema.factory\";\nimport { createFakeGame } from \"@tests/factories/game/schemas/game.schema.factory\";\nimport { createFakeCantVoteBySurvivorsPlayerAttribute, createFakeEatenByBigBadWolfPlayerAttribute, createFakeEatenByWerewolvesPlayerAttribute, createFakeInLoveByCupidPlayerAttribute, createFakePowerlessByElderPlayerAttribute, createFakeSheriffBySurvivorsPlayerAttribute } from \"@tests/factories/game/schemas/player/player-attribute/player-attribute.schema.factory\";\nimport { createFakePlayerDeath } from \"@tests/factories/game/schemas/player/player-death/player-death.schema.factory\";\nimport { createFakeAccursedWolfFatherAlivePlayer, createFakeAngelAlivePlayer, createFakeCupidAlivePlayer, createFakeDefenderAlivePlayer, createFakeDevotedServantAlivePlayer, createFakeHunterAlivePlayer, createFakeScapegoatAlivePlayer, createFakeSeerAlivePlayer, createFakeTwoSistersAlivePlayer, createFakeVillagerAlivePlayer, createFakeWerewolfAlivePlayer, createFakeWhiteWerewolfAlivePlayer, createFakeWildChildAlivePlayer, createFakeWitchAlivePlayer } from \"@tests/factories/game/schemas/player/player-with-role.schema.factory\";\nimport { createFakeDeadPlayer, createFakePlayer } from \"@tests/factories/game/schemas/player/player.schema.factory\";\n\ndescribe(\"Game Play Augmenter Service\", () => {\n let services: { gamePlayAugmenter: GamePlayAugmenterService };\n let mocks: {\n gamePlayAugmenterService: {\n canGamePlayBeSkipped: jest.SpyInstance;\n getGamePlaySourceInteractions: jest.SpyInstance;\n getExpectedPlayersToPlay: jest.SpyInstance;\n getSheriffSettlesVotesGamePlaySourceInteractions: jest.SpyInstance;\n getSheriffDelegatesGamePlaySourceInteractions: jest.SpyInstance;\n getSheriffGamePlaySourceInteractions: jest.SpyInstance;\n getSurvivorsVoteGamePlaySourceInteractionEligibleTargets: jest.SpyInstance;\n getSurvivorsVoteGamePlaySourceInteractions: jest.SpyInstance;\n getSurvivorsElectSheriffGamePlaySourceInteractions: jest.SpyInstance;\n getSurvivorsGamePlaySourceInteractions: jest.SpyInstance;\n getWerewolvesEatGamePlaySourceInteractions: jest.SpyInstance;\n getWerewolvesGamePlaySourceInteractions: jest.SpyInstance;\n getWhiteWerewolfEatGamePlaySourceInteractions: jest.SpyInstance;\n getWhiteWerewolfGamePlaySourceInteractions: jest.SpyInstance;\n getWitchUsesPotionsGamePlaySourceInteractions: jest.SpyInstance;\n getWitchGamePlaySourceInteractions: jest.SpyInstance;\n getBigBadWolfEatGamePlaySourceInteractions: jest.SpyInstance;\n getBigBadWolfGamePlaySourceInteractions: jest.SpyInstance;\n getFoxSniffsGamePlaySourceInteractions: jest.SpyInstance;\n getFoxGamePlaySourceInteractions: jest.SpyInstance;\n getDefenderProtectsGamePlaySourceInteractions: jest.SpyInstance;\n getDefenderGamePlaySourceInteractions: jest.SpyInstance;\n getHunterShootsGamePlaySourceInteractions: jest.SpyInstance;\n getHunterGamePlaySourceInteractions: jest.SpyInstance;\n getLoversMeetEachOtherGamePlaySourceInteractions: jest.SpyInstance;\n getLoversGamePlaySourceInteractions: jest.SpyInstance;\n getPiedPiperCharmsGamePlaySourceInteractions: jest.SpyInstance;\n getPiedPiperGamePlaySourceInteractions: jest.SpyInstance;\n getScandalmongerMarksGamePlaySourceInteractions: jest.SpyInstance;\n getScandalmongerGamePlaySourceInteractions: jest.SpyInstance;\n getScapegoatBansVotingGamePlaySourceInteractions: jest.SpyInstance;\n getScapegoatGamePlaySourceInteractions: jest.SpyInstance;\n getSeerLooksGamePlaySourceInteractions: jest.SpyInstance;\n getSeerGamePlaySourceInteractions: jest.SpyInstance;\n getThiefChoosesCardGamePlaySourceInteractions: jest.SpyInstance;\n getThiefGamePlaySourceInteractions: jest.SpyInstance;\n getThreeBrothersMeetEachOtherGamePlaySourceInteractions: jest.SpyInstance;\n getThreeBrothersGamePlaySourceInteractions: jest.SpyInstance;\n getTwoSistersMeetEachOtherGamePlaySourceInteractions: jest.SpyInstance;\n getTwoSistersGamePlaySourceInteractions: jest.SpyInstance;\n getWildChildChoosesModelGamePlaySourceInteractions: jest.SpyInstance;\n getWildChildGamePlaySourceInteractions: jest.SpyInstance;\n getCharmedMeetEachOtherGamePlaySourceInteractions: jest.SpyInstance;\n getCharmedGamePlaySourceInteractions: jest.SpyInstance;\n canSurvivorsSkipGamePlay: jest.SpyInstance;\n getSurvivorsBuryDeadBodiesGamePlaySourceDevotedServantInteraction: jest.SpyInstance;\n getSurvivorsBuryDeadBodiesGamePlaySourceInteractions: jest.SpyInstance;\n getWitchGamePlaySourceGiveLifePotionInteraction: jest.SpyInstance;\n getWitchGamePlaySourceGiveDeathPotionInteraction: jest.SpyInstance;\n getCupidGamePlaySourceInteractions: jest.SpyInstance;\n getAccursedWolfFatherGamePlaySourceInteractions: jest.SpyInstance;\n canBigBadWolfSkipGamePlay: jest.SpyInstance;\n canThiefSkipGamePlay: jest.SpyInstance;\n canCupidSkipGamePlay: jest.SpyInstance;\n };\n gameHelper: {\n getEligibleWerewolvesTargets: jest.SpyInstance;\n getEligibleBigBadWolfTargets: jest.SpyInstance;\n getEligibleWhiteWerewolfTargets: jest.SpyInstance;\n getEligiblePiedPiperTargets: jest.SpyInstance;\n getEligibleCupidTargets: jest.SpyInstance;\n getAllowedToVotePlayers: jest.SpyInstance;\n };\n gameHistoryRecordService: {\n getLastGameHistoryTieInVotesRecord: jest.SpyInstance;\n getLastGameHistoryDefenderProtectsRecord: jest.SpyInstance;\n getGameHistoryWitchUsesSpecificPotionRecords: jest.SpyInstance;\n getPreviousGameHistoryRecord: jest.SpyInstance;\n getGameHistoryAccursedWolfFatherInfectsWithTargetRecords: jest.SpyInstance;\n };\n unexpectedExceptionFactory: {\n createCantFindPlayerWithCurrentRoleUnexpectedException: jest.SpyInstance;\n createCantFindLastNominatedPlayersUnexpectedException: jest.SpyInstance;\n createMalformedCurrentGamePlayUnexpectedException: jest.SpyInstance;\n createNoCurrentGamePlayUnexpectedException: jest.SpyInstance;\n createCantFindLastDeadPlayersUnexpectedException: jest.SpyInstance;\n };\n };\n\n beforeEach(async() => {\n mocks = {\n gamePlayAugmenterService: {\n canGamePlayBeSkipped: jest.fn(),\n getGamePlaySourceInteractions: jest.fn(),\n getExpectedPlayersToPlay: jest.fn(),\n getSheriffSettlesVotesGamePlaySourceInteractions: jest.fn(),\n getSheriffDelegatesGamePlaySourceInteractions: jest.fn(),\n getSheriffGamePlaySourceInteractions: jest.fn(),\n getSurvivorsVoteGamePlaySourceInteractionEligibleTargets: jest.fn(),\n getSurvivorsBuryDeadBodiesGamePlaySourceDevotedServantInteraction: jest.fn(),\n getSurvivorsVoteGamePlaySourceInteractions: jest.fn(),\n getSurvivorsElectSheriffGamePlaySourceInteractions: jest.fn(),\n getSurvivorsGamePlaySourceInteractions: jest.fn(),\n getWerewolvesEatGamePlaySourceInteractions: jest.fn(),\n getWerewolvesGamePlaySourceInteractions: jest.fn(),\n getWhiteWerewolfEatGamePlaySourceInteractions: jest.fn(),\n getWhiteWerewolfGamePlaySourceInteractions: jest.fn(),\n getWitchUsesPotionsGamePlaySourceInteractions: jest.fn(),\n getWitchGamePlaySourceInteractions: jest.fn(),\n getBigBadWolfEatGamePlaySourceInteractions: jest.fn(),\n getBigBadWolfGamePlaySourceInteractions: jest.fn(),\n getFoxSniffsGamePlaySourceInteractions: jest.fn(),\n getFoxGamePlaySourceInteractions: jest.fn(),\n getDefenderProtectsGamePlaySourceInteractions: jest.fn(),\n getDefenderGamePlaySourceInteractions: jest.fn(),\n getHunterShootsGamePlaySourceInteractions: jest.fn(),\n getHunterGamePlaySourceInteractions: jest.fn(),\n getLoversMeetEachOtherGamePlaySourceInteractions: jest.fn(),\n getLoversGamePlaySourceInteractions: jest.fn(),\n getPiedPiperCharmsGamePlaySourceInteractions: jest.fn(),\n getPiedPiperGamePlaySourceInteractions: jest.fn(),\n getScandalmongerMarksGamePlaySourceInteractions: jest.fn(),\n getScandalmongerGamePlaySourceInteractions: jest.fn(),\n getScapegoatBansVotingGamePlaySourceInteractions: jest.fn(),\n getScapegoatGamePlaySourceInteractions: jest.fn(),\n getSeerLooksGamePlaySourceInteractions: jest.fn(),\n getSeerGamePlaySourceInteractions: jest.fn(),\n getThiefChoosesCardGamePlaySourceInteractions: jest.fn(),\n getThiefGamePlaySourceInteractions: jest.fn(),\n getThreeBrothersMeetEachOtherGamePlaySourceInteractions: jest.fn(),\n getThreeBrothersGamePlaySourceInteractions: jest.fn(),\n getTwoSistersMeetEachOtherGamePlaySourceInteractions: jest.fn(),\n getTwoSistersGamePlaySourceInteractions: jest.fn(),\n getWildChildChoosesModelGamePlaySourceInteractions: jest.fn(),\n getWildChildGamePlaySourceInteractions: jest.fn(),\n getCharmedMeetEachOtherGamePlaySourceInteractions: jest.fn(),\n getCharmedGamePlaySourceInteractions: jest.fn(),\n getSurvivorsBuryDeadBodiesGamePlaySourceInteractions: jest.fn(),\n canSurvivorsSkipGamePlay: jest.fn(),\n getWitchGamePlaySourceGiveDeathPotionInteraction: jest.fn(),\n getWitchGamePlaySourceGiveLifePotionInteraction: jest.fn(),\n getAccursedWolfFatherGamePlaySourceInteractions: jest.fn(),\n getCupidGamePlaySourceInteractions: jest.fn(),\n canBigBadWolfSkipGamePlay: jest.fn(),\n canThiefSkipGamePlay: jest.fn(),\n canCupidSkipGamePlay: jest.fn(),\n },\n gameHelper: {\n getEligibleWerewolvesTargets: jest.spyOn(GameHelper, \"getEligibleWerewolvesTargets\"),\n getEligibleBigBadWolfTargets: jest.spyOn(GameHelper, \"getEligibleBigBadWolfTargets\"),\n getEligibleWhiteWerewolfTargets: jest.spyOn(GameHelper, \"getEligibleWhiteWerewolfTargets\"),\n getEligiblePiedPiperTargets: jest.spyOn(GameHelper, \"getEligiblePiedPiperTargets\"),\n getEligibleCupidTargets: jest.spyOn(GameHelper, \"getEligibleCupidTargets\"),\n getAllowedToVotePlayers: jest.spyOn(GameHelper, \"getAllowedToVotePlayers\"),\n },\n gameHistoryRecordService: {\n getLastGameHistoryTieInVotesRecord: jest.fn(),\n getLastGameHistoryDefenderProtectsRecord: jest.fn(),\n getGameHistoryWitchUsesSpecificPotionRecords: jest.fn(),\n getPreviousGameHistoryRecord: jest.fn(),\n getGameHistoryAccursedWolfFatherInfectsWithTargetRecords: jest.fn(),\n },\n unexpectedExceptionFactory: {\n createCantFindPlayerWithCurrentRoleUnexpectedException: jest.spyOn(UnexpectedExceptionFactory, \"createCantFindPlayerWithCurrentRoleUnexpectedException\"),\n createCantFindLastNominatedPlayersUnexpectedException: jest.spyOn(UnexpectedExceptionFactory, \"createCantFindLastNominatedPlayersUnexpectedException\"),\n createMalformedCurrentGamePlayUnexpectedException: jest.spyOn(UnexpectedExceptionFactory, \"createMalformedCurrentGamePlayUnexpectedException\"),\n createNoCurrentGamePlayUnexpectedException: jest.spyOn(UnexpectedExceptionFactory, \"createNoCurrentGamePlayUnexpectedException\"),\n createCantFindLastDeadPlayersUnexpectedException: jest.spyOn(UnexpectedExceptionFactory, \"createCantFindLastDeadPlayersUnexpectedException\"),\n },\n };\n const module: TestingModule = await Test.createTestingModule({\n providers: [\n {\n provide: GameHistoryRecordService,\n useValue: mocks.gameHistoryRecordService,\n },\n GamePlayAugmenterService,\n ],\n }).compile();\n\n services = { gamePlayAugmenter: module.get(GamePlayAugmenterService) };\n });\n\n describe(\"setGamePlayCanBeSkipped\", () => {\n beforeEach(() => {\n mocks.gamePlayAugmenterService.canGamePlayBeSkipped = jest.spyOn(services.gamePlayAugmenter as unknown as { canGamePlayBeSkipped }, \"canGamePlayBeSkipped\");\n });\n\n it(\"should return game play with canBeSkipped when called.\", () => {\n const gamePlay = createFakeGamePlay();\n const game = createFakeGame();\n mocks.gamePlayAugmenterService.canGamePlayBeSkipped.mockReturnValueOnce(true);\n const expectedGamePlay = createFakeGamePlay({\n ...gamePlay,\n canBeSkipped: true,\n });\n\n expect(services.gamePlayAugmenter.setGamePlayCanBeSkipped(gamePlay, game)).toStrictEqual(expectedGamePlay);\n });\n });\n\n describe(\"setGamePlaySourceInteractions\", () => {\n beforeEach(() => {\n mocks.gamePlayAugmenterService.getGamePlaySourceInteractions = jest.spyOn(services.gamePlayAugmenter as unknown as { getGamePlaySourceInteractions }, \"getGamePlaySourceInteractions\");\n });\n\n it(\"should return game play with source interactions when called.\", async() => {\n const gamePlay = createFakeGamePlay();\n const game = createFakeGame();\n const expectedInteractions = [\n createFakeGamePlaySourceInteraction(),\n createFakeGamePlaySourceInteraction(),\n createFakeGamePlaySourceInteraction(),\n ];\n const expectedGamePlay = createFakeGamePlay({\n ...gamePlay,\n source: createFakeGamePlaySource({\n ...gamePlay.source,\n interactions: expectedInteractions,\n }),\n });\n mocks.gamePlayAugmenterService.getGamePlaySourceInteractions.mockResolvedValueOnce(expectedInteractions);\n\n await expect(services.gamePlayAugmenter.setGamePlaySourceInteractions(gamePlay, game)).resolves.toStrictEqual(expectedGamePlay);\n });\n });\n\n describe(\"setGamePlaySourcePlayers\", () => {\n beforeEach(() => {\n mocks.gamePlayAugmenterService.getExpectedPlayersToPlay = jest.spyOn(services.gamePlayAugmenter as unknown as { getExpectedPlayersToPlay }, \"getExpectedPlayersToPlay\");\n });\n\n it(\"should return game play with source players when called.\", () => {\n const gamePlay = createFakeGamePlay();\n const game = createFakeGame();\n const expectedGamePlaySourcePlayers = [createFakePlayer()];\n const expectedGamePlay = createFakeGamePlay({\n ...gamePlay,\n source: createFakeGamePlaySource({\n ...gamePlay.source,\n players: expectedGamePlaySourcePlayers,\n }),\n });\n mocks.gamePlayAugmenterService.getExpectedPlayersToPlay.mockReturnValue(expectedGamePlaySourcePlayers);\n\n expect(services.gamePlayAugmenter.setGamePlaySourcePlayers(gamePlay, game)).toStrictEqual(expectedGamePlay);\n });\n });\n\n describe(\"getSheriffSettlesVotesGamePlaySourceInteractions\", () => {\n beforeEach(() => {\n mocks.gameHistoryRecordService.getLastGameHistoryTieInVotesRecord.mockResolvedValue([]);\n });\n\n it(\"should throw error when there is no last tie in votes record.\", async() => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const mockedError = new UnexpectedException(\"error\", UnexpectedExceptionReasons.CANT_FIND_LAST_NOMINATED_PLAYERS, { gameId: game._id.toString() });\n mocks.gameHistoryRecordService.getLastGameHistoryTieInVotesRecord.mockResolvedValueOnce(null);\n mocks.unexpectedExceptionFactory.createCantFindLastNominatedPlayersUnexpectedException.mockReturnValue(mockedError);\n\n await expect(services.gamePlayAugmenter[\"getSheriffSettlesVotesGamePlaySourceInteractions\"](game)).rejects.toStrictEqual(mockedError);\n expect(mocks.unexpectedExceptionFactory.createCantFindLastNominatedPlayersUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"getSheriffSettlesVotesGamePlaySourceInteractions\", { gameId: game._id });\n });\n\n it(\"should throw error when there are not nominated players in last tie in votes record.\", async() => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const gameHistoryRecordPlayVoting = createFakeGameHistoryRecordPlayVoting({ nominatedPlayers: [] });\n const gameHistoryRecord = createFakeGameHistoryRecord({ play: createFakeGameHistoryRecordPlay({ voting: gameHistoryRecordPlayVoting }) });\n const mockedError = new UnexpectedException(\"error\", UnexpectedExceptionReasons.CANT_FIND_LAST_NOMINATED_PLAYERS, { gameId: game._id.toString() });\n mocks.gameHistoryRecordService.getLastGameHistoryTieInVotesRecord.mockResolvedValueOnce(gameHistoryRecord);\n mocks.unexpectedExceptionFactory.createCantFindLastNominatedPlayersUnexpectedException.mockReturnValue(mockedError);\n\n await expect(services.gamePlayAugmenter[\"getSheriffSettlesVotesGamePlaySourceInteractions\"](game)).rejects.toStrictEqual(mockedError);\n expect(mocks.unexpectedExceptionFactory.createCantFindLastNominatedPlayersUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"getSheriffSettlesVotesGamePlaySourceInteractions\", { gameId: game._id });\n });\n\n it(\"should return all nominated players with 1 to 1 boundaries when there are nominated players in last tie in votes record.\", async() => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const gameHistoryRecord = createFakeGameHistoryRecord({\n play: createFakeGameHistoryRecordPlay({\n voting: createFakeGameHistoryRecordPlayVoting({\n nominatedPlayers: [\n players[0],\n players[1],\n ],\n }),\n }),\n });\n mocks.gameHistoryRecordService.getLastGameHistoryTieInVotesRecord.mockResolvedValueOnce(gameHistoryRecord);\n const expectedInteraction = createFakeGamePlaySourceInteraction({\n source: \"sheriff\",\n type: \"sentence-to-death\",\n eligibleTargets: [players[0], players[1]],\n boundaries: {\n min: 1,\n max: 1,\n },\n });\n\n await expect(services.gamePlayAugmenter[\"getSheriffSettlesVotesGamePlaySourceInteractions\"](game)).resolves.toStrictEqual([expectedInteraction]);\n });\n });\n\n describe(\"getSheriffDelegatesGamePlaySourceInteractions\", () => {\n it(\"should return all alive and not sheriff players as eligible targets with 1 to 1 targets boundaries when called.\", () => {\n const players = [\n createFakeAngelAlivePlayer(),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeSheriffBySurvivorsPlayerAttribute()] }),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWitchAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"sheriff\",\n type: \"transfer-sheriff-role\",\n eligibleTargets: [players[0], players[3]],\n boundaries: {\n min: 1,\n max: 1,\n },\n });\n\n expect(services.gamePlayAugmenter[\"getSheriffDelegatesGamePlaySourceInteractions\"](game)).toStrictEqual([expectedGamePlaySourceInteraction]);\n });\n });\n\n describe(\"getSheriffGamePlaySourceInteractions\", () => {\n beforeEach(() => {\n mocks.gamePlayAugmenterService.getSheriffSettlesVotesGamePlaySourceInteractions = jest.spyOn(services.gamePlayAugmenter as unknown as { getSheriffSettlesVotesGamePlaySourceInteractions }, \"getSheriffSettlesVotesGamePlaySourceInteractions\").mockImplementation();\n mocks.gamePlayAugmenterService.getSheriffDelegatesGamePlaySourceInteractions = jest.spyOn(services.gamePlayAugmenter as unknown as { getSheriffDelegatesGamePlaySourceInteractions }, \"getSheriffDelegatesGamePlaySourceInteractions\").mockImplementation();\n });\n\n it(\"should call get sheriff delegates game play source interactions when game play action is delegate.\", async() => {\n const gamePlay = createFakeGamePlaySheriffDelegates();\n const game = createFakeGame();\n await services.gamePlayAugmenter[\"getSheriffGamePlaySourceInteractions\"](game, gamePlay);\n\n expect(mocks.gamePlayAugmenterService.getSheriffDelegatesGamePlaySourceInteractions).toHaveBeenCalledExactlyOnceWith(game);\n expect(mocks.gamePlayAugmenterService.getSheriffSettlesVotesGamePlaySourceInteractions).not.toHaveBeenCalled();\n });\n\n it(\"should call get sheriff settles votes game play source interactions when game play action is settles votes.\", async() => {\n const gamePlay = createFakeGamePlaySheriffSettlesVotes();\n const game = createFakeGame();\n await services.gamePlayAugmenter[\"getSheriffGamePlaySourceInteractions\"](game, gamePlay);\n\n expect(mocks.gamePlayAugmenterService.getSheriffSettlesVotesGamePlaySourceInteractions).toHaveBeenCalledExactlyOnceWith(game);\n expect(mocks.gamePlayAugmenterService.getSheriffDelegatesGamePlaySourceInteractions).not.toHaveBeenCalled();\n });\n\n it(\"should throw error when game play action is not delegate nor settles votes.\", async() => {\n const gamePlay = createFakeGamePlayScandalmongerMarks();\n const game = createFakeGame();\n const mockedError = new UnexpectedException(\"error\", UnexpectedExceptionReasons.MALFORMED_CURRENT_GAME_PLAY, { gamePlayAction: gamePlay.action });\n mocks.unexpectedExceptionFactory.createMalformedCurrentGamePlayUnexpectedException.mockReturnValue(mockedError);\n\n await expect(services.gamePlayAugmenter[\"getSheriffGamePlaySourceInteractions\"](game, gamePlay)).rejects.toThrow(mockedError);\n expect(mocks.unexpectedExceptionFactory.createMalformedCurrentGamePlayUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"getSheriffGamePlaySourceInteractions\", gamePlay, game._id);\n });\n });\n\n describe(\"getSurvivorsVoteGamePlaySourceInteractionEligibleTargets\", () => {\n it(\"should return all alive players when votes are not cause of previous tie in votes.\", async() => {\n const players = [\n createFakeAngelAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWitchAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const gamePlay = createFakeGamePlaySurvivorsVote({ causes: [\"angel-presence\"] });\n const expectedPlayers = [\n createFakePlayer(players[0]),\n createFakePlayer(players[1]),\n createFakePlayer(players[3]),\n ];\n\n await expect(services.gamePlayAugmenter[\"getSurvivorsVoteGamePlaySourceInteractionEligibleTargets\"](game, gamePlay)).resolves.toStrictEqual(expectedPlayers);\n });\n\n it(\"should return nominated players when votes are cause of previous tie in votes.\", async() => {\n const players = [\n createFakeAngelAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWitchAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const gamePlay = createFakeGamePlaySurvivorsVote({ causes: [\"previous-votes-were-in-ties\"] });\n const gameHistoryRecordPlayVoting = createFakeGameHistoryRecordPlayVoting({ nominatedPlayers: [players[0], players[1]] });\n const gameHistoryRecord = createFakeGameHistoryRecord({ play: createFakeGameHistoryRecordPlay({ voting: gameHistoryRecordPlayVoting }) });\n mocks.gameHistoryRecordService.getLastGameHistoryTieInVotesRecord.mockResolvedValueOnce(gameHistoryRecord);\n const expectedPlayers = [\n createFakePlayer(players[0]),\n createFakePlayer(players[1]),\n ];\n\n await expect(services.gamePlayAugmenter[\"getSurvivorsVoteGamePlaySourceInteractionEligibleTargets\"](game, gamePlay)).resolves.toStrictEqual(expectedPlayers);\n });\n\n it(\"should throw error when there is no last tie in votes record.\", async() => {\n const players = [\n createFakeAngelAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWitchAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const gamePlay = createFakeGamePlaySurvivorsVote({ causes: [\"previous-votes-were-in-ties\"] });\n const mockedError = new UnexpectedException(\"error\", UnexpectedExceptionReasons.CANT_FIND_LAST_NOMINATED_PLAYERS, { gameId: game._id.toString() });\n mocks.gameHistoryRecordService.getLastGameHistoryTieInVotesRecord.mockResolvedValueOnce(null);\n mocks.unexpectedExceptionFactory.createCantFindLastNominatedPlayersUnexpectedException.mockReturnValue(mockedError);\n\n await expect(async() => services.gamePlayAugmenter[\"getSurvivorsVoteGamePlaySourceInteractionEligibleTargets\"](game, gamePlay)).rejects.toStrictEqual(mockedError);\n expect(mocks.unexpectedExceptionFactory.createCantFindLastNominatedPlayersUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"getSurvivorsVoteGamePlaySourceInteractionEligibleTargets\", { gameId: game._id });\n });\n\n it(\"should throw error when there is no nominated players in last tie in votes record.\", async() => {\n const players = [\n createFakeAngelAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWitchAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const gamePlay = createFakeGamePlaySurvivorsVote({ causes: [\"previous-votes-were-in-ties\"] });\n const gameRecordPlayVoting = createFakeGameHistoryRecordPlayVoting({ nominatedPlayers: [] });\n const mockedError = new UnexpectedException(\"error\", UnexpectedExceptionReasons.CANT_FIND_LAST_NOMINATED_PLAYERS, { gameId: game._id.toString() });\n mocks.gameHistoryRecordService.getLastGameHistoryTieInVotesRecord.mockResolvedValueOnce(createFakeGameHistoryRecord({ play: createFakeGameHistoryRecordPlay({ voting: gameRecordPlayVoting }) }));\n mocks.unexpectedExceptionFactory.createCantFindLastNominatedPlayersUnexpectedException.mockReturnValue(mockedError);\n\n await expect(async() => services.gamePlayAugmenter[\"getSurvivorsVoteGamePlaySourceInteractionEligibleTargets\"](game, gamePlay)).rejects.toStrictEqual(mockedError);\n expect(mocks.unexpectedExceptionFactory.createCantFindLastNominatedPlayersUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"getSurvivorsVoteGamePlaySourceInteractionEligibleTargets\", { gameId: game._id });\n });\n });\n\n describe(\"getSurvivorsVoteGamePlaySourceInteractions\", () => {\n beforeEach(() => {\n mocks.gameHelper.getAllowedToVotePlayers.mockReturnValue([]);\n mocks.gamePlayAugmenterService.canSurvivorsSkipGamePlay = jest.spyOn(services.gamePlayAugmenter as unknown as { canSurvivorsSkipGamePlay }, \"canSurvivorsSkipGamePlay\").mockImplementation();\n mocks.gamePlayAugmenterService.getSurvivorsVoteGamePlaySourceInteractionEligibleTargets = jest.spyOn(services.gamePlayAugmenter as unknown as { getSurvivorsVoteGamePlaySourceInteractionEligibleTargets }, \"getSurvivorsVoteGamePlaySourceInteractionEligibleTargets\").mockImplementation();\n });\n\n it(\"should return no players as eligible targets with 1 to alive players length when votes can't be skipped.\", async() => {\n const players = [\n createFakeAngelAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWitchAlivePlayer(),\n ];\n const gamePlay = createFakeGamePlaySurvivorsVote({ canBeSkipped: false });\n const game = createFakeGame({ players });\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"survivors\",\n type: \"vote\",\n eligibleTargets: [],\n boundaries: {\n min: 1,\n max: 3,\n },\n });\n mocks.gameHelper.getAllowedToVotePlayers.mockReturnValueOnce([players[0], players[1], players[3]]);\n mocks.gamePlayAugmenterService.canSurvivorsSkipGamePlay.mockReturnValueOnce(false);\n mocks.gamePlayAugmenterService.getSurvivorsVoteGamePlaySourceInteractionEligibleTargets.mockResolvedValueOnce([]);\n\n await expect(services.gamePlayAugmenter[\"getSurvivorsVoteGamePlaySourceInteractions\"](game, gamePlay)).resolves.toStrictEqual([expectedGamePlaySourceInteraction]);\n });\n\n it(\"should return alive players as eligible targets with boundaries from 0 to alive players length when votes can be skipped.\", async() => {\n const players = [\n createFakeAngelAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWitchAlivePlayer(),\n ];\n const gamePlay = createFakeGamePlaySurvivorsVote({ canBeSkipped: true });\n const game = createFakeGame({ players });\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"survivors\",\n type: \"vote\",\n eligibleTargets: [],\n boundaries: {\n min: 0,\n max: 3,\n },\n });\n mocks.gameHelper.getAllowedToVotePlayers.mockReturnValueOnce([players[0], players[1], players[3]]);\n mocks.gamePlayAugmenterService.canSurvivorsSkipGamePlay.mockReturnValueOnce(true);\n mocks.gamePlayAugmenterService.getSurvivorsVoteGamePlaySourceInteractionEligibleTargets.mockResolvedValueOnce([]);\n\n await expect(services.gamePlayAugmenter[\"getSurvivorsVoteGamePlaySourceInteractions\"](game, gamePlay)).resolves.toStrictEqual([expectedGamePlaySourceInteraction]);\n });\n });\n\n describe(\"getSurvivorsElectSheriffGamePlaySourceInteractions\", () => {\n it(\"should return alive players as eligible targets with boundaries from 1 to 1 when called.\", async() => {\n const players = [\n createFakeAngelAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWitchAlivePlayer(),\n ];\n const gamePlay = createFakeGamePlaySurvivorsElectSheriff();\n const game = createFakeGame({ players });\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"survivors\",\n type: \"choose-as-sheriff\",\n eligibleTargets: [players[0], players[1], players[3]],\n boundaries: {\n min: 1,\n max: 3,\n },\n });\n\n await expect(services.gamePlayAugmenter[\"getSurvivorsElectSheriffGamePlaySourceInteractions\"](game, gamePlay)).resolves.toStrictEqual([expectedGamePlaySourceInteraction]);\n });\n });\n\n describe(\"getSurvivorsBuryDeadBodiesGamePlaySourceDevotedServantInteraction\", () => {\n it(\"should return undefined when there is no devoted servant in the game.\", () => {\n const players = [\n createFakeAngelAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWitchAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const deadPlayers = [\n createFakeDeadPlayer({ ...players[0], isAlive: false, death: createFakePlayerDeath() }),\n createFakeDeadPlayer({ ...players[1], isAlive: false, death: createFakePlayerDeath() }),\n ];\n\n expect(services.gamePlayAugmenter[\"getSurvivorsBuryDeadBodiesGamePlaySourceDevotedServantInteraction\"](game, deadPlayers)).toBeUndefined();\n });\n\n it(\"should return undefined when devoted servant is dead.\", () => {\n const players = [\n createFakeAngelAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeDevotedServantAlivePlayer({ isAlive: false }),\n ];\n const game = createFakeGame({ players });\n const deadPlayers = [\n createFakeDeadPlayer({ ...players[0], isAlive: false, death: createFakePlayerDeath() }),\n createFakeDeadPlayer({ ...players[1], isAlive: false, death: createFakePlayerDeath() }),\n ];\n\n expect(services.gamePlayAugmenter[\"getSurvivorsBuryDeadBodiesGamePlaySourceDevotedServantInteraction\"](game, deadPlayers)).toBeUndefined();\n });\n\n it(\"should return undefined when devoted servant is powerless.\", () => {\n const players = [\n createFakeAngelAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeDevotedServantAlivePlayer({ attributes: [createFakePowerlessByElderPlayerAttribute()] }),\n ];\n const game = createFakeGame({ players });\n const deadPlayers = [\n createFakeDeadPlayer({ ...players[0], isAlive: false, death: createFakePlayerDeath() }),\n createFakeDeadPlayer({ ...players[1], isAlive: false, death: createFakePlayerDeath() }),\n ];\n\n expect(services.gamePlayAugmenter[\"getSurvivorsBuryDeadBodiesGamePlaySourceDevotedServantInteraction\"](game, deadPlayers)).toBeUndefined();\n });\n\n it(\"should return undefined when devoted servant is in love.\", () => {\n const players = [\n createFakeAngelAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeDevotedServantAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n ];\n const game = createFakeGame({ players });\n const deadPlayers = [\n createFakeDeadPlayer({ ...players[0], isAlive: false, death: createFakePlayerDeath() }),\n createFakeDeadPlayer({ ...players[1], isAlive: false, death: createFakePlayerDeath() }),\n ];\n\n expect(services.gamePlayAugmenter[\"getSurvivorsBuryDeadBodiesGamePlaySourceDevotedServantInteraction\"](game, deadPlayers)).toBeUndefined();\n });\n\n it(\"should return interaction for devoted servant with dead players as eligible targets with boundaries from 0 to 1 when called.\", () => {\n const players = [\n createFakeAngelAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeDevotedServantAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const deadPlayers = [\n createFakeDeadPlayer({ ...players[0], isAlive: false, death: createFakePlayerDeath() }),\n createFakeDeadPlayer({ ...players[1], isAlive: false, death: createFakePlayerDeath() }),\n ];\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"devoted-servant\",\n type: \"steal-role\",\n eligibleTargets: [deadPlayers[0], deadPlayers[1]],\n boundaries: {\n min: 0,\n max: 1,\n },\n });\n\n expect(services.gamePlayAugmenter[\"getSurvivorsBuryDeadBodiesGamePlaySourceDevotedServantInteraction\"](game, deadPlayers)).toStrictEqual(expectedGamePlaySourceInteraction);\n });\n });\n\n describe(\"getSurvivorsBuryDeadBodiesGamePlaySourceInteractions\", () => {\n beforeEach(() => {\n mocks.gamePlayAugmenterService.getSurvivorsBuryDeadBodiesGamePlaySourceDevotedServantInteraction = jest.spyOn(services.gamePlayAugmenter as unknown as { getSurvivorsBuryDeadBodiesGamePlaySourceDevotedServantInteraction }, \"getSurvivorsBuryDeadBodiesGamePlaySourceDevotedServantInteraction\").mockImplementation();\n });\n\n it(\"should throw error when there is no previous game history record.\", async() => {\n const players = [\n createFakeAngelAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeDevotedServantAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const mockedError = new UnexpectedException(\"error\", UnexpectedExceptionReasons.CANT_FIND_LAST_DEAD_PLAYERS, { gameId: game._id.toString() });\n mocks.gameHistoryRecordService.getPreviousGameHistoryRecord.mockResolvedValueOnce(null);\n mocks.unexpectedExceptionFactory.createCantFindLastDeadPlayersUnexpectedException.mockReturnValue(mockedError);\n\n await expect(services.gamePlayAugmenter[\"getSurvivorsBuryDeadBodiesGamePlaySourceInteractions\"](game)).rejects.toStrictEqual(mockedError);\n expect(mocks.unexpectedExceptionFactory.createCantFindLastDeadPlayersUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"getSurvivorsBuryDeadBodiesGamePlaySourceInteractions\", { gameId: game._id });\n });\n\n it(\"should throw error when dead players are undefined in previous game history record.\", async() => {\n const players = [\n createFakeAngelAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeDevotedServantAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const gameHistoryRecord = createFakeGameHistoryRecord({ deadPlayers: undefined });\n const mockedError = new UnexpectedException(\"error\", UnexpectedExceptionReasons.CANT_FIND_LAST_DEAD_PLAYERS, { gameId: game._id.toString() });\n mocks.gameHistoryRecordService.getPreviousGameHistoryRecord.mockResolvedValueOnce(gameHistoryRecord);\n mocks.unexpectedExceptionFactory.createCantFindLastDeadPlayersUnexpectedException.mockReturnValue(mockedError);\n\n await expect(services.gamePlayAugmenter[\"getSurvivorsBuryDeadBodiesGamePlaySourceInteractions\"](game)).rejects.toStrictEqual(mockedError);\n expect(mocks.unexpectedExceptionFactory.createCantFindLastDeadPlayersUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"getSurvivorsBuryDeadBodiesGamePlaySourceInteractions\", { gameId: game._id });\n });\n\n it(\"should throw error when dead players are empty in previous game history record.\", async() => {\n const players = [\n createFakeAngelAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeDevotedServantAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const gameHistoryRecord = createFakeGameHistoryRecord({ deadPlayers: [] });\n const mockedError = new UnexpectedException(\"error\", UnexpectedExceptionReasons.CANT_FIND_LAST_DEAD_PLAYERS, { gameId: game._id.toString() });\n mocks.gameHistoryRecordService.getPreviousGameHistoryRecord.mockResolvedValueOnce(gameHistoryRecord);\n mocks.unexpectedExceptionFactory.createCantFindLastDeadPlayersUnexpectedException.mockReturnValue(mockedError);\n\n await expect(services.gamePlayAugmenter[\"getSurvivorsBuryDeadBodiesGamePlaySourceInteractions\"](game)).rejects.toStrictEqual(mockedError);\n expect(mocks.unexpectedExceptionFactory.createCantFindLastDeadPlayersUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"getSurvivorsBuryDeadBodiesGamePlaySourceInteractions\", { gameId: game._id });\n });\n\n it(\"should return inconsequential survivors bury dead bodies game play source interaction when called.\", async() => {\n const players = [\n createFakeAngelAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeDevotedServantAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const deadPlayers = [\n createFakeDeadPlayer({ ...players[0], isAlive: false, death: createFakePlayerDeath() }),\n createFakeDeadPlayer({ ...players[1], isAlive: false, death: createFakePlayerDeath() }),\n ];\n const gameHistoryRecord = createFakeGameHistoryRecord({ deadPlayers });\n mocks.gameHistoryRecordService.getPreviousGameHistoryRecord.mockResolvedValueOnce(gameHistoryRecord);\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"survivors\",\n type: \"bury\",\n eligibleTargets: deadPlayers,\n boundaries: {\n min: 0,\n max: 2,\n },\n isInconsequential: true,\n });\n\n await expect(services.gamePlayAugmenter[\"getSurvivorsBuryDeadBodiesGamePlaySourceInteractions\"](game)).resolves.toStrictEqual([expectedGamePlaySourceInteraction]);\n });\n\n it(\"should return devoted servant steals role game play source interaction plus bury interactions when there is devoted servant interaction.\", async() => {\n const players = [\n createFakeAngelAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeDevotedServantAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const deadPlayers = [\n createFakeDeadPlayer({ ...players[0], isAlive: false, death: createFakePlayerDeath() }),\n createFakeDeadPlayer({ ...players[1], isAlive: false, death: createFakePlayerDeath() }),\n ];\n const gameHistoryRecord = createFakeGameHistoryRecord({ deadPlayers });\n mocks.gameHistoryRecordService.getPreviousGameHistoryRecord.mockResolvedValueOnce(gameHistoryRecord);\n const expectedGamePlaySourceInteractionStealRole = createFakeGamePlaySourceInteraction({\n source: \"devoted-servant\",\n type: \"steal-role\",\n eligibleTargets: deadPlayers,\n boundaries: {\n min: 0,\n max: 1,\n },\n });\n mocks.gamePlayAugmenterService.getSurvivorsBuryDeadBodiesGamePlaySourceDevotedServantInteraction.mockReturnValueOnce(expectedGamePlaySourceInteractionStealRole);\n const expectedGamePlaySourceInteractionBury = createFakeGamePlaySourceInteraction({\n source: \"survivors\",\n type: \"bury\",\n eligibleTargets: deadPlayers,\n boundaries: {\n min: 0,\n max: 2,\n },\n isInconsequential: true,\n });\n const expectedInteractions = [expectedGamePlaySourceInteractionBury, expectedGamePlaySourceInteractionStealRole];\n\n await expect(services.gamePlayAugmenter[\"getSurvivorsBuryDeadBodiesGamePlaySourceInteractions\"](game)).resolves.toStrictEqual(expectedInteractions);\n });\n });\n\n describe(\"getSurvivorsGamePlaySourceInteractions\", () => {\n beforeEach(() => {\n mocks.gamePlayAugmenterService.getSurvivorsElectSheriffGamePlaySourceInteractions = jest.spyOn(services.gamePlayAugmenter as unknown as { getSurvivorsElectSheriffGamePlaySourceInteractions }, \"getSurvivorsElectSheriffGamePlaySourceInteractions\").mockImplementation();\n mocks.gamePlayAugmenterService.getSurvivorsVoteGamePlaySourceInteractions = jest.spyOn(services.gamePlayAugmenter as unknown as { getSurvivorsVoteGamePlaySourceInteractions }, \"getSurvivorsVoteGamePlaySourceInteractions\").mockImplementation();\n mocks.gamePlayAugmenterService.getSurvivorsBuryDeadBodiesGamePlaySourceInteractions = jest.spyOn(services.gamePlayAugmenter as unknown as { getSurvivorsBuryDeadBodiesGamePlaySourceInteractions }, \"getSurvivorsBuryDeadBodiesGamePlaySourceInteractions\").mockImplementation();\n });\n\n it(\"should call get survivors bury dead bodies game play eligible targets when game play action is bury dead bodies.\", async() => {\n const gamePlay = createFakeGamePlaySurvivorsBuryDeadBodies();\n const game = createFakeGame();\n await services.gamePlayAugmenter[\"getSurvivorsGamePlaySourceInteractions\"](game, gamePlay);\n\n expect(mocks.gamePlayAugmenterService.getSurvivorsBuryDeadBodiesGamePlaySourceInteractions).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call get survivors elect sheriff game play eligible targets when game play action is elect sheriff.\", async() => {\n const gamePlay = createFakeGamePlaySurvivorsElectSheriff();\n const game = createFakeGame();\n await services.gamePlayAugmenter[\"getSurvivorsGamePlaySourceInteractions\"](game, gamePlay);\n\n expect(mocks.gamePlayAugmenterService.getSurvivorsElectSheriffGamePlaySourceInteractions).toHaveBeenCalledExactlyOnceWith(game, gamePlay);\n expect(mocks.gamePlayAugmenterService.getSurvivorsVoteGamePlaySourceInteractions).not.toHaveBeenCalled();\n });\n\n it(\"should call get survivors vote game play eligible targets when game play action is vote.\", async() => {\n const gamePlay = createFakeGamePlaySurvivorsVote();\n const game = createFakeGame();\n await services.gamePlayAugmenter[\"getSurvivorsGamePlaySourceInteractions\"](game, gamePlay);\n\n expect(mocks.gamePlayAugmenterService.getSurvivorsVoteGamePlaySourceInteractions).toHaveBeenCalledExactlyOnceWith(game, gamePlay);\n expect(mocks.gamePlayAugmenterService.getSurvivorsElectSheriffGamePlaySourceInteractions).not.toHaveBeenCalled();\n });\n\n it(\"should throw error when game play action is not elect sheriff nor vote.\", async() => {\n const gamePlay = createFakeGamePlayWildChildChoosesModel();\n const game = createFakeGame();\n const mockedError = new UnexpectedException(\"error\", UnexpectedExceptionReasons.MALFORMED_CURRENT_GAME_PLAY, { gamePlayAction: gamePlay.action });\n mocks.unexpectedExceptionFactory.createMalformedCurrentGamePlayUnexpectedException.mockReturnValue(mockedError);\n\n await expect(services.gamePlayAugmenter[\"getSurvivorsGamePlaySourceInteractions\"](game, gamePlay)).rejects.toStrictEqual(mockedError);\n expect(mocks.unexpectedExceptionFactory.createMalformedCurrentGamePlayUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"getSurvivorsGamePlaySourceInteractions\", gamePlay, game._id);\n });\n });\n\n describe(\"getWerewolvesGamePlaySourceInteractions\", () => {\n it(\"should return alive villagers sided players as eligible targets with boundaries from 1 to 1 when called.\", () => {\n const players = [\n createFakeAngelAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWitchAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"werewolves\",\n type: \"eat\",\n eligibleTargets: [players[0], players[3]],\n boundaries: {\n min: 1,\n max: 1,\n },\n });\n\n expect(services.gamePlayAugmenter[\"getWerewolvesGamePlaySourceInteractions\"](game)).toStrictEqual([expectedGamePlaySourceInteraction]);\n });\n });\n\n describe(\"getBigBadWolfGamePlaySourceInteractions\", () => {\n it(\"should return alive villagers as eligible targets with boundaries from 1 to 1 when there are still left to eat targets.\", () => {\n const players = [\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n mocks.gameHelper.getEligibleBigBadWolfTargets.mockReturnValueOnce([\n players[0],\n players[1],\n ]);\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"big-bad-wolf\",\n type: \"eat\",\n eligibleTargets: [players[0], players[1]],\n boundaries: {\n min: 1,\n max: 1,\n },\n });\n\n expect(services.gamePlayAugmenter[\"getBigBadWolfGamePlaySourceInteractions\"](game)).toStrictEqual([expectedGamePlaySourceInteraction]);\n });\n\n it(\"should return no eligible targets with target boundaries from 0 to 0 when there are no left to eat targets.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({\n players,\n options: DEFAULT_GAME_OPTIONS,\n });\n mocks.gameHelper.getEligibleBigBadWolfTargets.mockReturnValueOnce([]);\n\n expect(services.gamePlayAugmenter[\"getBigBadWolfGamePlaySourceInteractions\"](game)).toStrictEqual([]);\n });\n });\n\n describe(\"getCupidGamePlaySourceInteractions\", () => {\n it(\"should return all alive eligible targets with 2 to 2 targets boundaries when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeCupidAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ cupid: createFakeCupidGameOptions({ mustWinWithLovers: false }) }) });\n const game = createFakeGame({ players, options });\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"cupid\",\n type: \"charm\",\n eligibleTargets: [players[0], players[3]],\n boundaries: {\n min: 2,\n max: 2,\n },\n });\n\n expect(services.gamePlayAugmenter[\"getCupidGamePlaySourceInteractions\"](game)).toStrictEqual([expectedGamePlaySourceInteraction]);\n });\n\n it(\"should return all alive and not cupid eligible targets with 2 to 2 targets boundaries when game options says that cupid must win with lovers.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeCupidAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ cupid: createFakeCupidGameOptions({ mustWinWithLovers: true }) }) });\n const game = createFakeGame({ players, options });\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"cupid\",\n type: \"charm\",\n eligibleTargets: [players[0], players[1]],\n boundaries: {\n min: 2,\n max: 2,\n },\n });\n\n expect(services.gamePlayAugmenter[\"getCupidGamePlaySourceInteractions\"](game)).toStrictEqual([expectedGamePlaySourceInteraction]);\n });\n\n it(\"should return empty array when there is not enough targets for cupid.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeCupidAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ cupid: createFakeCupidGameOptions({ mustWinWithLovers: true }) }) });\n const game = createFakeGame({ players, options });\n\n expect(services.gamePlayAugmenter[\"getCupidGamePlaySourceInteractions\"](game)).toStrictEqual([]);\n });\n });\n\n describe(\"getFoxGamePlaySourceInteractions\", () => {\n it(\"should return all alive eligible targets with 0 to 1 boundaries when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"fox\",\n type: \"sniff\",\n eligibleTargets: [players[0], players[3]],\n boundaries: {\n min: 0,\n max: 1,\n },\n });\n\n expect(services.gamePlayAugmenter[\"getFoxGamePlaySourceInteractions\"](game)).toStrictEqual([expectedGamePlaySourceInteraction]);\n });\n });\n\n describe(\"getDefenderGamePlaySourceInteractions\", () => {\n it(\"should throw error when there is no defender in the game.\", async() => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const mockedError = new UnexpectedException(\"error\", UnexpectedExceptionReasons.CANT_FIND_PLAYER_WITH_CURRENT_ROLE_IN_GAME, { gameId: game._id.toString(), roleName: \"defender\" });\n mocks.unexpectedExceptionFactory.createCantFindPlayerWithCurrentRoleUnexpectedException.mockReturnValue(mockedError);\n\n await expect(services.gamePlayAugmenter[\"getDefenderGamePlaySourceInteractions\"](game)).rejects.toStrictEqual(mockedError);\n expect(mocks.unexpectedExceptionFactory.createCantFindPlayerWithCurrentRoleUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"getDefenderGamePlaySourceInteractions\", { gameId: game._id, roleName: \"defender\" });\n });\n\n it(\"should return all alive players as eligible targets with boundaries from 1 to 1 when there is no last protected players.\", async() => {\n const players = [\n createFakeDefenderAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n mocks.gameHistoryRecordService.getLastGameHistoryDefenderProtectsRecord.mockResolvedValueOnce(null);\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"defender\",\n type: \"protect\",\n eligibleTargets: [players[0], players[1], players[2], players[3]],\n boundaries: { min: 1, max: 1 },\n });\n\n await expect(services.gamePlayAugmenter[\"getDefenderGamePlaySourceInteractions\"](game)).resolves.toStrictEqual([expectedGamePlaySourceInteraction]);\n });\n\n it(\"should return all alive players as eligible targets with boundaries from 1 to 1 when there is last protected players but defender can protect twice in a row.\", async() => {\n const players = [\n createFakeDefenderAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ defender: createFakeDefenderGameOptions({ canProtectTwice: true }) }) });\n const game = createFakeGame({ players, options });\n const gameHistoryRecord = createFakeGameHistoryRecord({ play: createFakeGameHistoryRecordPlay({ targets: [{ player: players[2] }] }) });\n mocks.gameHistoryRecordService.getLastGameHistoryDefenderProtectsRecord.mockResolvedValueOnce(gameHistoryRecord);\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"defender\",\n type: \"protect\",\n eligibleTargets: [players[0], players[2], players[3]],\n boundaries: { min: 1, max: 1 },\n });\n\n await expect(services.gamePlayAugmenter[\"getDefenderGamePlaySourceInteractions\"](game)).resolves.toStrictEqual([expectedGamePlaySourceInteraction]);\n });\n\n it(\"should return all alive players but last protected player as eligible targets with boundaries from 1 to 1 when there is last protected players but defender can't protect twice in a row.\", async() => {\n const players = [\n createFakeDefenderAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ defender: createFakeDefenderGameOptions({ canProtectTwice: false }) }) });\n const game = createFakeGame({ players, options });\n const gameHistoryRecord = createFakeGameHistoryRecord({ play: createFakeGameHistoryRecordPlay({ targets: [{ player: players[2] }] }) });\n mocks.gameHistoryRecordService.getLastGameHistoryDefenderProtectsRecord.mockResolvedValueOnce(gameHistoryRecord);\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"defender\",\n type: \"protect\",\n eligibleTargets: [players[0], players[3]],\n boundaries: { min: 1, max: 1 },\n });\n\n await expect(services.gamePlayAugmenter[\"getDefenderGamePlaySourceInteractions\"](game)).resolves.toStrictEqual([expectedGamePlaySourceInteraction]);\n });\n });\n\n describe(\"getHunterGamePlaySourceInteractions\", () => {\n it(\"should return all alive players as eligible targets with boundaries from 1 to 1 when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"hunter\",\n type: \"shoot\",\n eligibleTargets: [players[0], players[1], players[3]],\n boundaries: { min: 1, max: 1 },\n });\n\n expect(services.gamePlayAugmenter[\"getHunterGamePlaySourceInteractions\"](game)).toStrictEqual([expectedGamePlaySourceInteraction]);\n });\n });\n\n describe(\"getPiedPiperGamePlaySourceInteractions\", () => {\n it(\"should return 2 eligible targets with 2 to 2 targets boundaries when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ piedPiper: createFakePiedPiperGameOptions({ charmedPeopleCountPerNight: 4 }) }) });\n const game = createFakeGame({\n players,\n options,\n });\n mocks.gameHelper.getEligiblePiedPiperTargets.mockReturnValueOnce([\n players[0],\n players[1],\n ]);\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"pied-piper\",\n type: \"charm\",\n eligibleTargets: [players[0], players[1]],\n boundaries: {\n min: 2,\n max: 2,\n },\n });\n\n expect(services.gamePlayAugmenter[\"getPiedPiperGamePlaySourceInteractions\"](game)).toStrictEqual([expectedGamePlaySourceInteraction]);\n });\n\n it(\"should return 2 eligible targets with 1 to 1 targets boundaries when game options charm count is lower than left to charm players.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ piedPiper: createFakePiedPiperGameOptions({ charmedPeopleCountPerNight: 1 }) }) });\n const game = createFakeGame({\n players,\n options,\n });\n mocks.gameHelper.getEligiblePiedPiperTargets.mockReturnValueOnce([\n players[0],\n players[1],\n ]);\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"pied-piper\",\n type: \"charm\",\n eligibleTargets: [players[0], players[1]],\n boundaries: {\n min: 1,\n max: 1,\n },\n });\n\n expect(services.gamePlayAugmenter[\"getPiedPiperGamePlaySourceInteractions\"](game)).toStrictEqual([expectedGamePlaySourceInteraction]);\n });\n });\n\n describe(\"getScandalmongerGamePlaySourceInteractions\", () => {\n it(\"should return all alive eligible targets with 0 to 1 targets boundaries when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"scandalmonger\",\n type: \"mark\",\n eligibleTargets: [players[0], players[3]],\n boundaries: {\n min: 0,\n max: 1,\n },\n });\n\n expect(services.gamePlayAugmenter[\"getScandalmongerGamePlaySourceInteractions\"](game)).toStrictEqual([expectedGamePlaySourceInteraction]);\n });\n });\n\n describe(\"getScapegoatGamePlaySourceInteractions\", () => {\n it(\"should return all alive eligible targets with 0 to alive length target boundaries when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"scapegoat\",\n type: \"ban-voting\",\n eligibleTargets: [players[0], players[3]],\n boundaries: {\n min: 0,\n max: 2,\n },\n });\n\n expect(services.gamePlayAugmenter[\"getScapegoatGamePlaySourceInteractions\"](game)).toStrictEqual([expectedGamePlaySourceInteraction]);\n });\n });\n\n describe(\"getSeerGamePlaySourceInteractions\", () => {\n it(\"should return alive players but seer as eligible targets with boundaries from 1 to 1 when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeSeerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"seer\",\n type: \"look\",\n eligibleTargets: [players[0], players[3]],\n boundaries: { min: 1, max: 1 },\n });\n\n expect(services.gamePlayAugmenter[\"getSeerGamePlaySourceInteractions\"](game)).toStrictEqual([expectedGamePlaySourceInteraction]);\n });\n });\n\n describe(\"getWhiteWerewolfGamePlaySourceInteractions\", () => {\n it(\"should return two eligible targets with 0 to 1 boundaries when there are still wolves to eat.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n mocks.gameHelper.getEligibleWhiteWerewolfTargets.mockReturnValueOnce([\n players[0],\n players[1],\n ]);\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"white-werewolf\",\n type: \"eat\",\n eligibleTargets: [players[0], players[1]],\n boundaries: {\n min: 0,\n max: 1,\n },\n });\n\n expect(services.gamePlayAugmenter[\"getWhiteWerewolfGamePlaySourceInteractions\"](game)).toStrictEqual([expectedGamePlaySourceInteraction]);\n });\n\n it(\"should return no eligible player with 0 to 0 boundaries when there are no wolves to eat.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n mocks.gameHelper.getEligibleWhiteWerewolfTargets.mockReturnValueOnce([]);\n\n expect(services.gamePlayAugmenter[\"getWhiteWerewolfGamePlaySourceInteractions\"](game)).toStrictEqual([]);\n });\n });\n\n describe(\"getWildChildGamePlaySourceInteractions\", () => {\n it(\"should return alive players without wild child as eligible targets with 1 to 1 boundaries when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeWildChildAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"wild-child\",\n type: \"choose-as-model\",\n eligibleTargets: [players[0], players[3]],\n boundaries: { min: 1, max: 1 },\n });\n\n expect(services.gamePlayAugmenter[\"getWildChildGamePlaySourceInteractions\"](game)).toStrictEqual([expectedGamePlaySourceInteraction]);\n });\n });\n\n describe(\"getWitchGamePlaySourceGiveDeathPotionInteraction\", () => {\n it(\"should return undefined when witch used death potion before.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeEatenByBigBadWolfPlayerAttribute()] }),\n createFakeWitchAlivePlayer(),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n ];\n const game = createFakeGame({ players });\n\n expect(services.gamePlayAugmenter[\"getWitchGamePlaySourceGiveDeathPotionInteraction\"](game, true)).toBeUndefined();\n });\n\n it(\"should return interaction with alive not eaten eligible targets when witch didn't use her death potion before.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeEatenByBigBadWolfPlayerAttribute()] }),\n createFakeWitchAlivePlayer(),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n ];\n const game = createFakeGame({ players });\n const expectedDeathPotionInteraction = createFakeGamePlaySourceInteraction({\n source: \"witch\",\n type: \"give-death-potion\",\n eligibleTargets: [players[0], players[2]],\n boundaries: { min: 0, max: 1 },\n });\n\n expect(services.gamePlayAugmenter[\"getWitchGamePlaySourceGiveDeathPotionInteraction\"](game, false)).toStrictEqual(expectedDeathPotionInteraction);\n });\n });\n\n describe(\"getWitchGamePlaySourceGiveLifePotionInteraction\", () => {\n it(\"should return undefined when witch used life potion before.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeEatenByBigBadWolfPlayerAttribute()] }),\n createFakeWitchAlivePlayer(),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n ];\n const game = createFakeGame({ players });\n\n expect(services.gamePlayAugmenter[\"getWitchGamePlaySourceGiveLifePotionInteraction\"](game, true)).toBeUndefined();\n });\n\n it(\"should return interaction with alive eaten eligible targets when witch didn't use her life potion before.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeEatenByBigBadWolfPlayerAttribute()] }),\n createFakeWitchAlivePlayer(),\n createFakeVillagerAlivePlayer({ isAlive: false, attributes: [createFakeEatenByBigBadWolfPlayerAttribute()] }),\n ];\n const game = createFakeGame({ players });\n const expectedLifePotionInteraction = createFakeGamePlaySourceInteraction({\n source: \"witch\",\n type: \"give-life-potion\",\n eligibleTargets: [players[1]],\n boundaries: { min: 0, max: 1 },\n });\n\n expect(services.gamePlayAugmenter[\"getWitchGamePlaySourceGiveLifePotionInteraction\"](game, false)).toStrictEqual(expectedLifePotionInteraction);\n });\n });\n\n describe(\"getWitchGamePlaySourceInteractions\", () => {\n beforeEach(() => {\n mocks.gamePlayAugmenterService.getWitchGamePlaySourceGiveDeathPotionInteraction = jest.spyOn(services.gamePlayAugmenter as unknown as { getWitchGamePlaySourceGiveDeathPotionInteraction }, \"getWitchGamePlaySourceGiveDeathPotionInteraction\").mockImplementation();\n mocks.gamePlayAugmenterService.getWitchGamePlaySourceGiveLifePotionInteraction = jest.spyOn(services.gamePlayAugmenter as unknown as { getWitchGamePlaySourceGiveLifePotionInteraction }, \"getWitchGamePlaySourceGiveLifePotionInteraction\").mockImplementation();\n });\n\n it(\"should throw error when witch is not in the game.\", async() => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const mockedError = new UnexpectedException(\"getWitchGamePlaySourceInteractions\", UnexpectedExceptionReasons.CANT_FIND_PLAYER_WITH_CURRENT_ROLE_IN_GAME, { gameId: game._id.toString(), roleName: \"witch\" });\n mocks.unexpectedExceptionFactory.createCantFindPlayerWithCurrentRoleUnexpectedException.mockReturnValue(mockedError);\n\n await expect(services.gamePlayAugmenter[\"getWitchGamePlaySourceInteractions\"](game)).rejects.toStrictEqual(mockedError);\n expect(mocks.unexpectedExceptionFactory.createCantFindPlayerWithCurrentRoleUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"getWitchGamePlaySourceInteractions\", { gameId: game._id, roleName: \"witch\" });\n });\n\n it(\"should get eligible targets from game when called and there is no history for life potion and death potion.\", async() => {\n const players = [\n createFakeWitchAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords.mockResolvedValueOnce([]);\n mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords.mockResolvedValueOnce([]);\n await services.gamePlayAugmenter[\"getWitchGamePlaySourceInteractions\"](game);\n\n expect(mocks.gamePlayAugmenterService.getWitchGamePlaySourceGiveLifePotionInteraction).toHaveBeenCalledExactlyOnceWith(game, false);\n expect(mocks.gamePlayAugmenterService.getWitchGamePlaySourceGiveDeathPotionInteraction).toHaveBeenCalledExactlyOnceWith(game, false);\n });\n\n it(\"should get eligible targets from game with life potion used when called and there is history for life potion.\", async() => {\n const players = [\n createFakeWitchAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords.mockResolvedValueOnce([createFakeGameHistoryRecord()]);\n mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords.mockResolvedValueOnce([]);\n await services.gamePlayAugmenter[\"getWitchGamePlaySourceInteractions\"](game);\n\n expect(mocks.gamePlayAugmenterService.getWitchGamePlaySourceGiveLifePotionInteraction).toHaveBeenCalledExactlyOnceWith(game, true);\n expect(mocks.gamePlayAugmenterService.getWitchGamePlaySourceGiveDeathPotionInteraction).toHaveBeenCalledExactlyOnceWith(game, false);\n });\n\n it(\"should get eligible targets from game with death potion used when called and there is history for death potion.\", async() => {\n const players = [\n createFakeWitchAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords.mockResolvedValueOnce([]);\n mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords.mockResolvedValueOnce([createFakeGameHistoryRecord()]);\n await services.gamePlayAugmenter[\"getWitchGamePlaySourceInteractions\"](game);\n\n expect(mocks.gamePlayAugmenterService.getWitchGamePlaySourceGiveLifePotionInteraction).toHaveBeenCalledExactlyOnceWith(game, false);\n expect(mocks.gamePlayAugmenterService.getWitchGamePlaySourceGiveDeathPotionInteraction).toHaveBeenCalledExactlyOnceWith(game, true);\n });\n\n it(\"should return eligible targets for both life and death potions interactions when called.\", async() => {\n const players = [\n createFakeWitchAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const expectedLifePotionInteraction = createFakeGamePlaySourceInteraction({\n source: \"witch\",\n type: \"give-life-potion\",\n eligibleTargets: [players[1]],\n boundaries: { min: 0, max: 1 },\n });\n mocks.gameHistoryRecordService.getGameHistoryWitchUsesSpecificPotionRecords.mockResolvedValue([]);\n mocks.gamePlayAugmenterService.getWitchGamePlaySourceGiveLifePotionInteraction.mockReturnValueOnce(expectedLifePotionInteraction);\n mocks.gamePlayAugmenterService.getWitchGamePlaySourceGiveDeathPotionInteraction.mockReturnValueOnce(undefined);\n\n await expect(services.gamePlayAugmenter[\"getWitchGamePlaySourceInteractions\"](game)).resolves.toStrictEqual([expectedLifePotionInteraction]);\n });\n });\n\n describe(\"getAccursedWolfFatherGamePlaySourceInteractions\", () => {\n beforeEach(() => {\n mocks.gameHistoryRecordService.getGameHistoryAccursedWolfFatherInfectsWithTargetRecords.mockResolvedValue([]);\n });\n\n it(\"should throw error when there is no accursed wolf father in the game.\", async() => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const mockedError = new UnexpectedException(\"getAccursedWolfFatherGamePlaySourceInteractions\", UnexpectedExceptionReasons.CANT_FIND_PLAYER_WITH_CURRENT_ROLE_IN_GAME, { gameId: game._id.toString(), roleName: \"accursed-wolf-father\" });\n mocks.unexpectedExceptionFactory.createCantFindPlayerWithCurrentRoleUnexpectedException.mockReturnValue(mockedError);\n\n await expect(services.gamePlayAugmenter[\"getAccursedWolfFatherGamePlaySourceInteractions\"](game)).rejects.toStrictEqual(mockedError);\n expect(mocks.unexpectedExceptionFactory.createCantFindPlayerWithCurrentRoleUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"getAccursedWolfFatherGamePlaySourceInteractions\", { gameId: game._id, roleName: \"accursed-wolf-father\" });\n });\n\n it(\"should return empty array when there is a record for accursed wolf father infects with target.\", async() => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeAccursedWolfFatherAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const gameHistoryRecord = createFakeGameHistoryRecord({ play: createFakeGameHistoryRecordPlay({ targets: [{ player: players[3] }] }) });\n mocks.gameHistoryRecordService.getGameHistoryAccursedWolfFatherInfectsWithTargetRecords.mockResolvedValueOnce([gameHistoryRecord]);\n\n await expect(services.gamePlayAugmenter[\"getAccursedWolfFatherGamePlaySourceInteractions\"](game)).resolves.toStrictEqual([]);\n });\n\n it(\"should return all eaten by werewolves players as eligible targets with boundaries from 0 to 1 when called.\", async() => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeAccursedWolfFatherAlivePlayer(),\n createFakeVillagerAlivePlayer({ attributes: [createFakeEatenByWerewolvesPlayerAttribute()] }),\n ];\n const game = createFakeGame({ players });\n const expectedGamePlaySourceInteraction = createFakeGamePlaySourceInteraction({\n source: \"accursed-wolf-father\",\n type: \"infect\",\n eligibleTargets: [players[3]],\n boundaries: { min: 0, max: 1 },\n });\n\n await expect(services.gamePlayAugmenter[\"getAccursedWolfFatherGamePlaySourceInteractions\"](game)).resolves.toStrictEqual([expectedGamePlaySourceInteraction]);\n });\n });\n\n describe(\"getGamePlaySourceInteractions\", () => {\n beforeEach(() => {\n mocks.gamePlayAugmenterService.getSheriffGamePlaySourceInteractions = jest.spyOn(services.gamePlayAugmenter as unknown as {\n getSheriffGamePlaySourceInteractions;\n }, \"getSheriffGamePlaySourceInteractions\").mockImplementation().mockReturnValue([]);\n mocks.gamePlayAugmenterService.getSurvivorsGamePlaySourceInteractions = jest.spyOn(services.gamePlayAugmenter as unknown as {\n getSurvivorsGamePlaySourceInteractions;\n }, \"getSurvivorsGamePlaySourceInteractions\").mockImplementation().mockReturnValue([]);\n mocks.gamePlayAugmenterService.getWerewolvesGamePlaySourceInteractions = jest.spyOn(services.gamePlayAugmenter as unknown as {\n getWerewolvesGamePlaySourceInteractions;\n }, \"getWerewolvesGamePlaySourceInteractions\").mockImplementation().mockReturnValue([]);\n mocks.gamePlayAugmenterService.getBigBadWolfGamePlaySourceInteractions = jest.spyOn(services.gamePlayAugmenter as unknown as {\n getBigBadWolfGamePlaySourceInteractions;\n }, \"getBigBadWolfGamePlaySourceInteractions\").mockImplementation().mockReturnValue([]);\n mocks.gamePlayAugmenterService.getCupidGamePlaySourceInteractions = jest.spyOn(services.gamePlayAugmenter as unknown as {\n getCupidGamePlaySourceInteractions;\n }, \"getCupidGamePlaySourceInteractions\").mockImplementation().mockReturnValue([]);\n mocks.gamePlayAugmenterService.getFoxGamePlaySourceInteractions = jest.spyOn(services.gamePlayAugmenter as unknown as {\n getFoxGamePlaySourceInteractions;\n }, \"getFoxGamePlaySourceInteractions\").mockImplementation().mockReturnValue([]);\n mocks.gamePlayAugmenterService.getDefenderGamePlaySourceInteractions = jest.spyOn(services.gamePlayAugmenter as unknown as {\n getDefenderGamePlaySourceInteractions;\n }, \"getDefenderGamePlaySourceInteractions\").mockImplementation().mockReturnValue([]);\n mocks.gamePlayAugmenterService.getHunterGamePlaySourceInteractions = jest.spyOn(services.gamePlayAugmenter as unknown as {\n getHunterGamePlaySourceInteractions;\n }, \"getHunterGamePlaySourceInteractions\").mockImplementation().mockReturnValue([]);\n mocks.gamePlayAugmenterService.getPiedPiperGamePlaySourceInteractions = jest.spyOn(services.gamePlayAugmenter as unknown as {\n getPiedPiperGamePlaySourceInteractions;\n }, \"getPiedPiperGamePlaySourceInteractions\").mockImplementation().mockReturnValue([]);\n mocks.gamePlayAugmenterService.getScandalmongerGamePlaySourceInteractions = jest.spyOn(services.gamePlayAugmenter as unknown as {\n getScandalmongerGamePlaySourceInteractions;\n }, \"getScandalmongerGamePlaySourceInteractions\").mockImplementation().mockReturnValue([]);\n mocks.gamePlayAugmenterService.getScapegoatGamePlaySourceInteractions = jest.spyOn(services.gamePlayAugmenter as unknown as {\n getScapegoatGamePlaySourceInteractions;\n }, \"getScapegoatGamePlaySourceInteractions\").mockImplementation().mockReturnValue([]);\n mocks.gamePlayAugmenterService.getSeerGamePlaySourceInteractions = jest.spyOn(services.gamePlayAugmenter as unknown as {\n getSeerGamePlaySourceInteractions;\n }, \"getSeerGamePlaySourceInteractions\").mockImplementation().mockReturnValue([]);\n mocks.gamePlayAugmenterService.getWhiteWerewolfGamePlaySourceInteractions = jest.spyOn(services.gamePlayAugmenter as unknown as {\n getWhiteWerewolfGamePlaySourceInteractions;\n }, \"getWhiteWerewolfGamePlaySourceInteractions\").mockImplementation().mockReturnValue([]);\n mocks.gamePlayAugmenterService.getWildChildGamePlaySourceInteractions = jest.spyOn(services.gamePlayAugmenter as unknown as {\n getWildChildGamePlaySourceInteractions;\n }, \"getWildChildGamePlaySourceInteractions\").mockImplementation().mockReturnValue([]);\n mocks.gamePlayAugmenterService.getWitchGamePlaySourceInteractions = jest.spyOn(services.gamePlayAugmenter as unknown as {\n getWitchGamePlaySourceInteractions;\n }, \"getWitchGamePlaySourceInteractions\").mockImplementation().mockReturnValue([]);\n mocks.gamePlayAugmenterService.getAccursedWolfFatherGamePlaySourceInteractions = jest.spyOn(services.gamePlayAugmenter as unknown as {\n getAccursedWolfFatherGamePlaySourceInteractions;\n }, \"getAccursedWolfFatherGamePlaySourceInteractions\").mockImplementation().mockReturnValue([]);\n });\n\n it(\"should return undefined when game play source name is not in getGamePlaySourceInteractionsMethods.\", async() => {\n const gamePlay = createFakeGamePlayThreeBrothersMeetEachOther();\n const game = createFakeGame();\n\n await expect(services.gamePlayAugmenter[\"getGamePlaySourceInteractions\"](gamePlay, game)).resolves.toBeUndefined();\n });\n\n it(\"should return undefined when eligible targets are empty array.\", async() => {\n const gamePlay = createFakeGamePlaySheriffDelegates();\n const game = createFakeGame();\n mocks.gamePlayAugmenterService.getSheriffGamePlaySourceInteractions.mockReturnValueOnce([]);\n\n await expect(services.gamePlayAugmenter[\"getGamePlaySourceInteractions\"](gamePlay, game)).resolves.toBeUndefined();\n });\n\n it(\"should return game play eligible targets when game play method returns eligible targets.\", async() => {\n const gamePlay = createFakeGamePlaySheriffDelegates();\n const game = createFakeGame();\n const expectedInteractions = [\n createFakeGamePlaySourceInteraction(),\n createFakeGamePlaySourceInteraction(),\n ];\n mocks.gamePlayAugmenterService.getSheriffGamePlaySourceInteractions.mockReturnValueOnce(expectedInteractions);\n\n await expect(services.gamePlayAugmenter[\"getGamePlaySourceInteractions\"](gamePlay, game)).resolves.toStrictEqual(expectedInteractions);\n });\n\n it(\"should call get game play eligible targets for sheriff when game play source name is sheriff.\", async() => {\n const gamePlay = createFakeGamePlaySheriffDelegates();\n const game = createFakeGame();\n await services.gamePlayAugmenter[\"getGamePlaySourceInteractions\"](gamePlay, game);\n\n expect(mocks.gamePlayAugmenterService.getSheriffGamePlaySourceInteractions).toHaveBeenCalledExactlyOnceWith(game, gamePlay);\n });\n\n it(\"should call get game play eligible targets for survivors when game play source name is survivors.\", async() => {\n const gamePlay = createFakeGamePlaySurvivorsVote();\n const game = createFakeGame();\n await services.gamePlayAugmenter[\"getGamePlaySourceInteractions\"](gamePlay, game);\n\n expect(mocks.gamePlayAugmenterService.getSurvivorsGamePlaySourceInteractions).toHaveBeenCalledExactlyOnceWith(game, gamePlay);\n });\n\n it(\"should call get game play eligible targets for werewolves when game play source name is werewolves.\", async() => {\n const gamePlay = createFakeGamePlayWerewolvesEat();\n const game = createFakeGame();\n await services.gamePlayAugmenter[\"getGamePlaySourceInteractions\"](gamePlay, game);\n\n expect(mocks.gamePlayAugmenterService.getWerewolvesGamePlaySourceInteractions).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call get game play eligible targets for big bad wolf when game play source name is big bad wolf.\", async() => {\n const gamePlay = createFakeGamePlayBigBadWolfEats();\n const game = createFakeGame();\n await services.gamePlayAugmenter[\"getGamePlaySourceInteractions\"](gamePlay, game);\n\n expect(mocks.gamePlayAugmenterService.getBigBadWolfGamePlaySourceInteractions).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call get game play eligible targets for cupid when game play source name is cupid.\", async() => {\n const gamePlay = createFakeGamePlayCupidCharms();\n const game = createFakeGame();\n await services.gamePlayAugmenter[\"getGamePlaySourceInteractions\"](gamePlay, game);\n\n expect(mocks.gamePlayAugmenterService.getCupidGamePlaySourceInteractions).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call get game play eligible targets for fox when game play source name is fox.\", async() => {\n const gamePlay = createFakeGamePlayFoxSniffs();\n const game = createFakeGame();\n await services.gamePlayAugmenter[\"getGamePlaySourceInteractions\"](gamePlay, game);\n\n expect(mocks.gamePlayAugmenterService.getFoxGamePlaySourceInteractions).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call get game play eligible targets for defender when game play source name is defender.\", async() => {\n const gamePlay = createFakeGamePlayDefenderProtects();\n const game = createFakeGame();\n await services.gamePlayAugmenter[\"getGamePlaySourceInteractions\"](gamePlay, game);\n\n expect(mocks.gamePlayAugmenterService.getDefenderGamePlaySourceInteractions).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call get game play eligible targets for hunter when game play source name is hunter.\", async() => {\n const gamePlay = createFakeGamePlayHunterShoots();\n const game = createFakeGame();\n await services.gamePlayAugmenter[\"getGamePlaySourceInteractions\"](gamePlay, game);\n\n expect(mocks.gamePlayAugmenterService.getHunterGamePlaySourceInteractions).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call get game play eligible targets for pied piper when game play source name is pied piper.\", async() => {\n const gamePlay = createFakeGamePlayPiedPiperCharms();\n const game = createFakeGame();\n await services.gamePlayAugmenter[\"getGamePlaySourceInteractions\"](gamePlay, game);\n\n expect(mocks.gamePlayAugmenterService.getPiedPiperGamePlaySourceInteractions).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call get game play eligible targets for scandalmonger when game play source name is scandalmonger.\", async() => {\n const gamePlay = createFakeGamePlayScandalmongerMarks();\n const game = createFakeGame();\n await services.gamePlayAugmenter[\"getGamePlaySourceInteractions\"](gamePlay, game);\n\n expect(mocks.gamePlayAugmenterService.getScandalmongerGamePlaySourceInteractions).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call get game play eligible targets for scapegoat when game play source name is scapegoat.\", async() => {\n const gamePlay = createFakeGamePlayScapegoatBansVoting();\n const game = createFakeGame();\n await services.gamePlayAugmenter[\"getGamePlaySourceInteractions\"](gamePlay, game);\n\n expect(mocks.gamePlayAugmenterService.getScapegoatGamePlaySourceInteractions).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call get game play eligible targets for see when game play source name is see.\", async() => {\n const gamePlay = createFakeGamePlaySeerLooks();\n const game = createFakeGame();\n await services.gamePlayAugmenter[\"getGamePlaySourceInteractions\"](gamePlay, game);\n\n expect(mocks.gamePlayAugmenterService.getSeerGamePlaySourceInteractions).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call get game play eligible targets for white werewolf when game play source name is white werewolf.\", async() => {\n const gamePlay = createFakeGamePlayWhiteWerewolfEats();\n const game = createFakeGame();\n await services.gamePlayAugmenter[\"getGamePlaySourceInteractions\"](gamePlay, game);\n\n expect(mocks.gamePlayAugmenterService.getWhiteWerewolfGamePlaySourceInteractions).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call get game play eligible targets for wild child when game play source name is wild child.\", async() => {\n const gamePlay = createFakeGamePlayWildChildChoosesModel();\n const game = createFakeGame();\n await services.gamePlayAugmenter[\"getGamePlaySourceInteractions\"](gamePlay, game);\n\n expect(mocks.gamePlayAugmenterService.getWildChildGamePlaySourceInteractions).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call get game play eligible targets for witch when game play source name is witch.\", async() => {\n const gamePlay = createFakeGamePlayWitchUsesPotions();\n const game = createFakeGame();\n await services.gamePlayAugmenter[\"getGamePlaySourceInteractions\"](gamePlay, game);\n\n expect(mocks.gamePlayAugmenterService.getWitchGamePlaySourceInteractions).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call get game play eligible targets for accursed wolf-father when game play source name is accursed wolf-father.\", async() => {\n const gamePlay = createFakeGamePlayAccursedWolfFatherInfects();\n const game = createFakeGame();\n await services.gamePlayAugmenter[\"getGamePlaySourceInteractions\"](gamePlay, game);\n\n expect(mocks.gamePlayAugmenterService.getAccursedWolfFatherGamePlaySourceInteractions).toHaveBeenCalledExactlyOnceWith(game);\n });\n });\n\n describe(\"canSurvivorsSkipGamePlay\", () => {\n it.each<{\n test: string;\n gamePlay: GamePlay;\n game: Game;\n expected: boolean;\n }>([\n {\n test: \"should return false when game play action is elect sheriff.\",\n gamePlay: createFakeGamePlay({ action: \"elect-sheriff\" }),\n game: createFakeGame(),\n expected: false,\n },\n {\n test: \"should return false when game play action is vote and game play cause is angel presence.\",\n gamePlay: createFakeGamePlaySurvivorsVote({ causes: [\"angel-presence\"] }),\n game: createFakeGame({ options: createFakeGameOptions({ votes: createFakeVotesGameOptions({ canBeSkipped: true }) }) }),\n expected: false,\n },\n {\n test: \"should return true when game play action is bury dead bodies.\",\n gamePlay: createFakeGamePlay({ action: \"bury-dead-bodies\" }),\n game: createFakeGame({ options: createFakeGameOptions({ votes: createFakeVotesGameOptions({ canBeSkipped: false }) }) }),\n expected: true,\n },\n {\n test: \"should return true when game play action is not elect sheriff and game options say that votes can be skipped.\",\n gamePlay: createFakeGamePlay({ action: \"vote\" }),\n game: createFakeGame({ options: createFakeGameOptions({ votes: createFakeVotesGameOptions({ canBeSkipped: true }) }) }),\n expected: true,\n },\n {\n test: \"should return true when game play action is not vote but because angel presence.\",\n gamePlay: createFakeGamePlayScandalmongerMarks({ causes: [\"angel-presence\"] }),\n game: createFakeGame({ options: createFakeGameOptions({ votes: createFakeVotesGameOptions({ canBeSkipped: true }) }) }),\n expected: true,\n },\n {\n test: \"should return false when game play action is not elect sheriff and game options say that votes can't be skipped.\",\n gamePlay: createFakeGamePlay({ action: \"vote\" }),\n game: createFakeGame({\n options: createFakeGameOptions({ votes: createFakeVotesGameOptions({ canBeSkipped: false }) }),\n players: [\n createFakeWhiteWerewolfAlivePlayer({ attributes: [createFakeCantVoteBySurvivorsPlayerAttribute()] }),\n createFakeAngelAlivePlayer(),\n createFakeWitchAlivePlayer({ isAlive: false }),\n ],\n }),\n expected: false,\n },\n ])(\"$test\", ({ gamePlay, game, expected }) => {\n expect(services.gamePlayAugmenter[\"canSurvivorsSkipGamePlay\"](game, gamePlay)).toBe(expected);\n });\n });\n\n describe(\"canCupidSkipGamePlay\", () => {\n it.each<{\n test: string;\n game: Game;\n expected: boolean;\n }>([\n {\n test: \"should return false when expected there are at least 2 targets for cupid.\",\n game: createFakeGame({\n players: [\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ],\n }),\n expected: false,\n },\n {\n test: \"should return true when expected there are less than 2 targets for cupid.\",\n game: createFakeGame({ players: [createFakeVillagerAlivePlayer()] }),\n expected: true,\n },\n ])(\"$test\", ({ game, expected }) => {\n expect(services.gamePlayAugmenter[\"canCupidSkipGamePlay\"](game)).toBe(expected);\n });\n });\n\n describe(\"canBigBadWolfSkipGamePlay\", () => {\n it.each<{\n test: string;\n game: Game;\n expected: boolean;\n }>([\n {\n test: \"should return true when there are no players left to eat by werewolves.\",\n game: createFakeGame({ players: [createFakeWerewolfAlivePlayer()] }),\n expected: true,\n },\n {\n test: \"should return false when there are players left to eat by werewolves.\",\n game: createFakeGame({ players: [createFakeVillagerAlivePlayer()] }),\n expected: false,\n },\n ])(\"$test\", ({ game, expected }) => {\n expect(services.gamePlayAugmenter[\"canBigBadWolfSkipGamePlay\"](game)).toBe(expected);\n });\n });\n\n describe(\"canThiefSkipGamePlay\", () => {\n it.each<{\n test: string;\n game: Game;\n expected: boolean;\n }>([\n {\n test: \"should return true when game has undefined additional cards.\",\n game: createFakeGame(),\n expected: true,\n },\n {\n test: \"should return true when game has no additional cards.\",\n game: createFakeGame({ additionalCards: [], options: createFakeGameOptions({ roles: createFakeRolesGameOptions({ thief: createFakeThiefGameOptions({ mustChooseBetweenWerewolves: false }) }) }) }),\n expected: true,\n },\n {\n test: \"should return true when thief doesn't have to choose between werewolves cards.\",\n game: createFakeGame({\n additionalCards: [\n createFakeGameAdditionalCard({ roleName: \"seer\" }),\n createFakeGameAdditionalCard({ roleName: \"werewolf\" }),\n ],\n options: createFakeGameOptions({ roles: createFakeRolesGameOptions({ thief: createFakeThiefGameOptions({ mustChooseBetweenWerewolves: true }) }) }),\n }),\n expected: true,\n },\n {\n test: \"should return true when thief has to choose between werewolves cards but game options allow to skip.\",\n game: createFakeGame({\n additionalCards: [\n createFakeGameAdditionalCard({ roleName: \"werewolf\" }),\n createFakeGameAdditionalCard({ roleName: \"werewolf\" }),\n ],\n options: createFakeGameOptions({ roles: createFakeRolesGameOptions({ thief: createFakeThiefGameOptions({ mustChooseBetweenWerewolves: false }) }) }),\n }),\n expected: true,\n },\n {\n test: \"should return false when thief has to choose between werewolves cards and game options don't allow to skip.\",\n game: createFakeGame({\n additionalCards: [\n createFakeGameAdditionalCard({ roleName: \"werewolf\" }),\n createFakeGameAdditionalCard({ roleName: \"werewolf\" }),\n ],\n options: createFakeGameOptions({ roles: createFakeRolesGameOptions({ thief: createFakeThiefGameOptions({ mustChooseBetweenWerewolves: true }) }) }),\n }),\n expected: false,\n },\n ])(\"$test\", ({ game, expected }) => {\n expect(services.gamePlayAugmenter[\"canThiefSkipGamePlay\"](game)).toBe(expected);\n });\n });\n\n describe(\"canGamePlayBeSkipped\", () => {\n beforeEach(() => {\n mocks.gamePlayAugmenterService.canSurvivorsSkipGamePlay = jest.spyOn(services.gamePlayAugmenter as unknown as { canSurvivorsSkipGamePlay }, \"canSurvivorsSkipGamePlay\").mockImplementation();\n mocks.gamePlayAugmenterService.canBigBadWolfSkipGamePlay = jest.spyOn(services.gamePlayAugmenter as unknown as { canBigBadWolfSkipGamePlay }, \"canBigBadWolfSkipGamePlay\").mockImplementation();\n mocks.gamePlayAugmenterService.canThiefSkipGamePlay = jest.spyOn(services.gamePlayAugmenter as unknown as { canThiefSkipGamePlay }, \"canThiefSkipGamePlay\").mockImplementation();\n mocks.gamePlayAugmenterService.canCupidSkipGamePlay = jest.spyOn(services.gamePlayAugmenter as unknown as { canCupidSkipGamePlay }, \"canCupidSkipGamePlay\").mockImplementation();\n });\n\n it(\"should return false when game play source name is not in canBeSkippedPlayMethods.\", () => {\n const gamePlay = createFakeGamePlayWildChildChoosesModel();\n const game = createFakeGame();\n\n expect(services.gamePlayAugmenter[\"canGamePlayBeSkipped\"](game, gamePlay)).toBe(false);\n });\n\n it.each<{\n test: string;\n gamePlay: GamePlay;\n }>([\n {\n gamePlay: createFakeGamePlayLoversMeetEachOther(),\n test: \"should return true when game play source name are lovers.\",\n },\n {\n gamePlay: createFakeGamePlayCharmedMeetEachOther(),\n test: \"should return true when game play source name are charmed.\",\n },\n {\n gamePlay: createFakeGamePlayFoxSniffs(),\n test: \"should return true when game play source name is fox.\",\n },\n {\n gamePlay: createFakeGamePlayScandalmongerMarks(),\n test: \"should return true when game play source name is scandalmonger.\",\n },\n {\n gamePlay: createFakeGamePlayScapegoatBansVoting(),\n test: \"should return true when game play source name is scapegoat.\",\n },\n {\n gamePlay: createFakeGamePlayTwoSistersMeetEachOther(),\n test: \"should return true when game play source name are two sisters.\",\n },\n {\n gamePlay: createFakeGamePlayThreeBrothersMeetEachOther(),\n test: \"should return true when game play source name are three brothers.\",\n },\n {\n gamePlay: createFakeGamePlayWhiteWerewolfEats(),\n test: \"should return true when game play source name is white werewolf.\",\n },\n {\n gamePlay: createFakeGamePlayWitchUsesPotions(),\n test: \"should return true when game play source name is witch.\",\n },\n {\n gamePlay: createFakeGamePlayActorChoosesCard(),\n test: \"should return true when game play source name is actor.\",\n },\n {\n gamePlay: createFakeGamePlayAccursedWolfFatherInfects(),\n test: \"should return true when game play source name is accursed wolf-father.\",\n },\n {\n gamePlay: createFakeGamePlayStutteringJudgeRequestsAnotherVote(),\n test: \"should return true when game play source name is stuttering judge.\",\n },\n ])(\"$test\", ({ gamePlay }) => {\n const game = createFakeGame();\n\n expect(services.gamePlayAugmenter[\"canGamePlayBeSkipped\"](game, gamePlay)).toBe(true);\n });\n\n it(\"should call canSurvivorsSkipGamePlay method when game play source name is survivors.\", () => {\n const gamePlay = createFakeGamePlaySurvivorsVote();\n const game = createFakeGame();\n services.gamePlayAugmenter[\"canGamePlayBeSkipped\"](game, gamePlay);\n\n expect(mocks.gamePlayAugmenterService.canSurvivorsSkipGamePlay).toHaveBeenCalledExactlyOnceWith(game, gamePlay);\n });\n\n it(\"should call canBigBadWolfSkipGamePlay method when game play source name is big bad wolf.\", () => {\n const gamePlay = createFakeGamePlayBigBadWolfEats();\n const game = createFakeGame();\n services.gamePlayAugmenter[\"canGamePlayBeSkipped\"](game, gamePlay);\n\n expect(mocks.gamePlayAugmenterService.canBigBadWolfSkipGamePlay).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call canThiefSkipGamePlay method when game play source name is thief.\", () => {\n const gamePlay = createFakeGamePlayThiefChoosesCard();\n const game = createFakeGame();\n services.gamePlayAugmenter[\"canGamePlayBeSkipped\"](game, gamePlay);\n\n expect(mocks.gamePlayAugmenterService.canThiefSkipGamePlay).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call canCupidSkipGamePlay method when game play source name is cupid.\", () => {\n const gamePlay = createFakeGamePlayCupidCharms();\n const game = createFakeGame();\n services.gamePlayAugmenter[\"canGamePlayBeSkipped\"](game, gamePlay);\n\n expect(mocks.gamePlayAugmenterService.canCupidSkipGamePlay).toHaveBeenCalledExactlyOnceWith(game);\n });\n });\n\n describe(\"getExpectedPlayersToPlay\", () => {\n it(\"should throw error when there is no current play.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeWhiteWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer({ attributes: [createFakeSheriffBySurvivorsPlayerAttribute()] }),\n ];\n const game = createFakeGame({ players });\n const interpolations = { gameId: game._id };\n const mockedError = new UnexpectedException(\"getExpectedPlayersToPlay\", UnexpectedExceptionReasons.NO_CURRENT_GAME_PLAY, { gameId: game._id.toString() });\n mocks.unexpectedExceptionFactory.createNoCurrentGamePlayUnexpectedException.mockReturnValueOnce(mockedError);\n\n expect(() => services.gamePlayAugmenter[\"getExpectedPlayersToPlay\"](game)).toThrow(mockedError);\n expect(mocks.unexpectedExceptionFactory.createNoCurrentGamePlayUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"getExpectedPlayersToPlay\", interpolations);\n });\n\n it(\"should return alive werewolves when source is group of werewolves.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeWhiteWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer({ attributes: [createFakeSheriffBySurvivorsPlayerAttribute()] }),\n ];\n const game = createFakeGame({ players, currentPlay: createFakeGamePlayWerewolvesEat() });\n\n expect(services.gamePlayAugmenter[\"getExpectedPlayersToPlay\"](game)).toStrictEqual([\n players[0],\n players[2],\n ]);\n });\n\n it(\"should return alive two sisters when source is specific role.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeWhiteWerewolfAlivePlayer(),\n createFakeTwoSistersAlivePlayer(),\n createFakeTwoSistersAlivePlayer({ isAlive: false }),\n createFakeVillagerAlivePlayer({ attributes: [createFakeSheriffBySurvivorsPlayerAttribute()] }),\n ];\n const game = createFakeGame({ players, currentPlay: createFakeGamePlayTwoSistersMeetEachOther() });\n\n expect(services.gamePlayAugmenter[\"getExpectedPlayersToPlay\"](game)).toStrictEqual([players[3]]);\n });\n\n it(\"should not return sheriff when source is sheriff but action is not DELEGATE and sheriff is dead.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeWhiteWerewolfAlivePlayer(),\n createFakeTwoSistersAlivePlayer(),\n createFakeTwoSistersAlivePlayer({ isAlive: false }),\n createFakeVillagerAlivePlayer({ attributes: [createFakeSheriffBySurvivorsPlayerAttribute()], isAlive: false }),\n ];\n const game = createFakeGame({ players, currentPlay: createFakeGamePlaySheriffSettlesVotes() });\n\n expect(services.gamePlayAugmenter[\"getExpectedPlayersToPlay\"](game)).toStrictEqual([]);\n });\n\n it(\"should return sheriff when source is sheriff and action is DELEGATE even if he is dying.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeWhiteWerewolfAlivePlayer(),\n createFakeTwoSistersAlivePlayer(),\n createFakeTwoSistersAlivePlayer({ isAlive: false }),\n createFakeVillagerAlivePlayer({ attributes: [createFakeSheriffBySurvivorsPlayerAttribute()], isAlive: false }),\n ];\n const game = createFakeGame({ players, currentPlay: createFakeGamePlaySheriffDelegates() });\n\n expect(services.gamePlayAugmenter[\"getExpectedPlayersToPlay\"](game)).toStrictEqual([players[5]]);\n });\n\n it(\"should return hunter when source is hunter and action is SHOOT even if he is dying.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeWhiteWerewolfAlivePlayer(),\n createFakeTwoSistersAlivePlayer(),\n createFakeTwoSistersAlivePlayer({ isAlive: false }),\n createFakeHunterAlivePlayer({ attributes: [createFakeSheriffBySurvivorsPlayerAttribute()], isAlive: false }),\n ];\n const game = createFakeGame({ players, currentPlay: createFakeGamePlayHunterShoots() });\n\n expect(services.gamePlayAugmenter[\"getExpectedPlayersToPlay\"](game)).toStrictEqual([players[5]]);\n });\n\n it(\"should return scapegoat when source is scapegoat and action is BAN_VOTING even if he is dying.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeWhiteWerewolfAlivePlayer(),\n createFakeTwoSistersAlivePlayer({}),\n createFakeTwoSistersAlivePlayer({ isAlive: false }),\n createFakeScapegoatAlivePlayer({ attributes: [createFakeSheriffBySurvivorsPlayerAttribute(), createFakeCantVoteBySurvivorsPlayerAttribute()], isAlive: false }),\n ];\n const game = createFakeGame({ players, currentPlay: createFakeGamePlayScapegoatBansVoting() });\n\n expect(services.gamePlayAugmenter[\"getExpectedPlayersToPlay\"](game)).toStrictEqual([players[5]]);\n });\n\n it(\"should return alive players capable of vote when action is vote.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeWhiteWerewolfAlivePlayer(),\n createFakeTwoSistersAlivePlayer({ attributes: [createFakeCantVoteBySurvivorsPlayerAttribute()] }),\n createFakeTwoSistersAlivePlayer({ isAlive: false }),\n createFakeVillagerAlivePlayer({ attributes: [createFakeSheriffBySurvivorsPlayerAttribute()], isAlive: false }),\n ];\n const game = createFakeGame({ players, currentPlay: createFakeGamePlaySurvivorsVote() });\n\n expect(services.gamePlayAugmenter[\"getExpectedPlayersToPlay\"](game)).toStrictEqual([players[0], players[2]]);\n });\n });\n});" }, "tests/unit/specs/modules/game/providers/services/player/player-killer.service.spec.ts": { "tests": [ @@ -190748,7 +190750,7 @@ "location": { "start": { "column": 6, - "line": 166 + "line": 167 } } }, @@ -190758,7 +190760,7 @@ "location": { "start": { "column": 6, - "line": 193 + "line": 195 } } }, @@ -190768,7 +190770,7 @@ "location": { "start": { "column": 6, - "line": 215 + "line": 217 } } }, @@ -190778,7 +190780,7 @@ "location": { "start": { "column": 6, - "line": 237 + "line": 239 } } }, @@ -190788,7 +190790,7 @@ "location": { "start": { "column": 6, - "line": 259 + "line": 261 } } }, @@ -190798,7 +190800,7 @@ "location": { "start": { "column": 6, - "line": 281 + "line": 283 } } }, @@ -190808,7 +190810,7 @@ "location": { "start": { "column": 6, - "line": 316 + "line": 318 } } }, @@ -190818,7 +190820,7 @@ "location": { "start": { "column": 6, - "line": 331 + "line": 333 } } }, @@ -190828,7 +190830,7 @@ "location": { "start": { "column": 6, - "line": 358 + "line": 360 } } }, @@ -190838,7 +190840,7 @@ "location": { "start": { "column": 6, - "line": 370 + "line": 372 } } }, @@ -190848,7 +190850,7 @@ "location": { "start": { "column": 6, - "line": 382 + "line": 384 } } }, @@ -190858,7 +190860,7 @@ "location": { "start": { "column": 6, - "line": 400 + "line": 402 } } }, @@ -190868,7 +190870,7 @@ "location": { "start": { "column": 6, - "line": 418 + "line": 420 } } }, @@ -190878,7 +190880,7 @@ "location": { "start": { "column": 6, - "line": 440 + "line": 442 } } }, @@ -190888,7 +190890,7 @@ "location": { "start": { "column": 6, - "line": 477 + "line": 479 } } }, @@ -190898,7 +190900,7 @@ "location": { "start": { "column": 6, - "line": 497 + "line": 499 } } }, @@ -190908,7 +190910,7 @@ "location": { "start": { "column": 6, - "line": 521 + "line": 523 } } }, @@ -190918,7 +190920,7 @@ "location": { "start": { "column": 8, - "line": 567 + "line": 569 } } }, @@ -190928,7 +190930,7 @@ "location": { "start": { "column": 8, - "line": 567 + "line": 569 } } }, @@ -190938,7 +190940,7 @@ "location": { "start": { "column": 8, - "line": 567 + "line": 569 } } }, @@ -190948,7 +190950,7 @@ "location": { "start": { "column": 8, - "line": 639 + "line": 641 } } }, @@ -190958,7 +190960,7 @@ "location": { "start": { "column": 8, - "line": 639 + "line": 641 } } }, @@ -190968,7 +190970,7 @@ "location": { "start": { "column": 8, - "line": 639 + "line": 641 } } }, @@ -190978,7 +190980,7 @@ "location": { "start": { "column": 8, - "line": 639 + "line": 641 } } }, @@ -190988,7 +190990,7 @@ "location": { "start": { "column": 8, - "line": 639 + "line": 641 } } }, @@ -190998,7 +191000,7 @@ "location": { "start": { "column": 8, - "line": 639 + "line": 641 } } }, @@ -191008,7 +191010,7 @@ "location": { "start": { "column": 8, - "line": 639 + "line": 641 } } }, @@ -191018,7 +191020,7 @@ "location": { "start": { "column": 8, - "line": 639 + "line": 641 } } }, @@ -191028,7 +191030,7 @@ "location": { "start": { "column": 6, - "line": 645 + "line": 647 } } }, @@ -191038,7 +191040,7 @@ "location": { "start": { "column": 8, - "line": 702 + "line": 704 } } }, @@ -191048,7 +191050,7 @@ "location": { "start": { "column": 8, - "line": 702 + "line": 704 } } }, @@ -191058,7 +191060,7 @@ "location": { "start": { "column": 8, - "line": 702 + "line": 704 } } }, @@ -191068,7 +191070,7 @@ "location": { "start": { "column": 8, - "line": 702 + "line": 704 } } }, @@ -191078,7 +191080,7 @@ "location": { "start": { "column": 8, - "line": 750 + "line": 752 } } }, @@ -191088,7 +191090,7 @@ "location": { "start": { "column": 6, - "line": 754 + "line": 756 } } }, @@ -191098,7 +191100,7 @@ "location": { "start": { "column": 8, - "line": 750 + "line": 752 } } }, @@ -191108,7 +191110,7 @@ "location": { "start": { "column": 8, - "line": 750 + "line": 752 } } }, @@ -191118,7 +191120,7 @@ "location": { "start": { "column": 8, - "line": 750 + "line": 752 } } }, @@ -191128,7 +191130,7 @@ "location": { "start": { "column": 8, - "line": 750 + "line": 752 } } }, @@ -191138,7 +191140,7 @@ "location": { "start": { "column": 6, - "line": 770 + "line": 772 } } }, @@ -191148,7 +191150,7 @@ "location": { "start": { "column": 6, - "line": 778 + "line": 780 } } }, @@ -191158,7 +191160,7 @@ "location": { "start": { "column": 6, - "line": 787 + "line": 789 } } }, @@ -191168,7 +191170,7 @@ "location": { "start": { "column": 6, - "line": 796 + "line": 798 } } }, @@ -191178,7 +191180,7 @@ "location": { "start": { "column": 6, - "line": 805 + "line": 807 } } }, @@ -191188,7 +191190,7 @@ "location": { "start": { "column": 6, - "line": 814 + "line": 816 } } }, @@ -191198,7 +191200,7 @@ "location": { "start": { "column": 6, - "line": 823 + "line": 825 } } }, @@ -191208,7 +191210,7 @@ "location": { "start": { "column": 6, - "line": 832 + "line": 834 } } }, @@ -191218,7 +191220,7 @@ "location": { "start": { "column": 6, - "line": 844 + "line": 846 } } }, @@ -191228,7 +191230,7 @@ "location": { "start": { "column": 6, - "line": 856 + "line": 858 } } }, @@ -191238,7 +191240,7 @@ "location": { "start": { "column": 6, - "line": 868 + "line": 870 } } }, @@ -191248,7 +191250,7 @@ "location": { "start": { "column": 6, - "line": 880 + "line": 882 } } }, @@ -191258,7 +191260,7 @@ "location": { "start": { "column": 6, - "line": 904 + "line": 906 } } }, @@ -191268,7 +191270,7 @@ "location": { "start": { "column": 6, - "line": 933 + "line": 935 } } }, @@ -191278,7 +191280,7 @@ "location": { "start": { "column": 6, - "line": 968 + "line": 970 } } }, @@ -191288,7 +191290,7 @@ "location": { "start": { "column": 6, - "line": 980 + "line": 982 } } }, @@ -191298,7 +191300,7 @@ "location": { "start": { "column": 6, - "line": 992 + "line": 994 } } }, @@ -191308,7 +191310,7 @@ "location": { "start": { "column": 6, - "line": 1004 + "line": 1006 } } }, @@ -191318,7 +191320,7 @@ "location": { "start": { "column": 6, - "line": 1019 + "line": 1021 } } }, @@ -191328,7 +191330,7 @@ "location": { "start": { "column": 6, - "line": 1031 + "line": 1033 } } }, @@ -191338,7 +191340,7 @@ "location": { "start": { "column": 6, - "line": 1043 + "line": 1045 } } }, @@ -191348,7 +191350,7 @@ "location": { "start": { "column": 6, - "line": 1060 + "line": 1062 } } }, @@ -191358,7 +191360,7 @@ "location": { "start": { "column": 6, - "line": 1086 + "line": 1088 } } }, @@ -191368,7 +191370,7 @@ "location": { "start": { "column": 6, - "line": 1102 + "line": 1104 } } }, @@ -191378,7 +191380,7 @@ "location": { "start": { "column": 6, - "line": 1131 + "line": 1133 } } }, @@ -191388,7 +191390,7 @@ "location": { "start": { "column": 6, - "line": 1144 + "line": 1146 } } }, @@ -191398,7 +191400,7 @@ "location": { "start": { "column": 6, - "line": 1157 + "line": 1159 } } }, @@ -191408,7 +191410,7 @@ "location": { "start": { "column": 6, - "line": 1170 + "line": 1172 } } }, @@ -191418,7 +191420,7 @@ "location": { "start": { "column": 6, - "line": 1183 + "line": 1185 } } }, @@ -191428,7 +191430,7 @@ "location": { "start": { "column": 6, - "line": 1196 + "line": 1198 } } }, @@ -191438,7 +191440,7 @@ "location": { "start": { "column": 6, - "line": 1223 + "line": 1225 } } }, @@ -191448,7 +191450,7 @@ "location": { "start": { "column": 6, - "line": 1236 + "line": 1238 } } }, @@ -191458,7 +191460,7 @@ "location": { "start": { "column": 6, - "line": 1249 + "line": 1251 } } }, @@ -191468,7 +191470,7 @@ "location": { "start": { "column": 6, - "line": 1262 + "line": 1264 } } }, @@ -191478,7 +191480,7 @@ "location": { "start": { "column": 6, - "line": 1275 + "line": 1277 } } }, @@ -191488,7 +191490,7 @@ "location": { "start": { "column": 6, - "line": 1299 + "line": 1301 } } }, @@ -191498,7 +191500,7 @@ "location": { "start": { "column": 6, - "line": 1312 + "line": 1314 } } }, @@ -191508,7 +191510,7 @@ "location": { "start": { "column": 6, - "line": 1325 + "line": 1327 } } }, @@ -191518,7 +191520,7 @@ "location": { "start": { "column": 6, - "line": 1338 + "line": 1340 } } }, @@ -191528,7 +191530,7 @@ "location": { "start": { "column": 6, - "line": 1362 + "line": 1364 } } }, @@ -191538,7 +191540,7 @@ "location": { "start": { "column": 6, - "line": 1378 + "line": 1380 } } }, @@ -191548,7 +191550,7 @@ "location": { "start": { "column": 6, - "line": 1394 + "line": 1396 } } }, @@ -191558,7 +191560,7 @@ "location": { "start": { "column": 6, - "line": 1407 + "line": 1409 } } }, @@ -191568,7 +191570,7 @@ "location": { "start": { "column": 6, - "line": 1422 + "line": 1424 } } }, @@ -191578,7 +191580,7 @@ "location": { "start": { "column": 6, - "line": 1447 + "line": 1449 } } }, @@ -191588,7 +191590,7 @@ "location": { "start": { "column": 6, - "line": 1465 + "line": 1467 } } }, @@ -191598,7 +191600,7 @@ "location": { "start": { "column": 6, - "line": 1485 + "line": 1487 } } }, @@ -191608,7 +191610,7 @@ "location": { "start": { "column": 6, - "line": 1497 + "line": 1499 } } }, @@ -191618,7 +191620,7 @@ "location": { "start": { "column": 6, - "line": 1509 + "line": 1511 } } }, @@ -191628,7 +191630,7 @@ "location": { "start": { "column": 6, - "line": 1535 + "line": 1537 } } }, @@ -191638,7 +191640,7 @@ "location": { "start": { "column": 6, - "line": 1552 + "line": 1554 } } }, @@ -191648,7 +191650,7 @@ "location": { "start": { "column": 6, - "line": 1569 + "line": 1571 } } }, @@ -191658,7 +191660,7 @@ "location": { "start": { "column": 6, - "line": 1585 + "line": 1588 } } }, @@ -191668,7 +191670,7 @@ "location": { "start": { "column": 6, - "line": 1602 + "line": 1605 } } }, @@ -191678,7 +191680,7 @@ "location": { "start": { "column": 6, - "line": 1628 + "line": 1631 } } }, @@ -191688,7 +191690,7 @@ "location": { "start": { "column": 6, - "line": 1653 + "line": 1656 } } }, @@ -191698,7 +191700,7 @@ "location": { "start": { "column": 6, - "line": 1686 + "line": 1689 } } }, @@ -191708,12 +191710,12 @@ "location": { "start": { "column": 6, - "line": 1708 + "line": 1711 } } } ], - "source": "import type { TestingModule } from \"@nestjs/testing\";\nimport { Test } from \"@nestjs/testing\";\n\nimport * as GameHelper from \"@/modules/game/helpers/game.helpers\";\nimport { GameHistoryRecordService } from \"@/modules/game/providers/services/game-history/game-history-record.service\";\nimport { PlayerKillerService } from \"@/modules/game/providers/services/player/player-killer.service\";\nimport type { Game } from \"@/modules/game/schemas/game.schema\";\nimport type { DeadPlayer } from \"@/modules/game/schemas/player/dead-player.schema\";\nimport type { PlayerDeath } from \"@/modules/game/schemas/player/player-death/player-death.schema\";\nimport type { Player } from \"@/modules/game/schemas/player/player.schema\";\nimport type { PlayerDeathCause } from \"@/modules/game/types/player/player-death/player-death.types\";\n\nimport { UnexpectedExceptionReasons } from \"@/shared/exception/enums/unexpected-exception.enum\";\nimport * as UnexpectedExceptionFactory from \"@/shared/exception/helpers/unexpected-exception.factory\";\nimport { UnexpectedException } from \"@/shared/exception/types/unexpected-exception.types\";\n\nimport { createFakeGameHistoryRecord, createFakeGameHistoryRecordDefenderProtectPlay, createFakeGameHistoryRecordPlayTarget, createFakeGameHistoryRecordWerewolvesEatPlay, createFakeGameHistoryRecordWitchUsePotionsPlay } from \"@tests/factories/game/schemas/game-history-record/game-history-record.schema.factory\";\nimport { createFakeGameOptions } from \"@tests/factories/game/schemas/game-options/game-options.schema.factory\";\nimport { createFakeActorGameOptions, createFakeBigBadWolfGameOptions, createFakeElderGameOptions, createFakeIdiotGameOptions, createFakeLittleGirlGameOptions, createFakeRolesGameOptions } from \"@tests/factories/game/schemas/game-options/game-roles-options/game-roles-options.schema.factory\";\nimport { createFakeGamePlayHunterShoots, createFakeGamePlayScapegoatBansVoting, createFakeGamePlaySheriffDelegates, createFakeGamePlaySurvivorsBuryDeadBodies } from \"@tests/factories/game/schemas/game-play/game-play.schema.factory\";\nimport { createFakeGame } from \"@tests/factories/game/schemas/game.schema.factory\";\nimport { createFakeCantVoteBySurvivorsPlayerAttribute, createFakeContaminatedByRustySwordKnightPlayerAttribute, createFakeDrankLifePotionByWitchPlayerAttribute, createFakeEatenByWerewolvesPlayerAttribute, createFakeInLoveByCupidPlayerAttribute, createFakePowerlessByActorPlayerAttribute, createFakePowerlessByElderPlayerAttribute, createFakePowerlessByWerewolvesPlayerAttribute, createFakeProtectedByDefenderPlayerAttribute, createFakeScandalmongerMarkedByScandalmongerPlayerAttribute, createFakeSheriffBySurvivorsPlayerAttribute, createFakeWorshipedByWildChildPlayerAttribute } from \"@tests/factories/game/schemas/player/player-attribute/player-attribute.schema.factory\";\nimport { createFakePlayerBrokenHeartByCupidDeath, createFakePlayerDeathPotionByWitchDeath, createFakePlayerEatenByWerewolvesDeath, createFakePlayerReconsiderPardonBySurvivorsDeath, createFakePlayerVoteBySurvivorsDeath, createFakePlayerVoteScapegoatedBySurvivorsDeath } from \"@tests/factories/game/schemas/player/player-death/player-death.schema.factory\";\nimport { createFakeBigBadWolfAlivePlayer, createFakeDefenderAlivePlayer, createFakeElderAlivePlayer, createFakeHunterAlivePlayer, createFakeIdiotAlivePlayer, createFakeLittleGirlAlivePlayer, createFakeRustySwordKnightAlivePlayer, createFakeScapegoatAlivePlayer, createFakeSeerAlivePlayer, createFakeVillagerVillagerAlivePlayer, createFakeWerewolfAlivePlayer, createFakeWildChildAlivePlayer, createFakeWitchAlivePlayer } from \"@tests/factories/game/schemas/player/player-with-role.schema.factory\";\nimport { createFakePlayer, createFakePlayerRole, createFakePlayerSide } from \"@tests/factories/game/schemas/player/player.schema.factory\";\n\ndescribe(\"Player Killer Service\", () => {\n let mocks: {\n playerKillerService: {\n getPlayerToKillOrRevealInGame: jest.SpyInstance;\n isPlayerKillable: jest.SpyInstance;\n doesPlayerRoleMustBeRevealed: jest.SpyInstance;\n removePlayerAttributesAfterDeath: jest.SpyInstance;\n revealPlayerRole: jest.SpyInstance;\n killPlayer: jest.SpyInstance;\n applySheriffPlayerDeathOutcomes: jest.SpyInstance;\n applyInLovePlayerDeathOutcomes: jest.SpyInstance;\n applyWorshipedPlayerDeathOutcomes: jest.SpyInstance;\n applyHunterDeathOutcomes: jest.SpyInstance;\n applyElderDeathOutcomes: jest.SpyInstance;\n applyScapegoatDeathOutcomes: jest.SpyInstance;\n applyRustySwordKnightDeathOutcomes: jest.SpyInstance;\n applyPlayerRoleRevelationOutcomes: jest.SpyInstance;\n applyPlayerDeathOutcomes: jest.SpyInstance;\n applyPlayerSideDeathOutcomes: jest.SpyInstance;\n applyPlayerRoleDeathOutcomes: jest.SpyInstance;\n applyPlayerAttributesDeathOutcomes: jest.SpyInstance;\n getElderLivesCountAgainstWerewolves: jest.SpyInstance;\n isElderKillable: jest.SpyInstance;\n isIdiotKillable: jest.SpyInstance;\n canPlayerBeEaten: jest.SpyInstance;\n };\n gameHistoryRecordService: {\n getGameHistoryWerewolvesEatElderRecords: jest.SpyInstance;\n getGameHistoryElderProtectedFromWerewolvesRecords: jest.SpyInstance;\n };\n gameHelper: {\n getPlayerWithIdOrThrow: jest.SpyInstance;\n doesGameHaveCurrentOrUpcomingPlaySourceAndAction: jest.SpyInstance;\n };\n unexpectedExceptionFactory: {\n createCantFindPlayerWithIdUnexpectedException: jest.SpyInstance;\n createPlayerIsDeadUnexpectedException: jest.SpyInstance;\n };\n };\n let services: { playerKiller: PlayerKillerService };\n\n beforeEach(async() => {\n mocks = {\n playerKillerService: {\n getPlayerToKillOrRevealInGame: jest.fn(),\n isPlayerKillable: jest.fn(),\n doesPlayerRoleMustBeRevealed: jest.fn(),\n removePlayerAttributesAfterDeath: jest.fn(),\n revealPlayerRole: jest.fn(),\n killPlayer: jest.fn(),\n applySheriffPlayerDeathOutcomes: jest.fn(),\n applyInLovePlayerDeathOutcomes: jest.fn(),\n applyWorshipedPlayerDeathOutcomes: jest.fn(),\n applyHunterDeathOutcomes: jest.fn(),\n applyElderDeathOutcomes: jest.fn(),\n applyScapegoatDeathOutcomes: jest.fn(),\n applyRustySwordKnightDeathOutcomes: jest.fn(),\n applyPlayerRoleRevelationOutcomes: jest.fn(),\n applyPlayerDeathOutcomes: jest.fn(),\n applyPlayerSideDeathOutcomes: jest.fn(),\n applyPlayerRoleDeathOutcomes: jest.fn(),\n applyPlayerAttributesDeathOutcomes: jest.fn(),\n getElderLivesCountAgainstWerewolves: jest.fn(),\n isElderKillable: jest.fn(),\n isIdiotKillable: jest.fn(),\n canPlayerBeEaten: jest.fn(),\n },\n gameHistoryRecordService: {\n getGameHistoryWerewolvesEatElderRecords: jest.fn(),\n getGameHistoryElderProtectedFromWerewolvesRecords: jest.fn(),\n },\n gameHelper: {\n getPlayerWithIdOrThrow: jest.spyOn(GameHelper, \"getPlayerWithIdOrThrow\").mockImplementation(),\n doesGameHaveCurrentOrUpcomingPlaySourceAndAction: jest.spyOn(GameHelper, \"doesGameHaveCurrentOrUpcomingPlaySourceAndAction\").mockImplementation(),\n },\n unexpectedExceptionFactory: {\n createCantFindPlayerWithIdUnexpectedException: jest.spyOn(UnexpectedExceptionFactory, \"createCantFindPlayerWithIdUnexpectedException\").mockImplementation(),\n createPlayerIsDeadUnexpectedException: jest.spyOn(UnexpectedExceptionFactory, \"createPlayerIsDeadUnexpectedException\").mockImplementation(),\n },\n };\n\n const module: TestingModule = await Test.createTestingModule({\n providers: [\n {\n provide: GameHistoryRecordService,\n useValue: mocks.gameHistoryRecordService,\n },\n PlayerKillerService,\n ],\n }).compile();\n\n services = { playerKiller: module.get(PlayerKillerService) };\n });\n\n describe(\"killOrRevealPlayer\", () => {\n beforeEach(() => {\n mocks.playerKillerService.getPlayerToKillOrRevealInGame = jest.spyOn(services.playerKiller as unknown as { getPlayerToKillOrRevealInGame }, \"getPlayerToKillOrRevealInGame\");\n mocks.playerKillerService.isPlayerKillable = jest.spyOn(services.playerKiller as unknown as { isPlayerKillable }, \"isPlayerKillable\");\n mocks.playerKillerService.killPlayer = jest.spyOn(services.playerKiller as unknown as { killPlayer }, \"killPlayer\");\n mocks.playerKillerService.doesPlayerRoleMustBeRevealed = jest.spyOn(services.playerKiller as unknown as { doesPlayerRoleMustBeRevealed }, \"doesPlayerRoleMustBeRevealed\");\n mocks.playerKillerService.revealPlayerRole = jest.spyOn(services.playerKiller as unknown as { revealPlayerRole }, \"revealPlayerRole\");\n });\n\n it(\"should return game as is when player can't be revealed or killed.\", async() => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const death = createFakePlayerDeathPotionByWitchDeath();\n\n mocks.playerKillerService.getPlayerToKillOrRevealInGame.mockReturnValue(players[0]);\n mocks.playerKillerService.isPlayerKillable.mockReturnValue(false);\n mocks.playerKillerService.doesPlayerRoleMustBeRevealed.mockReturnValue(false);\n\n await expect(services.playerKiller.killOrRevealPlayer(players[0]._id, game, death)).resolves.toStrictEqual(game);\n expect(mocks.playerKillerService.killPlayer).not.toHaveBeenCalled();\n expect(mocks.playerKillerService.revealPlayerRole).not.toHaveBeenCalled();\n });\n\n it(\"should call kill method when player is killable.\", async() => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const death = createFakePlayerDeathPotionByWitchDeath();\n\n mocks.gameHelper.getPlayerWithIdOrThrow.mockReturnValue(players[0]);\n mocks.playerKillerService.getPlayerToKillOrRevealInGame.mockReturnValue(players[0]);\n mocks.playerKillerService.isPlayerKillable.mockReturnValue(true);\n mocks.playerKillerService.doesPlayerRoleMustBeRevealed.mockReturnValue(true);\n\n await services.playerKiller.killOrRevealPlayer(players[0]._id, game, death);\n expect(mocks.playerKillerService.killPlayer).toHaveBeenCalledExactlyOnceWith(players[0], game, death);\n });\n\n it(\"should call reveal role method when player role must be revealed but not killed.\", async() => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const death = createFakePlayerDeathPotionByWitchDeath();\n\n mocks.playerKillerService.getPlayerToKillOrRevealInGame.mockReturnValue(players[0]);\n mocks.gameHelper.getPlayerWithIdOrThrow.mockReturnValue(players[0]);\n mocks.playerKillerService.isPlayerKillable.mockReturnValue(false);\n mocks.playerKillerService.doesPlayerRoleMustBeRevealed.mockReturnValue(true);\n\n await services.playerKiller.killOrRevealPlayer(players[0]._id, game, death);\n expect(mocks.playerKillerService.killPlayer).not.toHaveBeenCalled();\n expect(mocks.playerKillerService.revealPlayerRole).toHaveBeenCalledExactlyOnceWith(players[0], game);\n });\n });\n\n describe(\"applyPlayerDeathOutcomes\", () => {\n beforeEach(() => {\n mocks.playerKillerService.applyPlayerRoleDeathOutcomes = jest.spyOn(services.playerKiller as unknown as { applyPlayerRoleDeathOutcomes }, \"applyPlayerRoleDeathOutcomes\").mockImplementation();\n mocks.playerKillerService.applyPlayerSideDeathOutcomes = jest.spyOn(services.playerKiller as unknown as { applyPlayerSideDeathOutcomes }, \"applyPlayerSideDeathOutcomes\").mockImplementation();\n mocks.playerKillerService.applyPlayerAttributesDeathOutcomes = jest.spyOn(services.playerKiller as unknown as { applyPlayerAttributesDeathOutcomes }, \"applyPlayerAttributesDeathOutcomes\").mockImplementation();\n });\n\n it(\"should create unexpected exception for later purposes when called.\", () => {\n const death = createFakePlayerDeathPotionByWitchDeath();\n const players = [\n createFakeRustySwordKnightAlivePlayer({ isAlive: false, death }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const exception = new UnexpectedException(\"applyPlayerAttributesDeathOutcomes\", UnexpectedExceptionReasons.CANT_FIND_PLAYER_WITH_ID_IN_GAME, { gameId: game._id.toString(), playerId: players[0]._id.toString() });\n\n mocks.unexpectedExceptionFactory.createCantFindPlayerWithIdUnexpectedException.mockReturnValue(exception);\n mocks.gameHelper.getPlayerWithIdOrThrow.mockReturnValue(players[0]);\n mocks.gameHelper.doesGameHaveCurrentOrUpcomingPlaySourceAndAction.mockReturnValue(true);\n mocks.playerKillerService.applyPlayerRoleDeathOutcomes.mockReturnValue(game);\n mocks.playerKillerService.applyPlayerSideDeathOutcomes.mockReturnValue(game);\n mocks.playerKillerService.applyPlayerAttributesDeathOutcomes.mockReturnValue(game);\n services.playerKiller.applyPlayerDeathOutcomes(players[0] as DeadPlayer, game);\n\n expect(mocks.unexpectedExceptionFactory.createCantFindPlayerWithIdUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"applyPlayerDeathOutcomes\", { gameId: game._id, playerId: players[0]._id });\n });\n\n it(\"should apply player role death outcomes when called.\", () => {\n const death = createFakePlayerDeathPotionByWitchDeath();\n const players = [\n createFakeRustySwordKnightAlivePlayer({ isAlive: false, death }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const exception = new UnexpectedException(\"applyPlayerAttributesDeathOutcomes\", UnexpectedExceptionReasons.CANT_FIND_PLAYER_WITH_ID_IN_GAME, { gameId: game._id.toString(), playerId: players[0]._id.toString() });\n\n mocks.unexpectedExceptionFactory.createCantFindPlayerWithIdUnexpectedException.mockReturnValue(exception);\n mocks.gameHelper.getPlayerWithIdOrThrow.mockReturnValue(players[0]);\n mocks.gameHelper.doesGameHaveCurrentOrUpcomingPlaySourceAndAction.mockReturnValue(true);\n mocks.playerKillerService.applyPlayerRoleDeathOutcomes.mockReturnValue(game);\n mocks.playerKillerService.applyPlayerSideDeathOutcomes.mockReturnValue(game);\n mocks.playerKillerService.applyPlayerAttributesDeathOutcomes.mockReturnValue(game);\n services.playerKiller.applyPlayerDeathOutcomes(players[0] as DeadPlayer, game);\n\n expect(mocks.playerKillerService.applyPlayerRoleDeathOutcomes).toHaveBeenCalledExactlyOnceWith(players[0], game);\n });\n\n it(\"should apply player side death outcomes when called.\", () => {\n const death = createFakePlayerDeathPotionByWitchDeath();\n const players = [\n createFakeRustySwordKnightAlivePlayer({ isAlive: false, death }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const exception = new UnexpectedException(\"applyPlayerAttributesDeathOutcomes\", UnexpectedExceptionReasons.CANT_FIND_PLAYER_WITH_ID_IN_GAME, { gameId: game._id.toString(), playerId: players[0]._id.toString() });\n\n mocks.unexpectedExceptionFactory.createCantFindPlayerWithIdUnexpectedException.mockReturnValue(exception);\n mocks.gameHelper.getPlayerWithIdOrThrow.mockReturnValue(players[0]);\n mocks.gameHelper.doesGameHaveCurrentOrUpcomingPlaySourceAndAction.mockReturnValue(true);\n mocks.playerKillerService.applyPlayerRoleDeathOutcomes.mockReturnValue(game);\n mocks.playerKillerService.applyPlayerSideDeathOutcomes.mockReturnValue(game);\n mocks.playerKillerService.applyPlayerAttributesDeathOutcomes.mockReturnValue(game);\n services.playerKiller.applyPlayerDeathOutcomes(players[0] as DeadPlayer, game);\n\n expect(mocks.playerKillerService.applyPlayerSideDeathOutcomes).toHaveBeenCalledExactlyOnceWith(players[0], game);\n });\n\n it(\"should apply player attributes death outcomes when called.\", () => {\n const death = createFakePlayerDeathPotionByWitchDeath();\n const players = [\n createFakeRustySwordKnightAlivePlayer({ isAlive: false, death }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const exception = new UnexpectedException(\"applyPlayerAttributesDeathOutcomes\", UnexpectedExceptionReasons.CANT_FIND_PLAYER_WITH_ID_IN_GAME, { gameId: game._id.toString(), playerId: players[0]._id.toString() });\n\n mocks.unexpectedExceptionFactory.createCantFindPlayerWithIdUnexpectedException.mockReturnValue(exception);\n mocks.gameHelper.getPlayerWithIdOrThrow.mockReturnValue(players[0]);\n mocks.gameHelper.doesGameHaveCurrentOrUpcomingPlaySourceAndAction.mockReturnValue(true);\n mocks.playerKillerService.applyPlayerRoleDeathOutcomes.mockReturnValue(game);\n mocks.playerKillerService.applyPlayerSideDeathOutcomes.mockReturnValue(game);\n mocks.playerKillerService.applyPlayerAttributesDeathOutcomes.mockReturnValue(game);\n services.playerKiller.applyPlayerDeathOutcomes(players[0] as DeadPlayer, game);\n\n expect(mocks.playerKillerService.applyPlayerAttributesDeathOutcomes).toHaveBeenCalledExactlyOnceWith(players[0], game);\n });\n\n it(\"should filter out player attributes which need to be removed after death when called.\", () => {\n const death = createFakePlayerDeathPotionByWitchDeath();\n const players = [\n createFakeRustySwordKnightAlivePlayer({ isAlive: false, death, attributes: [createFakeScandalmongerMarkedByScandalmongerPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const exception = new UnexpectedException(\"applyPlayerAttributesDeathOutcomes\", UnexpectedExceptionReasons.CANT_FIND_PLAYER_WITH_ID_IN_GAME, { gameId: game._id.toString(), playerId: players[0]._id.toString() });\n\n mocks.unexpectedExceptionFactory.createCantFindPlayerWithIdUnexpectedException.mockReturnValue(exception);\n mocks.gameHelper.getPlayerWithIdOrThrow.mockReturnValue(players[0]);\n mocks.gameHelper.doesGameHaveCurrentOrUpcomingPlaySourceAndAction.mockReturnValue(true);\n mocks.playerKillerService.applyPlayerRoleDeathOutcomes.mockReturnValue(game);\n mocks.playerKillerService.applyPlayerSideDeathOutcomes.mockReturnValue(game);\n mocks.playerKillerService.applyPlayerAttributesDeathOutcomes.mockReturnValue(game);\n const expectedGame = createFakeGame({\n ...game,\n players: [\n createFakePlayer({\n ...players[0],\n attributes: [],\n }),\n game.players[1],\n game.players[2],\n game.players[3],\n ],\n });\n\n expect(services.playerKiller.applyPlayerDeathOutcomes(players[0] as DeadPlayer, game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"revealPlayerRole\", () => {\n it(\"should create can't find player exception for later purposes when called.\", () => {\n const players = [\n createFakeWildChildAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const expectedInterpolations = { gameId: game._id, playerId: players[0]._id };\n mocks.gameHelper.getPlayerWithIdOrThrow.mockReturnValue(players[0]);\n services.playerKiller.revealPlayerRole(players[0], game);\n\n expect(mocks.unexpectedExceptionFactory.createCantFindPlayerWithIdUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"revealPlayerRole\", expectedInterpolations);\n });\n\n it(\"should reveal player role when called.\", () => {\n const players = [\n createFakeWildChildAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n createFakePlayer({\n ...players[0],\n role: createFakePlayerRole({ ...players[0].role, isRevealed: true }),\n }),\n game.players[1],\n game.players[2],\n game.players[3],\n ],\n });\n mocks.gameHelper.getPlayerWithIdOrThrow.mockReturnValue(players[0]);\n\n expect(services.playerKiller.revealPlayerRole(players[0], game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"getElderLivesCountAgainstWerewolves\", () => {\n it(\"should get elder lives count against werewolves when called.\", async() => {\n const livesCountAgainstWerewolves = 3;\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ elder: createFakeElderGameOptions({ livesCountAgainstWerewolves }) }) });\n const elderPlayer = createFakeElderAlivePlayer();\n const game = createFakeGame({ turn: 2, currentPlay: createFakeGamePlayHunterShoots(), options });\n mocks.gameHistoryRecordService.getGameHistoryWerewolvesEatElderRecords.mockResolvedValue([]);\n mocks.gameHistoryRecordService.getGameHistoryElderProtectedFromWerewolvesRecords.mockResolvedValue([]);\n await services.playerKiller[\"getElderLivesCountAgainstWerewolves\"](game, elderPlayer);\n\n expect(mocks.gameHistoryRecordService.getGameHistoryWerewolvesEatElderRecords).toHaveBeenCalledExactlyOnceWith(game._id, elderPlayer._id);\n });\n\n it(\"should get elder protected from werewolves records when called.\", async() => {\n const livesCountAgainstWerewolves = 3;\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ elder: createFakeElderGameOptions({ livesCountAgainstWerewolves }) }) });\n const elderPlayer = createFakeElderAlivePlayer();\n const game = createFakeGame({ turn: 2, currentPlay: createFakeGamePlayHunterShoots(), options });\n mocks.gameHistoryRecordService.getGameHistoryWerewolvesEatElderRecords.mockResolvedValue([]);\n mocks.gameHistoryRecordService.getGameHistoryElderProtectedFromWerewolvesRecords.mockResolvedValue([]);\n await services.playerKiller[\"getElderLivesCountAgainstWerewolves\"](game, elderPlayer);\n\n expect(mocks.gameHistoryRecordService.getGameHistoryElderProtectedFromWerewolvesRecords).toHaveBeenCalledExactlyOnceWith(game._id, elderPlayer._id);\n });\n\n it(\"should return same amount of lives when no werewolves attack against elder.\", async() => {\n const livesCountAgainstWerewolves = 3;\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ elder: createFakeElderGameOptions({ livesCountAgainstWerewolves }) }) });\n const elderPlayer = createFakeElderAlivePlayer();\n const game = createFakeGame({ turn: 2, currentPlay: createFakeGamePlayHunterShoots(), options });\n const gameHistoryRecordPlayElderTarget = createFakeGameHistoryRecordPlayTarget({ player: createFakeElderAlivePlayer() });\n const elderProtectedFromWerewolvesRecords = [\n createFakeGameHistoryRecord({\n play: createFakeGameHistoryRecordDefenderProtectPlay({ targets: [gameHistoryRecordPlayElderTarget] }),\n turn: 1,\n }),\n ];\n mocks.gameHistoryRecordService.getGameHistoryWerewolvesEatElderRecords.mockResolvedValue([]);\n mocks.gameHistoryRecordService.getGameHistoryElderProtectedFromWerewolvesRecords.mockResolvedValue(elderProtectedFromWerewolvesRecords);\n\n await expect(services.playerKiller[\"getElderLivesCountAgainstWerewolves\"](game, elderPlayer)).resolves.toBe(3);\n });\n\n it(\"should return amount of lives minus one when werewolves attacked the elder on current turn.\", async() => {\n const livesCountAgainstWerewolves = 3;\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ elder: createFakeElderGameOptions({ livesCountAgainstWerewolves }) }) });\n const elderPlayer = createFakeElderAlivePlayer({ attributes: [createFakeEatenByWerewolvesPlayerAttribute()] });\n const game = createFakeGame({ turn: 2, currentPlay: createFakeGamePlayHunterShoots(), options });\n const gameHistoryRecordPlayElderTarget = createFakeGameHistoryRecordPlayTarget({ player: elderPlayer });\n const elderProtectedFromWerewolvesRecords = [\n createFakeGameHistoryRecord({\n play: createFakeGameHistoryRecordDefenderProtectPlay({ targets: [gameHistoryRecordPlayElderTarget] }),\n turn: 1,\n }),\n ];\n mocks.gameHistoryRecordService.getGameHistoryWerewolvesEatElderRecords.mockResolvedValue([]);\n mocks.gameHistoryRecordService.getGameHistoryElderProtectedFromWerewolvesRecords.mockResolvedValue(elderProtectedFromWerewolvesRecords);\n\n await expect(services.playerKiller[\"getElderLivesCountAgainstWerewolves\"](game, elderPlayer)).resolves.toBe(2);\n });\n\n it(\"should return amount of lives minus two when werewolves attacked the elder on current turn and also before that.\", async() => {\n const livesCountAgainstWerewolves = 3;\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ elder: createFakeElderGameOptions({ livesCountAgainstWerewolves }) }) });\n const elderPlayer = createFakeElderAlivePlayer({ attributes: [createFakeEatenByWerewolvesPlayerAttribute()] });\n const game = createFakeGame({ turn: 2, currentPlay: createFakeGamePlayHunterShoots(), options });\n const gameHistoryRecordPlayElderTarget = createFakeGameHistoryRecordPlayTarget({ player: elderPlayer });\n const werewolvesEatElderRecords = [\n createFakeGameHistoryRecord({\n play: createFakeGameHistoryRecordWerewolvesEatPlay({ targets: [gameHistoryRecordPlayElderTarget] }),\n turn: 1,\n }),\n createFakeGameHistoryRecord({\n play: createFakeGameHistoryRecordWerewolvesEatPlay({ targets: [gameHistoryRecordPlayElderTarget] }),\n turn: 2,\n }),\n ];\n mocks.gameHistoryRecordService.getGameHistoryWerewolvesEatElderRecords.mockResolvedValue(werewolvesEatElderRecords);\n mocks.gameHistoryRecordService.getGameHistoryElderProtectedFromWerewolvesRecords.mockResolvedValue([]);\n\n await expect(services.playerKiller[\"getElderLivesCountAgainstWerewolves\"](game, elderPlayer)).resolves.toBe(1);\n });\n\n it(\"should return amount of lives minus one when elder was attacked three times but protected once and saved by witch once.\", async() => {\n const livesCountAgainstWerewolves = 3;\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ elder: createFakeElderGameOptions({ livesCountAgainstWerewolves }) }) });\n const elderPlayer = createFakeElderAlivePlayer();\n const game = createFakeGame({ turn: 4, currentPlay: createFakeGamePlayHunterShoots(), options });\n const gameHistoryRecordPlayElderTarget = createFakeGameHistoryRecordPlayTarget({ player: createFakeElderAlivePlayer() });\n const gameHistoryRecordPlayElderDrankLifePotionTarget = createFakeGameHistoryRecordPlayTarget({ ...gameHistoryRecordPlayElderTarget, drankPotion: \"life\" });\n const werewolvesEatElderRecords = [\n createFakeGameHistoryRecord({\n play: createFakeGameHistoryRecordWerewolvesEatPlay({ targets: [gameHistoryRecordPlayElderTarget] }),\n turn: 1,\n }),\n createFakeGameHistoryRecord({\n play: createFakeGameHistoryRecordWerewolvesEatPlay({ targets: [gameHistoryRecordPlayElderTarget] }),\n turn: 2,\n }),\n createFakeGameHistoryRecord({\n play: createFakeGameHistoryRecordWerewolvesEatPlay({ targets: [gameHistoryRecordPlayElderTarget] }),\n turn: 3,\n }),\n ];\n const elderProtectedFromWerewolvesRecords = [\n createFakeGameHistoryRecord({\n play: createFakeGameHistoryRecordDefenderProtectPlay({ targets: [gameHistoryRecordPlayElderTarget] }),\n turn: 1,\n }),\n createFakeGameHistoryRecord({\n play: createFakeGameHistoryRecordWitchUsePotionsPlay({ targets: [gameHistoryRecordPlayElderDrankLifePotionTarget] }),\n turn: 2,\n }),\n ];\n mocks.gameHistoryRecordService.getGameHistoryWerewolvesEatElderRecords.mockResolvedValue(werewolvesEatElderRecords);\n mocks.gameHistoryRecordService.getGameHistoryElderProtectedFromWerewolvesRecords.mockResolvedValue(elderProtectedFromWerewolvesRecords);\n\n await expect(services.playerKiller[\"getElderLivesCountAgainstWerewolves\"](game, elderPlayer)).resolves.toBe(2);\n });\n\n it(\"should return amount of lives minus 1 when elder was attacked but not protected or saved by witch.\", async() => {\n const livesCountAgainstWerewolves = 3;\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ elder: createFakeElderGameOptions({ livesCountAgainstWerewolves }) }) });\n const elderPlayer = createFakeElderAlivePlayer();\n const game = createFakeGame({ turn: 2, currentPlay: createFakeGamePlayHunterShoots(), options });\n const gameHistoryRecordPlayElderTarget = createFakeGameHistoryRecordPlayTarget({ player: createFakeElderAlivePlayer() });\n const werewolvesEatElderRecords = [\n createFakeGameHistoryRecord({\n play: createFakeGameHistoryRecordWerewolvesEatPlay({ targets: [gameHistoryRecordPlayElderTarget] }),\n turn: 1,\n }),\n ];\n mocks.gameHistoryRecordService.getGameHistoryWerewolvesEatElderRecords.mockResolvedValue(werewolvesEatElderRecords);\n mocks.gameHistoryRecordService.getGameHistoryElderProtectedFromWerewolvesRecords.mockResolvedValue([]);\n\n await expect(services.playerKiller[\"getElderLivesCountAgainstWerewolves\"](game, elderPlayer)).resolves.toBe(2);\n });\n });\n\n describe(\"applyPlayerRoleRevelationOutcomes\", () => {\n it(\"should add can't vote attribute when player is idiot.\", () => {\n const players = [\n createFakeIdiotAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n createFakePlayer({\n ...players[0],\n attributes: [createFakeCantVoteBySurvivorsPlayerAttribute()],\n }),\n game.players[1],\n game.players[2],\n game.players[3],\n ],\n });\n\n expect(services.playerKiller[\"applyPlayerRoleRevelationOutcomes\"](game.players[0], game)).toStrictEqual(expectedGame);\n });\n\n it(\"should return the game as is when player is not an idiot.\", () => {\n const players = [\n createFakeIdiotAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(services.playerKiller[\"applyPlayerRoleRevelationOutcomes\"](game.players[1], game)).toStrictEqual(game);\n });\n });\n\n describe(\"isElderKillable\", () => {\n beforeEach(() => {\n mocks.playerKillerService.getElderLivesCountAgainstWerewolves = jest.spyOn(services.playerKiller as unknown as { getElderLivesCountAgainstWerewolves }, \"getElderLivesCountAgainstWerewolves\").mockImplementation();\n });\n\n it.each<{\n test: string;\n elderPlayer: Player;\n cause: PlayerDeathCause;\n getElderLivesCountAgainstWerewolvesMockReturnValue: number;\n expected: boolean;\n }>([\n {\n test: \"should return true when cause is not EATEN.\",\n elderPlayer: createFakeElderAlivePlayer(),\n cause: \"vote\",\n getElderLivesCountAgainstWerewolvesMockReturnValue: 2,\n expected: true,\n },\n {\n test: \"should return false when cause is EATEN but elder still have at least one life left.\",\n elderPlayer: createFakeElderAlivePlayer(),\n cause: \"eaten\",\n getElderLivesCountAgainstWerewolvesMockReturnValue: 2,\n expected: false,\n },\n {\n test: \"should return true when cause is EATEN but elder has 0 life left.\",\n elderPlayer: createFakeElderAlivePlayer(),\n cause: \"eaten\",\n getElderLivesCountAgainstWerewolvesMockReturnValue: 0,\n expected: true,\n },\n ])(\"$test\", async({ elderPlayer, cause, getElderLivesCountAgainstWerewolvesMockReturnValue, expected }) => {\n const game = createFakeGame();\n mocks.playerKillerService.getElderLivesCountAgainstWerewolves.mockReturnValue(getElderLivesCountAgainstWerewolvesMockReturnValue);\n\n await expect(services.playerKiller.isElderKillable(game, elderPlayer, cause)).resolves.toBe(expected);\n });\n });\n\n describe(\"doesPlayerRoleMustBeRevealed\", () => {\n it.each<{\n test: string;\n player: Player;\n death: PlayerDeath;\n game: Game;\n expected: boolean;\n }>([\n {\n test: \"should return false when player role is already revealed.\",\n player: createFakeVillagerVillagerAlivePlayer(),\n death: createFakePlayerVoteBySurvivorsDeath(),\n game: createFakeGame(),\n expected: false,\n },\n {\n test: \"should return false when player is dead but options doesn't allow the role to be revealed.\",\n player: createFakeWitchAlivePlayer(),\n death: createFakePlayerVoteBySurvivorsDeath(),\n game: createFakeGame({ options: createFakeGameOptions({ roles: createFakeRolesGameOptions({ areRevealedOnDeath: false }) }) }),\n expected: false,\n },\n {\n test: \"should return false when player role is not idiot.\",\n player: createFakeSeerAlivePlayer(),\n death: createFakePlayerVoteBySurvivorsDeath(),\n game: createFakeGame(),\n expected: false,\n },\n {\n test: \"should return false when player role is idiot but powerless.\",\n player: createFakeIdiotAlivePlayer({ attributes: [createFakePowerlessByElderPlayerAttribute()] }),\n death: createFakePlayerVoteBySurvivorsDeath(),\n game: createFakeGame(),\n expected: false,\n },\n {\n test: \"should return false when player role is idiot but death cause is not vote.\",\n player: createFakeIdiotAlivePlayer(),\n death: createFakePlayerDeathPotionByWitchDeath(),\n game: createFakeGame(),\n expected: false,\n },\n {\n test: \"should return false when player is not dead and his role can be revealed to others.\",\n player: createFakeWitchAlivePlayer(),\n death: createFakePlayerVoteBySurvivorsDeath(),\n game: createFakeGame({ options: createFakeGameOptions({ roles: createFakeRolesGameOptions({ areRevealedOnDeath: true }) }) }),\n expected: false,\n },\n {\n test: \"should return true when player is dead and his role can be revealed to others.\",\n player: createFakeWitchAlivePlayer({ isAlive: false }),\n death: createFakePlayerVoteBySurvivorsDeath(),\n game: createFakeGame({ options: createFakeGameOptions({ roles: createFakeRolesGameOptions({ areRevealedOnDeath: true }) }) }),\n expected: true,\n },\n {\n test: \"should return true when player role is idiot and death cause is vote.\",\n player: createFakeIdiotAlivePlayer(),\n death: createFakePlayerVoteBySurvivorsDeath(),\n game: createFakeGame(),\n expected: true,\n },\n ])(\"$test\", ({ player, death, game, expected }) => {\n expect(services.playerKiller[\"doesPlayerRoleMustBeRevealed\"](player, death, game)).toBe(expected);\n });\n });\n\n describe(\"removePlayerAttributesAfterDeath\", () => {\n it(\"should remove player attributes which need to be removed after death when called.\", () => {\n const player = createFakePlayer({\n isAlive: false,\n attributes: [\n createFakeCantVoteBySurvivorsPlayerAttribute({ doesRemainAfterDeath: false }),\n createFakePowerlessByElderPlayerAttribute(),\n createFakeSheriffBySurvivorsPlayerAttribute({ doesRemainAfterDeath: true }),\n ],\n });\n const expectedPlayer = createFakePlayer({\n ...player,\n attributes: [\n player.attributes[1],\n player.attributes[2],\n ],\n });\n\n expect(services.playerKiller[\"removePlayerAttributesAfterDeath\"](player)).toStrictEqual(expectedPlayer);\n });\n });\n\n describe(\"isIdiotKillable\", () => {\n it.each<{\n test: string;\n player: Player;\n cause: PlayerDeathCause;\n game: Game;\n expected: boolean;\n }>([\n {\n test: \"should return true when idiot is already revealed.\",\n player: createFakeIdiotAlivePlayer({ role: createFakePlayerRole({ isRevealed: true }) }),\n cause: \"vote\",\n game: createFakeGame(),\n expected: true,\n },\n {\n test: \"should return true when idiot is killed by other cause than a vote.\",\n player: createFakeIdiotAlivePlayer(),\n cause: \"death-potion\",\n game: createFakeGame(),\n expected: true,\n },\n {\n test: \"should return true when idiot is killed by vote but powerless.\",\n player: createFakeIdiotAlivePlayer({ attributes: [createFakePowerlessByElderPlayerAttribute()] }),\n cause: \"vote\",\n game: createFakeGame(),\n expected: true,\n },\n {\n test: \"should return false when idiot is not revealed, dies from votes and is not powerless.\",\n player: createFakeIdiotAlivePlayer(),\n cause: \"vote\",\n game: createFakeGame(),\n expected: false,\n },\n ])(\"$test\", ({ player, cause, game, expected }) => {\n expect(services.playerKiller[\"isIdiotKillable\"](player, cause, game)).toBe(expected);\n });\n });\n\n describe(\"canPlayerBeEaten\", () => {\n it.each<{\n test: string;\n player: Player;\n game: Game;\n expected: boolean;\n }>([\n {\n test: \"should return false when player is saved by the witch.\",\n player: createFakeSeerAlivePlayer({ attributes: [createFakeDrankLifePotionByWitchPlayerAttribute()] }),\n game: createFakeGame(),\n expected: false,\n },\n {\n test: \"should return false when player is protected by defender and is not little girl.\",\n player: createFakeSeerAlivePlayer({ attributes: [createFakeProtectedByDefenderPlayerAttribute()] }),\n game: createFakeGame({ options: createFakeGameOptions({ roles: createFakeRolesGameOptions({ littleGirl: createFakeLittleGirlGameOptions({ isProtectedByDefender: true }) }) }) }),\n expected: false,\n },\n {\n test: \"should return false when player is protected by defender, is little girl but game options allows defender to protect her.\",\n player: createFakeLittleGirlAlivePlayer({ attributes: [createFakeProtectedByDefenderPlayerAttribute()] }),\n game: createFakeGame({ options: createFakeGameOptions({ roles: createFakeRolesGameOptions({ littleGirl: createFakeLittleGirlGameOptions({ isProtectedByDefender: true }) }) }) }),\n expected: false,\n },\n {\n test: \"should return true when player is protected by defender, is little girl but game options doesn't allow defender to protect her.\",\n player: createFakeLittleGirlAlivePlayer({ attributes: [createFakeProtectedByDefenderPlayerAttribute()] }),\n game: createFakeGame({ options: createFakeGameOptions({ roles: createFakeRolesGameOptions({ littleGirl: createFakeLittleGirlGameOptions({ isProtectedByDefender: false }) }) }) }),\n expected: true,\n },\n {\n test: \"should return false when little girl is saved by the witch.\",\n player: createFakeLittleGirlAlivePlayer({ attributes: [createFakeDrankLifePotionByWitchPlayerAttribute()] }),\n game: createFakeGame(),\n expected: false,\n },\n {\n test: \"should return true when player defenseless.\",\n player: createFakeSeerAlivePlayer({ attributes: [] }),\n game: createFakeGame({ options: createFakeGameOptions({ roles: createFakeRolesGameOptions({ littleGirl: createFakeLittleGirlGameOptions({ isProtectedByDefender: true }) }) }) }),\n expected: true,\n },\n ])(\"$test\", ({ player, game, expected }) => {\n expect(services.playerKiller[\"canPlayerBeEaten\"](player, game)).toBe(expected);\n });\n\n it(\"should return false when player is protected by defender and is not little girl.\", () => {\n const player = createFakeSeerAlivePlayer({ attributes: [createFakeProtectedByDefenderPlayerAttribute()] });\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ littleGirl: createFakeLittleGirlGameOptions({ isProtectedByDefender: false }) }) });\n const game = createFakeGame({ options });\n\n expect(services.playerKiller[\"canPlayerBeEaten\"](player, game)).toBe(false);\n });\n });\n\n describe(\"isPlayerKillable\", () => {\n beforeEach(() => {\n mocks.playerKillerService.isIdiotKillable = jest.spyOn(services.playerKiller as unknown as { isIdiotKillable }, \"isIdiotKillable\").mockImplementation();\n mocks.playerKillerService.isElderKillable = jest.spyOn(services.playerKiller as unknown as { isElderKillable }, \"isElderKillable\").mockImplementation();\n mocks.playerKillerService.canPlayerBeEaten = jest.spyOn(services.playerKiller as unknown as { canPlayerBeEaten }, \"canPlayerBeEaten\").mockImplementation();\n });\n\n it(\"should return false when cause is EATEN and player can't be eaten.\", async() => {\n const player = createFakePlayer();\n const game = createFakeGame();\n mocks.playerKillerService.canPlayerBeEaten.mockReturnValue(false);\n\n await expect(services.playerKiller[\"isPlayerKillable\"](player, game, \"eaten\")).resolves.toBe(false);\n });\n\n it(\"should not call can player be eaten validator when cause is not EATEN.\", async() => {\n const player = createFakePlayer();\n const game = createFakeGame();\n mocks.playerKillerService.canPlayerBeEaten.mockReturnValue(false);\n await services.playerKiller[\"isPlayerKillable\"](player, game, \"vote\");\n\n expect(mocks.playerKillerService.canPlayerBeEaten).not.toHaveBeenCalled();\n });\n\n it(\"should call is idiot killable when player is an idiot.\", async() => {\n const player = createFakeIdiotAlivePlayer();\n const game = createFakeGame();\n mocks.playerKillerService.isIdiotKillable.mockReturnValue(false);\n await services.playerKiller[\"isPlayerKillable\"](player, game, \"vote\");\n\n expect(mocks.playerKillerService.isIdiotKillable).toHaveBeenCalledExactlyOnceWith(player, \"vote\", game);\n });\n\n it(\"should not call is idiot killable when player is not an idiot.\", async() => {\n const player = createFakeSeerAlivePlayer();\n const game = createFakeGame();\n mocks.playerKillerService.isIdiotKillable.mockReturnValue(false);\n await services.playerKiller[\"isPlayerKillable\"](player, game, \"vote\");\n\n expect(mocks.playerKillerService.isIdiotKillable).not.toHaveBeenCalled();\n });\n\n it(\"should call is elder killable when player is an elder.\", async() => {\n const player = createFakeElderAlivePlayer();\n const game = createFakeGame();\n mocks.playerKillerService.isElderKillable.mockReturnValue(false);\n await services.playerKiller[\"isPlayerKillable\"](player, game, \"vote\");\n\n expect(mocks.playerKillerService.isElderKillable).toHaveBeenCalledExactlyOnceWith(game, player, \"vote\");\n });\n\n it(\"should not call is elder killable when player is not an elder.\", async() => {\n const player = createFakeSeerAlivePlayer();\n const game = createFakeGame();\n mocks.playerKillerService.isElderKillable.mockReturnValue(false);\n await services.playerKiller[\"isPlayerKillable\"](player, game, \"vote\");\n\n expect(mocks.playerKillerService.isElderKillable).not.toHaveBeenCalled();\n });\n\n it(\"should return true when there are no contraindications.\", async() => {\n const player = createFakeSeerAlivePlayer();\n const game = createFakeGame();\n\n await expect(services.playerKiller[\"isPlayerKillable\"](player, game, \"vote\")).resolves.toBe(true);\n });\n });\n\n describe(\"applyWorshipedPlayerDeathOutcomes\", () => {\n it(\"should return game as is when killed player doesn't have the worshiped attribute.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWildChildAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer({ attributes: [createFakeWorshipedByWildChildPlayerAttribute()] }),\n ];\n const game = createFakeGame({ players });\n\n expect(services.playerKiller[\"applyWorshipedPlayerDeathOutcomes\"](players[0], game)).toStrictEqual(game);\n });\n\n it(\"should return game as is when there is no wild child player.\", () => {\n const players = [\n createFakeSeerAlivePlayer({ attributes: [createFakeWorshipedByWildChildPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer(),\n createFakeWitchAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(services.playerKiller[\"applyWorshipedPlayerDeathOutcomes\"](players[0], game)).toStrictEqual(game);\n });\n\n it(\"should return game as is when wild child player is dead.\", () => {\n const players = [\n createFakeSeerAlivePlayer({ attributes: [createFakeWorshipedByWildChildPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer(),\n createFakeWildChildAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(services.playerKiller[\"applyWorshipedPlayerDeathOutcomes\"](players[0], game)).toStrictEqual(game);\n });\n\n it(\"should return game as is when wild child player is powerless.\", () => {\n const players = [\n createFakeSeerAlivePlayer({ attributes: [createFakeWorshipedByWildChildPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer(),\n createFakeWildChildAlivePlayer({ attributes: [createFakePowerlessByElderPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(services.playerKiller[\"applyWorshipedPlayerDeathOutcomes\"](players[0], game)).toStrictEqual(game);\n });\n\n it(\"should transform wild child to a werewolf sided player when called.\", () => {\n const players = [\n createFakeSeerAlivePlayer({ attributes: [createFakeWorshipedByWildChildPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWildChildAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n game.players[0],\n game.players[1],\n game.players[2],\n createFakePlayer({\n ...game.players[3],\n side: createFakePlayerSide({ ...game.players[3].side, current: \"werewolves\" }),\n }),\n ],\n });\n\n expect(services.playerKiller[\"applyWorshipedPlayerDeathOutcomes\"](players[0], game)).toStrictEqual(expectedGame);\n });\n\n it(\"should transform wild child to a werewolf sided player and add powerless attribute when wild child is actor in disguise.\", () => {\n const players = [\n createFakeSeerAlivePlayer({ attributes: [createFakeWorshipedByWildChildPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWildChildAlivePlayer({\n role: createFakePlayerRole({ original: \"actor\", current: \"wild-child\" }),\n attributes: [createFakeCantVoteBySurvivorsPlayerAttribute()],\n }),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ actor: createFakeActorGameOptions({ isPowerlessOnWerewolvesSide: true }) }) });\n const game = createFakeGame({ players, options });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n game.players[0],\n game.players[1],\n game.players[2],\n createFakePlayer({\n ...game.players[3],\n side: createFakePlayerSide({ ...game.players[3].side, current: \"werewolves\" }),\n attributes: [...game.players[3].attributes, createFakePowerlessByActorPlayerAttribute()],\n }),\n ],\n });\n\n expect(services.playerKiller[\"applyWorshipedPlayerDeathOutcomes\"](players[0], game)).toStrictEqual(expectedGame);\n });\n\n it(\"should transform wild child to a werewolf sided player but without powerless attribute when wild child is actor in disguise and game options are changed.\", () => {\n const players = [\n createFakeSeerAlivePlayer({ attributes: [createFakeWorshipedByWildChildPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWildChildAlivePlayer({\n role: createFakePlayerRole({ original: \"actor\", current: \"wild-child\" }),\n attributes: [createFakeCantVoteBySurvivorsPlayerAttribute()],\n }),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ actor: createFakeActorGameOptions({ isPowerlessOnWerewolvesSide: false }) }) });\n const game = createFakeGame({ players, options });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n game.players[0],\n game.players[1],\n game.players[2],\n createFakePlayer({\n ...game.players[3],\n side: createFakePlayerSide({ ...game.players[3].side, current: \"werewolves\" }),\n attributes: [...game.players[3].attributes],\n }),\n ],\n });\n\n expect(services.playerKiller[\"applyWorshipedPlayerDeathOutcomes\"](players[0], game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"applyInLovePlayerDeathOutcomes\", () => {\n beforeEach(() => {\n mocks.playerKillerService.killPlayer = jest.spyOn(services.playerKiller as unknown as { killPlayer }, \"killPlayer\").mockImplementation();\n });\n\n it(\"should return game as is when killed player doesn't have the in love attribute.\", () => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(services.playerKiller[\"applyInLovePlayerDeathOutcomes\"](players[0], game)).toStrictEqual(game);\n });\n\n it(\"should return game as is when the other lover is not found because no other one has the in love attribute.\", () => {\n const players = [\n createFakeSeerAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(services.playerKiller[\"applyInLovePlayerDeathOutcomes\"](players[0], game)).toStrictEqual(game);\n });\n\n it(\"should return game as is when the other lover is not found because he is dead.\", () => {\n const players = [\n createFakeSeerAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()], isAlive: false }),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(services.playerKiller[\"applyInLovePlayerDeathOutcomes\"](players[0], game)).toStrictEqual(game);\n });\n\n it(\"should kill the other lover when called.\", () => {\n const players = [\n createFakeSeerAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n services.playerKiller[\"applyInLovePlayerDeathOutcomes\"](players[1], game);\n\n expect(mocks.playerKillerService.killPlayer).toHaveBeenCalledExactlyOnceWith(players[0], game, createFakePlayerBrokenHeartByCupidDeath());\n });\n });\n\n describe(\"applySheriffPlayerDeathOutcomes\", () => {\n it(\"should return game as is when player is not the sheriff.\", () => {\n const players = [\n createFakeSeerAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(services.playerKiller[\"applySheriffPlayerDeathOutcomes\"](players[0], game)).toStrictEqual(game);\n });\n\n it(\"should return game as is when player is idiot and not powerless.\", () => {\n const players = [\n createFakeIdiotAlivePlayer({ attributes: [createFakeSheriffBySurvivorsPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(services.playerKiller[\"applySheriffPlayerDeathOutcomes\"](players[0], game)).toStrictEqual(game);\n });\n\n it(\"should prepend sheriff election game play when called with powerless idiot.\", () => {\n const players = [\n createFakeIdiotAlivePlayer({ attributes: [createFakeSheriffBySurvivorsPlayerAttribute(), createFakePowerlessByElderPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const upcomingPlays = [createFakeGamePlayHunterShoots()];\n const game = createFakeGame({ players, upcomingPlays });\n const expectedGame = createFakeGame({\n ...game,\n upcomingPlays: [createFakeGamePlaySheriffDelegates(), ...game.upcomingPlays],\n });\n\n expect(services.playerKiller[\"applySheriffPlayerDeathOutcomes\"](players[0], game)).toStrictEqual(expectedGame);\n });\n\n it(\"should prepend sheriff election game play when called with any other role.\", () => {\n const players = [\n createFakeWildChildAlivePlayer({ attributes: [createFakeSheriffBySurvivorsPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const upcomingPlays = [createFakeGamePlayHunterShoots()];\n const game = createFakeGame({ players, upcomingPlays });\n const expectedGame = createFakeGame({\n ...game,\n upcomingPlays: [createFakeGamePlaySheriffDelegates(), ...game.upcomingPlays],\n });\n\n expect(services.playerKiller[\"applySheriffPlayerDeathOutcomes\"](players[0], game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"applyPlayerAttributesDeathOutcomes\", () => {\n beforeEach(() => {\n mocks.playerKillerService.applySheriffPlayerDeathOutcomes = jest.spyOn(services.playerKiller as unknown as { applySheriffPlayerDeathOutcomes }, \"applySheriffPlayerDeathOutcomes\").mockImplementation();\n mocks.playerKillerService.applyInLovePlayerDeathOutcomes = jest.spyOn(services.playerKiller as unknown as { applyInLovePlayerDeathOutcomes }, \"applyInLovePlayerDeathOutcomes\").mockImplementation();\n mocks.playerKillerService.applyWorshipedPlayerDeathOutcomes = jest.spyOn(services.playerKiller as unknown as { applyWorshipedPlayerDeathOutcomes }, \"applyWorshipedPlayerDeathOutcomes\").mockImplementation();\n mocks.gameHelper.getPlayerWithIdOrThrow = jest.spyOn(GameHelper, \"getPlayerWithIdOrThrow\").mockImplementation();\n });\n\n it(\"should call no methods when player doesn't have the right attributes.\", () => {\n const players = [\n createFakeIdiotAlivePlayer({ attributes: [createFakePowerlessByElderPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n services.playerKiller[\"applyPlayerAttributesDeathOutcomes\"](game.players[0], game);\n\n expect(mocks.playerKillerService.applySheriffPlayerDeathOutcomes).not.toHaveBeenCalled();\n expect(mocks.playerKillerService.applyInLovePlayerDeathOutcomes).not.toHaveBeenCalled();\n expect(mocks.playerKillerService.applyWorshipedPlayerDeathOutcomes).not.toHaveBeenCalled();\n expect(mocks.gameHelper.getPlayerWithIdOrThrow).not.toHaveBeenCalled();\n });\n\n it(\"should call survivors methods when player have all attributes.\", () => {\n const players = [\n createFakeIdiotAlivePlayer({ attributes: [createFakePowerlessByElderPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeSheriffBySurvivorsPlayerAttribute(), createFakeInLoveByCupidPlayerAttribute(), createFakeWorshipedByWildChildPlayerAttribute()] }),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const interpolations = { gameId: game._id.toString(), playerId: players[2]._id.toString() };\n const exception = new UnexpectedException(\"applyPlayerAttributesDeathOutcomes\", UnexpectedExceptionReasons.CANT_FIND_PLAYER_WITH_ID_IN_GAME, interpolations);\n const expectedInterpolations = { gameId: game._id, playerId: players[2]._id };\n\n mocks.playerKillerService.applySheriffPlayerDeathOutcomes.mockReturnValue(game);\n mocks.playerKillerService.applyInLovePlayerDeathOutcomes.mockReturnValue(game);\n mocks.playerKillerService.applyWorshipedPlayerDeathOutcomes.mockReturnValue(game);\n mocks.gameHelper.getPlayerWithIdOrThrow.mockReturnValue(game.players[2]);\n mocks.unexpectedExceptionFactory.createCantFindPlayerWithIdUnexpectedException.mockReturnValue(exception);\n services.playerKiller[\"applyPlayerAttributesDeathOutcomes\"](game.players[2], game);\n\n expect(mocks.unexpectedExceptionFactory.createCantFindPlayerWithIdUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"applyPlayerAttributesDeathOutcomes\", expectedInterpolations);\n expect(mocks.playerKillerService.applySheriffPlayerDeathOutcomes).toHaveBeenCalledExactlyOnceWith(game.players[2], game);\n expect(mocks.playerKillerService.applyInLovePlayerDeathOutcomes).toHaveBeenCalledExactlyOnceWith(game.players[2], game);\n expect(mocks.playerKillerService.applyWorshipedPlayerDeathOutcomes).toHaveBeenCalledExactlyOnceWith(game.players[2], game);\n expect(mocks.gameHelper.getPlayerWithIdOrThrow).toHaveBeenNthCalledWith(1, game.players[2]._id, game, exception);\n expect(mocks.gameHelper.getPlayerWithIdOrThrow).toHaveBeenNthCalledWith(2, game.players[2]._id, game, exception);\n });\n });\n\n describe(\"applyPlayerSideDeathOutcomes\", () => {\n it(\"should return game as is when player is not a werewolf sided player.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeBigBadWolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ bigBadWolf: createFakeBigBadWolfGameOptions({ isPowerlessIfWerewolfDies: true }) }) });\n const game = createFakeGame({ players, options });\n\n expect(services.playerKiller[\"applyPlayerSideDeathOutcomes\"](players[3], game)).toStrictEqual(game);\n });\n\n it(\"should return game as is when player is a werewolf sided player but there is no big bad wolf in the game.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ bigBadWolf: createFakeBigBadWolfGameOptions({ isPowerlessIfWerewolfDies: true }) }) });\n const game = createFakeGame({ players, options });\n\n expect(services.playerKiller[\"applyPlayerSideDeathOutcomes\"](players[0], game)).toStrictEqual(game);\n });\n\n it(\"should return game as is when player is a werewolf sided player but game options say that big bad wolf is not powerless if one werewolf dies.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeBigBadWolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ bigBadWolf: createFakeBigBadWolfGameOptions({ isPowerlessIfWerewolfDies: false }) }) });\n const game = createFakeGame({ players, options });\n\n expect(services.playerKiller[\"applyPlayerSideDeathOutcomes\"](players[0], game)).toStrictEqual(game);\n });\n\n it(\"should return game as is when player is a werewolf sided player but killed player is big bad wolf himself.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeBigBadWolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ bigBadWolf: createFakeBigBadWolfGameOptions({ isPowerlessIfWerewolfDies: true }) }) });\n const game = createFakeGame({ players, options });\n\n expect(services.playerKiller[\"applyPlayerSideDeathOutcomes\"](players[2], game)).toStrictEqual(game);\n });\n\n it(\"should return game as is when player is a werewolf sided player but big bad wolf is already powerless by werewolves.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeBigBadWolfAlivePlayer({ attributes: [createFakePowerlessByWerewolvesPlayerAttribute()] }),\n createFakeSeerAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ bigBadWolf: createFakeBigBadWolfGameOptions({ isPowerlessIfWerewolfDies: true }) }) });\n const game = createFakeGame({ players, options });\n\n expect(services.playerKiller[\"applyPlayerSideDeathOutcomes\"](players[0], game)).toStrictEqual(game);\n });\n\n it(\"should return game with powerless big bad wolf when killer player is werewolf sided and big bad wolf is not already powerless by werewolves.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeBigBadWolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ bigBadWolf: createFakeBigBadWolfGameOptions({ isPowerlessIfWerewolfDies: true }) }) });\n const game = createFakeGame({ players, options });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n players[1],\n createFakePlayer({\n ...players[2],\n attributes: [createFakePowerlessByWerewolvesPlayerAttribute()],\n }),\n players[3],\n ],\n });\n\n expect(services.playerKiller[\"applyPlayerSideDeathOutcomes\"](players[0], game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"applyRustySwordKnightDeathOutcomes\", () => {\n it(\"should return game as is when killed player is not rusty sword knight.\", () => {\n const death = createFakePlayerEatenByWerewolvesDeath();\n const players = [\n createFakeIdiotAlivePlayer({ isAlive: false, death }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(services.playerKiller[\"applyRustySwordKnightDeathOutcomes\"](players[0] as DeadPlayer, game)).toStrictEqual(game);\n });\n\n it(\"should return game as is when killed player is powerless.\", () => {\n const death = createFakePlayerEatenByWerewolvesDeath();\n const players = [\n createFakeRustySwordKnightAlivePlayer({ attributes: [createFakePowerlessByElderPlayerAttribute()], isAlive: false, death }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(services.playerKiller[\"applyRustySwordKnightDeathOutcomes\"](players[0] as DeadPlayer, game)).toStrictEqual(game);\n });\n\n it(\"should return game as is when death cause is not eaten.\", () => {\n const death = createFakePlayerVoteBySurvivorsDeath();\n const players = [\n createFakeRustySwordKnightAlivePlayer({ isAlive: false, death }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(services.playerKiller[\"applyRustySwordKnightDeathOutcomes\"](players[0] as DeadPlayer, game)).toStrictEqual(game);\n });\n\n it(\"should return game as is when no left alive werewolf is found.\", () => {\n const death = createFakePlayerEatenByWerewolvesDeath();\n const players = [\n createFakeRustySwordKnightAlivePlayer({ isAlive: false, death }),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(services.playerKiller[\"applyRustySwordKnightDeathOutcomes\"](players[0] as DeadPlayer, game)).toStrictEqual(game);\n });\n\n it(\"should return game with first left alive werewolf player with contaminated attribute when called.\", () => {\n const death = createFakePlayerEatenByWerewolvesDeath();\n const players = [\n createFakeRustySwordKnightAlivePlayer({ position: 1, isAlive: false, death }),\n createFakeWerewolfAlivePlayer({ position: 2 }),\n createFakeWerewolfAlivePlayer({ position: 3 }),\n createFakeDefenderAlivePlayer({ position: 4 }),\n ];\n const game = createFakeGame({ players });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n players[1],\n createFakePlayer({ ...players[2], attributes: [createFakeContaminatedByRustySwordKnightPlayerAttribute()] }),\n players[3],\n ],\n });\n\n expect(services.playerKiller[\"applyRustySwordKnightDeathOutcomes\"](players[0] as DeadPlayer, game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"applyScapegoatDeathOutcomes\", () => {\n it(\"should return game as is when killed player is not scapegoat.\", () => {\n const death = createFakePlayerVoteScapegoatedBySurvivorsDeath();\n const players = [\n createFakeIdiotAlivePlayer({ isAlive: false, death }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(services.playerKiller[\"applyScapegoatDeathOutcomes\"](players[0] as DeadPlayer, game)).toStrictEqual(game);\n });\n\n it(\"should return game as is when killed player is powerless.\", () => {\n const death = createFakePlayerVoteScapegoatedBySurvivorsDeath();\n const players = [\n createFakeScapegoatAlivePlayer({ attributes: [createFakePowerlessByElderPlayerAttribute()], isAlive: false, death }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(services.playerKiller[\"applyScapegoatDeathOutcomes\"](players[0] as DeadPlayer, game)).toStrictEqual(game);\n });\n\n it(\"should return game as is when killed player was not scapegoated.\", () => {\n const death = createFakePlayerVoteBySurvivorsDeath();\n const players = [\n createFakeScapegoatAlivePlayer({ isAlive: false, death }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(services.playerKiller[\"applyScapegoatDeathOutcomes\"](players[0] as DeadPlayer, game)).toStrictEqual(game);\n });\n\n it(\"should return game with upcoming scapegoat bans votes play when called.\", () => {\n const death = createFakePlayerVoteScapegoatedBySurvivorsDeath();\n const players = [\n createFakeScapegoatAlivePlayer({ isAlive: false, death }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const upcomingPlays = [createFakeGamePlayHunterShoots()];\n const game = createFakeGame({ players, upcomingPlays });\n const expectedGame = createFakeGame({\n ...game,\n upcomingPlays: [createFakeGamePlayScapegoatBansVoting(), ...upcomingPlays],\n });\n\n expect(services.playerKiller[\"applyScapegoatDeathOutcomes\"](players[0] as DeadPlayer, game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"applyElderDeathOutcomes\", () => {\n beforeEach(() => {\n mocks.playerKillerService.killPlayer = jest.spyOn(services.playerKiller as unknown as { killPlayer }, \"killPlayer\").mockImplementation();\n });\n\n it(\"should return game as is when killed player is not elder.\", () => {\n const death = createFakePlayerVoteScapegoatedBySurvivorsDeath();\n const players = [\n createFakeWerewolfAlivePlayer({ isAlive: false, death }),\n createFakeIdiotAlivePlayer({ role: createFakePlayerRole({ isRevealed: true, current: \"idiot\", original: \"idiot\" }) }),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const elderOptions = createFakeElderGameOptions({ doesTakeHisRevenge: true });\n const idiotOptions = createFakeIdiotGameOptions({ doesDieOnElderDeath: true });\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ idiot: idiotOptions, elder: elderOptions }) });\n const game = createFakeGame({ players, options });\n\n expect(services.playerKiller[\"applyElderDeathOutcomes\"](players[0] as DeadPlayer, game)).toStrictEqual(game);\n });\n\n it(\"should return game as is when killed player is powerless.\", () => {\n const death = createFakePlayerVoteBySurvivorsDeath();\n const players = [\n createFakeElderAlivePlayer({ attributes: [createFakePowerlessByElderPlayerAttribute()], isAlive: false, death }),\n createFakeIdiotAlivePlayer({ role: createFakePlayerRole({ isRevealed: true, current: \"idiot\", original: \"idiot\" }) }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const elderOptions = createFakeElderGameOptions({ doesTakeHisRevenge: true });\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ elder: elderOptions }) });\n const game = createFakeGame({ players, options });\n\n expect(services.playerKiller[\"applyElderDeathOutcomes\"](players[0] as DeadPlayer, game)).toStrictEqual(game);\n });\n\n it(\"should return game as is when elder doesn't take his revenge and idiot is not revealed.\", () => {\n const death = createFakePlayerEatenByWerewolvesDeath();\n const players = [\n createFakeElderAlivePlayer({ isAlive: false, death }),\n createFakeIdiotAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(services.playerKiller[\"applyElderDeathOutcomes\"](players[0] as DeadPlayer, game)).toStrictEqual(game);\n });\n\n it(\"should game as is when elder doesn't take his revenge from game options.\", () => {\n const death = createFakePlayerDeathPotionByWitchDeath();\n const players = [\n createFakeElderAlivePlayer({ isAlive: false, death }),\n createFakeIdiotAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n createFakeSeerAlivePlayer({ isAlive: false }),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ elder: createFakeElderGameOptions({ doesTakeHisRevenge: false }) }) });\n const game = createFakeGame({ players, options });\n\n expect(services.playerKiller[\"applyElderDeathOutcomes\"](players[0] as DeadPlayer, game)).toStrictEqual(game);\n });\n\n it(\"should return game with all villagers powerless when elder takes his revenge.\", () => {\n const death = createFakePlayerDeathPotionByWitchDeath();\n const players = [\n createFakeElderAlivePlayer({ isAlive: false, death }),\n createFakeIdiotAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n createFakeSeerAlivePlayer({ isAlive: false }),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ elder: createFakeElderGameOptions({ doesTakeHisRevenge: true }) }) });\n const game = createFakeGame({ players, options });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n createFakePlayer({ ...players[1], attributes: [createFakePowerlessByElderPlayerAttribute()] }),\n players[2],\n createFakePlayer({ ...players[3], attributes: [createFakePowerlessByElderPlayerAttribute()] }),\n createFakePlayer(players[4]),\n ],\n });\n\n expect(services.playerKiller[\"applyElderDeathOutcomes\"](players[0] as DeadPlayer, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should return game as is when idiot was revealed before but doesn't die on elder death thanks to game options.\", () => {\n const death = createFakePlayerDeathPotionByWitchDeath();\n const players = [\n createFakeElderAlivePlayer({ isAlive: false, death }),\n createFakeIdiotAlivePlayer({ role: createFakePlayerRole({ isRevealed: true, current: \"idiot\", original: \"idiot\" }) }),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n createFakeSeerAlivePlayer({ isAlive: false }),\n ];\n const elderOptions = createFakeElderGameOptions({ doesTakeHisRevenge: false });\n const idiotOptions = createFakeIdiotGameOptions({ doesDieOnElderDeath: false });\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ elder: elderOptions, idiot: idiotOptions }) });\n const game = createFakeGame({ players, options });\n\n expect(services.playerKiller[\"applyElderDeathOutcomes\"](players[0] as DeadPlayer, game)).toStrictEqual(game);\n expect(mocks.playerKillerService.killPlayer).not.toHaveBeenCalled();\n });\n\n it(\"should return game with killed idiot when idiot was revealed before.\", () => {\n const death = createFakePlayerDeathPotionByWitchDeath();\n const players = [\n createFakeElderAlivePlayer({ isAlive: false, death }),\n createFakeIdiotAlivePlayer({ role: createFakePlayerRole({ isRevealed: true, current: \"idiot\", original: \"idiot\" }) }),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n createFakeSeerAlivePlayer({ isAlive: false }),\n ];\n const elderOptions = createFakeElderGameOptions({ doesTakeHisRevenge: false });\n const idiotOptions = createFakeIdiotGameOptions({ doesDieOnElderDeath: true });\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ elder: elderOptions, idiot: idiotOptions }) });\n const game = createFakeGame({ players, options });\n services.playerKiller[\"applyElderDeathOutcomes\"](players[0] as DeadPlayer, game);\n\n expect(mocks.playerKillerService.killPlayer).toHaveBeenCalledExactlyOnceWith(players[1], game, createFakePlayerReconsiderPardonBySurvivorsDeath());\n });\n });\n\n describe(\"applyHunterDeathOutcomes\", () => {\n it(\"should return game as is when killed player is not hunter.\", () => {\n const players = [\n createFakeIdiotAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(services.playerKiller[\"applyHunterDeathOutcomes\"](players[0], game)).toStrictEqual(game);\n });\n\n it(\"should return game as is when killed player powerless.\", () => {\n const players = [\n createFakeHunterAlivePlayer({ attributes: [createFakePowerlessByElderPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(services.playerKiller[\"applyHunterDeathOutcomes\"](players[0], game)).toStrictEqual(game);\n });\n\n it(\"should return game with upcoming hunter shoots play when called.\", () => {\n const players = [\n createFakeHunterAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const upcomingPlays = [createFakeGamePlayScapegoatBansVoting()];\n const game = createFakeGame({ players, upcomingPlays });\n const expectedGame = createFakeGame({\n ...game,\n upcomingPlays: [createFakeGamePlayHunterShoots(), ...upcomingPlays],\n });\n\n expect(services.playerKiller[\"applyHunterDeathOutcomes\"](players[0], game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"applyPlayerRoleDeathOutcomes\", () => {\n beforeEach(() => {\n mocks.playerKillerService.applyHunterDeathOutcomes = jest.spyOn(services.playerKiller as unknown as { applyHunterDeathOutcomes }, \"applyHunterDeathOutcomes\").mockImplementation();\n mocks.playerKillerService.applyElderDeathOutcomes = jest.spyOn(services.playerKiller as unknown as { applyElderDeathOutcomes }, \"applyElderDeathOutcomes\").mockImplementation();\n mocks.playerKillerService.applyScapegoatDeathOutcomes = jest.spyOn(services.playerKiller as unknown as { applyScapegoatDeathOutcomes }, \"applyScapegoatDeathOutcomes\").mockImplementation();\n mocks.playerKillerService.applyRustySwordKnightDeathOutcomes = jest.spyOn(services.playerKiller as unknown as { applyRustySwordKnightDeathOutcomes }, \"applyRustySwordKnightDeathOutcomes\").mockImplementation();\n });\n\n it(\"should return game as is without calling role method outcomes when killed player doesn't have the right role.\", () => {\n const death = createFakePlayerDeathPotionByWitchDeath();\n const players = [\n createFakeWerewolfAlivePlayer({ isAlive: false, death }),\n createFakeHunterAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(services.playerKiller[\"applyPlayerRoleDeathOutcomes\"](players[0] as DeadPlayer, game)).toStrictEqual(game);\n expect(mocks.playerKillerService.applyHunterDeathOutcomes).not.toHaveBeenCalled();\n expect(mocks.playerKillerService.applyElderDeathOutcomes).not.toHaveBeenCalled();\n expect(mocks.playerKillerService.applyScapegoatDeathOutcomes).not.toHaveBeenCalled();\n expect(mocks.playerKillerService.applyRustySwordKnightDeathOutcomes).not.toHaveBeenCalled();\n });\n\n it(\"should call killed hunter outcomes method when killed player is hunter.\", () => {\n const death = createFakePlayerDeathPotionByWitchDeath();\n const players = [\n createFakeHunterAlivePlayer({ isAlive: false, death }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n services.playerKiller[\"applyPlayerRoleDeathOutcomes\"](players[0] as DeadPlayer, game);\n\n expect(mocks.playerKillerService.applyHunterDeathOutcomes).toHaveBeenCalledExactlyOnceWith(players[0], game);\n expect(mocks.playerKillerService.applyElderDeathOutcomes).not.toHaveBeenCalled();\n expect(mocks.playerKillerService.applyScapegoatDeathOutcomes).not.toHaveBeenCalled();\n expect(mocks.playerKillerService.applyRustySwordKnightDeathOutcomes).not.toHaveBeenCalled();\n });\n\n it(\"should call killed elder outcomes method when killed player is elder.\", () => {\n const death = createFakePlayerDeathPotionByWitchDeath();\n const players = [\n createFakeElderAlivePlayer({ isAlive: false, death }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n services.playerKiller[\"applyPlayerRoleDeathOutcomes\"](players[0] as DeadPlayer, game);\n expect(mocks.playerKillerService.applyElderDeathOutcomes).toHaveBeenCalledExactlyOnceWith(players[0], game);\n expect(mocks.playerKillerService.applyHunterDeathOutcomes).not.toHaveBeenCalled();\n expect(mocks.playerKillerService.applyScapegoatDeathOutcomes).not.toHaveBeenCalled();\n expect(mocks.playerKillerService.applyRustySwordKnightDeathOutcomes).not.toHaveBeenCalled();\n });\n\n it(\"should call killed scapegoat outcomes method when killed player is scapegoat.\", () => {\n const death = createFakePlayerDeathPotionByWitchDeath();\n const players = [\n createFakeScapegoatAlivePlayer({ isAlive: false, death }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n services.playerKiller[\"applyPlayerRoleDeathOutcomes\"](players[0] as DeadPlayer, game);\n\n expect(mocks.playerKillerService.applyScapegoatDeathOutcomes).toHaveBeenCalledExactlyOnceWith(players[0], game);\n expect(mocks.playerKillerService.applyHunterDeathOutcomes).not.toHaveBeenCalled();\n expect(mocks.playerKillerService.applyElderDeathOutcomes).not.toHaveBeenCalled();\n expect(mocks.playerKillerService.applyRustySwordKnightDeathOutcomes).not.toHaveBeenCalled();\n });\n\n it(\"should call killed rusty sword knight outcomes method when killed player is rusty sword knight.\", () => {\n const death = createFakePlayerDeathPotionByWitchDeath();\n const players = [\n createFakeRustySwordKnightAlivePlayer({ isAlive: false, death }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n services.playerKiller[\"applyPlayerRoleDeathOutcomes\"](players[0] as DeadPlayer, game);\n\n expect(mocks.playerKillerService.applyRustySwordKnightDeathOutcomes).toHaveBeenCalledExactlyOnceWith(players[0], game);\n expect(mocks.playerKillerService.applyHunterDeathOutcomes).not.toHaveBeenCalled();\n expect(mocks.playerKillerService.applyElderDeathOutcomes).not.toHaveBeenCalled();\n expect(mocks.playerKillerService.applyScapegoatDeathOutcomes).not.toHaveBeenCalled();\n });\n });\n\n describe(\"killPlayer\", () => {\n beforeEach(() => {\n mocks.playerKillerService.removePlayerAttributesAfterDeath = jest.spyOn(services.playerKiller as unknown as { removePlayerAttributesAfterDeath }, \"removePlayerAttributesAfterDeath\").mockImplementation();\n mocks.playerKillerService.applyPlayerDeathOutcomes = jest.spyOn(services.playerKiller as unknown as { applyPlayerDeathOutcomes }, \"applyPlayerDeathOutcomes\").mockImplementation();\n mocks.unexpectedExceptionFactory.createCantFindPlayerWithIdUnexpectedException = jest.spyOn(UnexpectedExceptionFactory, \"createCantFindPlayerWithIdUnexpectedException\").mockImplementation();\n mocks.gameHelper.getPlayerWithIdOrThrow = jest.spyOn(GameHelper, \"getPlayerWithIdOrThrow\").mockImplementation();\n });\n\n it(\"should set player to dead with his death and add survivors bury dead bodies game play when not present in upcoming plays.\", () => {\n const players = [\n createFakeRustySwordKnightAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ areRevealedOnDeath: true }) });\n const game = createFakeGame({ players, options });\n const death = createFakePlayerDeathPotionByWitchDeath();\n const expectedKilledPlayer = createFakePlayer({ ...players[0], isAlive: false, death });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n expectedKilledPlayer,\n players[1],\n players[2],\n players[3],\n ],\n upcomingPlays: [createFakeGamePlaySurvivorsBuryDeadBodies()],\n });\n\n expect(services.playerKiller[\"killPlayer\"](players[0], game, death)).toStrictEqual(expectedGame);\n });\n\n it(\"should set player to dead with his death but doesn't add survivors bury dead bodies game play when present in upcoming plays.\", () => {\n const players = [\n createFakeRustySwordKnightAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ areRevealedOnDeath: true }) });\n const game = createFakeGame({\n upcomingPlays: [\n createFakeGamePlaySheriffDelegates(),\n createFakeGamePlaySurvivorsBuryDeadBodies(),\n ],\n players,\n options,\n });\n const death = createFakePlayerDeathPotionByWitchDeath();\n const expectedKilledPlayer = createFakePlayer({ ...players[0], isAlive: false, death });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n expectedKilledPlayer,\n players[1],\n players[2],\n players[3],\n ],\n });\n\n expect(services.playerKiller[\"killPlayer\"](players[0], game, death)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"getPlayerToKillOrRevealInGame\", () => {\n it(\"should throw error when player is already dead.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeSeerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const interpolations = { gameId: game._id.toString(), playerId: players[1]._id.toString() };\n const cantFindPlayerException = new UnexpectedException(\"getPlayerToKillOrRevealInGame\", UnexpectedExceptionReasons.CANT_FIND_PLAYER_WITH_ID_IN_GAME, interpolations);\n const playerIsDeadException = new UnexpectedException(\"getPlayerToKillOrRevealInGame\", UnexpectedExceptionReasons.PLAYER_IS_DEAD, interpolations);\n const expectedInterpolations = { gameId: game._id, playerId: players[1]._id };\n\n mocks.unexpectedExceptionFactory.createCantFindPlayerWithIdUnexpectedException.mockReturnValue(cantFindPlayerException);\n mocks.gameHelper.getPlayerWithIdOrThrow.mockReturnValue(players[1]);\n mocks.unexpectedExceptionFactory.createCantFindPlayerWithIdUnexpectedException.mockReturnValue(cantFindPlayerException);\n mocks.unexpectedExceptionFactory.createPlayerIsDeadUnexpectedException.mockReturnValue(playerIsDeadException);\n\n expect(() => services.playerKiller[\"getPlayerToKillOrRevealInGame\"](players[1]._id, game)).toThrow(playerIsDeadException);\n expect(mocks.unexpectedExceptionFactory.createCantFindPlayerWithIdUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"getPlayerToKillOrRevealInGame\", expectedInterpolations);\n expect(mocks.unexpectedExceptionFactory.createPlayerIsDeadUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"getPlayerToKillOrRevealInGame\", expectedInterpolations);\n });\n\n it(\"should get player to kill when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n mocks.gameHelper.getPlayerWithIdOrThrow.mockReturnValue(players[1]);\n\n expect(services.playerKiller[\"getPlayerToKillOrRevealInGame\"](players[1]._id, game)).toStrictEqual(players[1]);\n });\n });\n});" + "source": "import type { TestingModule } from \"@nestjs/testing\";\nimport { Test } from \"@nestjs/testing\";\n\nimport * as GameHelper from \"@/modules/game/helpers/game.helpers\";\nimport { GameHistoryRecordService } from \"@/modules/game/providers/services/game-history/game-history-record.service\";\nimport { PlayerKillerService } from \"@/modules/game/providers/services/player/player-killer.service\";\nimport type { Game } from \"@/modules/game/schemas/game.schema\";\nimport type { DeadPlayer } from \"@/modules/game/schemas/player/dead-player.schema\";\nimport type { PlayerDeath } from \"@/modules/game/schemas/player/player-death/player-death.schema\";\nimport type { Player } from \"@/modules/game/schemas/player/player.schema\";\nimport type { PlayerDeathCause } from \"@/modules/game/types/player/player-death/player-death.types\";\n\nimport { UnexpectedExceptionReasons } from \"@/shared/exception/enums/unexpected-exception.enums\";\nimport * as UnexpectedExceptionFactory from \"@/shared/exception/helpers/unexpected-exception.factory\";\nimport { UnexpectedException } from \"@/shared/exception/types/unexpected-exception.types\";\n\nimport { createFakeGameHistoryRecord, createFakeGameHistoryRecordDefenderProtectPlay, createFakeGameHistoryRecordPlayTarget, createFakeGameHistoryRecordWerewolvesEatPlay, createFakeGameHistoryRecordWitchUsePotionsPlay } from \"@tests/factories/game/schemas/game-history-record/game-history-record.schema.factory\";\nimport { createFakeGameOptions } from \"@tests/factories/game/schemas/game-options/game-options.schema.factory\";\nimport { createFakeActorGameOptions, createFakeBigBadWolfGameOptions, createFakeElderGameOptions, createFakeIdiotGameOptions, createFakeLittleGirlGameOptions, createFakeRolesGameOptions } from \"@tests/factories/game/schemas/game-options/game-roles-options/game-roles-options.schema.factory\";\nimport { createFakeGamePlayHunterShoots, createFakeGamePlayScapegoatBansVoting, createFakeGamePlaySheriffDelegates, createFakeGamePlaySurvivorsBuryDeadBodies } from \"@tests/factories/game/schemas/game-play/game-play.schema.factory\";\nimport { createFakeGame } from \"@tests/factories/game/schemas/game.schema.factory\";\nimport { createFakeCantVoteBySurvivorsPlayerAttribute, createFakeContaminatedByRustySwordKnightPlayerAttribute, createFakeDrankLifePotionByWitchPlayerAttribute, createFakeEatenByWerewolvesPlayerAttribute, createFakeInLoveByCupidPlayerAttribute, createFakePowerlessByActorPlayerAttribute, createFakePowerlessByElderPlayerAttribute, createFakePowerlessByWerewolvesPlayerAttribute, createFakeProtectedByDefenderPlayerAttribute, createFakeScandalmongerMarkedByScandalmongerPlayerAttribute, createFakeSheriffBySurvivorsPlayerAttribute, createFakeWorshipedByWildChildPlayerAttribute } from \"@tests/factories/game/schemas/player/player-attribute/player-attribute.schema.factory\";\nimport { createFakePlayerBrokenHeartByCupidDeath, createFakePlayerDeathPotionByWitchDeath, createFakePlayerEatenByWerewolvesDeath, createFakePlayerReconsiderPardonBySurvivorsDeath, createFakePlayerVoteBySurvivorsDeath, createFakePlayerVoteScapegoatedBySurvivorsDeath } from \"@tests/factories/game/schemas/player/player-death/player-death.schema.factory\";\nimport { createFakeBigBadWolfAlivePlayer, createFakeDefenderAlivePlayer, createFakeElderAlivePlayer, createFakeHunterAlivePlayer, createFakeIdiotAlivePlayer, createFakeLittleGirlAlivePlayer, createFakeRustySwordKnightAlivePlayer, createFakeScapegoatAlivePlayer, createFakeSeerAlivePlayer, createFakeVillagerVillagerAlivePlayer, createFakeWerewolfAlivePlayer, createFakeWildChildAlivePlayer, createFakeWitchAlivePlayer } from \"@tests/factories/game/schemas/player/player-with-role.schema.factory\";\nimport { createFakePlayer, createFakePlayerRole, createFakePlayerSide } from \"@tests/factories/game/schemas/player/player.schema.factory\";\n\ndescribe(\"Player Killer Service\", () => {\n let mocks: {\n playerKillerService: {\n getPlayerToKillOrRevealInGame: jest.SpyInstance;\n isPlayerKillable: jest.SpyInstance;\n doesPlayerRoleMustBeRevealed: jest.SpyInstance;\n removePlayerAttributesAfterDeath: jest.SpyInstance;\n revealPlayerRole: jest.SpyInstance;\n killPlayer: jest.SpyInstance;\n applySheriffPlayerDeathOutcomes: jest.SpyInstance;\n applyInLovePlayerDeathOutcomes: jest.SpyInstance;\n applyWorshipedPlayerDeathOutcomes: jest.SpyInstance;\n applyHunterDeathOutcomes: jest.SpyInstance;\n applyElderDeathOutcomes: jest.SpyInstance;\n applyScapegoatDeathOutcomes: jest.SpyInstance;\n applyRustySwordKnightDeathOutcomes: jest.SpyInstance;\n applyPlayerRoleRevelationOutcomes: jest.SpyInstance;\n applyPlayerDeathOutcomes: jest.SpyInstance;\n applyPlayerSideDeathOutcomes: jest.SpyInstance;\n applyPlayerRoleDeathOutcomes: jest.SpyInstance;\n applyPlayerAttributesDeathOutcomes: jest.SpyInstance;\n getElderLivesCountAgainstWerewolves: jest.SpyInstance;\n isElderKillable: jest.SpyInstance;\n isIdiotKillable: jest.SpyInstance;\n canPlayerBeEaten: jest.SpyInstance;\n };\n gameHistoryRecordService: {\n getGameHistoryWerewolvesEatElderRecords: jest.SpyInstance;\n getGameHistoryElderProtectedFromWerewolvesRecords: jest.SpyInstance;\n };\n gameHelper: {\n getPlayerWithIdOrThrow: jest.SpyInstance;\n doesGameHaveCurrentOrUpcomingPlaySourceAndAction: jest.SpyInstance;\n };\n unexpectedExceptionFactory: {\n createCantFindPlayerWithIdUnexpectedException: jest.SpyInstance;\n createPlayerIsDeadUnexpectedException: jest.SpyInstance;\n };\n };\n let services: { playerKiller: PlayerKillerService };\n\n beforeEach(async() => {\n mocks = {\n playerKillerService: {\n getPlayerToKillOrRevealInGame: jest.fn(),\n isPlayerKillable: jest.fn(),\n doesPlayerRoleMustBeRevealed: jest.fn(),\n removePlayerAttributesAfterDeath: jest.fn(),\n revealPlayerRole: jest.fn(),\n killPlayer: jest.fn(),\n applySheriffPlayerDeathOutcomes: jest.fn(),\n applyInLovePlayerDeathOutcomes: jest.fn(),\n applyWorshipedPlayerDeathOutcomes: jest.fn(),\n applyHunterDeathOutcomes: jest.fn(),\n applyElderDeathOutcomes: jest.fn(),\n applyScapegoatDeathOutcomes: jest.fn(),\n applyRustySwordKnightDeathOutcomes: jest.fn(),\n applyPlayerRoleRevelationOutcomes: jest.fn(),\n applyPlayerDeathOutcomes: jest.fn(),\n applyPlayerSideDeathOutcomes: jest.fn(),\n applyPlayerRoleDeathOutcomes: jest.fn(),\n applyPlayerAttributesDeathOutcomes: jest.fn(),\n getElderLivesCountAgainstWerewolves: jest.fn(),\n isElderKillable: jest.fn(),\n isIdiotKillable: jest.fn(),\n canPlayerBeEaten: jest.fn(),\n },\n gameHistoryRecordService: {\n getGameHistoryWerewolvesEatElderRecords: jest.fn(),\n getGameHistoryElderProtectedFromWerewolvesRecords: jest.fn(),\n },\n gameHelper: {\n getPlayerWithIdOrThrow: jest.spyOn(GameHelper, \"getPlayerWithIdOrThrow\").mockImplementation(),\n doesGameHaveCurrentOrUpcomingPlaySourceAndAction: jest.spyOn(GameHelper, \"doesGameHaveCurrentOrUpcomingPlaySourceAndAction\").mockImplementation(),\n },\n unexpectedExceptionFactory: {\n createCantFindPlayerWithIdUnexpectedException: jest.spyOn(UnexpectedExceptionFactory, \"createCantFindPlayerWithIdUnexpectedException\").mockImplementation(),\n createPlayerIsDeadUnexpectedException: jest.spyOn(UnexpectedExceptionFactory, \"createPlayerIsDeadUnexpectedException\").mockImplementation(),\n },\n };\n\n const module: TestingModule = await Test.createTestingModule({\n providers: [\n {\n provide: GameHistoryRecordService,\n useValue: mocks.gameHistoryRecordService,\n },\n PlayerKillerService,\n ],\n }).compile();\n\n services = { playerKiller: module.get(PlayerKillerService) };\n });\n\n describe(\"killOrRevealPlayer\", () => {\n beforeEach(() => {\n mocks.playerKillerService.getPlayerToKillOrRevealInGame = jest.spyOn(services.playerKiller as unknown as { getPlayerToKillOrRevealInGame }, \"getPlayerToKillOrRevealInGame\");\n mocks.playerKillerService.isPlayerKillable = jest.spyOn(services.playerKiller as unknown as { isPlayerKillable }, \"isPlayerKillable\");\n mocks.playerKillerService.killPlayer = jest.spyOn(services.playerKiller as unknown as { killPlayer }, \"killPlayer\");\n mocks.playerKillerService.doesPlayerRoleMustBeRevealed = jest.spyOn(services.playerKiller as unknown as { doesPlayerRoleMustBeRevealed }, \"doesPlayerRoleMustBeRevealed\");\n mocks.playerKillerService.revealPlayerRole = jest.spyOn(services.playerKiller as unknown as { revealPlayerRole }, \"revealPlayerRole\");\n });\n\n it(\"should return game as is when player can't be revealed or killed.\", async() => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const death = createFakePlayerDeathPotionByWitchDeath();\n\n mocks.playerKillerService.getPlayerToKillOrRevealInGame.mockReturnValue(players[0]);\n mocks.playerKillerService.isPlayerKillable.mockReturnValue(false);\n mocks.playerKillerService.doesPlayerRoleMustBeRevealed.mockReturnValue(false);\n\n await expect(services.playerKiller.killOrRevealPlayer(players[0]._id, game, death)).resolves.toStrictEqual(game);\n expect(mocks.playerKillerService.killPlayer).not.toHaveBeenCalled();\n expect(mocks.playerKillerService.revealPlayerRole).not.toHaveBeenCalled();\n });\n\n it(\"should call kill method when player is killable.\", async() => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const death = createFakePlayerDeathPotionByWitchDeath();\n\n mocks.gameHelper.getPlayerWithIdOrThrow.mockReturnValue(players[0]);\n mocks.playerKillerService.getPlayerToKillOrRevealInGame.mockReturnValue(players[0]);\n mocks.playerKillerService.isPlayerKillable.mockReturnValue(true);\n mocks.playerKillerService.doesPlayerRoleMustBeRevealed.mockReturnValue(true);\n\n await services.playerKiller.killOrRevealPlayer(players[0]._id, game, death);\n\n expect(mocks.playerKillerService.killPlayer).toHaveBeenCalledExactlyOnceWith(players[0], game, death);\n });\n\n it(\"should call reveal role method when player role must be revealed but not killed.\", async() => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const death = createFakePlayerDeathPotionByWitchDeath();\n\n mocks.playerKillerService.getPlayerToKillOrRevealInGame.mockReturnValue(players[0]);\n mocks.gameHelper.getPlayerWithIdOrThrow.mockReturnValue(players[0]);\n mocks.playerKillerService.isPlayerKillable.mockReturnValue(false);\n mocks.playerKillerService.doesPlayerRoleMustBeRevealed.mockReturnValue(true);\n\n await services.playerKiller.killOrRevealPlayer(players[0]._id, game, death);\n\n expect(mocks.playerKillerService.killPlayer).not.toHaveBeenCalled();\n expect(mocks.playerKillerService.revealPlayerRole).toHaveBeenCalledExactlyOnceWith(players[0], game);\n });\n });\n\n describe(\"applyPlayerDeathOutcomes\", () => {\n beforeEach(() => {\n mocks.playerKillerService.applyPlayerRoleDeathOutcomes = jest.spyOn(services.playerKiller as unknown as { applyPlayerRoleDeathOutcomes }, \"applyPlayerRoleDeathOutcomes\").mockImplementation();\n mocks.playerKillerService.applyPlayerSideDeathOutcomes = jest.spyOn(services.playerKiller as unknown as { applyPlayerSideDeathOutcomes }, \"applyPlayerSideDeathOutcomes\").mockImplementation();\n mocks.playerKillerService.applyPlayerAttributesDeathOutcomes = jest.spyOn(services.playerKiller as unknown as { applyPlayerAttributesDeathOutcomes }, \"applyPlayerAttributesDeathOutcomes\").mockImplementation();\n });\n\n it(\"should create unexpected exception for later purposes when called.\", () => {\n const death = createFakePlayerDeathPotionByWitchDeath();\n const players = [\n createFakeRustySwordKnightAlivePlayer({ isAlive: false, death }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const exception = new UnexpectedException(\"applyPlayerAttributesDeathOutcomes\", UnexpectedExceptionReasons.CANT_FIND_PLAYER_WITH_ID_IN_GAME, { gameId: game._id.toString(), playerId: players[0]._id.toString() });\n\n mocks.unexpectedExceptionFactory.createCantFindPlayerWithIdUnexpectedException.mockReturnValue(exception);\n mocks.gameHelper.getPlayerWithIdOrThrow.mockReturnValue(players[0]);\n mocks.gameHelper.doesGameHaveCurrentOrUpcomingPlaySourceAndAction.mockReturnValue(true);\n mocks.playerKillerService.applyPlayerRoleDeathOutcomes.mockReturnValue(game);\n mocks.playerKillerService.applyPlayerSideDeathOutcomes.mockReturnValue(game);\n mocks.playerKillerService.applyPlayerAttributesDeathOutcomes.mockReturnValue(game);\n services.playerKiller.applyPlayerDeathOutcomes(players[0] as DeadPlayer, game);\n\n expect(mocks.unexpectedExceptionFactory.createCantFindPlayerWithIdUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"applyPlayerDeathOutcomes\", { gameId: game._id, playerId: players[0]._id });\n });\n\n it(\"should apply player role death outcomes when called.\", () => {\n const death = createFakePlayerDeathPotionByWitchDeath();\n const players = [\n createFakeRustySwordKnightAlivePlayer({ isAlive: false, death }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const exception = new UnexpectedException(\"applyPlayerAttributesDeathOutcomes\", UnexpectedExceptionReasons.CANT_FIND_PLAYER_WITH_ID_IN_GAME, { gameId: game._id.toString(), playerId: players[0]._id.toString() });\n\n mocks.unexpectedExceptionFactory.createCantFindPlayerWithIdUnexpectedException.mockReturnValue(exception);\n mocks.gameHelper.getPlayerWithIdOrThrow.mockReturnValue(players[0]);\n mocks.gameHelper.doesGameHaveCurrentOrUpcomingPlaySourceAndAction.mockReturnValue(true);\n mocks.playerKillerService.applyPlayerRoleDeathOutcomes.mockReturnValue(game);\n mocks.playerKillerService.applyPlayerSideDeathOutcomes.mockReturnValue(game);\n mocks.playerKillerService.applyPlayerAttributesDeathOutcomes.mockReturnValue(game);\n services.playerKiller.applyPlayerDeathOutcomes(players[0] as DeadPlayer, game);\n\n expect(mocks.playerKillerService.applyPlayerRoleDeathOutcomes).toHaveBeenCalledExactlyOnceWith(players[0], game);\n });\n\n it(\"should apply player side death outcomes when called.\", () => {\n const death = createFakePlayerDeathPotionByWitchDeath();\n const players = [\n createFakeRustySwordKnightAlivePlayer({ isAlive: false, death }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const exception = new UnexpectedException(\"applyPlayerAttributesDeathOutcomes\", UnexpectedExceptionReasons.CANT_FIND_PLAYER_WITH_ID_IN_GAME, { gameId: game._id.toString(), playerId: players[0]._id.toString() });\n\n mocks.unexpectedExceptionFactory.createCantFindPlayerWithIdUnexpectedException.mockReturnValue(exception);\n mocks.gameHelper.getPlayerWithIdOrThrow.mockReturnValue(players[0]);\n mocks.gameHelper.doesGameHaveCurrentOrUpcomingPlaySourceAndAction.mockReturnValue(true);\n mocks.playerKillerService.applyPlayerRoleDeathOutcomes.mockReturnValue(game);\n mocks.playerKillerService.applyPlayerSideDeathOutcomes.mockReturnValue(game);\n mocks.playerKillerService.applyPlayerAttributesDeathOutcomes.mockReturnValue(game);\n services.playerKiller.applyPlayerDeathOutcomes(players[0] as DeadPlayer, game);\n\n expect(mocks.playerKillerService.applyPlayerSideDeathOutcomes).toHaveBeenCalledExactlyOnceWith(players[0], game);\n });\n\n it(\"should apply player attributes death outcomes when called.\", () => {\n const death = createFakePlayerDeathPotionByWitchDeath();\n const players = [\n createFakeRustySwordKnightAlivePlayer({ isAlive: false, death }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const exception = new UnexpectedException(\"applyPlayerAttributesDeathOutcomes\", UnexpectedExceptionReasons.CANT_FIND_PLAYER_WITH_ID_IN_GAME, { gameId: game._id.toString(), playerId: players[0]._id.toString() });\n\n mocks.unexpectedExceptionFactory.createCantFindPlayerWithIdUnexpectedException.mockReturnValue(exception);\n mocks.gameHelper.getPlayerWithIdOrThrow.mockReturnValue(players[0]);\n mocks.gameHelper.doesGameHaveCurrentOrUpcomingPlaySourceAndAction.mockReturnValue(true);\n mocks.playerKillerService.applyPlayerRoleDeathOutcomes.mockReturnValue(game);\n mocks.playerKillerService.applyPlayerSideDeathOutcomes.mockReturnValue(game);\n mocks.playerKillerService.applyPlayerAttributesDeathOutcomes.mockReturnValue(game);\n services.playerKiller.applyPlayerDeathOutcomes(players[0] as DeadPlayer, game);\n\n expect(mocks.playerKillerService.applyPlayerAttributesDeathOutcomes).toHaveBeenCalledExactlyOnceWith(players[0], game);\n });\n\n it(\"should filter out player attributes which need to be removed after death when called.\", () => {\n const death = createFakePlayerDeathPotionByWitchDeath();\n const players = [\n createFakeRustySwordKnightAlivePlayer({ isAlive: false, death, attributes: [createFakeScandalmongerMarkedByScandalmongerPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const exception = new UnexpectedException(\"applyPlayerAttributesDeathOutcomes\", UnexpectedExceptionReasons.CANT_FIND_PLAYER_WITH_ID_IN_GAME, { gameId: game._id.toString(), playerId: players[0]._id.toString() });\n\n mocks.unexpectedExceptionFactory.createCantFindPlayerWithIdUnexpectedException.mockReturnValue(exception);\n mocks.gameHelper.getPlayerWithIdOrThrow.mockReturnValue(players[0]);\n mocks.gameHelper.doesGameHaveCurrentOrUpcomingPlaySourceAndAction.mockReturnValue(true);\n mocks.playerKillerService.applyPlayerRoleDeathOutcomes.mockReturnValue(game);\n mocks.playerKillerService.applyPlayerSideDeathOutcomes.mockReturnValue(game);\n mocks.playerKillerService.applyPlayerAttributesDeathOutcomes.mockReturnValue(game);\n const expectedGame = createFakeGame({\n ...game,\n players: [\n createFakePlayer({\n ...players[0],\n attributes: [],\n }),\n game.players[1],\n game.players[2],\n game.players[3],\n ],\n });\n\n expect(services.playerKiller.applyPlayerDeathOutcomes(players[0] as DeadPlayer, game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"revealPlayerRole\", () => {\n it(\"should create can't find player exception for later purposes when called.\", () => {\n const players = [\n createFakeWildChildAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const expectedInterpolations = { gameId: game._id, playerId: players[0]._id };\n mocks.gameHelper.getPlayerWithIdOrThrow.mockReturnValue(players[0]);\n services.playerKiller.revealPlayerRole(players[0], game);\n\n expect(mocks.unexpectedExceptionFactory.createCantFindPlayerWithIdUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"revealPlayerRole\", expectedInterpolations);\n });\n\n it(\"should reveal player role when called.\", () => {\n const players = [\n createFakeWildChildAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n createFakePlayer({\n ...players[0],\n role: createFakePlayerRole({ ...players[0].role, isRevealed: true }),\n }),\n game.players[1],\n game.players[2],\n game.players[3],\n ],\n });\n mocks.gameHelper.getPlayerWithIdOrThrow.mockReturnValue(players[0]);\n\n expect(services.playerKiller.revealPlayerRole(players[0], game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"getElderLivesCountAgainstWerewolves\", () => {\n it(\"should get elder lives count against werewolves when called.\", async() => {\n const livesCountAgainstWerewolves = 3;\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ elder: createFakeElderGameOptions({ livesCountAgainstWerewolves }) }) });\n const elderPlayer = createFakeElderAlivePlayer();\n const game = createFakeGame({ turn: 2, currentPlay: createFakeGamePlayHunterShoots(), options });\n mocks.gameHistoryRecordService.getGameHistoryWerewolvesEatElderRecords.mockResolvedValue([]);\n mocks.gameHistoryRecordService.getGameHistoryElderProtectedFromWerewolvesRecords.mockResolvedValue([]);\n await services.playerKiller[\"getElderLivesCountAgainstWerewolves\"](game, elderPlayer);\n\n expect(mocks.gameHistoryRecordService.getGameHistoryWerewolvesEatElderRecords).toHaveBeenCalledExactlyOnceWith(game._id, elderPlayer._id);\n });\n\n it(\"should get elder protected from werewolves records when called.\", async() => {\n const livesCountAgainstWerewolves = 3;\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ elder: createFakeElderGameOptions({ livesCountAgainstWerewolves }) }) });\n const elderPlayer = createFakeElderAlivePlayer();\n const game = createFakeGame({ turn: 2, currentPlay: createFakeGamePlayHunterShoots(), options });\n mocks.gameHistoryRecordService.getGameHistoryWerewolvesEatElderRecords.mockResolvedValue([]);\n mocks.gameHistoryRecordService.getGameHistoryElderProtectedFromWerewolvesRecords.mockResolvedValue([]);\n await services.playerKiller[\"getElderLivesCountAgainstWerewolves\"](game, elderPlayer);\n\n expect(mocks.gameHistoryRecordService.getGameHistoryElderProtectedFromWerewolvesRecords).toHaveBeenCalledExactlyOnceWith(game._id, elderPlayer._id);\n });\n\n it(\"should return same amount of lives when no werewolves attack against elder.\", async() => {\n const livesCountAgainstWerewolves = 3;\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ elder: createFakeElderGameOptions({ livesCountAgainstWerewolves }) }) });\n const elderPlayer = createFakeElderAlivePlayer();\n const game = createFakeGame({ turn: 2, currentPlay: createFakeGamePlayHunterShoots(), options });\n const gameHistoryRecordPlayElderTarget = createFakeGameHistoryRecordPlayTarget({ player: createFakeElderAlivePlayer() });\n const elderProtectedFromWerewolvesRecords = [\n createFakeGameHistoryRecord({\n play: createFakeGameHistoryRecordDefenderProtectPlay({ targets: [gameHistoryRecordPlayElderTarget] }),\n turn: 1,\n }),\n ];\n mocks.gameHistoryRecordService.getGameHistoryWerewolvesEatElderRecords.mockResolvedValue([]);\n mocks.gameHistoryRecordService.getGameHistoryElderProtectedFromWerewolvesRecords.mockResolvedValue(elderProtectedFromWerewolvesRecords);\n\n await expect(services.playerKiller[\"getElderLivesCountAgainstWerewolves\"](game, elderPlayer)).resolves.toBe(3);\n });\n\n it(\"should return amount of lives minus one when werewolves attacked the elder on current turn.\", async() => {\n const livesCountAgainstWerewolves = 3;\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ elder: createFakeElderGameOptions({ livesCountAgainstWerewolves }) }) });\n const elderPlayer = createFakeElderAlivePlayer({ attributes: [createFakeEatenByWerewolvesPlayerAttribute()] });\n const game = createFakeGame({ turn: 2, currentPlay: createFakeGamePlayHunterShoots(), options });\n const gameHistoryRecordPlayElderTarget = createFakeGameHistoryRecordPlayTarget({ player: elderPlayer });\n const elderProtectedFromWerewolvesRecords = [\n createFakeGameHistoryRecord({\n play: createFakeGameHistoryRecordDefenderProtectPlay({ targets: [gameHistoryRecordPlayElderTarget] }),\n turn: 1,\n }),\n ];\n mocks.gameHistoryRecordService.getGameHistoryWerewolvesEatElderRecords.mockResolvedValue([]);\n mocks.gameHistoryRecordService.getGameHistoryElderProtectedFromWerewolvesRecords.mockResolvedValue(elderProtectedFromWerewolvesRecords);\n\n await expect(services.playerKiller[\"getElderLivesCountAgainstWerewolves\"](game, elderPlayer)).resolves.toBe(2);\n });\n\n it(\"should return amount of lives minus two when werewolves attacked the elder on current turn and also before that.\", async() => {\n const livesCountAgainstWerewolves = 3;\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ elder: createFakeElderGameOptions({ livesCountAgainstWerewolves }) }) });\n const elderPlayer = createFakeElderAlivePlayer({ attributes: [createFakeEatenByWerewolvesPlayerAttribute()] });\n const game = createFakeGame({ turn: 2, currentPlay: createFakeGamePlayHunterShoots(), options });\n const gameHistoryRecordPlayElderTarget = createFakeGameHistoryRecordPlayTarget({ player: elderPlayer });\n const werewolvesEatElderRecords = [\n createFakeGameHistoryRecord({\n play: createFakeGameHistoryRecordWerewolvesEatPlay({ targets: [gameHistoryRecordPlayElderTarget] }),\n turn: 1,\n }),\n createFakeGameHistoryRecord({\n play: createFakeGameHistoryRecordWerewolvesEatPlay({ targets: [gameHistoryRecordPlayElderTarget] }),\n turn: 2,\n }),\n ];\n mocks.gameHistoryRecordService.getGameHistoryWerewolvesEatElderRecords.mockResolvedValue(werewolvesEatElderRecords);\n mocks.gameHistoryRecordService.getGameHistoryElderProtectedFromWerewolvesRecords.mockResolvedValue([]);\n\n await expect(services.playerKiller[\"getElderLivesCountAgainstWerewolves\"](game, elderPlayer)).resolves.toBe(1);\n });\n\n it(\"should return amount of lives minus one when elder was attacked three times but protected once and saved by witch once.\", async() => {\n const livesCountAgainstWerewolves = 3;\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ elder: createFakeElderGameOptions({ livesCountAgainstWerewolves }) }) });\n const elderPlayer = createFakeElderAlivePlayer();\n const game = createFakeGame({ turn: 4, currentPlay: createFakeGamePlayHunterShoots(), options });\n const gameHistoryRecordPlayElderTarget = createFakeGameHistoryRecordPlayTarget({ player: createFakeElderAlivePlayer() });\n const gameHistoryRecordPlayElderDrankLifePotionTarget = createFakeGameHistoryRecordPlayTarget({ ...gameHistoryRecordPlayElderTarget, drankPotion: \"life\" });\n const werewolvesEatElderRecords = [\n createFakeGameHistoryRecord({\n play: createFakeGameHistoryRecordWerewolvesEatPlay({ targets: [gameHistoryRecordPlayElderTarget] }),\n turn: 1,\n }),\n createFakeGameHistoryRecord({\n play: createFakeGameHistoryRecordWerewolvesEatPlay({ targets: [gameHistoryRecordPlayElderTarget] }),\n turn: 2,\n }),\n createFakeGameHistoryRecord({\n play: createFakeGameHistoryRecordWerewolvesEatPlay({ targets: [gameHistoryRecordPlayElderTarget] }),\n turn: 3,\n }),\n ];\n const elderProtectedFromWerewolvesRecords = [\n createFakeGameHistoryRecord({\n play: createFakeGameHistoryRecordDefenderProtectPlay({ targets: [gameHistoryRecordPlayElderTarget] }),\n turn: 1,\n }),\n createFakeGameHistoryRecord({\n play: createFakeGameHistoryRecordWitchUsePotionsPlay({ targets: [gameHistoryRecordPlayElderDrankLifePotionTarget] }),\n turn: 2,\n }),\n ];\n mocks.gameHistoryRecordService.getGameHistoryWerewolvesEatElderRecords.mockResolvedValue(werewolvesEatElderRecords);\n mocks.gameHistoryRecordService.getGameHistoryElderProtectedFromWerewolvesRecords.mockResolvedValue(elderProtectedFromWerewolvesRecords);\n\n await expect(services.playerKiller[\"getElderLivesCountAgainstWerewolves\"](game, elderPlayer)).resolves.toBe(2);\n });\n\n it(\"should return amount of lives minus 1 when elder was attacked but not protected or saved by witch.\", async() => {\n const livesCountAgainstWerewolves = 3;\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ elder: createFakeElderGameOptions({ livesCountAgainstWerewolves }) }) });\n const elderPlayer = createFakeElderAlivePlayer();\n const game = createFakeGame({ turn: 2, currentPlay: createFakeGamePlayHunterShoots(), options });\n const gameHistoryRecordPlayElderTarget = createFakeGameHistoryRecordPlayTarget({ player: createFakeElderAlivePlayer() });\n const werewolvesEatElderRecords = [\n createFakeGameHistoryRecord({\n play: createFakeGameHistoryRecordWerewolvesEatPlay({ targets: [gameHistoryRecordPlayElderTarget] }),\n turn: 1,\n }),\n ];\n mocks.gameHistoryRecordService.getGameHistoryWerewolvesEatElderRecords.mockResolvedValue(werewolvesEatElderRecords);\n mocks.gameHistoryRecordService.getGameHistoryElderProtectedFromWerewolvesRecords.mockResolvedValue([]);\n\n await expect(services.playerKiller[\"getElderLivesCountAgainstWerewolves\"](game, elderPlayer)).resolves.toBe(2);\n });\n });\n\n describe(\"applyPlayerRoleRevelationOutcomes\", () => {\n it(\"should add can't vote attribute when player is idiot.\", () => {\n const players = [\n createFakeIdiotAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n createFakePlayer({\n ...players[0],\n attributes: [createFakeCantVoteBySurvivorsPlayerAttribute()],\n }),\n game.players[1],\n game.players[2],\n game.players[3],\n ],\n });\n\n expect(services.playerKiller[\"applyPlayerRoleRevelationOutcomes\"](game.players[0], game)).toStrictEqual(expectedGame);\n });\n\n it(\"should return the game as is when player is not an idiot.\", () => {\n const players = [\n createFakeIdiotAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(services.playerKiller[\"applyPlayerRoleRevelationOutcomes\"](game.players[1], game)).toStrictEqual(game);\n });\n });\n\n describe(\"isElderKillable\", () => {\n beforeEach(() => {\n mocks.playerKillerService.getElderLivesCountAgainstWerewolves = jest.spyOn(services.playerKiller as unknown as { getElderLivesCountAgainstWerewolves }, \"getElderLivesCountAgainstWerewolves\").mockImplementation();\n });\n\n it.each<{\n test: string;\n elderPlayer: Player;\n cause: PlayerDeathCause;\n getElderLivesCountAgainstWerewolvesMockReturnValue: number;\n expected: boolean;\n }>([\n {\n test: \"should return true when cause is not EATEN.\",\n elderPlayer: createFakeElderAlivePlayer(),\n cause: \"vote\",\n getElderLivesCountAgainstWerewolvesMockReturnValue: 2,\n expected: true,\n },\n {\n test: \"should return false when cause is EATEN but elder still have at least one life left.\",\n elderPlayer: createFakeElderAlivePlayer(),\n cause: \"eaten\",\n getElderLivesCountAgainstWerewolvesMockReturnValue: 2,\n expected: false,\n },\n {\n test: \"should return true when cause is EATEN but elder has 0 life left.\",\n elderPlayer: createFakeElderAlivePlayer(),\n cause: \"eaten\",\n getElderLivesCountAgainstWerewolvesMockReturnValue: 0,\n expected: true,\n },\n ])(\"$test\", async({ elderPlayer, cause, getElderLivesCountAgainstWerewolvesMockReturnValue, expected }) => {\n const game = createFakeGame();\n mocks.playerKillerService.getElderLivesCountAgainstWerewolves.mockReturnValue(getElderLivesCountAgainstWerewolvesMockReturnValue);\n\n await expect(services.playerKiller.isElderKillable(game, elderPlayer, cause)).resolves.toBe(expected);\n });\n });\n\n describe(\"doesPlayerRoleMustBeRevealed\", () => {\n it.each<{\n test: string;\n player: Player;\n death: PlayerDeath;\n game: Game;\n expected: boolean;\n }>([\n {\n test: \"should return false when player role is already revealed.\",\n player: createFakeVillagerVillagerAlivePlayer(),\n death: createFakePlayerVoteBySurvivorsDeath(),\n game: createFakeGame(),\n expected: false,\n },\n {\n test: \"should return false when player is dead but options doesn't allow the role to be revealed.\",\n player: createFakeWitchAlivePlayer(),\n death: createFakePlayerVoteBySurvivorsDeath(),\n game: createFakeGame({ options: createFakeGameOptions({ roles: createFakeRolesGameOptions({ areRevealedOnDeath: false }) }) }),\n expected: false,\n },\n {\n test: \"should return false when player role is not idiot.\",\n player: createFakeSeerAlivePlayer(),\n death: createFakePlayerVoteBySurvivorsDeath(),\n game: createFakeGame(),\n expected: false,\n },\n {\n test: \"should return false when player role is idiot but powerless.\",\n player: createFakeIdiotAlivePlayer({ attributes: [createFakePowerlessByElderPlayerAttribute()] }),\n death: createFakePlayerVoteBySurvivorsDeath(),\n game: createFakeGame(),\n expected: false,\n },\n {\n test: \"should return false when player role is idiot but death cause is not vote.\",\n player: createFakeIdiotAlivePlayer(),\n death: createFakePlayerDeathPotionByWitchDeath(),\n game: createFakeGame(),\n expected: false,\n },\n {\n test: \"should return false when player is not dead and his role can be revealed to others.\",\n player: createFakeWitchAlivePlayer(),\n death: createFakePlayerVoteBySurvivorsDeath(),\n game: createFakeGame({ options: createFakeGameOptions({ roles: createFakeRolesGameOptions({ areRevealedOnDeath: true }) }) }),\n expected: false,\n },\n {\n test: \"should return true when player is dead and his role can be revealed to others.\",\n player: createFakeWitchAlivePlayer({ isAlive: false }),\n death: createFakePlayerVoteBySurvivorsDeath(),\n game: createFakeGame({ options: createFakeGameOptions({ roles: createFakeRolesGameOptions({ areRevealedOnDeath: true }) }) }),\n expected: true,\n },\n {\n test: \"should return true when player role is idiot and death cause is vote.\",\n player: createFakeIdiotAlivePlayer(),\n death: createFakePlayerVoteBySurvivorsDeath(),\n game: createFakeGame(),\n expected: true,\n },\n ])(\"$test\", ({ player, death, game, expected }) => {\n expect(services.playerKiller[\"doesPlayerRoleMustBeRevealed\"](player, death, game)).toBe(expected);\n });\n });\n\n describe(\"removePlayerAttributesAfterDeath\", () => {\n it(\"should remove player attributes which need to be removed after death when called.\", () => {\n const player = createFakePlayer({\n isAlive: false,\n attributes: [\n createFakeCantVoteBySurvivorsPlayerAttribute({ doesRemainAfterDeath: false }),\n createFakePowerlessByElderPlayerAttribute(),\n createFakeSheriffBySurvivorsPlayerAttribute({ doesRemainAfterDeath: true }),\n ],\n });\n const expectedPlayer = createFakePlayer({\n ...player,\n attributes: [\n player.attributes[1],\n player.attributes[2],\n ],\n });\n\n expect(services.playerKiller[\"removePlayerAttributesAfterDeath\"](player)).toStrictEqual(expectedPlayer);\n });\n });\n\n describe(\"isIdiotKillable\", () => {\n it.each<{\n test: string;\n player: Player;\n cause: PlayerDeathCause;\n game: Game;\n expected: boolean;\n }>([\n {\n test: \"should return true when idiot is already revealed.\",\n player: createFakeIdiotAlivePlayer({ role: createFakePlayerRole({ isRevealed: true }) }),\n cause: \"vote\",\n game: createFakeGame(),\n expected: true,\n },\n {\n test: \"should return true when idiot is killed by other cause than a vote.\",\n player: createFakeIdiotAlivePlayer(),\n cause: \"death-potion\",\n game: createFakeGame(),\n expected: true,\n },\n {\n test: \"should return true when idiot is killed by vote but powerless.\",\n player: createFakeIdiotAlivePlayer({ attributes: [createFakePowerlessByElderPlayerAttribute()] }),\n cause: \"vote\",\n game: createFakeGame(),\n expected: true,\n },\n {\n test: \"should return false when idiot is not revealed, dies from votes and is not powerless.\",\n player: createFakeIdiotAlivePlayer(),\n cause: \"vote\",\n game: createFakeGame(),\n expected: false,\n },\n ])(\"$test\", ({ player, cause, game, expected }) => {\n expect(services.playerKiller[\"isIdiotKillable\"](player, cause, game)).toBe(expected);\n });\n });\n\n describe(\"canPlayerBeEaten\", () => {\n it.each<{\n test: string;\n player: Player;\n game: Game;\n expected: boolean;\n }>([\n {\n test: \"should return false when player is saved by the witch.\",\n player: createFakeSeerAlivePlayer({ attributes: [createFakeDrankLifePotionByWitchPlayerAttribute()] }),\n game: createFakeGame(),\n expected: false,\n },\n {\n test: \"should return false when player is protected by defender and is not little girl.\",\n player: createFakeSeerAlivePlayer({ attributes: [createFakeProtectedByDefenderPlayerAttribute()] }),\n game: createFakeGame({ options: createFakeGameOptions({ roles: createFakeRolesGameOptions({ littleGirl: createFakeLittleGirlGameOptions({ isProtectedByDefender: true }) }) }) }),\n expected: false,\n },\n {\n test: \"should return false when player is protected by defender, is little girl but game options allows defender to protect her.\",\n player: createFakeLittleGirlAlivePlayer({ attributes: [createFakeProtectedByDefenderPlayerAttribute()] }),\n game: createFakeGame({ options: createFakeGameOptions({ roles: createFakeRolesGameOptions({ littleGirl: createFakeLittleGirlGameOptions({ isProtectedByDefender: true }) }) }) }),\n expected: false,\n },\n {\n test: \"should return true when player is protected by defender, is little girl but game options doesn't allow defender to protect her.\",\n player: createFakeLittleGirlAlivePlayer({ attributes: [createFakeProtectedByDefenderPlayerAttribute()] }),\n game: createFakeGame({ options: createFakeGameOptions({ roles: createFakeRolesGameOptions({ littleGirl: createFakeLittleGirlGameOptions({ isProtectedByDefender: false }) }) }) }),\n expected: true,\n },\n {\n test: \"should return false when little girl is saved by the witch.\",\n player: createFakeLittleGirlAlivePlayer({ attributes: [createFakeDrankLifePotionByWitchPlayerAttribute()] }),\n game: createFakeGame(),\n expected: false,\n },\n {\n test: \"should return true when player defenseless.\",\n player: createFakeSeerAlivePlayer({ attributes: [] }),\n game: createFakeGame({ options: createFakeGameOptions({ roles: createFakeRolesGameOptions({ littleGirl: createFakeLittleGirlGameOptions({ isProtectedByDefender: true }) }) }) }),\n expected: true,\n },\n ])(\"$test\", ({ player, game, expected }) => {\n expect(services.playerKiller[\"canPlayerBeEaten\"](player, game)).toBe(expected);\n });\n\n it(\"should return false when player is protected by defender and is not little girl.\", () => {\n const player = createFakeSeerAlivePlayer({ attributes: [createFakeProtectedByDefenderPlayerAttribute()] });\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ littleGirl: createFakeLittleGirlGameOptions({ isProtectedByDefender: false }) }) });\n const game = createFakeGame({ options });\n\n expect(services.playerKiller[\"canPlayerBeEaten\"](player, game)).toBe(false);\n });\n });\n\n describe(\"isPlayerKillable\", () => {\n beforeEach(() => {\n mocks.playerKillerService.isIdiotKillable = jest.spyOn(services.playerKiller as unknown as { isIdiotKillable }, \"isIdiotKillable\").mockImplementation();\n mocks.playerKillerService.isElderKillable = jest.spyOn(services.playerKiller as unknown as { isElderKillable }, \"isElderKillable\").mockImplementation();\n mocks.playerKillerService.canPlayerBeEaten = jest.spyOn(services.playerKiller as unknown as { canPlayerBeEaten }, \"canPlayerBeEaten\").mockImplementation();\n });\n\n it(\"should return false when cause is EATEN and player can't be eaten.\", async() => {\n const player = createFakePlayer();\n const game = createFakeGame();\n mocks.playerKillerService.canPlayerBeEaten.mockReturnValue(false);\n\n await expect(services.playerKiller[\"isPlayerKillable\"](player, game, \"eaten\")).resolves.toBe(false);\n });\n\n it(\"should not call can player be eaten validator when cause is not EATEN.\", async() => {\n const player = createFakePlayer();\n const game = createFakeGame();\n mocks.playerKillerService.canPlayerBeEaten.mockReturnValue(false);\n await services.playerKiller[\"isPlayerKillable\"](player, game, \"vote\");\n\n expect(mocks.playerKillerService.canPlayerBeEaten).not.toHaveBeenCalled();\n });\n\n it(\"should call is idiot killable when player is an idiot.\", async() => {\n const player = createFakeIdiotAlivePlayer();\n const game = createFakeGame();\n mocks.playerKillerService.isIdiotKillable.mockReturnValue(false);\n await services.playerKiller[\"isPlayerKillable\"](player, game, \"vote\");\n\n expect(mocks.playerKillerService.isIdiotKillable).toHaveBeenCalledExactlyOnceWith(player, \"vote\", game);\n });\n\n it(\"should not call is idiot killable when player is not an idiot.\", async() => {\n const player = createFakeSeerAlivePlayer();\n const game = createFakeGame();\n mocks.playerKillerService.isIdiotKillable.mockReturnValue(false);\n await services.playerKiller[\"isPlayerKillable\"](player, game, \"vote\");\n\n expect(mocks.playerKillerService.isIdiotKillable).not.toHaveBeenCalled();\n });\n\n it(\"should call is elder killable when player is an elder.\", async() => {\n const player = createFakeElderAlivePlayer();\n const game = createFakeGame();\n mocks.playerKillerService.isElderKillable.mockReturnValue(false);\n await services.playerKiller[\"isPlayerKillable\"](player, game, \"vote\");\n\n expect(mocks.playerKillerService.isElderKillable).toHaveBeenCalledExactlyOnceWith(game, player, \"vote\");\n });\n\n it(\"should not call is elder killable when player is not an elder.\", async() => {\n const player = createFakeSeerAlivePlayer();\n const game = createFakeGame();\n mocks.playerKillerService.isElderKillable.mockReturnValue(false);\n await services.playerKiller[\"isPlayerKillable\"](player, game, \"vote\");\n\n expect(mocks.playerKillerService.isElderKillable).not.toHaveBeenCalled();\n });\n\n it(\"should return true when there are no contraindications.\", async() => {\n const player = createFakeSeerAlivePlayer();\n const game = createFakeGame();\n\n await expect(services.playerKiller[\"isPlayerKillable\"](player, game, \"vote\")).resolves.toBe(true);\n });\n });\n\n describe(\"applyWorshipedPlayerDeathOutcomes\", () => {\n it(\"should return game as is when killed player doesn't have the worshiped attribute.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWildChildAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer({ attributes: [createFakeWorshipedByWildChildPlayerAttribute()] }),\n ];\n const game = createFakeGame({ players });\n\n expect(services.playerKiller[\"applyWorshipedPlayerDeathOutcomes\"](players[0], game)).toStrictEqual(game);\n });\n\n it(\"should return game as is when there is no wild child player.\", () => {\n const players = [\n createFakeSeerAlivePlayer({ attributes: [createFakeWorshipedByWildChildPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer(),\n createFakeWitchAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(services.playerKiller[\"applyWorshipedPlayerDeathOutcomes\"](players[0], game)).toStrictEqual(game);\n });\n\n it(\"should return game as is when wild child player is dead.\", () => {\n const players = [\n createFakeSeerAlivePlayer({ attributes: [createFakeWorshipedByWildChildPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer(),\n createFakeWildChildAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(services.playerKiller[\"applyWorshipedPlayerDeathOutcomes\"](players[0], game)).toStrictEqual(game);\n });\n\n it(\"should return game as is when wild child player is powerless.\", () => {\n const players = [\n createFakeSeerAlivePlayer({ attributes: [createFakeWorshipedByWildChildPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer(),\n createFakeWildChildAlivePlayer({ attributes: [createFakePowerlessByElderPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(services.playerKiller[\"applyWorshipedPlayerDeathOutcomes\"](players[0], game)).toStrictEqual(game);\n });\n\n it(\"should transform wild child to a werewolf sided player when called.\", () => {\n const players = [\n createFakeSeerAlivePlayer({ attributes: [createFakeWorshipedByWildChildPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWildChildAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n game.players[0],\n game.players[1],\n game.players[2],\n createFakePlayer({\n ...game.players[3],\n side: createFakePlayerSide({ ...game.players[3].side, current: \"werewolves\" }),\n }),\n ],\n });\n\n expect(services.playerKiller[\"applyWorshipedPlayerDeathOutcomes\"](players[0], game)).toStrictEqual(expectedGame);\n });\n\n it(\"should transform wild child to a werewolf sided player and add powerless attribute when wild child is actor in disguise.\", () => {\n const players = [\n createFakeSeerAlivePlayer({ attributes: [createFakeWorshipedByWildChildPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWildChildAlivePlayer({\n role: createFakePlayerRole({ original: \"actor\", current: \"wild-child\" }),\n attributes: [createFakeCantVoteBySurvivorsPlayerAttribute()],\n }),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ actor: createFakeActorGameOptions({ isPowerlessOnWerewolvesSide: true }) }) });\n const game = createFakeGame({ players, options });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n game.players[0],\n game.players[1],\n game.players[2],\n createFakePlayer({\n ...game.players[3],\n side: createFakePlayerSide({ ...game.players[3].side, current: \"werewolves\" }),\n attributes: [...game.players[3].attributes, createFakePowerlessByActorPlayerAttribute()],\n }),\n ],\n });\n\n expect(services.playerKiller[\"applyWorshipedPlayerDeathOutcomes\"](players[0], game)).toStrictEqual(expectedGame);\n });\n\n it(\"should transform wild child to a werewolf sided player but without powerless attribute when wild child is actor in disguise and game options are changed.\", () => {\n const players = [\n createFakeSeerAlivePlayer({ attributes: [createFakeWorshipedByWildChildPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWildChildAlivePlayer({\n role: createFakePlayerRole({ original: \"actor\", current: \"wild-child\" }),\n attributes: [createFakeCantVoteBySurvivorsPlayerAttribute()],\n }),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ actor: createFakeActorGameOptions({ isPowerlessOnWerewolvesSide: false }) }) });\n const game = createFakeGame({ players, options });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n game.players[0],\n game.players[1],\n game.players[2],\n createFakePlayer({\n ...game.players[3],\n side: createFakePlayerSide({ ...game.players[3].side, current: \"werewolves\" }),\n attributes: [...game.players[3].attributes],\n }),\n ],\n });\n\n expect(services.playerKiller[\"applyWorshipedPlayerDeathOutcomes\"](players[0], game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"applyInLovePlayerDeathOutcomes\", () => {\n beforeEach(() => {\n mocks.playerKillerService.killPlayer = jest.spyOn(services.playerKiller as unknown as { killPlayer }, \"killPlayer\").mockImplementation();\n });\n\n it(\"should return game as is when killed player doesn't have the in love attribute.\", () => {\n const players = [\n createFakeSeerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(services.playerKiller[\"applyInLovePlayerDeathOutcomes\"](players[0], game)).toStrictEqual(game);\n });\n\n it(\"should return game as is when the other lover is not found because no other one has the in love attribute.\", () => {\n const players = [\n createFakeSeerAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(services.playerKiller[\"applyInLovePlayerDeathOutcomes\"](players[0], game)).toStrictEqual(game);\n });\n\n it(\"should return game as is when the other lover is not found because he is dead.\", () => {\n const players = [\n createFakeSeerAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()], isAlive: false }),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(services.playerKiller[\"applyInLovePlayerDeathOutcomes\"](players[0], game)).toStrictEqual(game);\n });\n\n it(\"should kill the other lover when called.\", () => {\n const players = [\n createFakeSeerAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n services.playerKiller[\"applyInLovePlayerDeathOutcomes\"](players[1], game);\n\n expect(mocks.playerKillerService.killPlayer).toHaveBeenCalledExactlyOnceWith(players[0], game, createFakePlayerBrokenHeartByCupidDeath());\n });\n });\n\n describe(\"applySheriffPlayerDeathOutcomes\", () => {\n it(\"should return game as is when player is not the sheriff.\", () => {\n const players = [\n createFakeSeerAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(services.playerKiller[\"applySheriffPlayerDeathOutcomes\"](players[0], game)).toStrictEqual(game);\n });\n\n it(\"should return game as is when player is idiot and not powerless.\", () => {\n const players = [\n createFakeIdiotAlivePlayer({ attributes: [createFakeSheriffBySurvivorsPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(services.playerKiller[\"applySheriffPlayerDeathOutcomes\"](players[0], game)).toStrictEqual(game);\n });\n\n it(\"should prepend sheriff election game play when called with powerless idiot.\", () => {\n const players = [\n createFakeIdiotAlivePlayer({ attributes: [createFakeSheriffBySurvivorsPlayerAttribute(), createFakePowerlessByElderPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const upcomingPlays = [createFakeGamePlayHunterShoots()];\n const game = createFakeGame({ players, upcomingPlays });\n const expectedGame = createFakeGame({\n ...game,\n upcomingPlays: [createFakeGamePlaySheriffDelegates(), ...game.upcomingPlays],\n });\n\n expect(services.playerKiller[\"applySheriffPlayerDeathOutcomes\"](players[0], game)).toStrictEqual(expectedGame);\n });\n\n it(\"should prepend sheriff election game play when called with any other role.\", () => {\n const players = [\n createFakeWildChildAlivePlayer({ attributes: [createFakeSheriffBySurvivorsPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const upcomingPlays = [createFakeGamePlayHunterShoots()];\n const game = createFakeGame({ players, upcomingPlays });\n const expectedGame = createFakeGame({\n ...game,\n upcomingPlays: [createFakeGamePlaySheriffDelegates(), ...game.upcomingPlays],\n });\n\n expect(services.playerKiller[\"applySheriffPlayerDeathOutcomes\"](players[0], game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"applyPlayerAttributesDeathOutcomes\", () => {\n beforeEach(() => {\n mocks.playerKillerService.applySheriffPlayerDeathOutcomes = jest.spyOn(services.playerKiller as unknown as { applySheriffPlayerDeathOutcomes }, \"applySheriffPlayerDeathOutcomes\").mockImplementation();\n mocks.playerKillerService.applyInLovePlayerDeathOutcomes = jest.spyOn(services.playerKiller as unknown as { applyInLovePlayerDeathOutcomes }, \"applyInLovePlayerDeathOutcomes\").mockImplementation();\n mocks.playerKillerService.applyWorshipedPlayerDeathOutcomes = jest.spyOn(services.playerKiller as unknown as { applyWorshipedPlayerDeathOutcomes }, \"applyWorshipedPlayerDeathOutcomes\").mockImplementation();\n mocks.gameHelper.getPlayerWithIdOrThrow = jest.spyOn(GameHelper, \"getPlayerWithIdOrThrow\").mockImplementation();\n });\n\n it(\"should call no methods when player doesn't have the right attributes.\", () => {\n const players = [\n createFakeIdiotAlivePlayer({ attributes: [createFakePowerlessByElderPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n services.playerKiller[\"applyPlayerAttributesDeathOutcomes\"](game.players[0], game);\n\n expect(mocks.playerKillerService.applySheriffPlayerDeathOutcomes).not.toHaveBeenCalled();\n expect(mocks.playerKillerService.applyInLovePlayerDeathOutcomes).not.toHaveBeenCalled();\n expect(mocks.playerKillerService.applyWorshipedPlayerDeathOutcomes).not.toHaveBeenCalled();\n expect(mocks.gameHelper.getPlayerWithIdOrThrow).not.toHaveBeenCalled();\n });\n\n it(\"should call survivors methods when player have all attributes.\", () => {\n const players = [\n createFakeIdiotAlivePlayer({ attributes: [createFakePowerlessByElderPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeSheriffBySurvivorsPlayerAttribute(), createFakeInLoveByCupidPlayerAttribute(), createFakeWorshipedByWildChildPlayerAttribute()] }),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const interpolations = { gameId: game._id.toString(), playerId: players[2]._id.toString() };\n const exception = new UnexpectedException(\"applyPlayerAttributesDeathOutcomes\", UnexpectedExceptionReasons.CANT_FIND_PLAYER_WITH_ID_IN_GAME, interpolations);\n const expectedInterpolations = { gameId: game._id, playerId: players[2]._id };\n\n mocks.playerKillerService.applySheriffPlayerDeathOutcomes.mockReturnValue(game);\n mocks.playerKillerService.applyInLovePlayerDeathOutcomes.mockReturnValue(game);\n mocks.playerKillerService.applyWorshipedPlayerDeathOutcomes.mockReturnValue(game);\n mocks.gameHelper.getPlayerWithIdOrThrow.mockReturnValue(game.players[2]);\n mocks.unexpectedExceptionFactory.createCantFindPlayerWithIdUnexpectedException.mockReturnValue(exception);\n services.playerKiller[\"applyPlayerAttributesDeathOutcomes\"](game.players[2], game);\n\n expect(mocks.unexpectedExceptionFactory.createCantFindPlayerWithIdUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"applyPlayerAttributesDeathOutcomes\", expectedInterpolations);\n expect(mocks.playerKillerService.applySheriffPlayerDeathOutcomes).toHaveBeenCalledExactlyOnceWith(game.players[2], game);\n expect(mocks.playerKillerService.applyInLovePlayerDeathOutcomes).toHaveBeenCalledExactlyOnceWith(game.players[2], game);\n expect(mocks.playerKillerService.applyWorshipedPlayerDeathOutcomes).toHaveBeenCalledExactlyOnceWith(game.players[2], game);\n expect(mocks.gameHelper.getPlayerWithIdOrThrow).toHaveBeenNthCalledWith(1, game.players[2]._id, game, exception);\n expect(mocks.gameHelper.getPlayerWithIdOrThrow).toHaveBeenNthCalledWith(2, game.players[2]._id, game, exception);\n });\n });\n\n describe(\"applyPlayerSideDeathOutcomes\", () => {\n it(\"should return game as is when player is not a werewolf sided player.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeBigBadWolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ bigBadWolf: createFakeBigBadWolfGameOptions({ isPowerlessIfWerewolfDies: true }) }) });\n const game = createFakeGame({ players, options });\n\n expect(services.playerKiller[\"applyPlayerSideDeathOutcomes\"](players[3], game)).toStrictEqual(game);\n });\n\n it(\"should return game as is when player is a werewolf sided player but there is no big bad wolf in the game.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ bigBadWolf: createFakeBigBadWolfGameOptions({ isPowerlessIfWerewolfDies: true }) }) });\n const game = createFakeGame({ players, options });\n\n expect(services.playerKiller[\"applyPlayerSideDeathOutcomes\"](players[0], game)).toStrictEqual(game);\n });\n\n it(\"should return game as is when player is a werewolf sided player but game options say that big bad wolf is not powerless if one werewolf dies.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeBigBadWolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ bigBadWolf: createFakeBigBadWolfGameOptions({ isPowerlessIfWerewolfDies: false }) }) });\n const game = createFakeGame({ players, options });\n\n expect(services.playerKiller[\"applyPlayerSideDeathOutcomes\"](players[0], game)).toStrictEqual(game);\n });\n\n it(\"should return game as is when player is a werewolf sided player but killed player is big bad wolf himself.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeBigBadWolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ bigBadWolf: createFakeBigBadWolfGameOptions({ isPowerlessIfWerewolfDies: true }) }) });\n const game = createFakeGame({ players, options });\n\n expect(services.playerKiller[\"applyPlayerSideDeathOutcomes\"](players[2], game)).toStrictEqual(game);\n });\n\n it(\"should return game as is when player is a werewolf sided player but big bad wolf is already powerless by werewolves.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeBigBadWolfAlivePlayer({ attributes: [createFakePowerlessByWerewolvesPlayerAttribute()] }),\n createFakeSeerAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ bigBadWolf: createFakeBigBadWolfGameOptions({ isPowerlessIfWerewolfDies: true }) }) });\n const game = createFakeGame({ players, options });\n\n expect(services.playerKiller[\"applyPlayerSideDeathOutcomes\"](players[0], game)).toStrictEqual(game);\n });\n\n it(\"should return game with powerless big bad wolf when killer player is werewolf sided and big bad wolf is not already powerless by werewolves.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeBigBadWolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ bigBadWolf: createFakeBigBadWolfGameOptions({ isPowerlessIfWerewolfDies: true }) }) });\n const game = createFakeGame({ players, options });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n players[1],\n createFakePlayer({\n ...players[2],\n attributes: [createFakePowerlessByWerewolvesPlayerAttribute()],\n }),\n players[3],\n ],\n });\n\n expect(services.playerKiller[\"applyPlayerSideDeathOutcomes\"](players[0], game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"applyRustySwordKnightDeathOutcomes\", () => {\n it(\"should return game as is when killed player is not rusty sword knight.\", () => {\n const death = createFakePlayerEatenByWerewolvesDeath();\n const players = [\n createFakeIdiotAlivePlayer({ isAlive: false, death }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(services.playerKiller[\"applyRustySwordKnightDeathOutcomes\"](players[0] as DeadPlayer, game)).toStrictEqual(game);\n });\n\n it(\"should return game as is when killed player is powerless.\", () => {\n const death = createFakePlayerEatenByWerewolvesDeath();\n const players = [\n createFakeRustySwordKnightAlivePlayer({ attributes: [createFakePowerlessByElderPlayerAttribute()], isAlive: false, death }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(services.playerKiller[\"applyRustySwordKnightDeathOutcomes\"](players[0] as DeadPlayer, game)).toStrictEqual(game);\n });\n\n it(\"should return game as is when death cause is not eaten.\", () => {\n const death = createFakePlayerVoteBySurvivorsDeath();\n const players = [\n createFakeRustySwordKnightAlivePlayer({ isAlive: false, death }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(services.playerKiller[\"applyRustySwordKnightDeathOutcomes\"](players[0] as DeadPlayer, game)).toStrictEqual(game);\n });\n\n it(\"should return game as is when no left alive werewolf is found.\", () => {\n const death = createFakePlayerEatenByWerewolvesDeath();\n const players = [\n createFakeRustySwordKnightAlivePlayer({ isAlive: false, death }),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(services.playerKiller[\"applyRustySwordKnightDeathOutcomes\"](players[0] as DeadPlayer, game)).toStrictEqual(game);\n });\n\n it(\"should return game with first left alive werewolf player with contaminated attribute when called.\", () => {\n const death = createFakePlayerEatenByWerewolvesDeath();\n const players = [\n createFakeRustySwordKnightAlivePlayer({ position: 1, isAlive: false, death }),\n createFakeWerewolfAlivePlayer({ position: 2 }),\n createFakeWerewolfAlivePlayer({ position: 3 }),\n createFakeDefenderAlivePlayer({ position: 4 }),\n ];\n const game = createFakeGame({ players });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n players[1],\n createFakePlayer({ ...players[2], attributes: [createFakeContaminatedByRustySwordKnightPlayerAttribute()] }),\n players[3],\n ],\n });\n\n expect(services.playerKiller[\"applyRustySwordKnightDeathOutcomes\"](players[0] as DeadPlayer, game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"applyScapegoatDeathOutcomes\", () => {\n it(\"should return game as is when killed player is not scapegoat.\", () => {\n const death = createFakePlayerVoteScapegoatedBySurvivorsDeath();\n const players = [\n createFakeIdiotAlivePlayer({ isAlive: false, death }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(services.playerKiller[\"applyScapegoatDeathOutcomes\"](players[0] as DeadPlayer, game)).toStrictEqual(game);\n });\n\n it(\"should return game as is when killed player is powerless.\", () => {\n const death = createFakePlayerVoteScapegoatedBySurvivorsDeath();\n const players = [\n createFakeScapegoatAlivePlayer({ attributes: [createFakePowerlessByElderPlayerAttribute()], isAlive: false, death }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(services.playerKiller[\"applyScapegoatDeathOutcomes\"](players[0] as DeadPlayer, game)).toStrictEqual(game);\n });\n\n it(\"should return game as is when killed player was not scapegoated.\", () => {\n const death = createFakePlayerVoteBySurvivorsDeath();\n const players = [\n createFakeScapegoatAlivePlayer({ isAlive: false, death }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(services.playerKiller[\"applyScapegoatDeathOutcomes\"](players[0] as DeadPlayer, game)).toStrictEqual(game);\n });\n\n it(\"should return game with upcoming scapegoat bans votes play when called.\", () => {\n const death = createFakePlayerVoteScapegoatedBySurvivorsDeath();\n const players = [\n createFakeScapegoatAlivePlayer({ isAlive: false, death }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const upcomingPlays = [createFakeGamePlayHunterShoots()];\n const game = createFakeGame({ players, upcomingPlays });\n const expectedGame = createFakeGame({\n ...game,\n upcomingPlays: [createFakeGamePlayScapegoatBansVoting(), ...upcomingPlays],\n });\n\n expect(services.playerKiller[\"applyScapegoatDeathOutcomes\"](players[0] as DeadPlayer, game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"applyElderDeathOutcomes\", () => {\n beforeEach(() => {\n mocks.playerKillerService.killPlayer = jest.spyOn(services.playerKiller as unknown as { killPlayer }, \"killPlayer\").mockImplementation();\n });\n\n it(\"should return game as is when killed player is not elder.\", () => {\n const death = createFakePlayerVoteScapegoatedBySurvivorsDeath();\n const players = [\n createFakeWerewolfAlivePlayer({ isAlive: false, death }),\n createFakeIdiotAlivePlayer({ role: createFakePlayerRole({ isRevealed: true, current: \"idiot\", original: \"idiot\" }) }),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const elderOptions = createFakeElderGameOptions({ doesTakeHisRevenge: true });\n const idiotOptions = createFakeIdiotGameOptions({ doesDieOnElderDeath: true });\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ idiot: idiotOptions, elder: elderOptions }) });\n const game = createFakeGame({ players, options });\n\n expect(services.playerKiller[\"applyElderDeathOutcomes\"](players[0] as DeadPlayer, game)).toStrictEqual(game);\n });\n\n it(\"should return game as is when killed player is powerless.\", () => {\n const death = createFakePlayerVoteBySurvivorsDeath();\n const players = [\n createFakeElderAlivePlayer({ attributes: [createFakePowerlessByElderPlayerAttribute()], isAlive: false, death }),\n createFakeIdiotAlivePlayer({ role: createFakePlayerRole({ isRevealed: true, current: \"idiot\", original: \"idiot\" }) }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const elderOptions = createFakeElderGameOptions({ doesTakeHisRevenge: true });\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ elder: elderOptions }) });\n const game = createFakeGame({ players, options });\n\n expect(services.playerKiller[\"applyElderDeathOutcomes\"](players[0] as DeadPlayer, game)).toStrictEqual(game);\n });\n\n it(\"should return game as is when elder doesn't take his revenge and idiot is not revealed.\", () => {\n const death = createFakePlayerEatenByWerewolvesDeath();\n const players = [\n createFakeElderAlivePlayer({ isAlive: false, death }),\n createFakeIdiotAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(services.playerKiller[\"applyElderDeathOutcomes\"](players[0] as DeadPlayer, game)).toStrictEqual(game);\n });\n\n it(\"should game as is when elder doesn't take his revenge from game options.\", () => {\n const death = createFakePlayerDeathPotionByWitchDeath();\n const players = [\n createFakeElderAlivePlayer({ isAlive: false, death }),\n createFakeIdiotAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n createFakeSeerAlivePlayer({ isAlive: false }),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ elder: createFakeElderGameOptions({ doesTakeHisRevenge: false }) }) });\n const game = createFakeGame({ players, options });\n\n expect(services.playerKiller[\"applyElderDeathOutcomes\"](players[0] as DeadPlayer, game)).toStrictEqual(game);\n });\n\n it(\"should return game with all villagers powerless when elder takes his revenge.\", () => {\n const death = createFakePlayerDeathPotionByWitchDeath();\n const players = [\n createFakeElderAlivePlayer({ isAlive: false, death }),\n createFakeIdiotAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n createFakeSeerAlivePlayer({ isAlive: false }),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ elder: createFakeElderGameOptions({ doesTakeHisRevenge: true }) }) });\n const game = createFakeGame({ players, options });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n players[0],\n createFakePlayer({ ...players[1], attributes: [createFakePowerlessByElderPlayerAttribute()] }),\n players[2],\n createFakePlayer({ ...players[3], attributes: [createFakePowerlessByElderPlayerAttribute()] }),\n createFakePlayer(players[4]),\n ],\n });\n\n expect(services.playerKiller[\"applyElderDeathOutcomes\"](players[0] as DeadPlayer, game)).toStrictEqual(expectedGame);\n });\n\n it(\"should return game as is when idiot was revealed before but doesn't die on elder death thanks to game options.\", () => {\n const death = createFakePlayerDeathPotionByWitchDeath();\n const players = [\n createFakeElderAlivePlayer({ isAlive: false, death }),\n createFakeIdiotAlivePlayer({ role: createFakePlayerRole({ isRevealed: true, current: \"idiot\", original: \"idiot\" }) }),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n createFakeSeerAlivePlayer({ isAlive: false }),\n ];\n const elderOptions = createFakeElderGameOptions({ doesTakeHisRevenge: false });\n const idiotOptions = createFakeIdiotGameOptions({ doesDieOnElderDeath: false });\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ elder: elderOptions, idiot: idiotOptions }) });\n const game = createFakeGame({ players, options });\n\n expect(services.playerKiller[\"applyElderDeathOutcomes\"](players[0] as DeadPlayer, game)).toStrictEqual(game);\n expect(mocks.playerKillerService.killPlayer).not.toHaveBeenCalled();\n });\n\n it(\"should return game with killed idiot when idiot was revealed before.\", () => {\n const death = createFakePlayerDeathPotionByWitchDeath();\n const players = [\n createFakeElderAlivePlayer({ isAlive: false, death }),\n createFakeIdiotAlivePlayer({ role: createFakePlayerRole({ isRevealed: true, current: \"idiot\", original: \"idiot\" }) }),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n createFakeSeerAlivePlayer({ isAlive: false }),\n ];\n const elderOptions = createFakeElderGameOptions({ doesTakeHisRevenge: false });\n const idiotOptions = createFakeIdiotGameOptions({ doesDieOnElderDeath: true });\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ elder: elderOptions, idiot: idiotOptions }) });\n const game = createFakeGame({ players, options });\n services.playerKiller[\"applyElderDeathOutcomes\"](players[0] as DeadPlayer, game);\n\n expect(mocks.playerKillerService.killPlayer).toHaveBeenCalledExactlyOnceWith(players[1], game, createFakePlayerReconsiderPardonBySurvivorsDeath());\n });\n });\n\n describe(\"applyHunterDeathOutcomes\", () => {\n it(\"should return game as is when killed player is not hunter.\", () => {\n const players = [\n createFakeIdiotAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(services.playerKiller[\"applyHunterDeathOutcomes\"](players[0], game)).toStrictEqual(game);\n });\n\n it(\"should return game as is when killed player powerless.\", () => {\n const players = [\n createFakeHunterAlivePlayer({ attributes: [createFakePowerlessByElderPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(services.playerKiller[\"applyHunterDeathOutcomes\"](players[0], game)).toStrictEqual(game);\n });\n\n it(\"should return game with upcoming hunter shoots play when called.\", () => {\n const players = [\n createFakeHunterAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const upcomingPlays = [createFakeGamePlayScapegoatBansVoting()];\n const game = createFakeGame({ players, upcomingPlays });\n const expectedGame = createFakeGame({\n ...game,\n upcomingPlays: [createFakeGamePlayHunterShoots(), ...upcomingPlays],\n });\n\n expect(services.playerKiller[\"applyHunterDeathOutcomes\"](players[0], game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"applyPlayerRoleDeathOutcomes\", () => {\n beforeEach(() => {\n mocks.playerKillerService.applyHunterDeathOutcomes = jest.spyOn(services.playerKiller as unknown as { applyHunterDeathOutcomes }, \"applyHunterDeathOutcomes\").mockImplementation();\n mocks.playerKillerService.applyElderDeathOutcomes = jest.spyOn(services.playerKiller as unknown as { applyElderDeathOutcomes }, \"applyElderDeathOutcomes\").mockImplementation();\n mocks.playerKillerService.applyScapegoatDeathOutcomes = jest.spyOn(services.playerKiller as unknown as { applyScapegoatDeathOutcomes }, \"applyScapegoatDeathOutcomes\").mockImplementation();\n mocks.playerKillerService.applyRustySwordKnightDeathOutcomes = jest.spyOn(services.playerKiller as unknown as { applyRustySwordKnightDeathOutcomes }, \"applyRustySwordKnightDeathOutcomes\").mockImplementation();\n });\n\n it(\"should return game as is without calling role method outcomes when killed player doesn't have the right role.\", () => {\n const death = createFakePlayerDeathPotionByWitchDeath();\n const players = [\n createFakeWerewolfAlivePlayer({ isAlive: false, death }),\n createFakeHunterAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(services.playerKiller[\"applyPlayerRoleDeathOutcomes\"](players[0] as DeadPlayer, game)).toStrictEqual(game);\n expect(mocks.playerKillerService.applyHunterDeathOutcomes).not.toHaveBeenCalled();\n expect(mocks.playerKillerService.applyElderDeathOutcomes).not.toHaveBeenCalled();\n expect(mocks.playerKillerService.applyScapegoatDeathOutcomes).not.toHaveBeenCalled();\n expect(mocks.playerKillerService.applyRustySwordKnightDeathOutcomes).not.toHaveBeenCalled();\n });\n\n it(\"should call killed hunter outcomes method when killed player is hunter.\", () => {\n const death = createFakePlayerDeathPotionByWitchDeath();\n const players = [\n createFakeHunterAlivePlayer({ isAlive: false, death }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n services.playerKiller[\"applyPlayerRoleDeathOutcomes\"](players[0] as DeadPlayer, game);\n\n expect(mocks.playerKillerService.applyHunterDeathOutcomes).toHaveBeenCalledExactlyOnceWith(players[0], game);\n expect(mocks.playerKillerService.applyElderDeathOutcomes).not.toHaveBeenCalled();\n expect(mocks.playerKillerService.applyScapegoatDeathOutcomes).not.toHaveBeenCalled();\n expect(mocks.playerKillerService.applyRustySwordKnightDeathOutcomes).not.toHaveBeenCalled();\n });\n\n it(\"should call killed elder outcomes method when killed player is elder.\", () => {\n const death = createFakePlayerDeathPotionByWitchDeath();\n const players = [\n createFakeElderAlivePlayer({ isAlive: false, death }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n services.playerKiller[\"applyPlayerRoleDeathOutcomes\"](players[0] as DeadPlayer, game);\n\n expect(mocks.playerKillerService.applyElderDeathOutcomes).toHaveBeenCalledExactlyOnceWith(players[0], game);\n expect(mocks.playerKillerService.applyHunterDeathOutcomes).not.toHaveBeenCalled();\n expect(mocks.playerKillerService.applyScapegoatDeathOutcomes).not.toHaveBeenCalled();\n expect(mocks.playerKillerService.applyRustySwordKnightDeathOutcomes).not.toHaveBeenCalled();\n });\n\n it(\"should call killed scapegoat outcomes method when killed player is scapegoat.\", () => {\n const death = createFakePlayerDeathPotionByWitchDeath();\n const players = [\n createFakeScapegoatAlivePlayer({ isAlive: false, death }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n services.playerKiller[\"applyPlayerRoleDeathOutcomes\"](players[0] as DeadPlayer, game);\n\n expect(mocks.playerKillerService.applyScapegoatDeathOutcomes).toHaveBeenCalledExactlyOnceWith(players[0], game);\n expect(mocks.playerKillerService.applyHunterDeathOutcomes).not.toHaveBeenCalled();\n expect(mocks.playerKillerService.applyElderDeathOutcomes).not.toHaveBeenCalled();\n expect(mocks.playerKillerService.applyRustySwordKnightDeathOutcomes).not.toHaveBeenCalled();\n });\n\n it(\"should call killed rusty sword knight outcomes method when killed player is rusty sword knight.\", () => {\n const death = createFakePlayerDeathPotionByWitchDeath();\n const players = [\n createFakeRustySwordKnightAlivePlayer({ isAlive: false, death }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n services.playerKiller[\"applyPlayerRoleDeathOutcomes\"](players[0] as DeadPlayer, game);\n\n expect(mocks.playerKillerService.applyRustySwordKnightDeathOutcomes).toHaveBeenCalledExactlyOnceWith(players[0], game);\n expect(mocks.playerKillerService.applyHunterDeathOutcomes).not.toHaveBeenCalled();\n expect(mocks.playerKillerService.applyElderDeathOutcomes).not.toHaveBeenCalled();\n expect(mocks.playerKillerService.applyScapegoatDeathOutcomes).not.toHaveBeenCalled();\n });\n });\n\n describe(\"killPlayer\", () => {\n beforeEach(() => {\n mocks.playerKillerService.removePlayerAttributesAfterDeath = jest.spyOn(services.playerKiller as unknown as { removePlayerAttributesAfterDeath }, \"removePlayerAttributesAfterDeath\").mockImplementation();\n mocks.playerKillerService.applyPlayerDeathOutcomes = jest.spyOn(services.playerKiller as unknown as { applyPlayerDeathOutcomes }, \"applyPlayerDeathOutcomes\").mockImplementation();\n mocks.unexpectedExceptionFactory.createCantFindPlayerWithIdUnexpectedException = jest.spyOn(UnexpectedExceptionFactory, \"createCantFindPlayerWithIdUnexpectedException\").mockImplementation();\n mocks.gameHelper.getPlayerWithIdOrThrow = jest.spyOn(GameHelper, \"getPlayerWithIdOrThrow\").mockImplementation();\n });\n\n it(\"should set player to dead with his death and add survivors bury dead bodies game play when not present in upcoming plays.\", () => {\n const players = [\n createFakeRustySwordKnightAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ areRevealedOnDeath: true }) });\n const game = createFakeGame({ players, options });\n const death = createFakePlayerDeathPotionByWitchDeath();\n const expectedKilledPlayer = createFakePlayer({ ...players[0], isAlive: false, death });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n expectedKilledPlayer,\n players[1],\n players[2],\n players[3],\n ],\n upcomingPlays: [createFakeGamePlaySurvivorsBuryDeadBodies()],\n });\n\n expect(services.playerKiller[\"killPlayer\"](players[0], game, death)).toStrictEqual(expectedGame);\n });\n\n it(\"should set player to dead with his death but doesn't add survivors bury dead bodies game play when present in upcoming plays.\", () => {\n const players = [\n createFakeRustySwordKnightAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeDefenderAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ areRevealedOnDeath: true }) });\n const game = createFakeGame({\n upcomingPlays: [\n createFakeGamePlaySheriffDelegates(),\n createFakeGamePlaySurvivorsBuryDeadBodies(),\n ],\n players,\n options,\n });\n const death = createFakePlayerDeathPotionByWitchDeath();\n const expectedKilledPlayer = createFakePlayer({ ...players[0], isAlive: false, death });\n const expectedGame = createFakeGame({\n ...game,\n players: [\n expectedKilledPlayer,\n players[1],\n players[2],\n players[3],\n ],\n });\n\n expect(services.playerKiller[\"killPlayer\"](players[0], game, death)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"getPlayerToKillOrRevealInGame\", () => {\n it(\"should throw error when player is already dead.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeSeerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const interpolations = { gameId: game._id.toString(), playerId: players[1]._id.toString() };\n const cantFindPlayerException = new UnexpectedException(\"getPlayerToKillOrRevealInGame\", UnexpectedExceptionReasons.CANT_FIND_PLAYER_WITH_ID_IN_GAME, interpolations);\n const playerIsDeadException = new UnexpectedException(\"getPlayerToKillOrRevealInGame\", UnexpectedExceptionReasons.PLAYER_IS_DEAD, interpolations);\n const expectedInterpolations = { gameId: game._id, playerId: players[1]._id };\n\n mocks.unexpectedExceptionFactory.createCantFindPlayerWithIdUnexpectedException.mockReturnValue(cantFindPlayerException);\n mocks.gameHelper.getPlayerWithIdOrThrow.mockReturnValue(players[1]);\n mocks.unexpectedExceptionFactory.createCantFindPlayerWithIdUnexpectedException.mockReturnValue(cantFindPlayerException);\n mocks.unexpectedExceptionFactory.createPlayerIsDeadUnexpectedException.mockReturnValue(playerIsDeadException);\n\n expect(() => services.playerKiller[\"getPlayerToKillOrRevealInGame\"](players[1]._id, game)).toThrow(playerIsDeadException);\n expect(mocks.unexpectedExceptionFactory.createCantFindPlayerWithIdUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"getPlayerToKillOrRevealInGame\", expectedInterpolations);\n expect(mocks.unexpectedExceptionFactory.createPlayerIsDeadUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"getPlayerToKillOrRevealInGame\", expectedInterpolations);\n });\n\n it(\"should get player to kill when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n mocks.gameHelper.getPlayerWithIdOrThrow.mockReturnValue(players[1]);\n\n expect(services.playerKiller[\"getPlayerToKillOrRevealInGame\"](players[1]._id, game)).toStrictEqual(players[1]);\n });\n });\n});" }, "tests/e2e/specs/modules/game/controllers/game.controller.e2e-spec.ts": { "tests": [ @@ -192538,7 +192540,7 @@ } } ], - "source": "import { DEFAULT_GAME_OPTIONS } from \"@/modules/game/constants/game-options/game-options.constants\";\nimport type { CreateGameFeedbackDto } from \"@/modules/game/dto/create-game-feedback/create-game-feedback.dto\";\nimport type { CreateGamePlayerDto } from \"@/modules/game/dto/create-game/create-game-player/create-game-player.dto\";\nimport type { CreateGameDto } from \"@/modules/game/dto/create-game/create-game.dto\";\nimport type { GetGameRandomCompositionDto } from \"@/modules/game/dto/get-game-random-composition/get-game-random-composition.dto\";\nimport type { MakeGamePlayDto } from \"@/modules/game/dto/make-game-play/make-game-play.dto\";\nimport type { GameAdditionalCard } from \"@/modules/game/schemas/game-additional-card/game-additional-card.schema\";\nimport type { GameEvent } from \"@/modules/game/schemas/game-event/game-event.schema\";\nimport type { GameFeedback } from \"@/modules/game/schemas/game-feedback/game-feedback.schema\";\nimport { GameHistoryRecord } from \"@/modules/game/schemas/game-history-record/game-history-record.schema\";\nimport type { GameOptions } from \"@/modules/game/schemas/game-options/game-options.schema\";\n\nimport type { GamePhase } from \"@/modules/game/schemas/game-phase/game-phase.schema\";\nimport type { GamePlay } from \"@/modules/game/schemas/game-play/game-play.schema\";\nimport { Game } from \"@/modules/game/schemas/game.schema\";\nimport type { Player } from \"@/modules/game/schemas/player/player.schema\";\nimport { ELIGIBLE_ACTOR_ADDITIONAL_CARDS_ROLE_NAMES, ELIGIBLE_THIEF_ADDITIONAL_CARDS_ROLE_NAMES } from \"@/modules/role/constants/role-set.constants\";\n\nimport { ApiSortOrder } from \"@/shared/api/enums/api.enums\";\nimport { toJSON } from \"@/shared/misc/helpers/object.helpers\";\nimport { faker } from \"@faker-js/faker\";\nimport type { BadRequestException, NotFoundException } from \"@nestjs/common\";\nimport { HttpStatus } from \"@nestjs/common\";\nimport { getModelToken } from \"@nestjs/mongoose\";\nimport type { NestFastifyApplication } from \"@nestjs/platform-fastify\";\nimport type { TestingModule } from \"@nestjs/testing\";\nimport { truncateAllCollections } from \"@tests/e2e/helpers/mongoose.helpers\";\nimport { initNestApp } from \"@tests/e2e/helpers/nest-app.helpers\";\nimport { createFakeCreateGameFeedbackDto } from \"@tests/factories/game/dto/create-game-feedback/create-game-feedback.dto.factory\";\nimport { createFakeCreateGameAdditionalCardDto } from \"@tests/factories/game/dto/create-game/create-game-additional-card/create-game-additional-card.dto.factory\";\nimport { createFakeGameOptionsDto } from \"@tests/factories/game/dto/create-game/create-game-options/create-game-options.dto.factory\";\nimport { bulkCreateFakeCreateGamePlayerDto, createFakeCreateGamePlayerDto } from \"@tests/factories/game/dto/create-game/create-game-player/create-game-player.dto.factory\";\nimport { createFakeCreateGameDto, createFakeCreateGameWithPlayersDto } from \"@tests/factories/game/dto/create-game/create-game.dto.factory\";\nimport { createFakeGetGameHistoryDto } from \"@tests/factories/game/dto/get-game-history/get-game-history.dto.factory\";\nimport { createFakeMakeGamePlayDto } from \"@tests/factories/game/dto/make-game-play/make-game-play.dto.factory\";\nimport { createFakeGameAdditionalCard } from \"@tests/factories/game/schemas/game-additional-card/game-additional-card.schema.factory\";\nimport { createFakeGameEvent } from \"@tests/factories/game/schemas/game-event/game-event.schema.factory\";\nimport { createFakeGameHistoryRecord, createFakeGameHistoryRecordPlay, createFakeGameHistoryRecordPlaySource } from \"@tests/factories/game/schemas/game-history-record/game-history-record.schema.factory\";\nimport { createFakeCompositionGameOptions } from \"@tests/factories/game/schemas/game-options/composition-game-options.schema.factory\";\nimport { createFakeGameOptions } from \"@tests/factories/game/schemas/game-options/game-options.schema.factory\";\nimport { createFakeVotesGameOptions } from \"@tests/factories/game/schemas/game-options/votes-game-options.schema.factory\";\n\nimport { createFakeGamePhase } from \"@tests/factories/game/schemas/game-phase/game-phase.schema.factory\";\nimport { createFakeGamePlaySourceInteraction } from \"@tests/factories/game/schemas/game-play/game-play-source/game-play-source-interaction/game-play-source-interaction.schema.factory\";\nimport { createFakeGamePlaySource } from \"@tests/factories/game/schemas/game-play/game-play-source/game-play-source.schema.factory\";\nimport { createFakeGamePlayCupidCharms, createFakeGamePlaySeerLooks, createFakeGamePlaySurvivorsVote, createFakeGamePlayThiefChoosesCard, createFakeGamePlayWerewolvesEat, createFakeGamePlayWhiteWerewolfEats, createFakeGamePlayWolfHoundChoosesSide } from \"@tests/factories/game/schemas/game-play/game-play.schema.factory\";\nimport { createFakeGame, createFakeGameWithCurrentPlay } from \"@tests/factories/game/schemas/game.schema.factory\";\nimport { createFakeSeenBySeerPlayerAttribute } from \"@tests/factories/game/schemas/player/player-attribute/player-attribute.schema.factory\";\nimport { createFakeSeerAlivePlayer, createFakeVillagerAlivePlayer, createFakeWerewolfAlivePlayer } from \"@tests/factories/game/schemas/player/player-with-role.schema.factory\";\nimport { createFakePlayer } from \"@tests/factories/game/schemas/player/player.schema.factory\";\nimport { createFakeObjectId } from \"@tests/factories/shared/mongoose/mongoose.factory\";\nimport { createObjectIdFromString } from \"@tests/helpers/mongoose/mongoose.helpers\";\nimport type { ExceptionResponse } from \"@tests/types/exception/exception.types\";\nimport type { Model, Types } from \"mongoose\";\nimport { stringify } from \"qs\";\n\ndescribe(\"Game Controller\", () => {\n let app: NestFastifyApplication;\n let testingModule: TestingModule;\n let models: {\n game: Model;\n gameHistoryRecord: Model;\n };\n\n beforeAll(async() => {\n const { app: server, module } = await initNestApp();\n app = server;\n testingModule = module;\n models = {\n game: testingModule.get>(getModelToken(Game.name)),\n gameHistoryRecord: testingModule.get>(getModelToken(GameHistoryRecord.name)),\n };\n });\n\n beforeEach(async() => {\n await truncateAllCollections(testingModule);\n });\n\n afterEach(async() => {\n await truncateAllCollections(testingModule);\n });\n\n afterAll(async() => {\n await app.close();\n });\n\n describe(\"GET /games\", () => {\n it(\"should get no games when no populate yet.\", async() => {\n const response = await app.inject({\n method: \"GET\",\n url: \"/games\",\n });\n\n expect(response.statusCode).toBe(HttpStatus.OK);\n expect(response.json()).toStrictEqual([]);\n });\n\n it(\"should get 3 games when 3 games were created.\", async() => {\n const games = [\n createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWolfHoundChoosesSide() }),\n createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWolfHoundChoosesSide() }),\n createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWolfHoundChoosesSide() }),\n ];\n await models.game.create(games);\n const response = await app.inject({\n method: \"GET\",\n url: \"/games\",\n });\n\n expect(response.statusCode).toBe(HttpStatus.OK);\n expect(response.json()).toHaveLength(3);\n });\n });\n\n describe(\"GET /games/random-composition\", () => {\n it.each<{\n test: string;\n query: Record;\n errorMessage: string;\n }>([\n {\n test: \"should not allow getting random game composition when there is not enough players.\",\n query: { players: undefined },\n errorMessage: \"players must contain at least 4 elements\",\n },\n {\n test: \"should not allow getting random game composition when there is not enough players.\",\n query: { players: [{ name: \"Antoine\" }] },\n errorMessage: \"players must contain at least 4 elements\",\n },\n {\n test: \"should not allow getting random game composition when the maximum of players is reached.\",\n query: { players: bulkCreateFakeCreateGamePlayerDto(45) },\n errorMessage: \"players must contain no more than 40 elements\",\n },\n {\n test: \"should not allow getting random game composition when one of the player name is too short.\",\n query: {\n players: [\n createFakeCreateGamePlayerDto({ name: \"\" }),\n createFakeCreateGamePlayerDto({ name: \"JB\" }),\n createFakeCreateGamePlayerDto({ name: \"Olivia\" }),\n createFakeCreateGamePlayerDto({ name: \"Thomas\" }),\n ],\n },\n errorMessage: \"players.0.name must be longer than or equal to 1 characters\",\n },\n {\n test: \"should not allow getting random game composition when one of the player name is too long.\",\n query: {\n players: [\n createFakeCreateGamePlayerDto({ name: faker.string.sample(31) }),\n createFakeCreateGamePlayerDto({ name: \"JB\" }),\n createFakeCreateGamePlayerDto({ name: \"Olivia\" }),\n createFakeCreateGamePlayerDto({ name: \"Thomas\" }),\n ],\n },\n errorMessage: \"players.0.name must be shorter than or equal to 30 characters\",\n },\n {\n test: \"should not allow getting random game composition when two players have the same name.\",\n query: {\n players: [\n createFakeCreateGamePlayerDto({ name: \"JB\" }),\n createFakeCreateGamePlayerDto({ name: \"JB\" }),\n ],\n },\n errorMessage: \"players.name must be unique\",\n },\n {\n test: \"should not allow getting random game composition when werewolf is in excluded roles\",\n query: {\n \"players\": bulkCreateFakeCreateGamePlayerDto(4),\n \"excluded-roles\": [\"werewolf\", \"seer\"],\n },\n errorMessage: \"excludedRoles should not contain villager, werewolf values\",\n },\n {\n test: \"should not allow getting random game composition when villager is in excluded roles.\",\n query: {\n players: bulkCreateFakeCreateGamePlayerDto(4),\n excludedRoles: [\"villager\", \"seer\"],\n },\n errorMessage: \"excludedRoles should not contain villager, werewolf values\",\n },\n {\n test: \"should not allow getting random game composition when there is twice the same excluded role.\",\n query: {\n players: bulkCreateFakeCreateGamePlayerDto(4),\n excludedRoles: [\"seer\", \"seer\"],\n },\n errorMessage: \"excluded roles must be unique\",\n },\n ])(\"$test\", async({\n query,\n errorMessage,\n }) => {\n const response = await app.inject({\n method: \"GET\",\n url: \"/games/random-composition\",\n query: stringify(query),\n });\n\n expect(response.statusCode).toBe(HttpStatus.BAD_REQUEST);\n expect(response.json().message).toContainEqual(errorMessage);\n });\n\n it(\"should get random composition when called.\", async() => {\n const query: Partial = {\n players: [\n createFakeCreateGamePlayerDto({ name: \"1\" }),\n createFakeCreateGamePlayerDto({ name: \"2\" }),\n createFakeCreateGamePlayerDto({ name: \"3\" }),\n createFakeCreateGamePlayerDto({ name: \"4\" }),\n createFakeCreateGamePlayerDto({ name: \"5\" }),\n createFakeCreateGamePlayerDto({ name: \"6\" }),\n createFakeCreateGamePlayerDto({ name: \"7\" }),\n createFakeCreateGamePlayerDto({ name: \"8\" }),\n createFakeCreateGamePlayerDto({ name: \"9\" }),\n createFakeCreateGamePlayerDto({ name: \"10\" }),\n createFakeCreateGamePlayerDto({ name: \"11\" }),\n createFakeCreateGamePlayerDto({ name: \"12\" }),\n createFakeCreateGamePlayerDto({ name: \"13\" }),\n createFakeCreateGamePlayerDto({ name: \"14\" }),\n createFakeCreateGamePlayerDto({ name: \"15\" }),\n createFakeCreateGamePlayerDto({ name: \"16\" }),\n createFakeCreateGamePlayerDto({ name: \"17\" }),\n createFakeCreateGamePlayerDto({ name: \"18\" }),\n createFakeCreateGamePlayerDto({ name: \"19\" }),\n createFakeCreateGamePlayerDto({ name: \"20\" }),\n createFakeCreateGamePlayerDto({ name: \"21\" }),\n createFakeCreateGamePlayerDto({ name: \"22\" }),\n createFakeCreateGamePlayerDto({ name: \"23\" }),\n createFakeCreateGamePlayerDto({ name: \"24\" }),\n createFakeCreateGamePlayerDto({ name: \"25\" }),\n createFakeCreateGamePlayerDto({ name: \"26\" }),\n createFakeCreateGamePlayerDto({ name: \"27\" }),\n createFakeCreateGamePlayerDto({ name: \"28\" }),\n createFakeCreateGamePlayerDto({ name: \"29\" }),\n createFakeCreateGamePlayerDto({ name: \"30\" }),\n createFakeCreateGamePlayerDto({ name: \"31\" }),\n createFakeCreateGamePlayerDto({ name: \"32\" }),\n createFakeCreateGamePlayerDto({ name: \"33\" }),\n createFakeCreateGamePlayerDto({ name: \"34\" }),\n createFakeCreateGamePlayerDto({ name: \"35\" }),\n createFakeCreateGamePlayerDto({ name: \"36\" }),\n createFakeCreateGamePlayerDto({ name: \"37\" }),\n createFakeCreateGamePlayerDto({ name: \"38\" }),\n createFakeCreateGamePlayerDto({ name: \"39\" }),\n createFakeCreateGamePlayerDto({ name: \"40\" }),\n ],\n arePowerfulVillagerRolesPrioritized: false,\n };\n const response = await app.inject({\n method: \"GET\",\n url: \"/games/random-composition\",\n query: stringify(query),\n });\n const players = response.json();\n\n expect(response.statusCode).toBe(HttpStatus.OK);\n expect(players).toSatisfyAll(({ role, side }) => role.current !== undefined && role.current === role.original &&\n side.current !== undefined && side.current === side.original);\n });\n });\n\n describe(\"GET /game/:id\", () => {\n it(\"should get a bad request error when id is not mongoId.\", async() => {\n const response = await app.inject({\n method: \"GET\",\n url: \"/games/123\",\n });\n\n expect(response.statusCode).toBe(HttpStatus.BAD_REQUEST);\n expect(response.json().message).toBe(\"Validation failed (Mongo ObjectId is expected)\");\n });\n\n it(\"should get a not found error when id doesn't exist in base.\", async() => {\n const unknownId = faker.database.mongodbObjectId();\n const response = await app.inject({\n method: \"GET\",\n url: `/games/${unknownId}`,\n });\n\n expect(response.statusCode).toBe(HttpStatus.NOT_FOUND);\n expect(response.json().message).toBe(`Game with id \"${unknownId}\" not found`);\n });\n\n it(\"should get a game when id exists in base.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWolfHoundChoosesSide() });\n await models.game.create(game);\n const response = await app.inject({\n method: \"GET\",\n url: `/games/${game._id.toString()}`,\n });\n\n expect(response.statusCode).toBe(HttpStatus.OK);\n expect(response.json()).toStrictEqual({\n ...toJSON(game) as Game,\n _id: expect.any(String) as Types.ObjectId,\n createdAt: expect.any(String) as Date,\n updatedAt: expect.any(String) as Date,\n });\n });\n });\n\n describe(\"POST /games\", () => {\n it.each<{\n test: string;\n payload: CreateGameDto;\n errorMessage: string;\n }>([\n {\n test: \"should not allow game creation when no players are provided.\",\n payload: createFakeCreateGameDto({}, { players: undefined }),\n errorMessage: \"players must be an array\",\n },\n {\n test: \"should not allow game creation when the minimum of players is not reached.\",\n payload: createFakeCreateGameDto({ players: bulkCreateFakeCreateGamePlayerDto(3) }),\n errorMessage: \"players must contain at least 4 elements\",\n },\n {\n test: \"should not allow game creation when the maximum of players is reached.\",\n payload: createFakeCreateGameDto({ players: bulkCreateFakeCreateGamePlayerDto(45) }),\n errorMessage: \"players must contain no more than 40 elements\",\n },\n {\n test: \"should not allow game creation when one of the player name is too short.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ name: \"\" }),\n createFakeCreateGamePlayerDto({ name: \"JB\" }),\n createFakeCreateGamePlayerDto({ name: \"Olivia\" }),\n createFakeCreateGamePlayerDto({ name: \"Thomas\" }),\n ],\n }),\n errorMessage: \"players.0.name must be longer than or equal to 1 characters\",\n },\n {\n test: \"should not allow game creation when one of the player name is too long.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ name: faker.string.sample(31) }),\n createFakeCreateGamePlayerDto({ name: \"JB\" }),\n createFakeCreateGamePlayerDto({ name: \"Olivia\" }),\n createFakeCreateGamePlayerDto({ name: \"Thomas\" }),\n ],\n }),\n errorMessage: \"players.0.name must be shorter than or equal to 30 characters\",\n },\n {\n test: \"should not allow game creation when two players have the same name.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ name: \"John\", role: { name: \"three-brothers\" } }),\n createFakeCreateGamePlayerDto({ name: \"John\" }),\n ],\n }),\n errorMessage: \"players.name must be unique\",\n },\n {\n test: \"should not allow game creation when there is only one brother in the same game.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"three-brothers\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"villager-villager\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"seer\" } }),\n ],\n }),\n errorMessage: \"players.role minimum occurrences in game must be reached. Please check `minInGame` property of roles\",\n },\n {\n test: \"should not allow game creation when there is two witches in the same game.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n ],\n }),\n errorMessage: \"players.role can't exceed role maximum occurrences in game. Please check `maxInGame` property of roles\",\n },\n {\n test: \"should not allow game creation when there is no villager in game's composition.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"white-werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n ],\n }),\n errorMessage: \"one of the players.role must have at least one role from `villagers` side\",\n },\n {\n test: \"should not allow game creation when there is no werewolf in game's composition.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"pied-piper\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"seer\" } }),\n ],\n }),\n errorMessage: \"one of the players.role must have at least one role from `werewolves` side\",\n },\n {\n test: \"should not allow game creation when one of the player position is lower than 0.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" }, position: -1 }),\n createFakeCreateGamePlayerDto({ role: { name: \"pied-piper\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"seer\" } }),\n ],\n }),\n errorMessage: \"players.0.position must not be less than 0\",\n },\n {\n test: \"should not allow game creation when one of the player position is not consistent faced to others.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" }, position: 0 }),\n createFakeCreateGamePlayerDto({ role: { name: \"pied-piper\" }, position: 1 }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" }, position: 2 }),\n createFakeCreateGamePlayerDto({ role: { name: \"seer\" }, position: 666 }),\n ],\n }),\n errorMessage: \"players.position must be all set or all undefined. Please check that every player has unique position, from 0 to players.length - 1\",\n },\n {\n test: \"should not allow game creation when thief is in the game but additional cards are not set.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"pied-piper\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"thief\" } }),\n ],\n }),\n errorMessage: \"additionalCards must be set if there is a player with one of the following roles : thief,actor\",\n },\n {\n test: \"should not allow game creation when thief is not in the game but additional cards are set.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"pied-piper\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" } }),\n ],\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"werewolf\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"werewolf\", recipient: \"thief\" }),\n ],\n }),\n errorMessage: \"additionalCards can't be set if there is no player with one of the following roles : thief,actor\",\n },\n {\n test: \"should not allow game creation when thief additional cards are more than the expected default limit.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"pied-piper\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"thief\" } }),\n ],\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"werewolf\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"werewolf\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"werewolf\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"werewolf\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"werewolf\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"werewolf\", recipient: \"thief\" }),\n ],\n }),\n errorMessage: \"additionalCards length for thief must be between 1 and 5\",\n },\n {\n test: \"should not allow game creation when one thief additional card is the thief himself.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"pied-piper\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"thief\" } }),\n ],\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"werewolf\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"thief\", recipient: \"thief\" }),\n ],\n }),\n errorMessage: `additionalCards.roleName for thief must be one of the following values: ${ELIGIBLE_THIEF_ADDITIONAL_CARDS_ROLE_NAMES.toString()}`,\n },\n {\n test: \"should not allow game creation when one thief additional card (thief role) is is not available for thief.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"pied-piper\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"thief\" } }),\n ],\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"werewolf\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"two-sisters\", recipient: \"thief\" }),\n ],\n }),\n errorMessage: `additionalCards.roleName for thief must be one of the following values: ${ELIGIBLE_THIEF_ADDITIONAL_CARDS_ROLE_NAMES.toString()}`,\n },\n {\n test: \"should not allow game creation when one thief additional card (two-sisters role) is is not available for thief.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"pied-piper\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"two-sisters\" } }),\n ],\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"werewolf\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"two-sisters\", recipient: \"thief\" }),\n ],\n }),\n errorMessage: `additionalCards.roleName for thief must be one of the following values: ${ELIGIBLE_THIEF_ADDITIONAL_CARDS_ROLE_NAMES.toString()}`,\n },\n {\n test: \"should not allow game creation when one thief additional card (three-brothers role) is is not available for thief.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"pied-piper\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"three-brothers\" } }),\n ],\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"werewolf\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"two-sisters\", recipient: \"thief\" }),\n ],\n }),\n errorMessage: `additionalCards.roleName for thief must be one of the following values: ${ELIGIBLE_THIEF_ADDITIONAL_CARDS_ROLE_NAMES.toString()}`,\n },\n {\n test: \"should not allow game creation when two thief additional role cards exceed the maximum occurrences in game possible.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"pied-piper\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"thief\" } }),\n ],\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"wolf-hound\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"wolf-hound\", recipient: \"thief\" }),\n ],\n }),\n errorMessage: \"additionalCards.roleName can't exceed role maximum occurrences in game. Please check `maxInGame` property of roles\",\n },\n {\n test: \"should not allow game creation when one thief additional role card exceeds the maximum occurrences in game possible because another player has it.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"pied-piper\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"thief\" } }),\n ],\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"witch\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"werewolf\", recipient: \"thief\" }),\n ],\n }),\n errorMessage: \"additionalCards.roleName can't exceed role maximum occurrences in game. Please check `maxInGame` property of roles\",\n },\n {\n test: \"should not allow game creation when prejudiced manipulator is in the game and one of the player's group is not set\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"prejudiced-manipulator\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"fox\" } }),\n ],\n }),\n errorMessage: \"each player must have a group if there is a player with role `prejudiced-manipulator`\",\n },\n {\n test: \"should not allow game creation when prejudiced manipulator is in the game and there is only one group among players\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" }, group: \"toto\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"prejudiced-manipulator\" }, group: \"toto\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" }, group: \"toto\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"fox\" }, group: \"toto\" }),\n ],\n }),\n errorMessage: \"there must be exactly two groups among players when `prejudiced-manipulator` in the game\",\n },\n {\n test: \"should not allow game creation when prejudiced manipulator is in the game and there are three groups among players\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" }, group: \"toto\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"prejudiced-manipulator\" }, group: \"tata\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" }, group: \"tutu\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"fox\" }, group: \"toto\" }),\n ],\n }),\n errorMessage: \"there must be exactly two groups among players when `prejudiced-manipulator` in the game\",\n },\n {\n test: \"should not allow game creation when prejudiced manipulator is in the game and one of the group name is too short\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" }, group: \"toto\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"prejudiced-manipulator\" }, group: \"\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" }, group: \"\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"fox\" }, group: \"toto\" }),\n ],\n }),\n errorMessage: \"players.1.group must be longer than or equal to 1 characters\",\n },\n {\n test: \"should not allow game creation when prejudiced manipulator is in the game and one of the group name is too long\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" }, group: \"toto\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"prejudiced-manipulator\" }, group: \"I'm the longest name for a group that you ever seen\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" }, group: \"I'm the longest name for a group that you ever seen\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"fox\" }, group: \"toto\" }),\n ],\n }),\n errorMessage: \"players.2.group must be shorter than or equal to 30 characters\",\n },\n {\n test: \"should not allow game creation when prejudiced manipulator is not in the game and there groups among players\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" }, group: \"toto\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" }, group: \"tata\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" }, group: \"tutu\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"fox\" }, group: \"toto\" }),\n ],\n }),\n errorMessage: \"any player can't have a group if there is no player with role `prejudiced-manipulator`\",\n },\n {\n test: \"should not allow game creation when actor is in the game but additional cards are not set.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"pied-piper\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"actor\" } }),\n ],\n }),\n errorMessage: \"additionalCards must be set if there is a player with one of the following roles : thief,actor\",\n },\n {\n test: \"should not allow game creation when actor is not in the game but additional cards are set.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"pied-piper\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" } }),\n ],\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"werewolf\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"werewolf\", recipient: \"actor\" }),\n ],\n }),\n errorMessage: \"additionalCards can't be set if there is no player with one of the following roles : thief,actor\",\n },\n {\n test: \"should not allow game creation when actor additional cards are more than the expected default limit.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"pied-piper\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"actor\" } }),\n ],\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"werewolf\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"werewolf\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"werewolf\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"werewolf\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"werewolf\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"werewolf\", recipient: \"actor\" }),\n ],\n }),\n errorMessage: \"additionalCards length for actor must be between 1 and 5\",\n },\n {\n test: \"should not allow game creation when actor additional cards are more than the expected.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"pied-piper\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"actor\" } }),\n ],\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"seer\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"hunter\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"idiot\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"elder\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"little-girl\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"defender\", recipient: \"actor\" }),\n ],\n }),\n errorMessage: \"additionalCards length for actor must be between 1 and 5\",\n },\n {\n test: \"should not allow game creation when one actor additional card (werewolf role) is is not available for actor.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"pied-piper\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"actor\" } }),\n ],\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"seer\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"idiot\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"werewolf\", recipient: \"actor\" }),\n ],\n }),\n errorMessage: `additionalCards.roleName for actor must be one of the following values: ${ELIGIBLE_ACTOR_ADDITIONAL_CARDS_ROLE_NAMES.toString()}`,\n },\n {\n test: \"should not allow game creation when one actor additional card (big-bad-wolf role) is is not available for actor.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"pied-piper\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"actor\" } }),\n ],\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"seer\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"idiot\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"big-bad-wolf\", recipient: \"actor\" }),\n ],\n }),\n errorMessage: `additionalCards.roleName for actor must be one of the following values: ${ELIGIBLE_ACTOR_ADDITIONAL_CARDS_ROLE_NAMES.toString()}`,\n },\n {\n test: \"should not allow game creation when one actor additional card (two-sisters role) is is not available for actor.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"pied-piper\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"actor\" } }),\n ],\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"seer\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"idiot\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"two-sisters\", recipient: \"actor\" }),\n ],\n }),\n errorMessage: `additionalCards.roleName for actor must be one of the following values: ${ELIGIBLE_ACTOR_ADDITIONAL_CARDS_ROLE_NAMES.toString()}`,\n },\n {\n test: \"should not allow game creation when one actor additional card (actor role) is is not available for actor.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"pied-piper\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"actor\" } }),\n ],\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"seer\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"idiot\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"actor\", recipient: \"actor\" }),\n ],\n }),\n errorMessage: `additionalCards.roleName for actor must be one of the following values: ${ELIGIBLE_ACTOR_ADDITIONAL_CARDS_ROLE_NAMES.toString()}`,\n },\n {\n test: \"should not allow game creation when one actor additional role card exceeds the maximum occurrences in game possible because another player has it.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"pied-piper\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"actor\" } }),\n ],\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"witch\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"seer\", recipient: \"actor\" }),\n ],\n }),\n errorMessage: \"additionalCards.roleName can't exceed role maximum occurrences in game. Please check `maxInGame` property of roles\",\n },\n ])(\"$test\", async({\n payload,\n errorMessage,\n }) => {\n const response = await app.inject({\n method: \"POST\",\n url: \"/games\",\n payload,\n });\n\n expect(response.statusCode).toBe(HttpStatus.BAD_REQUEST);\n expect(response.json().message).toContainEqual(errorMessage);\n });\n\n it(`should create game when called.`, async() => {\n const payload = createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" }, name: \"Antoine\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" }, name: \"Mathis\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"villager-villager\" }, name: \"Virgil\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"white-werewolf\" }, name: \"JB\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"cupid\" }, name: \"Doudou\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"seer\" }, name: \"Juju\" }),\n ],\n }, { options: undefined });\n const response = await app.inject({\n method: \"POST\",\n url: \"/games\",\n payload,\n });\n const expectedPlayers = payload.players.map((player, index) => ({\n _id: expect.any(String) as Types.ObjectId,\n name: player.name,\n role: {\n current: player.role.name,\n original: player.role.name,\n isRevealed: player.role.name === \"villager-villager\",\n },\n side: {\n current: [\"villager\", \"villager-villager\", \"cupid\", \"seer\"].includes(player.role.name) ? \"villagers\" : \"werewolves\",\n original: [\"villager\", \"villager-villager\", \"cupid\", \"seer\"].includes(player.role.name) ? \"villagers\" : \"werewolves\",\n },\n attributes: [],\n position: index,\n isAlive: true,\n }));\n const expectedCurrentPlay: GamePlay = {\n type: \"vote\",\n action: \"elect-sheriff\",\n source: {\n name: \"survivors\",\n players: expectedPlayers,\n interactions: [\n {\n source: \"survivors\",\n type: \"choose-as-sheriff\",\n eligibleTargets: expectedPlayers,\n boundaries: { min: 1, max: 6 },\n },\n ],\n },\n occurrence: \"anytime\",\n canBeSkipped: false,\n };\n const expectedGame: Game = {\n _id: expect.any(String) as Types.ObjectId,\n phase: toJSON(createFakeGamePhase({ name: \"twilight\", tick: 1 })) as GamePhase,\n status: \"playing\",\n turn: 1,\n tick: 1,\n players: expectedPlayers,\n currentPlay: expectedCurrentPlay,\n upcomingPlays: toJSON([\n createFakeGamePlayCupidCharms(),\n createFakeGamePlaySeerLooks(),\n createFakeGamePlayWerewolvesEat(),\n createFakeGamePlayWhiteWerewolfEats(),\n ]) as GamePlay[],\n events: expect.any(Array) as GameEvent[],\n options: DEFAULT_GAME_OPTIONS,\n lastGameHistoryRecord: null,\n feedback: null,\n createdAt: expect.any(String) as Date,\n updatedAt: expect.any(String) as Date,\n };\n\n expect(response.statusCode).toBe(HttpStatus.CREATED);\n expect(response.json()).toStrictEqual(expectedGame);\n });\n\n it(`should create game with additional cards when thief is in the game.`, async() => {\n const payload = createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"thief\" }, name: \"Antoine\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" }, name: \"Mathis\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"villager-villager\" }, name: \"Virgil\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"white-werewolf\" }, name: \"JB\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"cupid\" }, name: \"Doudou\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"seer\" }, name: \"Juju\" }),\n ],\n additionalCards: [\n createFakeGameAdditionalCard({ roleName: \"werewolf\", recipient: \"thief\" }),\n createFakeGameAdditionalCard({ roleName: \"accursed-wolf-father\", recipient: \"thief\" }),\n ],\n }, { options: undefined });\n const expectedPlayers = payload.players.map((player, index) => ({\n _id: expect.any(String) as Types.ObjectId,\n name: player.name,\n role: {\n current: player.role.name,\n original: player.role.name,\n isRevealed: player.role.name === \"villager-villager\",\n },\n side: {\n current: [\"villager\", \"villager-villager\", \"cupid\", \"seer\", \"thief\"].includes(player.role.name) ? \"villagers\" : \"werewolves\",\n original: [\"villager\", \"villager-villager\", \"cupid\", \"seer\", \"thief\"].includes(player.role.name) ? \"villagers\" : \"werewolves\",\n },\n attributes: [],\n position: index,\n isAlive: true,\n }));\n const expectedGameAdditionalCards = payload.additionalCards?.map(additionalCard => ({\n _id: expect.any(String) as Types.ObjectId,\n roleName: additionalCard.roleName,\n recipient: additionalCard.recipient,\n isUsed: false,\n }));\n const expectedCurrentPlay: GamePlay = {\n type: \"vote\",\n action: \"elect-sheriff\",\n source: {\n name: \"survivors\",\n players: expectedPlayers,\n interactions: [\n {\n source: \"survivors\",\n type: \"choose-as-sheriff\",\n eligibleTargets: expectedPlayers,\n boundaries: { min: 1, max: 6 },\n },\n ],\n },\n occurrence: \"anytime\",\n canBeSkipped: false,\n };\n const expectedGame: Game = {\n _id: expect.any(String) as Types.ObjectId,\n phase: toJSON(createFakeGamePhase({ name: \"twilight\", tick: 1 })) as GamePhase,\n status: \"playing\",\n turn: 1,\n tick: 1,\n players: expectedPlayers,\n currentPlay: expectedCurrentPlay,\n upcomingPlays: toJSON([\n createFakeGamePlayThiefChoosesCard(),\n createFakeGamePlayCupidCharms(),\n createFakeGamePlaySeerLooks(),\n createFakeGamePlayWerewolvesEat(),\n createFakeGamePlayWhiteWerewolfEats(),\n ]) as GamePlay[],\n events: expect.any(Array) as GameEvent[],\n additionalCards: expectedGameAdditionalCards,\n options: DEFAULT_GAME_OPTIONS,\n lastGameHistoryRecord: null,\n feedback: null,\n createdAt: expect.any(String) as Date,\n updatedAt: expect.any(String) as Date,\n };\n const response = await app.inject({\n method: \"POST\",\n url: \"/games\",\n payload,\n });\n\n expect(response.statusCode).toBe(HttpStatus.CREATED);\n expect(response.json()).toStrictEqual(expectedGame);\n });\n\n it(`should create game with different options when called with options specified and some omitted.`, async() => {\n const options: Partial = {\n votes: {\n canBeSkipped: false,\n duration: 10,\n },\n roles: {\n areRevealedOnDeath: false,\n doSkipCallIfNoTarget: true,\n sheriff: {\n isEnabled: false,\n electedAt: {\n turn: 5,\n phaseName: \"day\",\n },\n hasDoubledVote: false,\n mustSettleTieInVotes: false,\n },\n werewolf: { canEatEachOther: true },\n bigBadWolf: { isPowerlessIfWerewolfDies: false },\n whiteWerewolf: { wakingUpInterval: 5 },\n seer: {\n isTalkative: false,\n canSeeRoles: false,\n },\n cupid: {\n lovers: { doRevealRoleToEachOther: true },\n mustWinWithLovers: true,\n },\n littleGirl: { isProtectedByDefender: true },\n defender: { canProtectTwice: true },\n elder: {\n livesCountAgainstWerewolves: 1,\n doesTakeHisRevenge: false,\n },\n idiot: { doesDieOnElderDeath: false },\n twoSisters: { wakingUpInterval: 0 },\n threeBrothers: { wakingUpInterval: 5 },\n fox: { isPowerlessIfMissesWerewolf: false },\n bearTamer: { doesGrowlOnWerewolvesSide: false },\n stutteringJudge: { voteRequestsCount: 3 },\n wildChild: { isTransformationRevealed: true },\n wolfHound: {\n isChosenSideRevealed: true,\n isSideRandomlyChosen: true,\n },\n thief: {\n mustChooseBetweenWerewolves: false,\n isChosenCardRevealed: true,\n },\n piedPiper: {\n charmedPeopleCountPerNight: 1,\n isPowerlessOnWerewolvesSide: false,\n areCharmedPeopleRevealed: true,\n },\n scandalmonger: { markPenalty: 5 },\n witch: { doesKnowWerewolvesTargets: false },\n prejudicedManipulator: { isPowerlessOnWerewolvesSide: false },\n actor: {\n isPowerlessOnWerewolvesSide: false,\n },\n },\n };\n const payload = createFakeCreateGameWithPlayersDto({}, { options });\n const expectedOptions = createFakeGameOptionsDto({\n ...options,\n composition: createFakeCompositionGameOptions({ isHidden: DEFAULT_GAME_OPTIONS.composition.isHidden }),\n });\n const response = await app.inject({\n method: \"POST\",\n url: \"/games\",\n payload,\n });\n\n expect(response.statusCode).toBe(HttpStatus.CREATED);\n expect(response.json().options).toStrictEqual(toJSON(expectedOptions) as GameOptions);\n });\n });\n\n describe(\"DELETE /game/:id\", () => {\n it(\"should get a bad request error when id is not mongoId.\", async() => {\n const response = await app.inject({\n method: \"DELETE\",\n url: \"/games/123\",\n });\n\n expect(response.statusCode).toBe(HttpStatus.BAD_REQUEST);\n expect(response.json().message).toBe(\"Validation failed (Mongo ObjectId is expected)\");\n });\n\n it(\"should get a not found error when id doesn't exist in base.\", async() => {\n const unknownId = faker.database.mongodbObjectId();\n const response = await app.inject({\n method: \"DELETE\",\n url: `/games/${unknownId}`,\n });\n\n expect(response.statusCode).toBe(HttpStatus.NOT_FOUND);\n expect(response.json().message).toBe(`Game with id \"${unknownId}\" not found`);\n });\n\n it(\"should get a bad request error when game doesn't have playing status.\", async() => {\n const game = createFakeGameWithCurrentPlay({ status: \"canceled\", currentPlay: createFakeGamePlayWolfHoundChoosesSide() });\n await models.game.create(game);\n const response = await app.inject({\n method: \"DELETE\",\n url: `/games/${game._id.toString()}`,\n });\n\n expect(response.statusCode).toBe(HttpStatus.BAD_REQUEST);\n expect(response.json()).toStrictEqual({\n statusCode: HttpStatus.BAD_REQUEST,\n message: `Bad mutation for Game with id \"${game._id.toString()}\"`,\n error: `Game doesn't have status with value \"playing\"`,\n });\n });\n\n it(\"should update game status to canceled when called.\", async() => {\n const game = createFakeGameWithCurrentPlay({ status: \"playing\", currentPlay: createFakeGamePlayWolfHoundChoosesSide() });\n await models.game.create(game);\n const response = await app.inject({\n method: \"DELETE\",\n url: `/games/${game._id.toString()}`,\n });\n\n expect(response.statusCode).toBe(HttpStatus.OK);\n expect(response.json()).toStrictEqual({\n ...toJSON(game) as Game,\n status: \"canceled\",\n createdAt: expect.any(String) as Date,\n updatedAt: expect.any(String) as Date,\n });\n });\n });\n\n describe(\"POST /game/:id/play\", () => {\n it(\"should not allow game play when game id is not a mongo id.\", async() => {\n const response = await app.inject({\n method: \"POST\",\n url: `/games/123/play`,\n });\n\n expect(response.statusCode).toBe(HttpStatus.BAD_REQUEST);\n expect(response.json().message).toBe(\"Validation failed (Mongo ObjectId is expected)\");\n });\n\n it.each<{\n test: string;\n payload: MakeGamePlayDto;\n errorMessage: string;\n }>([\n {\n test: \"should not allow game play when player ids in targets must be unique.\",\n payload: createFakeMakeGamePlayDto({ targets: [{ playerId: createObjectIdFromString(\"507f1f77bcf86cd799439011\") }, { playerId: createObjectIdFromString(\"507f1f77bcf86cd799439011\") }] }),\n errorMessage: \"targets.playerId must be unique\",\n },\n {\n test: \"should not allow game play when player ids in targets must be unique.\",\n payload: createFakeMakeGamePlayDto({\n votes: [\n { sourceId: createObjectIdFromString(\"507f1f77bcf86cd799439011\"), targetId: createObjectIdFromString(\"507f1f77bcf86cd799439012\") },\n { sourceId: createObjectIdFromString(\"507f1f77bcf86cd799439011\"), targetId: createObjectIdFromString(\"507f1f77bcf86cd799439012\") },\n ],\n }),\n errorMessage: \"votes.sourceId must be unique\",\n },\n ])(\"$test\", async({\n payload,\n errorMessage,\n }) => {\n const response = await app.inject({\n method: \"POST\",\n url: `/games/${faker.database.mongodbObjectId()}/play`,\n payload,\n });\n\n expect(response.statusCode).toBe(HttpStatus.BAD_REQUEST);\n expect(response.json().message).toContainEqual(errorMessage);\n });\n\n it(\"should not allow game play when game id not found.\", async() => {\n const unknownId = faker.database.mongodbObjectId();\n const response = await app.inject({\n method: \"POST\",\n url: `/games/${unknownId}/play`,\n });\n\n expect(response.statusCode).toBe(HttpStatus.NOT_FOUND);\n expect(response.json().message).toBe(`Game with id \"${unknownId}\" not found`);\n });\n\n it(\"should not allow game play when payload contains unknown resources id.\", async() => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({\n status: \"playing\",\n currentPlay: createFakeGamePlayWolfHoundChoosesSide(),\n upcomingPlays: [createFakeGamePlaySurvivorsVote()],\n players,\n });\n await models.game.create(game);\n const unknownPlayerId = faker.database.mongodbObjectId();\n const payload = createFakeMakeGamePlayDto({ targets: [{ playerId: createObjectIdFromString(unknownPlayerId) }] });\n const response = await app.inject({\n method: \"POST\",\n url: `/games/${game._id.toString()}/play`,\n payload,\n });\n\n expect(response.statusCode).toBe(HttpStatus.NOT_FOUND);\n expect(response.json()).toStrictEqual({\n statusCode: HttpStatus.NOT_FOUND,\n message: `Player with id \"${unknownPlayerId.toString()}\" not found`,\n error: \"Game Play - Player in `targets.player` is not in the game players\",\n });\n });\n\n it(\"should not allow game play when payload is not valid.\", async() => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const options = createFakeGameOptions({ votes: createFakeVotesGameOptions({ canBeSkipped: false }) });\n const game = createFakeGame({\n status: \"playing\",\n currentPlay: createFakeGamePlaySurvivorsVote({ canBeSkipped: false }),\n players,\n options,\n });\n await models.game.create(game);\n const payload = createFakeMakeGamePlayDto({});\n const response = await app.inject({\n method: \"POST\",\n url: `/games/${game._id.toString()}/play`,\n payload,\n });\n\n expect(response.statusCode).toBe(HttpStatus.BAD_REQUEST);\n expect(response.json()).toStrictEqual({\n statusCode: HttpStatus.BAD_REQUEST,\n message: `Bad game play payload`,\n error: \"`votes` is required on this current game's state\",\n });\n });\n\n it(\"should make a game play when called with votes.\", async() => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const options = createFakeGameOptions({ votes: createFakeVotesGameOptions({ canBeSkipped: false }) });\n const currentPlay = createFakeGamePlaySurvivorsVote({\n source: createFakeGamePlaySource({\n name: \"survivors\",\n players,\n interactions: [\n createFakeGamePlaySourceInteraction({\n source: \"survivors\",\n type: \"vote\",\n eligibleTargets: [players[0], players[1]],\n boundaries: { min: 1, max: 4 },\n }),\n ],\n }),\n });\n const game = createFakeGame({\n status: \"playing\",\n phase: createFakeGamePhase({ name: \"day\" }),\n currentPlay,\n upcomingPlays: [\n createFakeGamePlaySeerLooks(),\n createFakeGamePlayWerewolvesEat(),\n ],\n players,\n options,\n });\n await models.game.create(game);\n const payload = createFakeMakeGamePlayDto({\n votes: [\n { sourceId: players[0]._id, targetId: players[1]._id },\n { sourceId: players[1]._id, targetId: players[0]._id },\n ],\n });\n const expectedPhase = createFakeGamePhase({ ...game.phase, tick: game.phase.tick + 1 });\n const expectedCurrentPlay = createFakeGamePlaySurvivorsVote({\n causes: [\"previous-votes-were-in-ties\"],\n source: createFakeGamePlaySource({\n name: \"survivors\",\n players,\n interactions: [\n createFakeGamePlaySourceInteraction({\n source: \"survivors\",\n type: \"vote\",\n eligibleTargets: [players[1], players[0]],\n boundaries: { min: 1, max: 4 },\n }),\n ],\n }),\n canBeSkipped: false,\n });\n const expectedGameEvents = [\n createFakeGameEvent({\n type: \"game-turn-starts\",\n players,\n }),\n ];\n const expectedGame = createFakeGame({\n ...game,\n phase: expectedPhase,\n tick: game.tick + 1,\n currentPlay: expectedCurrentPlay,\n events: expectedGameEvents,\n });\n const response = await app.inject({\n method: \"POST\",\n url: `/games/${game._id.toString()}/play`,\n payload,\n });\n\n expect(response.statusCode).toBe(HttpStatus.OK);\n expect(response.json()).toStrictEqual({\n ...toJSON(expectedGame) as Game,\n lastGameHistoryRecord: expect.any(Object) as GameHistoryRecord,\n createdAt: expect.any(String) as Date,\n updatedAt: expect.any(String) as Date,\n });\n });\n\n it(\"should make a game play when called with targets.\", async() => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const currentPlay = createFakeGamePlaySeerLooks({\n source: createFakeGamePlaySource({\n name: \"seer\",\n players: [players[1]],\n interactions: [\n createFakeGamePlaySourceInteraction({\n source: \"seer\",\n type: \"look\",\n eligibleTargets: [players[0]],\n boundaries: { min: 1, max: 1 },\n }),\n ],\n }),\n });\n const game = createFakeGame({\n phase: createFakeGamePhase({ name: \"night\" }),\n status: \"playing\",\n currentPlay,\n upcomingPlays: [createFakeGamePlayWerewolvesEat()],\n players,\n options: DEFAULT_GAME_OPTIONS,\n });\n await models.game.create(game);\n const payload = createFakeMakeGamePlayDto({ targets: [{ playerId: players[0]._id }] });\n const seenPlayer = createFakePlayer({ ...players[0], attributes: [createFakeSeenBySeerPlayerAttribute()] });\n const expectedCurrentPlay = createFakeGamePlayWerewolvesEat({\n source: createFakeGamePlaySource({\n name: \"werewolves\",\n players: [seenPlayer, players[3]],\n interactions: [\n createFakeGamePlaySourceInteraction({\n source: \"werewolves\",\n type: \"eat\",\n eligibleTargets: [players[1], players[2]],\n boundaries: { min: 1, max: 1 },\n }),\n ],\n }),\n canBeSkipped: false,\n });\n const expectedGameEvents = [\n createFakeGameEvent({\n type: \"seer-has-seen\",\n players: [seenPlayer],\n }),\n createFakeGameEvent({\n type: \"game-turn-starts\",\n players: [seenPlayer, players[3]],\n }),\n ];\n\n const expectedGame = createFakeGame({\n ...game,\n tick: game.tick + 1,\n phase: createFakeGamePhase({ ...game.phase, tick: game.phase.tick + 1 }),\n currentPlay: expectedCurrentPlay,\n upcomingPlays: [],\n players: [\n seenPlayer,\n players[1],\n players[2],\n players[3],\n ],\n events: expectedGameEvents,\n options: DEFAULT_GAME_OPTIONS,\n });\n const response = await app.inject({\n method: \"POST\",\n url: `/games/${game._id.toString()}/play`,\n payload,\n });\n\n expect(response.statusCode).toBe(HttpStatus.OK);\n expect(response.json()).toStrictEqual({\n ...toJSON(expectedGame) as Game,\n lastGameHistoryRecord: expect.any(Object) as GameHistoryRecord,\n createdAt: expect.any(String) as Date,\n updatedAt: expect.any(String) as Date,\n });\n });\n });\n\n describe(\"GET /games/:id/history\", () => {\n it.each<{\n test: string;\n query: Record;\n errorMessage: string;\n }>([\n {\n test: \"should get bad request error on getting game history when limit is negative.\",\n query: { limit: -1 },\n errorMessage: \"limit must not be less than 0\",\n },\n {\n test: \"should get bad request error on getting game history when limit is not a number.\",\n query: { limit: \"lol\" },\n errorMessage: \"limit must be an integer number\",\n },\n {\n test: \"should get bad request error on getting game history when order is not asc nor desc.\",\n query: { order: \"unknown\" },\n errorMessage: \"order must be one of the following values: asc, desc\",\n },\n ])(\"$test\", async({\n query,\n errorMessage,\n }) => {\n const response = await app.inject({\n method: \"GET\",\n url: `/games/${faker.database.mongodbObjectId()}/history`,\n query: stringify(query),\n });\n\n expect(response.statusCode).toBe(HttpStatus.BAD_REQUEST);\n expect(response.json().message).toContainEqual(errorMessage);\n });\n\n it(\"should get a bad request error when id is not mongoId.\", async() => {\n const response = await app.inject({\n method: \"GET\",\n url: \"/games/123/history\",\n });\n\n expect(response.statusCode).toBe(HttpStatus.BAD_REQUEST);\n expect(response.json().message).toBe(\"Validation failed (Mongo ObjectId is expected)\");\n });\n\n it(\"should get a not found error when id doesn't exist in base.\", async() => {\n const unknownId = faker.database.mongodbObjectId();\n const response = await app.inject({\n method: \"GET\",\n url: `/games/${unknownId}/history`,\n });\n\n expect(response.statusCode).toBe(HttpStatus.NOT_FOUND);\n expect(response.json().message).toBe(`Game with id \"${unknownId}\" not found`);\n });\n\n it(\"should return no game history records when game doesn't have any.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWolfHoundChoosesSide() });\n const secondGame = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWolfHoundChoosesSide() });\n const gameHistoryRecordPlay = createFakeGameHistoryRecordPlay({ source: createFakeGameHistoryRecordPlaySource({ name: \"big-bad-wolf\" }) });\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ gameId: game._id, play: gameHistoryRecordPlay }),\n createFakeGameHistoryRecord({ gameId: game._id, play: gameHistoryRecordPlay }),\n createFakeGameHistoryRecord({ gameId: game._id, play: gameHistoryRecordPlay }),\n ];\n await models.game.insertMany([game, secondGame]);\n await models.gameHistoryRecord.insertMany(gameHistoryRecords);\n\n const response = await app.inject({\n method: \"GET\",\n url: `/games/${secondGame._id.toString()}/history`,\n });\n\n expect(response.statusCode).toBe(HttpStatus.OK);\n expect(response.json()).toStrictEqual([]);\n });\n\n it(\"should return 3 game history records when game have 3 records.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWolfHoundChoosesSide() });\n const secondGame = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWolfHoundChoosesSide() });\n const gameHistoryRecordPlay = createFakeGameHistoryRecordPlay({ source: createFakeGameHistoryRecordPlaySource({ name: \"big-bad-wolf\" }) });\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ gameId: game._id, play: gameHistoryRecordPlay, createdAt: new Date(\"2022-01-01\") }),\n createFakeGameHistoryRecord({ gameId: game._id, play: gameHistoryRecordPlay, createdAt: new Date(\"2023-01-01\") }),\n createFakeGameHistoryRecord({ gameId: game._id, play: gameHistoryRecordPlay, createdAt: new Date(\"2024-01-01\") }),\n ];\n await models.game.insertMany([game, secondGame]);\n await models.gameHistoryRecord.insertMany(gameHistoryRecords);\n\n const response = await app.inject({\n method: \"GET\",\n url: `/games/${game._id.toString()}/history`,\n });\n\n expect(response.statusCode).toBe(HttpStatus.OK);\n expect(response.json()).toStrictEqual([\n {\n ...toJSON(gameHistoryRecords[0]),\n createdAt: expect.any(String) as Date,\n },\n {\n ...toJSON(gameHistoryRecords[1]),\n createdAt: expect.any(String) as Date,\n },\n {\n ...toJSON(gameHistoryRecords[2]),\n createdAt: expect.any(String) as Date,\n },\n ] as GameHistoryRecord[]);\n });\n\n it(\"should return last recent game history record when limit is 1 and order is desc.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWolfHoundChoosesSide() });\n const getGameHistoryDto = createFakeGetGameHistoryDto({ limit: 1, order: ApiSortOrder.DESC });\n const secondGame = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWolfHoundChoosesSide() });\n const gameHistoryRecordPlay = createFakeGameHistoryRecordPlay({ source: createFakeGameHistoryRecordPlaySource({ name: \"big-bad-wolf\" }) });\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ gameId: game._id, play: gameHistoryRecordPlay, createdAt: new Date(\"2022-01-01\") }),\n createFakeGameHistoryRecord({ gameId: game._id, play: gameHistoryRecordPlay, createdAt: new Date(\"2023-01-01\") }),\n createFakeGameHistoryRecord({ gameId: game._id, play: gameHistoryRecordPlay, createdAt: new Date(\"2024-01-01\") }),\n ];\n await models.game.insertMany([game, secondGame]);\n await models.gameHistoryRecord.insertMany(gameHistoryRecords);\n\n const response = await app.inject({\n method: \"GET\",\n url: `/games/${game._id.toString()}/history`,\n query: stringify(getGameHistoryDto),\n });\n\n expect(response.statusCode).toBe(HttpStatus.OK);\n expect(response.json()).toStrictEqual([\n {\n ...toJSON(gameHistoryRecords[2]),\n createdAt: expect.any(String) as Date,\n },\n ] as GameHistoryRecord[]);\n });\n });\n\n describe(\"POST /games/:id/feedback\", () => {\n it.each<{\n test: string;\n gameId: string;\n payload: CreateGameFeedbackDto;\n errorMessage: string;\n }>([\n {\n test: \"should not allow game feedback creation when score is lower than 1.\",\n gameId: createFakeObjectId().toString(),\n payload: createFakeCreateGameFeedbackDto({ score: 0 }),\n errorMessage: \"score must not be less than 1\",\n },\n {\n test: \"should not allow game feedback creation when score is greater than 5.\",\n gameId: createFakeObjectId().toString(),\n payload: createFakeCreateGameFeedbackDto({ score: 6 }),\n errorMessage: \"score must not be greater than 5\",\n },\n {\n test: \"should not allow game feedback creation when score is not an integer.\",\n gameId: createFakeObjectId().toString(),\n payload: createFakeCreateGameFeedbackDto({ score: 4.5 }),\n errorMessage: \"score must be an integer number\",\n },\n {\n test: \"should not allow game feedback creation when review is longer than 1000 characters.\",\n gameId: createFakeObjectId().toString(),\n payload: createFakeCreateGameFeedbackDto({ review: faker.lorem.paragraphs(20) }),\n errorMessage: \"review must be shorter than or equal to 1000 characters\",\n },\n ])(\"$test\", async({\n gameId,\n payload,\n errorMessage,\n }) => {\n const response = await app.inject({\n method: \"POST\",\n url: `/games/${gameId}/feedback`,\n payload,\n });\n\n expect(response.statusCode).toBe(HttpStatus.BAD_REQUEST);\n expect(response.json().message).toContainEqual(errorMessage);\n });\n\n it(\"should not allow game feedback creation when game id is not mongoId.\", async() => {\n const response = await app.inject({\n method: \"POST\",\n url: \"/games/123/feedback\",\n payload: createFakeCreateGameFeedbackDto(),\n });\n\n expect(response.statusCode).toBe(HttpStatus.BAD_REQUEST);\n expect(response.json().message).toBe(\"Validation failed (Mongo ObjectId is expected)\");\n });\n\n it(\"should not allow game feedback creation when game id doesn't exist in base.\", async() => {\n const unknownId = faker.database.mongodbObjectId();\n const response = await app.inject({\n method: \"POST\",\n url: `/games/${unknownId}/feedback`,\n payload: createFakeCreateGameFeedbackDto(),\n });\n\n expect(response.statusCode).toBe(HttpStatus.NOT_FOUND);\n expect(response.json().message).toBe(`Game with id \"${unknownId}\" not found`);\n });\n\n it(\"should create game feedback when called.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWolfHoundChoosesSide() });\n await models.game.create(game);\n const payload = createFakeCreateGameFeedbackDto();\n const response = await app.inject({\n method: \"POST\",\n url: `/games/${game._id.toString()}/feedback`,\n payload,\n });\n\n expect(response.statusCode).toBe(HttpStatus.CREATED);\n expect(response.json()).toStrictEqual({\n ...toJSON(game) as Game,\n _id: expect.any(String) as Types.ObjectId,\n feedback: {\n ...toJSON(payload) as GameFeedback,\n _id: expect.any(String) as Types.ObjectId,\n gameId: game._id.toString() as unknown as Types.ObjectId,\n createdAt: expect.any(String) as Date,\n },\n createdAt: expect.any(String) as Date,\n updatedAt: expect.any(String) as Date,\n });\n });\n });\n});" + "source": "import { faker } from \"@faker-js/faker\";\nimport type { BadRequestException, NotFoundException } from \"@nestjs/common\";\nimport { HttpStatus } from \"@nestjs/common\";\nimport { getModelToken } from \"@nestjs/mongoose\";\nimport type { NestFastifyApplication } from \"@nestjs/platform-fastify\";\nimport type { TestingModule } from \"@nestjs/testing\";\nimport type { Model, Types } from \"mongoose\";\nimport { stringify } from \"qs\";\n\nimport { DEFAULT_GAME_OPTIONS } from \"@/modules/game/constants/game-options/game-options.constants\";\nimport type { CreateGameFeedbackDto } from \"@/modules/game/dto/create-game-feedback/create-game-feedback.dto\";\nimport type { CreateGamePlayerDto } from \"@/modules/game/dto/create-game/create-game-player/create-game-player.dto\";\nimport type { CreateGameDto } from \"@/modules/game/dto/create-game/create-game.dto\";\nimport type { GetGameRandomCompositionDto } from \"@/modules/game/dto/get-game-random-composition/get-game-random-composition.dto\";\nimport type { MakeGamePlayDto } from \"@/modules/game/dto/make-game-play/make-game-play.dto\";\nimport type { GameAdditionalCard } from \"@/modules/game/schemas/game-additional-card/game-additional-card.schema\";\nimport type { GameEvent } from \"@/modules/game/schemas/game-event/game-event.schema\";\nimport type { GameFeedback } from \"@/modules/game/schemas/game-feedback/game-feedback.schema\";\nimport { GameHistoryRecord } from \"@/modules/game/schemas/game-history-record/game-history-record.schema\";\nimport type { GameOptions } from \"@/modules/game/schemas/game-options/game-options.schema\";\nimport type { GamePhase } from \"@/modules/game/schemas/game-phase/game-phase.schema\";\nimport type { GamePlay } from \"@/modules/game/schemas/game-play/game-play.schema\";\nimport { Game } from \"@/modules/game/schemas/game.schema\";\nimport type { Player } from \"@/modules/game/schemas/player/player.schema\";\nimport { ELIGIBLE_ACTOR_ADDITIONAL_CARDS_ROLE_NAMES, ELIGIBLE_THIEF_ADDITIONAL_CARDS_ROLE_NAMES } from \"@/modules/role/constants/role-set.constants\";\n\nimport { ApiSortOrder } from \"@/shared/api/enums/api.enums\";\nimport { toJSON } from \"@/shared/misc/helpers/object.helpers\";\n\nimport { truncateAllCollections } from \"@tests/e2e/helpers/mongoose.helpers\";\nimport { initNestApp } from \"@tests/e2e/helpers/nest-app.helpers\";\nimport { createFakeCreateGameFeedbackDto } from \"@tests/factories/game/dto/create-game-feedback/create-game-feedback.dto.factory\";\nimport { createFakeCreateGameAdditionalCardDto } from \"@tests/factories/game/dto/create-game/create-game-additional-card/create-game-additional-card.dto.factory\";\nimport { createFakeGameOptionsDto } from \"@tests/factories/game/dto/create-game/create-game-options/create-game-options.dto.factory\";\nimport { bulkCreateFakeCreateGamePlayerDto, createFakeCreateGamePlayerDto } from \"@tests/factories/game/dto/create-game/create-game-player/create-game-player.dto.factory\";\nimport { createFakeCreateGameDto, createFakeCreateGameWithPlayersDto } from \"@tests/factories/game/dto/create-game/create-game.dto.factory\";\nimport { createFakeGetGameHistoryDto } from \"@tests/factories/game/dto/get-game-history/get-game-history.dto.factory\";\nimport { createFakeMakeGamePlayDto } from \"@tests/factories/game/dto/make-game-play/make-game-play.dto.factory\";\nimport { createFakeGameAdditionalCard } from \"@tests/factories/game/schemas/game-additional-card/game-additional-card.schema.factory\";\nimport { createFakeGameEvent } from \"@tests/factories/game/schemas/game-event/game-event.schema.factory\";\nimport { createFakeGameHistoryRecord, createFakeGameHistoryRecordPlay, createFakeGameHistoryRecordPlaySource } from \"@tests/factories/game/schemas/game-history-record/game-history-record.schema.factory\";\nimport { createFakeCompositionGameOptions } from \"@tests/factories/game/schemas/game-options/composition-game-options.schema.factory\";\nimport { createFakeGameOptions } from \"@tests/factories/game/schemas/game-options/game-options.schema.factory\";\nimport { createFakeVotesGameOptions } from \"@tests/factories/game/schemas/game-options/votes-game-options.schema.factory\";\nimport { createFakeGamePhase } from \"@tests/factories/game/schemas/game-phase/game-phase.schema.factory\";\nimport { createFakeGamePlaySourceInteraction } from \"@tests/factories/game/schemas/game-play/game-play-source/game-play-source-interaction/game-play-source-interaction.schema.factory\";\nimport { createFakeGamePlaySource } from \"@tests/factories/game/schemas/game-play/game-play-source/game-play-source.schema.factory\";\nimport { createFakeGamePlayCupidCharms, createFakeGamePlaySeerLooks, createFakeGamePlaySurvivorsVote, createFakeGamePlayThiefChoosesCard, createFakeGamePlayWerewolvesEat, createFakeGamePlayWhiteWerewolfEats, createFakeGamePlayWolfHoundChoosesSide } from \"@tests/factories/game/schemas/game-play/game-play.schema.factory\";\nimport { createFakeGame, createFakeGameWithCurrentPlay } from \"@tests/factories/game/schemas/game.schema.factory\";\nimport { createFakeSeenBySeerPlayerAttribute } from \"@tests/factories/game/schemas/player/player-attribute/player-attribute.schema.factory\";\nimport { createFakeSeerAlivePlayer, createFakeVillagerAlivePlayer, createFakeWerewolfAlivePlayer } from \"@tests/factories/game/schemas/player/player-with-role.schema.factory\";\nimport { createFakePlayer } from \"@tests/factories/game/schemas/player/player.schema.factory\";\nimport { createFakeObjectId } from \"@tests/factories/shared/mongoose/mongoose.factory\";\nimport { createObjectIdFromString } from \"@tests/helpers/mongoose/mongoose.helpers\";\nimport type { ExceptionResponse } from \"@tests/types/exception/exception.types\";\n\ndescribe(\"Game Controller\", () => {\n let app: NestFastifyApplication;\n let testingModule: TestingModule;\n let models: {\n game: Model;\n gameHistoryRecord: Model;\n };\n\n beforeAll(async() => {\n const { app: server, module } = await initNestApp();\n app = server;\n testingModule = module;\n models = {\n game: testingModule.get>(getModelToken(Game.name)),\n gameHistoryRecord: testingModule.get>(getModelToken(GameHistoryRecord.name)),\n };\n });\n\n beforeEach(async() => {\n await truncateAllCollections(testingModule);\n });\n\n afterEach(async() => {\n await truncateAllCollections(testingModule);\n });\n\n afterAll(async() => {\n await app.close();\n });\n\n describe(\"GET /games\", () => {\n it(\"should get no games when no populate yet.\", async() => {\n const response = await app.inject({\n method: \"GET\",\n url: \"/games\",\n });\n\n expect(response.statusCode).toBe(HttpStatus.OK);\n expect(response.json()).toStrictEqual([]);\n });\n\n it(\"should get 3 games when 3 games were created.\", async() => {\n const games = [\n createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWolfHoundChoosesSide() }),\n createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWolfHoundChoosesSide() }),\n createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWolfHoundChoosesSide() }),\n ];\n await models.game.create(games);\n const response = await app.inject({\n method: \"GET\",\n url: \"/games\",\n });\n\n expect(response.statusCode).toBe(HttpStatus.OK);\n expect(response.json()).toHaveLength(3);\n });\n });\n\n describe(\"GET /games/random-composition\", () => {\n it.each<{\n test: string;\n query: Record;\n errorMessage: string;\n }>([\n {\n test: \"should not allow getting random game composition when there is not enough players.\",\n query: { players: undefined },\n errorMessage: \"players must contain at least 4 elements\",\n },\n {\n test: \"should not allow getting random game composition when there is not enough players.\",\n query: { players: [{ name: \"Antoine\" }] },\n errorMessage: \"players must contain at least 4 elements\",\n },\n {\n test: \"should not allow getting random game composition when the maximum of players is reached.\",\n query: { players: bulkCreateFakeCreateGamePlayerDto(45) },\n errorMessage: \"players must contain no more than 40 elements\",\n },\n {\n test: \"should not allow getting random game composition when one of the player name is too short.\",\n query: {\n players: [\n createFakeCreateGamePlayerDto({ name: \"\" }),\n createFakeCreateGamePlayerDto({ name: \"JB\" }),\n createFakeCreateGamePlayerDto({ name: \"Olivia\" }),\n createFakeCreateGamePlayerDto({ name: \"Thomas\" }),\n ],\n },\n errorMessage: \"players.0.name must be longer than or equal to 1 characters\",\n },\n {\n test: \"should not allow getting random game composition when one of the player name is too long.\",\n query: {\n players: [\n createFakeCreateGamePlayerDto({ name: faker.string.sample(31) }),\n createFakeCreateGamePlayerDto({ name: \"JB\" }),\n createFakeCreateGamePlayerDto({ name: \"Olivia\" }),\n createFakeCreateGamePlayerDto({ name: \"Thomas\" }),\n ],\n },\n errorMessage: \"players.0.name must be shorter than or equal to 30 characters\",\n },\n {\n test: \"should not allow getting random game composition when two players have the same name.\",\n query: {\n players: [\n createFakeCreateGamePlayerDto({ name: \"JB\" }),\n createFakeCreateGamePlayerDto({ name: \"JB\" }),\n ],\n },\n errorMessage: \"players.name must be unique\",\n },\n {\n test: \"should not allow getting random game composition when werewolf is in excluded roles\",\n query: {\n \"players\": bulkCreateFakeCreateGamePlayerDto(4),\n \"excluded-roles\": [\"werewolf\", \"seer\"],\n },\n errorMessage: \"excludedRoles should not contain villager, werewolf values\",\n },\n {\n test: \"should not allow getting random game composition when villager is in excluded roles.\",\n query: {\n players: bulkCreateFakeCreateGamePlayerDto(4),\n excludedRoles: [\"villager\", \"seer\"],\n },\n errorMessage: \"excludedRoles should not contain villager, werewolf values\",\n },\n {\n test: \"should not allow getting random game composition when there is twice the same excluded role.\",\n query: {\n players: bulkCreateFakeCreateGamePlayerDto(4),\n excludedRoles: [\"seer\", \"seer\"],\n },\n errorMessage: \"excluded roles must be unique\",\n },\n ])(\"$test\", async({\n query,\n errorMessage,\n }) => {\n const response = await app.inject({\n method: \"GET\",\n url: \"/games/random-composition\",\n query: stringify(query),\n });\n\n expect(response.statusCode).toBe(HttpStatus.BAD_REQUEST);\n expect(response.json().message).toContainEqual(errorMessage);\n });\n\n it(\"should get random composition when called.\", async() => {\n const query: Partial = {\n players: [\n createFakeCreateGamePlayerDto({ name: \"1\" }),\n createFakeCreateGamePlayerDto({ name: \"2\" }),\n createFakeCreateGamePlayerDto({ name: \"3\" }),\n createFakeCreateGamePlayerDto({ name: \"4\" }),\n createFakeCreateGamePlayerDto({ name: \"5\" }),\n createFakeCreateGamePlayerDto({ name: \"6\" }),\n createFakeCreateGamePlayerDto({ name: \"7\" }),\n createFakeCreateGamePlayerDto({ name: \"8\" }),\n createFakeCreateGamePlayerDto({ name: \"9\" }),\n createFakeCreateGamePlayerDto({ name: \"10\" }),\n createFakeCreateGamePlayerDto({ name: \"11\" }),\n createFakeCreateGamePlayerDto({ name: \"12\" }),\n createFakeCreateGamePlayerDto({ name: \"13\" }),\n createFakeCreateGamePlayerDto({ name: \"14\" }),\n createFakeCreateGamePlayerDto({ name: \"15\" }),\n createFakeCreateGamePlayerDto({ name: \"16\" }),\n createFakeCreateGamePlayerDto({ name: \"17\" }),\n createFakeCreateGamePlayerDto({ name: \"18\" }),\n createFakeCreateGamePlayerDto({ name: \"19\" }),\n createFakeCreateGamePlayerDto({ name: \"20\" }),\n createFakeCreateGamePlayerDto({ name: \"21\" }),\n createFakeCreateGamePlayerDto({ name: \"22\" }),\n createFakeCreateGamePlayerDto({ name: \"23\" }),\n createFakeCreateGamePlayerDto({ name: \"24\" }),\n createFakeCreateGamePlayerDto({ name: \"25\" }),\n createFakeCreateGamePlayerDto({ name: \"26\" }),\n createFakeCreateGamePlayerDto({ name: \"27\" }),\n createFakeCreateGamePlayerDto({ name: \"28\" }),\n createFakeCreateGamePlayerDto({ name: \"29\" }),\n createFakeCreateGamePlayerDto({ name: \"30\" }),\n createFakeCreateGamePlayerDto({ name: \"31\" }),\n createFakeCreateGamePlayerDto({ name: \"32\" }),\n createFakeCreateGamePlayerDto({ name: \"33\" }),\n createFakeCreateGamePlayerDto({ name: \"34\" }),\n createFakeCreateGamePlayerDto({ name: \"35\" }),\n createFakeCreateGamePlayerDto({ name: \"36\" }),\n createFakeCreateGamePlayerDto({ name: \"37\" }),\n createFakeCreateGamePlayerDto({ name: \"38\" }),\n createFakeCreateGamePlayerDto({ name: \"39\" }),\n createFakeCreateGamePlayerDto({ name: \"40\" }),\n ],\n arePowerfulVillagerRolesPrioritized: false,\n };\n const response = await app.inject({\n method: \"GET\",\n url: \"/games/random-composition\",\n query: stringify(query),\n });\n const players = response.json();\n\n expect(response.statusCode).toBe(HttpStatus.OK);\n expect(players).toSatisfyAll(({ role, side }) => role.current !== undefined && role.current === role.original &&\n side.current !== undefined && side.current === side.original);\n });\n });\n\n describe(\"GET /game/:id\", () => {\n it(\"should get a bad request error when id is not mongoId.\", async() => {\n const response = await app.inject({\n method: \"GET\",\n url: \"/games/123\",\n });\n\n expect(response.statusCode).toBe(HttpStatus.BAD_REQUEST);\n expect(response.json().message).toBe(\"Validation failed (Mongo ObjectId is expected)\");\n });\n\n it(\"should get a not found error when id doesn't exist in base.\", async() => {\n const unknownId = faker.database.mongodbObjectId();\n const response = await app.inject({\n method: \"GET\",\n url: `/games/${unknownId}`,\n });\n\n expect(response.statusCode).toBe(HttpStatus.NOT_FOUND);\n expect(response.json().message).toBe(`Game with id \"${unknownId}\" not found`);\n });\n\n it(\"should get a game when id exists in base.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWolfHoundChoosesSide() });\n await models.game.create(game);\n const response = await app.inject({\n method: \"GET\",\n url: `/games/${game._id.toString()}`,\n });\n\n expect(response.statusCode).toBe(HttpStatus.OK);\n expect(response.json()).toStrictEqual({\n ...toJSON(game) as Game,\n _id: expect.any(String) as Types.ObjectId,\n createdAt: expect.any(String) as Date,\n updatedAt: expect.any(String) as Date,\n });\n });\n });\n\n describe(\"POST /games\", () => {\n it.each<{\n test: string;\n payload: CreateGameDto;\n errorMessage: string;\n }>([\n {\n test: \"should not allow game creation when no players are provided.\",\n payload: createFakeCreateGameDto({}, { players: undefined }),\n errorMessage: \"players must be an array\",\n },\n {\n test: \"should not allow game creation when the minimum of players is not reached.\",\n payload: createFakeCreateGameDto({ players: bulkCreateFakeCreateGamePlayerDto(3) }),\n errorMessage: \"players must contain at least 4 elements\",\n },\n {\n test: \"should not allow game creation when the maximum of players is reached.\",\n payload: createFakeCreateGameDto({ players: bulkCreateFakeCreateGamePlayerDto(45) }),\n errorMessage: \"players must contain no more than 40 elements\",\n },\n {\n test: \"should not allow game creation when one of the player name is too short.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ name: \"\" }),\n createFakeCreateGamePlayerDto({ name: \"JB\" }),\n createFakeCreateGamePlayerDto({ name: \"Olivia\" }),\n createFakeCreateGamePlayerDto({ name: \"Thomas\" }),\n ],\n }),\n errorMessage: \"players.0.name must be longer than or equal to 1 characters\",\n },\n {\n test: \"should not allow game creation when one of the player name is too long.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ name: faker.string.sample(31) }),\n createFakeCreateGamePlayerDto({ name: \"JB\" }),\n createFakeCreateGamePlayerDto({ name: \"Olivia\" }),\n createFakeCreateGamePlayerDto({ name: \"Thomas\" }),\n ],\n }),\n errorMessage: \"players.0.name must be shorter than or equal to 30 characters\",\n },\n {\n test: \"should not allow game creation when two players have the same name.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ name: \"John\", role: { name: \"three-brothers\" } }),\n createFakeCreateGamePlayerDto({ name: \"John\" }),\n ],\n }),\n errorMessage: \"players.name must be unique\",\n },\n {\n test: \"should not allow game creation when there is only one brother in the same game.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"three-brothers\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"villager-villager\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"seer\" } }),\n ],\n }),\n errorMessage: \"players.role minimum occurrences in game must be reached. Please check `minInGame` property of roles\",\n },\n {\n test: \"should not allow game creation when there is two witches in the same game.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n ],\n }),\n errorMessage: \"players.role can't exceed role maximum occurrences in game. Please check `maxInGame` property of roles\",\n },\n {\n test: \"should not allow game creation when there is no villager in game's composition.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"white-werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n ],\n }),\n errorMessage: \"one of the players.role must have at least one role from `villagers` side\",\n },\n {\n test: \"should not allow game creation when there is no werewolf in game's composition.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"pied-piper\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"seer\" } }),\n ],\n }),\n errorMessage: \"one of the players.role must have at least one role from `werewolves` side\",\n },\n {\n test: \"should not allow game creation when one of the player position is lower than 0.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" }, position: -1 }),\n createFakeCreateGamePlayerDto({ role: { name: \"pied-piper\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"seer\" } }),\n ],\n }),\n errorMessage: \"players.0.position must not be less than 0\",\n },\n {\n test: \"should not allow game creation when one of the player position is not consistent faced to others.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" }, position: 0 }),\n createFakeCreateGamePlayerDto({ role: { name: \"pied-piper\" }, position: 1 }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" }, position: 2 }),\n createFakeCreateGamePlayerDto({ role: { name: \"seer\" }, position: 666 }),\n ],\n }),\n errorMessage: \"players.position must be all set or all undefined. Please check that every player has unique position, from 0 to players.length - 1\",\n },\n {\n test: \"should not allow game creation when thief is in the game but additional cards are not set.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"pied-piper\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"thief\" } }),\n ],\n }),\n errorMessage: \"additionalCards must be set if there is a player with one of the following roles : thief,actor\",\n },\n {\n test: \"should not allow game creation when thief is not in the game but additional cards are set.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"pied-piper\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" } }),\n ],\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"werewolf\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"werewolf\", recipient: \"thief\" }),\n ],\n }),\n errorMessage: \"additionalCards can't be set if there is no player with one of the following roles : thief,actor\",\n },\n {\n test: \"should not allow game creation when thief additional cards are more than the expected default limit.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"pied-piper\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"thief\" } }),\n ],\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"werewolf\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"werewolf\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"werewolf\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"werewolf\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"werewolf\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"werewolf\", recipient: \"thief\" }),\n ],\n }),\n errorMessage: \"additionalCards length for thief must be between 1 and 5\",\n },\n {\n test: \"should not allow game creation when one thief additional card is the thief himself.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"pied-piper\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"thief\" } }),\n ],\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"werewolf\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"thief\", recipient: \"thief\" }),\n ],\n }),\n errorMessage: `additionalCards.roleName for thief must be one of the following values: ${ELIGIBLE_THIEF_ADDITIONAL_CARDS_ROLE_NAMES.toString()}`,\n },\n {\n test: \"should not allow game creation when one thief additional card (thief role) is is not available for thief.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"pied-piper\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"thief\" } }),\n ],\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"werewolf\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"two-sisters\", recipient: \"thief\" }),\n ],\n }),\n errorMessage: `additionalCards.roleName for thief must be one of the following values: ${ELIGIBLE_THIEF_ADDITIONAL_CARDS_ROLE_NAMES.toString()}`,\n },\n {\n test: \"should not allow game creation when one thief additional card (two-sisters role) is is not available for thief.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"pied-piper\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"two-sisters\" } }),\n ],\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"werewolf\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"two-sisters\", recipient: \"thief\" }),\n ],\n }),\n errorMessage: `additionalCards.roleName for thief must be one of the following values: ${ELIGIBLE_THIEF_ADDITIONAL_CARDS_ROLE_NAMES.toString()}`,\n },\n {\n test: \"should not allow game creation when one thief additional card (three-brothers role) is is not available for thief.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"pied-piper\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"three-brothers\" } }),\n ],\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"werewolf\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"two-sisters\", recipient: \"thief\" }),\n ],\n }),\n errorMessage: `additionalCards.roleName for thief must be one of the following values: ${ELIGIBLE_THIEF_ADDITIONAL_CARDS_ROLE_NAMES.toString()}`,\n },\n {\n test: \"should not allow game creation when two thief additional role cards exceed the maximum occurrences in game possible.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"pied-piper\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"thief\" } }),\n ],\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"wolf-hound\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"wolf-hound\", recipient: \"thief\" }),\n ],\n }),\n errorMessage: \"additionalCards.roleName can't exceed role maximum occurrences in game. Please check `maxInGame` property of roles\",\n },\n {\n test: \"should not allow game creation when one thief additional role card exceeds the maximum occurrences in game possible because another player has it.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"pied-piper\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"thief\" } }),\n ],\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"witch\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"werewolf\", recipient: \"thief\" }),\n ],\n }),\n errorMessage: \"additionalCards.roleName can't exceed role maximum occurrences in game. Please check `maxInGame` property of roles\",\n },\n {\n test: \"should not allow game creation when prejudiced manipulator is in the game and one of the player's group is not set\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"prejudiced-manipulator\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"fox\" } }),\n ],\n }),\n errorMessage: \"each player must have a group if there is a player with role `prejudiced-manipulator`\",\n },\n {\n test: \"should not allow game creation when prejudiced manipulator is in the game and there is only one group among players\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" }, group: \"toto\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"prejudiced-manipulator\" }, group: \"toto\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" }, group: \"toto\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"fox\" }, group: \"toto\" }),\n ],\n }),\n errorMessage: \"there must be exactly two groups among players when `prejudiced-manipulator` in the game\",\n },\n {\n test: \"should not allow game creation when prejudiced manipulator is in the game and there are three groups among players\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" }, group: \"toto\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"prejudiced-manipulator\" }, group: \"tata\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" }, group: \"tutu\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"fox\" }, group: \"toto\" }),\n ],\n }),\n errorMessage: \"there must be exactly two groups among players when `prejudiced-manipulator` in the game\",\n },\n {\n test: \"should not allow game creation when prejudiced manipulator is in the game and one of the group name is too short\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" }, group: \"toto\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"prejudiced-manipulator\" }, group: \"\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" }, group: \"\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"fox\" }, group: \"toto\" }),\n ],\n }),\n errorMessage: \"players.1.group must be longer than or equal to 1 characters\",\n },\n {\n test: \"should not allow game creation when prejudiced manipulator is in the game and one of the group name is too long\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" }, group: \"toto\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"prejudiced-manipulator\" }, group: \"I'm the longest name for a group that you ever seen\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" }, group: \"I'm the longest name for a group that you ever seen\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"fox\" }, group: \"toto\" }),\n ],\n }),\n errorMessage: \"players.2.group must be shorter than or equal to 30 characters\",\n },\n {\n test: \"should not allow game creation when prejudiced manipulator is not in the game and there groups among players\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" }, group: \"toto\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" }, group: \"tata\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" }, group: \"tutu\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"fox\" }, group: \"toto\" }),\n ],\n }),\n errorMessage: \"any player can't have a group if there is no player with role `prejudiced-manipulator`\",\n },\n {\n test: \"should not allow game creation when actor is in the game but additional cards are not set.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"pied-piper\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"actor\" } }),\n ],\n }),\n errorMessage: \"additionalCards must be set if there is a player with one of the following roles : thief,actor\",\n },\n {\n test: \"should not allow game creation when actor is not in the game but additional cards are set.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"pied-piper\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" } }),\n ],\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"werewolf\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"werewolf\", recipient: \"actor\" }),\n ],\n }),\n errorMessage: \"additionalCards can't be set if there is no player with one of the following roles : thief,actor\",\n },\n {\n test: \"should not allow game creation when actor additional cards are more than the expected default limit.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"pied-piper\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"actor\" } }),\n ],\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"werewolf\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"werewolf\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"werewolf\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"werewolf\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"werewolf\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"werewolf\", recipient: \"actor\" }),\n ],\n }),\n errorMessage: \"additionalCards length for actor must be between 1 and 5\",\n },\n {\n test: \"should not allow game creation when actor additional cards are more than the expected.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"pied-piper\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"actor\" } }),\n ],\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"seer\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"hunter\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"idiot\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"elder\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"little-girl\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"defender\", recipient: \"actor\" }),\n ],\n }),\n errorMessage: \"additionalCards length for actor must be between 1 and 5\",\n },\n {\n test: \"should not allow game creation when one actor additional card (werewolf role) is is not available for actor.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"pied-piper\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"actor\" } }),\n ],\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"seer\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"idiot\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"werewolf\", recipient: \"actor\" }),\n ],\n }),\n errorMessage: `additionalCards.roleName for actor must be one of the following values: ${ELIGIBLE_ACTOR_ADDITIONAL_CARDS_ROLE_NAMES.toString()}`,\n },\n {\n test: \"should not allow game creation when one actor additional card (big-bad-wolf role) is is not available for actor.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"pied-piper\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"actor\" } }),\n ],\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"seer\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"idiot\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"big-bad-wolf\", recipient: \"actor\" }),\n ],\n }),\n errorMessage: `additionalCards.roleName for actor must be one of the following values: ${ELIGIBLE_ACTOR_ADDITIONAL_CARDS_ROLE_NAMES.toString()}`,\n },\n {\n test: \"should not allow game creation when one actor additional card (two-sisters role) is is not available for actor.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"pied-piper\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"actor\" } }),\n ],\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"seer\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"idiot\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"two-sisters\", recipient: \"actor\" }),\n ],\n }),\n errorMessage: `additionalCards.roleName for actor must be one of the following values: ${ELIGIBLE_ACTOR_ADDITIONAL_CARDS_ROLE_NAMES.toString()}`,\n },\n {\n test: \"should not allow game creation when one actor additional card (actor role) is is not available for actor.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"pied-piper\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"actor\" } }),\n ],\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"seer\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"idiot\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"actor\", recipient: \"actor\" }),\n ],\n }),\n errorMessage: `additionalCards.roleName for actor must be one of the following values: ${ELIGIBLE_ACTOR_ADDITIONAL_CARDS_ROLE_NAMES.toString()}`,\n },\n {\n test: \"should not allow game creation when one actor additional role card exceeds the maximum occurrences in game possible because another player has it.\",\n payload: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"pied-piper\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"actor\" } }),\n ],\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"witch\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"seer\", recipient: \"actor\" }),\n ],\n }),\n errorMessage: \"additionalCards.roleName can't exceed role maximum occurrences in game. Please check `maxInGame` property of roles\",\n },\n ])(\"$test\", async({\n payload,\n errorMessage,\n }) => {\n const response = await app.inject({\n method: \"POST\",\n url: \"/games\",\n payload,\n });\n\n expect(response.statusCode).toBe(HttpStatus.BAD_REQUEST);\n expect(response.json().message).toContainEqual(errorMessage);\n });\n\n it(`should create game when called.`, async() => {\n const payload = createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" }, name: \"Antoine\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" }, name: \"Mathis\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"villager-villager\" }, name: \"Virgil\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"white-werewolf\" }, name: \"JB\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"cupid\" }, name: \"Doudou\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"seer\" }, name: \"Juju\" }),\n ],\n }, { options: undefined });\n const response = await app.inject({\n method: \"POST\",\n url: \"/games\",\n payload,\n });\n const expectedPlayers = payload.players.map((player, index) => ({\n _id: expect.any(String) as Types.ObjectId,\n name: player.name,\n role: {\n current: player.role.name,\n original: player.role.name,\n isRevealed: player.role.name === \"villager-villager\",\n },\n side: {\n current: [\"villager\", \"villager-villager\", \"cupid\", \"seer\"].includes(player.role.name) ? \"villagers\" : \"werewolves\",\n original: [\"villager\", \"villager-villager\", \"cupid\", \"seer\"].includes(player.role.name) ? \"villagers\" : \"werewolves\",\n },\n attributes: [],\n position: index,\n isAlive: true,\n }));\n const expectedCurrentPlay: GamePlay = {\n type: \"vote\",\n action: \"elect-sheriff\",\n source: {\n name: \"survivors\",\n players: expectedPlayers,\n interactions: [\n {\n source: \"survivors\",\n type: \"choose-as-sheriff\",\n eligibleTargets: expectedPlayers,\n boundaries: { min: 1, max: 6 },\n },\n ],\n },\n occurrence: \"anytime\",\n canBeSkipped: false,\n };\n const expectedGame: Game = {\n _id: expect.any(String) as Types.ObjectId,\n phase: toJSON(createFakeGamePhase({ name: \"twilight\", tick: 1 })) as GamePhase,\n status: \"playing\",\n turn: 1,\n tick: 1,\n players: expectedPlayers,\n currentPlay: expectedCurrentPlay,\n upcomingPlays: toJSON([\n createFakeGamePlayCupidCharms(),\n createFakeGamePlaySeerLooks(),\n createFakeGamePlayWerewolvesEat(),\n createFakeGamePlayWhiteWerewolfEats(),\n ]) as GamePlay[],\n events: expect.any(Array) as GameEvent[],\n options: DEFAULT_GAME_OPTIONS,\n lastGameHistoryRecord: null,\n feedback: null,\n createdAt: expect.any(String) as Date,\n updatedAt: expect.any(String) as Date,\n };\n\n expect(response.statusCode).toBe(HttpStatus.CREATED);\n expect(response.json()).toStrictEqual(expectedGame);\n });\n\n it(`should create game with additional cards when thief is in the game.`, async() => {\n const payload = createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"thief\" }, name: \"Antoine\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" }, name: \"Mathis\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"villager-villager\" }, name: \"Virgil\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"white-werewolf\" }, name: \"JB\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"cupid\" }, name: \"Doudou\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"seer\" }, name: \"Juju\" }),\n ],\n additionalCards: [\n createFakeGameAdditionalCard({ roleName: \"werewolf\", recipient: \"thief\" }),\n createFakeGameAdditionalCard({ roleName: \"accursed-wolf-father\", recipient: \"thief\" }),\n ],\n }, { options: undefined });\n const expectedPlayers = payload.players.map((player, index) => ({\n _id: expect.any(String) as Types.ObjectId,\n name: player.name,\n role: {\n current: player.role.name,\n original: player.role.name,\n isRevealed: player.role.name === \"villager-villager\",\n },\n side: {\n current: [\"villager\", \"villager-villager\", \"cupid\", \"seer\", \"thief\"].includes(player.role.name) ? \"villagers\" : \"werewolves\",\n original: [\"villager\", \"villager-villager\", \"cupid\", \"seer\", \"thief\"].includes(player.role.name) ? \"villagers\" : \"werewolves\",\n },\n attributes: [],\n position: index,\n isAlive: true,\n }));\n const expectedGameAdditionalCards = payload.additionalCards?.map(additionalCard => ({\n _id: expect.any(String) as Types.ObjectId,\n roleName: additionalCard.roleName,\n recipient: additionalCard.recipient,\n isUsed: false,\n }));\n const expectedCurrentPlay: GamePlay = {\n type: \"vote\",\n action: \"elect-sheriff\",\n source: {\n name: \"survivors\",\n players: expectedPlayers,\n interactions: [\n {\n source: \"survivors\",\n type: \"choose-as-sheriff\",\n eligibleTargets: expectedPlayers,\n boundaries: { min: 1, max: 6 },\n },\n ],\n },\n occurrence: \"anytime\",\n canBeSkipped: false,\n };\n const expectedGame: Game = {\n _id: expect.any(String) as Types.ObjectId,\n phase: toJSON(createFakeGamePhase({ name: \"twilight\", tick: 1 })) as GamePhase,\n status: \"playing\",\n turn: 1,\n tick: 1,\n players: expectedPlayers,\n currentPlay: expectedCurrentPlay,\n upcomingPlays: toJSON([\n createFakeGamePlayThiefChoosesCard(),\n createFakeGamePlayCupidCharms(),\n createFakeGamePlaySeerLooks(),\n createFakeGamePlayWerewolvesEat(),\n createFakeGamePlayWhiteWerewolfEats(),\n ]) as GamePlay[],\n events: expect.any(Array) as GameEvent[],\n additionalCards: expectedGameAdditionalCards,\n options: DEFAULT_GAME_OPTIONS,\n lastGameHistoryRecord: null,\n feedback: null,\n createdAt: expect.any(String) as Date,\n updatedAt: expect.any(String) as Date,\n };\n const response = await app.inject({\n method: \"POST\",\n url: \"/games\",\n payload,\n });\n\n expect(response.statusCode).toBe(HttpStatus.CREATED);\n expect(response.json()).toStrictEqual(expectedGame);\n });\n\n it(`should create game with different options when called with options specified and some omitted.`, async() => {\n const options: Partial = {\n votes: {\n canBeSkipped: false,\n duration: 10,\n },\n roles: {\n areRevealedOnDeath: false,\n doSkipCallIfNoTarget: true,\n sheriff: {\n isEnabled: false,\n electedAt: {\n turn: 5,\n phaseName: \"day\",\n },\n hasDoubledVote: false,\n mustSettleTieInVotes: false,\n },\n werewolf: { canEatEachOther: true },\n bigBadWolf: { isPowerlessIfWerewolfDies: false },\n whiteWerewolf: { wakingUpInterval: 5 },\n seer: {\n isTalkative: false,\n canSeeRoles: false,\n },\n cupid: {\n lovers: { doRevealRoleToEachOther: true },\n mustWinWithLovers: true,\n },\n littleGirl: { isProtectedByDefender: true },\n defender: { canProtectTwice: true },\n elder: {\n livesCountAgainstWerewolves: 1,\n doesTakeHisRevenge: false,\n },\n idiot: { doesDieOnElderDeath: false },\n twoSisters: { wakingUpInterval: 0 },\n threeBrothers: { wakingUpInterval: 5 },\n fox: { isPowerlessIfMissesWerewolf: false },\n bearTamer: { doesGrowlOnWerewolvesSide: false },\n stutteringJudge: { voteRequestsCount: 3 },\n wildChild: { isTransformationRevealed: true },\n wolfHound: {\n isChosenSideRevealed: true,\n isSideRandomlyChosen: true,\n },\n thief: {\n mustChooseBetweenWerewolves: false,\n isChosenCardRevealed: true,\n },\n piedPiper: {\n charmedPeopleCountPerNight: 1,\n isPowerlessOnWerewolvesSide: false,\n areCharmedPeopleRevealed: true,\n },\n scandalmonger: { markPenalty: 5 },\n witch: { doesKnowWerewolvesTargets: false },\n prejudicedManipulator: { isPowerlessOnWerewolvesSide: false },\n actor: {\n isPowerlessOnWerewolvesSide: false,\n },\n },\n };\n const payload = createFakeCreateGameWithPlayersDto({}, { options });\n const expectedOptions = createFakeGameOptionsDto({\n ...options,\n composition: createFakeCompositionGameOptions({ isHidden: DEFAULT_GAME_OPTIONS.composition.isHidden }),\n });\n const response = await app.inject({\n method: \"POST\",\n url: \"/games\",\n payload,\n });\n\n expect(response.statusCode).toBe(HttpStatus.CREATED);\n expect(response.json().options).toStrictEqual(toJSON(expectedOptions) as GameOptions);\n });\n });\n\n describe(\"DELETE /game/:id\", () => {\n it(\"should get a bad request error when id is not mongoId.\", async() => {\n const response = await app.inject({\n method: \"DELETE\",\n url: \"/games/123\",\n });\n\n expect(response.statusCode).toBe(HttpStatus.BAD_REQUEST);\n expect(response.json().message).toBe(\"Validation failed (Mongo ObjectId is expected)\");\n });\n\n it(\"should get a not found error when id doesn't exist in base.\", async() => {\n const unknownId = faker.database.mongodbObjectId();\n const response = await app.inject({\n method: \"DELETE\",\n url: `/games/${unknownId}`,\n });\n\n expect(response.statusCode).toBe(HttpStatus.NOT_FOUND);\n expect(response.json().message).toBe(`Game with id \"${unknownId}\" not found`);\n });\n\n it(\"should get a bad request error when game doesn't have playing status.\", async() => {\n const game = createFakeGameWithCurrentPlay({ status: \"canceled\", currentPlay: createFakeGamePlayWolfHoundChoosesSide() });\n await models.game.create(game);\n const response = await app.inject({\n method: \"DELETE\",\n url: `/games/${game._id.toString()}`,\n });\n\n expect(response.statusCode).toBe(HttpStatus.BAD_REQUEST);\n expect(response.json()).toStrictEqual({\n statusCode: HttpStatus.BAD_REQUEST,\n message: `Bad mutation for Game with id \"${game._id.toString()}\"`,\n error: `Game doesn't have status with value \"playing\"`,\n });\n });\n\n it(\"should update game status to canceled when called.\", async() => {\n const game = createFakeGameWithCurrentPlay({ status: \"playing\", currentPlay: createFakeGamePlayWolfHoundChoosesSide() });\n await models.game.create(game);\n const response = await app.inject({\n method: \"DELETE\",\n url: `/games/${game._id.toString()}`,\n });\n\n expect(response.statusCode).toBe(HttpStatus.OK);\n expect(response.json()).toStrictEqual({\n ...toJSON(game) as Game,\n status: \"canceled\",\n createdAt: expect.any(String) as Date,\n updatedAt: expect.any(String) as Date,\n });\n });\n });\n\n describe(\"POST /game/:id/play\", () => {\n it(\"should not allow game play when game id is not a mongo id.\", async() => {\n const response = await app.inject({\n method: \"POST\",\n url: `/games/123/play`,\n });\n\n expect(response.statusCode).toBe(HttpStatus.BAD_REQUEST);\n expect(response.json().message).toBe(\"Validation failed (Mongo ObjectId is expected)\");\n });\n\n it.each<{\n test: string;\n payload: MakeGamePlayDto;\n errorMessage: string;\n }>([\n {\n test: \"should not allow game play when player ids in targets must be unique.\",\n payload: createFakeMakeGamePlayDto({ targets: [{ playerId: createObjectIdFromString(\"507f1f77bcf86cd799439011\") }, { playerId: createObjectIdFromString(\"507f1f77bcf86cd799439011\") }] }),\n errorMessage: \"targets.playerId must be unique\",\n },\n {\n test: \"should not allow game play when player ids in targets must be unique.\",\n payload: createFakeMakeGamePlayDto({\n votes: [\n { sourceId: createObjectIdFromString(\"507f1f77bcf86cd799439011\"), targetId: createObjectIdFromString(\"507f1f77bcf86cd799439012\") },\n { sourceId: createObjectIdFromString(\"507f1f77bcf86cd799439011\"), targetId: createObjectIdFromString(\"507f1f77bcf86cd799439012\") },\n ],\n }),\n errorMessage: \"votes.sourceId must be unique\",\n },\n ])(\"$test\", async({\n payload,\n errorMessage,\n }) => {\n const response = await app.inject({\n method: \"POST\",\n url: `/games/${faker.database.mongodbObjectId()}/play`,\n payload,\n });\n\n expect(response.statusCode).toBe(HttpStatus.BAD_REQUEST);\n expect(response.json().message).toContainEqual(errorMessage);\n });\n\n it(\"should not allow game play when game id not found.\", async() => {\n const unknownId = faker.database.mongodbObjectId();\n const response = await app.inject({\n method: \"POST\",\n url: `/games/${unknownId}/play`,\n });\n\n expect(response.statusCode).toBe(HttpStatus.NOT_FOUND);\n expect(response.json().message).toBe(`Game with id \"${unknownId}\" not found`);\n });\n\n it(\"should not allow game play when payload contains unknown resources id.\", async() => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({\n status: \"playing\",\n currentPlay: createFakeGamePlayWolfHoundChoosesSide(),\n upcomingPlays: [createFakeGamePlaySurvivorsVote()],\n players,\n });\n await models.game.create(game);\n const unknownPlayerId = faker.database.mongodbObjectId();\n const payload = createFakeMakeGamePlayDto({ targets: [{ playerId: createObjectIdFromString(unknownPlayerId) }] });\n const response = await app.inject({\n method: \"POST\",\n url: `/games/${game._id.toString()}/play`,\n payload,\n });\n\n expect(response.statusCode).toBe(HttpStatus.NOT_FOUND);\n expect(response.json()).toStrictEqual({\n statusCode: HttpStatus.NOT_FOUND,\n message: `Player with id \"${unknownPlayerId.toString()}\" not found`,\n error: \"Game Play - Player in `targets.player` is not in the game players\",\n });\n });\n\n it(\"should not allow game play when payload is not valid.\", async() => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const options = createFakeGameOptions({ votes: createFakeVotesGameOptions({ canBeSkipped: false }) });\n const game = createFakeGame({\n status: \"playing\",\n currentPlay: createFakeGamePlaySurvivorsVote({ canBeSkipped: false }),\n players,\n options,\n });\n await models.game.create(game);\n const payload = createFakeMakeGamePlayDto({});\n const response = await app.inject({\n method: \"POST\",\n url: `/games/${game._id.toString()}/play`,\n payload,\n });\n\n expect(response.statusCode).toBe(HttpStatus.BAD_REQUEST);\n expect(response.json()).toStrictEqual({\n statusCode: HttpStatus.BAD_REQUEST,\n message: `Bad game play payload`,\n error: \"`votes` is required on this current game's state\",\n });\n });\n\n it(\"should make a game play when called with votes.\", async() => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const options = createFakeGameOptions({ votes: createFakeVotesGameOptions({ canBeSkipped: false }) });\n const currentPlay = createFakeGamePlaySurvivorsVote({\n source: createFakeGamePlaySource({\n name: \"survivors\",\n players,\n interactions: [\n createFakeGamePlaySourceInteraction({\n source: \"survivors\",\n type: \"vote\",\n eligibleTargets: [players[0], players[1]],\n boundaries: { min: 1, max: 4 },\n }),\n ],\n }),\n });\n const game = createFakeGame({\n status: \"playing\",\n phase: createFakeGamePhase({ name: \"day\" }),\n currentPlay,\n upcomingPlays: [\n createFakeGamePlaySeerLooks(),\n createFakeGamePlayWerewolvesEat(),\n ],\n players,\n options,\n });\n await models.game.create(game);\n const payload = createFakeMakeGamePlayDto({\n votes: [\n { sourceId: players[0]._id, targetId: players[1]._id },\n { sourceId: players[1]._id, targetId: players[0]._id },\n ],\n });\n const expectedPhase = createFakeGamePhase({ ...game.phase, tick: game.phase.tick + 1 });\n const expectedCurrentPlay = createFakeGamePlaySurvivorsVote({\n causes: [\"previous-votes-were-in-ties\"],\n source: createFakeGamePlaySource({\n name: \"survivors\",\n players,\n interactions: [\n createFakeGamePlaySourceInteraction({\n source: \"survivors\",\n type: \"vote\",\n eligibleTargets: [players[1], players[0]],\n boundaries: { min: 1, max: 4 },\n }),\n ],\n }),\n canBeSkipped: false,\n });\n const expectedGameEvents = [\n createFakeGameEvent({\n type: \"game-turn-starts\",\n players,\n }),\n ];\n const expectedGame = createFakeGame({\n ...game,\n phase: expectedPhase,\n tick: game.tick + 1,\n currentPlay: expectedCurrentPlay,\n events: expectedGameEvents,\n });\n const response = await app.inject({\n method: \"POST\",\n url: `/games/${game._id.toString()}/play`,\n payload,\n });\n\n expect(response.statusCode).toBe(HttpStatus.OK);\n expect(response.json()).toStrictEqual({\n ...toJSON(expectedGame) as Game,\n lastGameHistoryRecord: expect.any(Object) as GameHistoryRecord,\n createdAt: expect.any(String) as Date,\n updatedAt: expect.any(String) as Date,\n });\n });\n\n it(\"should make a game play when called with targets.\", async() => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const currentPlay = createFakeGamePlaySeerLooks({\n source: createFakeGamePlaySource({\n name: \"seer\",\n players: [players[1]],\n interactions: [\n createFakeGamePlaySourceInteraction({\n source: \"seer\",\n type: \"look\",\n eligibleTargets: [players[0]],\n boundaries: { min: 1, max: 1 },\n }),\n ],\n }),\n });\n const game = createFakeGame({\n phase: createFakeGamePhase({ name: \"night\" }),\n status: \"playing\",\n currentPlay,\n upcomingPlays: [createFakeGamePlayWerewolvesEat()],\n players,\n options: DEFAULT_GAME_OPTIONS,\n });\n await models.game.create(game);\n const payload = createFakeMakeGamePlayDto({ targets: [{ playerId: players[0]._id }] });\n const seenPlayer = createFakePlayer({ ...players[0], attributes: [createFakeSeenBySeerPlayerAttribute()] });\n const expectedCurrentPlay = createFakeGamePlayWerewolvesEat({\n source: createFakeGamePlaySource({\n name: \"werewolves\",\n players: [seenPlayer, players[3]],\n interactions: [\n createFakeGamePlaySourceInteraction({\n source: \"werewolves\",\n type: \"eat\",\n eligibleTargets: [players[1], players[2]],\n boundaries: { min: 1, max: 1 },\n }),\n ],\n }),\n canBeSkipped: false,\n });\n const expectedGameEvents = [\n createFakeGameEvent({\n type: \"seer-has-seen\",\n players: [seenPlayer],\n }),\n createFakeGameEvent({\n type: \"game-turn-starts\",\n players: [seenPlayer, players[3]],\n }),\n ];\n\n const expectedGame = createFakeGame({\n ...game,\n tick: game.tick + 1,\n phase: createFakeGamePhase({ ...game.phase, tick: game.phase.tick + 1 }),\n currentPlay: expectedCurrentPlay,\n upcomingPlays: [],\n players: [\n seenPlayer,\n players[1],\n players[2],\n players[3],\n ],\n events: expectedGameEvents,\n options: DEFAULT_GAME_OPTIONS,\n });\n const response = await app.inject({\n method: \"POST\",\n url: `/games/${game._id.toString()}/play`,\n payload,\n });\n\n expect(response.statusCode).toBe(HttpStatus.OK);\n expect(response.json()).toStrictEqual({\n ...toJSON(expectedGame) as Game,\n lastGameHistoryRecord: expect.any(Object) as GameHistoryRecord,\n createdAt: expect.any(String) as Date,\n updatedAt: expect.any(String) as Date,\n });\n });\n });\n\n describe(\"GET /games/:id/history\", () => {\n it.each<{\n test: string;\n query: Record;\n errorMessage: string;\n }>([\n {\n test: \"should get bad request error on getting game history when limit is negative.\",\n query: { limit: -1 },\n errorMessage: \"limit must not be less than 0\",\n },\n {\n test: \"should get bad request error on getting game history when limit is not a number.\",\n query: { limit: \"lol\" },\n errorMessage: \"limit must be an integer number\",\n },\n {\n test: \"should get bad request error on getting game history when order is not asc nor desc.\",\n query: { order: \"unknown\" },\n errorMessage: \"order must be one of the following values: asc, desc\",\n },\n ])(\"$test\", async({\n query,\n errorMessage,\n }) => {\n const response = await app.inject({\n method: \"GET\",\n url: `/games/${faker.database.mongodbObjectId()}/history`,\n query: stringify(query),\n });\n\n expect(response.statusCode).toBe(HttpStatus.BAD_REQUEST);\n expect(response.json().message).toContainEqual(errorMessage);\n });\n\n it(\"should get a bad request error when id is not mongoId.\", async() => {\n const response = await app.inject({\n method: \"GET\",\n url: \"/games/123/history\",\n });\n\n expect(response.statusCode).toBe(HttpStatus.BAD_REQUEST);\n expect(response.json().message).toBe(\"Validation failed (Mongo ObjectId is expected)\");\n });\n\n it(\"should get a not found error when id doesn't exist in base.\", async() => {\n const unknownId = faker.database.mongodbObjectId();\n const response = await app.inject({\n method: \"GET\",\n url: `/games/${unknownId}/history`,\n });\n\n expect(response.statusCode).toBe(HttpStatus.NOT_FOUND);\n expect(response.json().message).toBe(`Game with id \"${unknownId}\" not found`);\n });\n\n it(\"should return no game history records when game doesn't have any.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWolfHoundChoosesSide() });\n const secondGame = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWolfHoundChoosesSide() });\n const gameHistoryRecordPlay = createFakeGameHistoryRecordPlay({ source: createFakeGameHistoryRecordPlaySource({ name: \"big-bad-wolf\" }) });\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ gameId: game._id, play: gameHistoryRecordPlay }),\n createFakeGameHistoryRecord({ gameId: game._id, play: gameHistoryRecordPlay }),\n createFakeGameHistoryRecord({ gameId: game._id, play: gameHistoryRecordPlay }),\n ];\n await models.game.insertMany([game, secondGame]);\n await models.gameHistoryRecord.insertMany(gameHistoryRecords);\n\n const response = await app.inject({\n method: \"GET\",\n url: `/games/${secondGame._id.toString()}/history`,\n });\n\n expect(response.statusCode).toBe(HttpStatus.OK);\n expect(response.json()).toStrictEqual([]);\n });\n\n it(\"should return 3 game history records when game have 3 records.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWolfHoundChoosesSide() });\n const secondGame = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWolfHoundChoosesSide() });\n const gameHistoryRecordPlay = createFakeGameHistoryRecordPlay({ source: createFakeGameHistoryRecordPlaySource({ name: \"big-bad-wolf\" }) });\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ gameId: game._id, play: gameHistoryRecordPlay, createdAt: new Date(\"2022-01-01\") }),\n createFakeGameHistoryRecord({ gameId: game._id, play: gameHistoryRecordPlay, createdAt: new Date(\"2023-01-01\") }),\n createFakeGameHistoryRecord({ gameId: game._id, play: gameHistoryRecordPlay, createdAt: new Date(\"2024-01-01\") }),\n ];\n await models.game.insertMany([game, secondGame]);\n await models.gameHistoryRecord.insertMany(gameHistoryRecords);\n\n const response = await app.inject({\n method: \"GET\",\n url: `/games/${game._id.toString()}/history`,\n });\n\n expect(response.statusCode).toBe(HttpStatus.OK);\n expect(response.json()).toStrictEqual([\n {\n ...toJSON(gameHistoryRecords[0]),\n createdAt: expect.any(String) as Date,\n },\n {\n ...toJSON(gameHistoryRecords[1]),\n createdAt: expect.any(String) as Date,\n },\n {\n ...toJSON(gameHistoryRecords[2]),\n createdAt: expect.any(String) as Date,\n },\n ] as GameHistoryRecord[]);\n });\n\n it(\"should return last recent game history record when limit is 1 and order is desc.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWolfHoundChoosesSide() });\n const getGameHistoryDto = createFakeGetGameHistoryDto({ limit: 1, order: ApiSortOrder.DESC });\n const secondGame = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWolfHoundChoosesSide() });\n const gameHistoryRecordPlay = createFakeGameHistoryRecordPlay({ source: createFakeGameHistoryRecordPlaySource({ name: \"big-bad-wolf\" }) });\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ gameId: game._id, play: gameHistoryRecordPlay, createdAt: new Date(\"2022-01-01\") }),\n createFakeGameHistoryRecord({ gameId: game._id, play: gameHistoryRecordPlay, createdAt: new Date(\"2023-01-01\") }),\n createFakeGameHistoryRecord({ gameId: game._id, play: gameHistoryRecordPlay, createdAt: new Date(\"2024-01-01\") }),\n ];\n await models.game.insertMany([game, secondGame]);\n await models.gameHistoryRecord.insertMany(gameHistoryRecords);\n\n const response = await app.inject({\n method: \"GET\",\n url: `/games/${game._id.toString()}/history`,\n query: stringify(getGameHistoryDto),\n });\n\n expect(response.statusCode).toBe(HttpStatus.OK);\n expect(response.json()).toStrictEqual([\n {\n ...toJSON(gameHistoryRecords[2]),\n createdAt: expect.any(String) as Date,\n },\n ] as GameHistoryRecord[]);\n });\n });\n\n describe(\"POST /games/:id/feedback\", () => {\n it.each<{\n test: string;\n gameId: string;\n payload: CreateGameFeedbackDto;\n errorMessage: string;\n }>([\n {\n test: \"should not allow game feedback creation when score is lower than 1.\",\n gameId: createFakeObjectId().toString(),\n payload: createFakeCreateGameFeedbackDto({ score: 0 }),\n errorMessage: \"score must not be less than 1\",\n },\n {\n test: \"should not allow game feedback creation when score is greater than 5.\",\n gameId: createFakeObjectId().toString(),\n payload: createFakeCreateGameFeedbackDto({ score: 6 }),\n errorMessage: \"score must not be greater than 5\",\n },\n {\n test: \"should not allow game feedback creation when score is not an integer.\",\n gameId: createFakeObjectId().toString(),\n payload: createFakeCreateGameFeedbackDto({ score: 4.5 }),\n errorMessage: \"score must be an integer number\",\n },\n {\n test: \"should not allow game feedback creation when review is longer than 1000 characters.\",\n gameId: createFakeObjectId().toString(),\n payload: createFakeCreateGameFeedbackDto({ review: faker.lorem.paragraphs(20) }),\n errorMessage: \"review must be shorter than or equal to 1000 characters\",\n },\n ])(\"$test\", async({\n gameId,\n payload,\n errorMessage,\n }) => {\n const response = await app.inject({\n method: \"POST\",\n url: `/games/${gameId}/feedback`,\n payload,\n });\n\n expect(response.statusCode).toBe(HttpStatus.BAD_REQUEST);\n expect(response.json().message).toContainEqual(errorMessage);\n });\n\n it(\"should not allow game feedback creation when game id is not mongoId.\", async() => {\n const response = await app.inject({\n method: \"POST\",\n url: \"/games/123/feedback\",\n payload: createFakeCreateGameFeedbackDto(),\n });\n\n expect(response.statusCode).toBe(HttpStatus.BAD_REQUEST);\n expect(response.json().message).toBe(\"Validation failed (Mongo ObjectId is expected)\");\n });\n\n it(\"should not allow game feedback creation when game id doesn't exist in base.\", async() => {\n const unknownId = faker.database.mongodbObjectId();\n const response = await app.inject({\n method: \"POST\",\n url: `/games/${unknownId}/feedback`,\n payload: createFakeCreateGameFeedbackDto(),\n });\n\n expect(response.statusCode).toBe(HttpStatus.NOT_FOUND);\n expect(response.json().message).toBe(`Game with id \"${unknownId}\" not found`);\n });\n\n it(\"should create game feedback when called.\", async() => {\n const game = createFakeGameWithCurrentPlay({ currentPlay: createFakeGamePlayWolfHoundChoosesSide() });\n await models.game.create(game);\n const payload = createFakeCreateGameFeedbackDto();\n const response = await app.inject({\n method: \"POST\",\n url: `/games/${game._id.toString()}/feedback`,\n payload,\n });\n\n expect(response.statusCode).toBe(HttpStatus.CREATED);\n expect(response.json()).toStrictEqual({\n ...toJSON(game) as Game,\n _id: expect.any(String) as Types.ObjectId,\n feedback: {\n ...toJSON(payload) as GameFeedback,\n _id: expect.any(String) as Types.ObjectId,\n gameId: game._id.toString() as unknown as Types.ObjectId,\n createdAt: expect.any(String) as Date,\n },\n createdAt: expect.any(String) as Date,\n updatedAt: expect.any(String) as Date,\n });\n });\n });\n});" }, "tests/e2e/specs/modules/game/providers/repositories/game-history-record.repository.e2e-spec.ts": { "tests": [ @@ -193063,7 +193065,7 @@ } } ], - "source": "import { GameHistoryRecordRepository } from \"@/modules/game/providers/repositories/game-history-record/game-history-record.repository\";\nimport { getModelToken } from \"@nestjs/mongoose\";\nimport type { NestFastifyApplication } from \"@nestjs/platform-fastify\";\nimport type { TestingModule } from \"@nestjs/testing\";\nimport type { Model, Types } from \"mongoose\";\n\nimport type { GamePhaseName } from \"@/modules/game/types/game-phase/game-phase.types\";\nimport type { RoleSide } from \"@/modules/role/types/role.types\";\nimport { GameHistoryRecord } from \"@/modules/game/schemas/game-history-record/game-history-record.schema\";\nimport type { GamePlay } from \"@/modules/game/schemas/game-play/game-play.schema\";\nimport type { GameHistoryRecordToInsert, GameHistoryRecordVotingResult } from \"@/modules/game/types/game-history-record/game-history-record.types\";\nimport type { GamePlaySourceName, WitchPotion } from \"@/modules/game/types/game-play/game-play.types\";\n\nimport { ApiSortOrder } from \"@/shared/api/enums/api.enums\";\nimport { toJSON } from \"@/shared/misc/helpers/object.helpers\";\n\nimport { createFakeGamePhase } from \"@tests/factories/game/schemas/game-phase/game-phase.schema.factory\";\nimport { truncateAllCollections } from \"@tests/e2e/helpers/mongoose.helpers\";\nimport { initNestApp } from \"@tests/e2e/helpers/nest-app.helpers\";\nimport { createFakeGetGameHistoryDto } from \"@tests/factories/game/dto/get-game-history/get-game-history.dto.factory\";\nimport { createFakeGameHistoryRecord, createFakeGameHistoryRecordAccursedWolfFatherInfectsPlay, createFakeGameHistoryRecordBigBadWolfEatPlay, createFakeGameHistoryRecordDefenderProtectPlay, createFakeGameHistoryRecordPlay, createFakeGameHistoryRecordPlaySource, createFakeGameHistoryRecordPlayTarget, createFakeGameHistoryRecordPlayVoting, createFakeGameHistoryRecordStutteringJudgeRequestsAnotherVotePlay, createFakeGameHistoryRecordSurvivorsElectSheriffPlay, createFakeGameHistoryRecordSurvivorsVotePlay, createFakeGameHistoryRecordWerewolvesEatPlay, createFakeGameHistoryRecordWitchUsePotionsPlay } from \"@tests/factories/game/schemas/game-history-record/game-history-record.schema.factory\";\nimport { createFakeGamePlayCupidCharms, createFakeGamePlayPiedPiperCharms, createFakeGamePlayWerewolvesEat } from \"@tests/factories/game/schemas/game-play/game-play.schema.factory\";\nimport { createFakeElderAlivePlayer, createFakeStutteringJudgeAlivePlayer, createFakeWitchAlivePlayer } from \"@tests/factories/game/schemas/player/player-with-role.schema.factory\";\nimport { createFakePlayer } from \"@tests/factories/game/schemas/player/player.schema.factory\";\nimport { createFakeGameHistoryRecordToInsert } from \"@tests/factories/game/types/game-history-record/game-history-record.type.factory\";\nimport { createFakeObjectId } from \"@tests/factories/shared/mongoose/mongoose.factory\";\n\ndescribe(\"Game History Record Repository\", () => {\n let app: NestFastifyApplication;\n let testingModule: TestingModule;\n let models: { gameHistoryRecord: Model };\n let repositories: { gameHistoryRecord: GameHistoryRecordRepository };\n\n beforeAll(async() => {\n const { app: server, module } = await initNestApp();\n app = server;\n testingModule = module;\n\n repositories = { gameHistoryRecord: app.get(GameHistoryRecordRepository) };\n models = { gameHistoryRecord: module.get>(getModelToken(GameHistoryRecord.name)) };\n });\n\n beforeEach(async() => {\n await truncateAllCollections(testingModule);\n });\n\n afterEach(async() => {\n await truncateAllCollections(testingModule);\n });\n\n afterAll(async() => {\n await app.close();\n });\n\n async function populate(gameHistoryRecords: GameHistoryRecord[]): Promise {\n return models.gameHistoryRecord.insertMany(gameHistoryRecords);\n }\n\n describe(\"getGameHistory\", () => {\n it(\"should get nothing when there are no record.\", async() => {\n const gameId = createFakeObjectId();\n const getGameHistoryDto = createFakeGetGameHistoryDto();\n\n await expect(repositories.gameHistoryRecord.getGameHistory(gameId, getGameHistoryDto)).resolves.toStrictEqual([]);\n });\n\n it(\"should get all ascending records when called with gameId with records with default get game history dto.\", async() => {\n const gameId = createFakeObjectId();\n const getGameHistoryDto = createFakeGetGameHistoryDto();\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWerewolvesEatPlay(), createdAt: new Date(\"2022-01-01\") }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWitchUsePotionsPlay(), createdAt: new Date(\"2023-01-01\") }),\n ];\n await populate(gameHistoryRecords);\n const records = await repositories.gameHistoryRecord.getGameHistory(gameId, getGameHistoryDto);\n\n expect(toJSON(records)).toStrictEqual(toJSON(gameHistoryRecords) as GameHistoryRecord[]);\n });\n\n it(\"should get only one record when called with get game history dto limit set to 1.\", async() => {\n const gameId = createFakeObjectId();\n const getGameHistoryDto = createFakeGetGameHistoryDto({ limit: 1 });\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsElectSheriffPlay(), createdAt: new Date(\"2022-01-01\") }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWerewolvesEatPlay(), createdAt: new Date(\"2023-01-01\") }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWitchUsePotionsPlay(), createdAt: new Date(\"2024-01-01\") }),\n ];\n await populate(gameHistoryRecords);\n const records = await repositories.gameHistoryRecord.getGameHistory(gameId, getGameHistoryDto);\n\n expect(toJSON(records)).toStrictEqual([toJSON(gameHistoryRecords[0]) as GameHistoryRecord]);\n });\n\n it(\"should get records in descending order when called with get game history dto order set to DESC.\", async() => {\n const gameId = createFakeObjectId();\n const getGameHistoryDto = createFakeGetGameHistoryDto({ order: ApiSortOrder.DESC });\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsElectSheriffPlay(), createdAt: new Date(\"2022-01-01\") }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWerewolvesEatPlay(), createdAt: new Date(\"2023-01-01\") }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWitchUsePotionsPlay(), createdAt: new Date(\"2024-01-01\") }),\n ];\n await populate(gameHistoryRecords);\n const records = await repositories.gameHistoryRecord.getGameHistory(gameId, getGameHistoryDto);\n\n expect(toJSON(records)).toStrictEqual(toJSON(gameHistoryRecords.reverse()) as GameHistoryRecord[]);\n });\n });\n\n describe(\"create\", () => {\n it.each<{\n test: string;\n toInsert: GameHistoryRecordToInsert;\n errorMessage: string;\n }>([\n {\n test: \"should not create history record when turn is lower than 1.\",\n toInsert: createFakeGameHistoryRecord({ turn: 0 }),\n errorMessage: \"GameHistoryRecord validation failed: turn: Path `turn` (0) is less than minimum allowed value (1).\",\n },\n {\n test: \"should not create history record when tick is lower than 1.\",\n toInsert: createFakeGameHistoryRecord({ tick: -1 }),\n errorMessage: \"GameHistoryRecord validation failed: tick: Path `tick` (-1) is less than minimum allowed value (1).\",\n },\n {\n test: \"should not create history record when phase name is not in enum.\",\n toInsert: createFakeGameHistoryRecord({ phase: createFakeGamePhase({ name: \"Noon\" as GamePhaseName }) }),\n errorMessage: \"GameHistoryRecord validation failed: phase.name: `Noon` is not a valid enum value for path `name`.\",\n },\n {\n test: \"should not create history record when phase tick is not greater than 0.\",\n toInsert: createFakeGameHistoryRecord({ phase: createFakeGamePhase({ tick: 0 }) }),\n errorMessage: \"GameHistoryRecord validation failed: phase.tick: Path `tick` (0) is less than minimum allowed value (1).\",\n },\n {\n test: \"should not create history record when players in play's source is empty.\",\n toInsert: createFakeGameHistoryRecord({ play: createFakeGameHistoryRecordPlay({ source: { name: \"sheriff\", players: [] } }) }),\n errorMessage: \"GameHistoryRecord validation failed: play.source.players: Path `play.source.players` length is less than minimum allowed value (1).\",\n },\n {\n test: \"should not create history record when source in play's source is not in enum.\",\n toInsert: createFakeGameHistoryRecord({ play: createFakeGameHistoryRecordPlay({ source: { name: \"Bad source\" as GamePlaySourceName, players: [createFakePlayer()] } }) }),\n errorMessage: \"GameHistoryRecord validation failed: play.source.name: `Bad source` is not a valid enum value for path `name`.\",\n },\n {\n test: \"should not create history record when potion in play's target is not in enum.\",\n toInsert: createFakeGameHistoryRecord({ play: createFakeGameHistoryRecordPlay({ targets: [{ player: createFakePlayer(), drankPotion: \"Love Potion\" as WitchPotion }] }) }),\n errorMessage: \"GameHistoryRecord validation failed: play.targets.0.drankPotion: `Love Potion` is not a valid enum value for path `drankPotion`.\",\n },\n {\n test: \"should not create history record when voting result is not in enum.\",\n toInsert: createFakeGameHistoryRecord({ play: createFakeGameHistoryRecordPlay({ voting: createFakeGameHistoryRecordPlayVoting({ result: \"President election\" as GameHistoryRecordVotingResult }) }) }),\n errorMessage: \"GameHistoryRecord validation failed: play.voting.result: `President election` is not a valid enum value for path `result`.\",\n },\n {\n test: \"should not create history record when chosen side is not in enum.\",\n toInsert: createFakeGameHistoryRecord({ play: createFakeGameHistoryRecordPlay({ chosenSide: \"Dark side\" as RoleSide }) }),\n errorMessage: \"GameHistoryRecord validation failed: play.chosenSide: `Dark side` is not a valid enum value for path `chosenSide`.\",\n },\n ])(\"$test\", async({ toInsert, errorMessage }) => {\n const gameHistoryRecordToInsert = createFakeGameHistoryRecordToInsert(toInsert);\n\n await expect(repositories.gameHistoryRecord.create(gameHistoryRecordToInsert)).rejects.toThrow(errorMessage);\n });\n\n it(\"should create history record when called.\", async() => {\n const gameHistoryRecordPlayToInsert = createFakeGameHistoryRecordPlay({ source: createFakeGameHistoryRecordPlaySource({ name: \"seer\", players: [createFakePlayer()] }) });\n const gameHistoryRecordToInsert = createFakeGameHistoryRecordToInsert({ play: gameHistoryRecordPlayToInsert });\n const gameHistoryRecord = await repositories.gameHistoryRecord.create(gameHistoryRecordToInsert);\n\n expect(toJSON(gameHistoryRecord)).toStrictEqual({\n ...(toJSON(gameHistoryRecordToInsert) as GameHistoryRecordToInsert),\n _id: expect.any(String) as Types.ObjectId,\n createdAt: expect.any(String) as Date,\n });\n });\n });\n\n describe(\"getLastGameHistoryDefenderProtectsRecord\", () => {\n it(\"should return no record when there is no defender play in the history.\", async() => {\n const defenderPlayerId = createFakeObjectId();\n const gameId = createFakeObjectId();\n await populate([\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWerewolvesEatPlay() }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWitchUsePotionsPlay() }),\n ]);\n\n await expect(repositories.gameHistoryRecord.getLastGameHistoryDefenderProtectsRecord(gameId, defenderPlayerId)).resolves.toBeNull();\n });\n\n it(\"should return no record when there gameId is not the good one.\", async() => {\n const defenderPlayerId = createFakeObjectId();\n const players = [\n createFakePlayer(),\n createFakePlayer({ _id: defenderPlayerId }),\n createFakePlayer(),\n ];\n const gameId = createFakeObjectId();\n const otherGameId = createFakeObjectId();\n await populate([\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordDefenderProtectPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"defender\",\n players,\n }),\n }),\n }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWitchUsePotionsPlay() }),\n ]);\n\n await expect(repositories.gameHistoryRecord.getLastGameHistoryDefenderProtectsRecord(otherGameId, defenderPlayerId)).resolves.toBeNull();\n });\n\n it(\"should return the last defender game history play record when called.\", async() => {\n const defenderPlayerId = createFakeObjectId();\n const players = [\n createFakePlayer(),\n createFakePlayer({ _id: defenderPlayerId }),\n createFakePlayer(),\n ];\n const gameId = createFakeObjectId();\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordDefenderProtectPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"defender\",\n players,\n }),\n }),\n createdAt: new Date(\"2020-01-01\"),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordWitchUsePotionsPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"witch\",\n players,\n }),\n }),\n createdAt: new Date(\"2021-01-01\"),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordDefenderProtectPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"defender\",\n players,\n }),\n }),\n createdAt: new Date(\"2022-01-01\"),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordWitchUsePotionsPlay(),\n createdAt: new Date(\"2023-01-01\"),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordDefenderProtectPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"defender\",\n players: [createFakePlayer()],\n }),\n }),\n createdAt: new Date(\"2024-01-01\"),\n }),\n ];\n await populate(gameHistoryRecords);\n const record = await repositories.gameHistoryRecord.getLastGameHistoryDefenderProtectsRecord(gameId, defenderPlayerId);\n\n expect(toJSON(record)).toStrictEqual(toJSON(gameHistoryRecords[2]) as GameHistoryRecord);\n });\n });\n\n describe(\"getLastGameHistorySurvivorsVoteRecord\", () => {\n it(\"should return no record when there is no defender play in the history.\", async() => {\n const gameId = createFakeObjectId();\n await populate([\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWerewolvesEatPlay() }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWitchUsePotionsPlay() }),\n ]);\n\n await expect(repositories.gameHistoryRecord.getLastGameHistorySurvivorsVoteRecord(gameId)).resolves.toBeNull();\n });\n\n it(\"should return no record when there gameId is not the good one.\", async() => {\n const gameId = createFakeObjectId();\n const otherGameId = createFakeObjectId();\n await populate([\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordSurvivorsVotePlay(),\n }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWitchUsePotionsPlay() }),\n ]);\n\n await expect(repositories.gameHistoryRecord.getLastGameHistorySurvivorsVoteRecord(otherGameId)).resolves.toBeNull();\n });\n\n it(\"should one record when game history contains one survivors vote.\", async() => {\n const gameId = createFakeObjectId();\n const otherGameId = createFakeObjectId();\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordWitchUsePotionsPlay(),\n createdAt: new Date(\"2019-01-01\"),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordSurvivorsVotePlay(),\n createdAt: new Date(\"2020-01-01\"),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordSurvivorsVotePlay(),\n createdAt: new Date(\"2021-01-01\"),\n }),\n createFakeGameHistoryRecord({\n gameId: otherGameId,\n play: createFakeGameHistoryRecordSurvivorsVotePlay(),\n createdAt: new Date(\"2022-01-01\"),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordSurvivorsElectSheriffPlay(),\n createdAt: new Date(\"2023-01-01\"),\n }),\n ];\n await populate(gameHistoryRecords);\n const record = await repositories.gameHistoryRecord.getLastGameHistorySurvivorsVoteRecord(gameId);\n\n expect(toJSON(record)).toStrictEqual(toJSON(gameHistoryRecords[2]) as GameHistoryRecord);\n });\n });\n\n describe(\"getLastGameHistoryTieInVotesRecord\", () => {\n it(\"should return no record when there is no vote play in the history.\", async() => {\n const gameId = createFakeObjectId();\n await populate([\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWerewolvesEatPlay() }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWitchUsePotionsPlay() }),\n ]);\n\n await expect(repositories.gameHistoryRecord.getLastGameHistoryTieInVotesRecord(gameId, \"vote\")).resolves.toBeNull();\n });\n\n it(\"should return no record when there is no tie in vote play in the history.\", async() => {\n const gameId = createFakeObjectId();\n const gameHistoryRecordPlayTieVoting = createFakeGameHistoryRecordPlayVoting({ result: \"death\" });\n await populate([\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay({ voting: gameHistoryRecordPlayTieVoting }) }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay() }),\n ]);\n\n await expect(repositories.gameHistoryRecord.getLastGameHistoryTieInVotesRecord(gameId, \"vote\")).resolves.toBeNull();\n });\n\n it(\"should return no record when there gameId is not the good one.\", async() => {\n const gameId = createFakeObjectId();\n const otherGameId = createFakeObjectId();\n const gameHistoryRecordPlayTieVoting = createFakeGameHistoryRecordPlayVoting({ result: \"tie\" });\n await populate([\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordDefenderProtectPlay() }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay({ voting: gameHistoryRecordPlayTieVoting }) }),\n ]);\n\n await expect(repositories.gameHistoryRecord.getLastGameHistoryTieInVotesRecord(otherGameId, \"vote\")).resolves.toBeNull();\n });\n\n it(\"should return the last tie in vote game history play record when called.\", async() => {\n const gameId = createFakeObjectId();\n const gameHistoryRecordPlayTieVoting = createFakeGameHistoryRecordPlayVoting({ result: \"tie\" });\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay({ voting: gameHistoryRecordPlayTieVoting }), createdAt: new Date(\"2020-01-01\") }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWitchUsePotionsPlay(), createdAt: new Date(\"2021-01-01\") }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordDefenderProtectPlay(), createdAt: new Date(\"2022-01-01\") }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay({ voting: gameHistoryRecordPlayTieVoting }), createdAt: new Date(\"2024-01-01\") }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsElectSheriffPlay({ voting: gameHistoryRecordPlayTieVoting }), createdAt: new Date(\"2025-01-01\") }),\n ];\n await populate(gameHistoryRecords);\n const record = await repositories.gameHistoryRecord.getLastGameHistoryTieInVotesRecord(gameId, \"vote\");\n\n expect(toJSON(record)).toStrictEqual(toJSON(gameHistoryRecords[3]) as GameHistoryRecord);\n });\n });\n\n describe(\"getGameHistoryWitchUsesSpecificPotionRecords\", () => {\n it(\"should get no record when there are no witch play.\", async() => {\n const witchPlayerId = createFakeObjectId();\n const players = [\n createFakePlayer(),\n createFakeWitchAlivePlayer({ _id: witchPlayerId }),\n createFakePlayer(),\n ];\n const gameId = createFakeObjectId();\n const gameHistoryRecordPlayTieVoting = createFakeGameHistoryRecordPlayVoting({ result: \"tie\" });\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay({ voting: gameHistoryRecordPlayTieVoting }) }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordWerewolvesEatPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"werewolves\",\n players,\n }),\n }),\n }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordDefenderProtectPlay() }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay({ voting: gameHistoryRecordPlayTieVoting }) }),\n ];\n await populate(gameHistoryRecords);\n const records = await repositories.gameHistoryRecord.getGameHistoryWitchUsesSpecificPotionRecords(gameId, witchPlayerId, \"life\");\n\n expect(toJSON(records)).toStrictEqual([]);\n });\n\n it(\"should get no record when there are no witch using life potion play.\", async() => {\n const witchPlayerId = createFakeObjectId();\n const players = [\n createFakePlayer(),\n createFakeWitchAlivePlayer({ _id: witchPlayerId }),\n createFakePlayer(),\n ];\n const gameId = createFakeObjectId();\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay() }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordWitchUsePotionsPlay({\n targets: [createFakeGameHistoryRecordPlayTarget({ drankPotion: \"death\" })],\n source: createFakeGameHistoryRecordPlaySource({\n name: \"witch\",\n players,\n }),\n }),\n }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWitchUsePotionsPlay() }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordWitchUsePotionsPlay({\n targets: [createFakeGameHistoryRecordPlayTarget({ drankPotion: \"life\" })],\n source: createFakeGameHistoryRecordPlaySource({\n name: \"witch\",\n players: [\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n ],\n }),\n }),\n }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay() }),\n ];\n await populate(gameHistoryRecords);\n const records = await repositories.gameHistoryRecord.getGameHistoryWitchUsesSpecificPotionRecords(gameId, witchPlayerId, \"life\");\n\n expect(toJSON(records)).toStrictEqual([]);\n });\n\n it(\"should get records of witch using life potion for this gameId when called.\", async() => {\n const witchPlayerId = createFakeObjectId();\n const players = [\n createFakePlayer(),\n createFakeWitchAlivePlayer({ _id: witchPlayerId }),\n createFakePlayer(),\n ];\n const gameId = createFakeObjectId();\n const otherGameId = createFakeObjectId();\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay() }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordWitchUsePotionsPlay({\n targets: [createFakeGameHistoryRecordPlayTarget({ drankPotion: \"life\" })],\n source: createFakeGameHistoryRecordPlaySource({\n name: \"witch\",\n players,\n }),\n }),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordWitchUsePotionsPlay({\n targets: [\n createFakeGameHistoryRecordPlayTarget({ drankPotion: \"life\" }),\n createFakeGameHistoryRecordPlayTarget({ drankPotion: \"death\" }),\n ],\n source: createFakeGameHistoryRecordPlaySource({\n name: \"witch\",\n players,\n }),\n }),\n }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWitchUsePotionsPlay() }),\n createFakeGameHistoryRecord({\n gameId: otherGameId,\n play: createFakeGameHistoryRecordWitchUsePotionsPlay({\n targets: [createFakeGameHistoryRecordPlayTarget({ drankPotion: \"life\" })],\n source: createFakeGameHistoryRecordPlaySource({\n name: \"witch\",\n players,\n }),\n }),\n }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay() }),\n ];\n await populate(gameHistoryRecords);\n const records = await repositories.gameHistoryRecord.getGameHistoryWitchUsesSpecificPotionRecords(gameId, witchPlayerId, \"life\");\n const expectedRecords = [gameHistoryRecords[1], gameHistoryRecords[2]];\n\n expect(toJSON(records)).toStrictEqual(toJSON(expectedRecords) as GameHistoryRecord[]);\n });\n\n it(\"should get no record when there are no witch using death potion play.\", async() => {\n const witchPlayerId = createFakeObjectId();\n const players = [\n createFakePlayer(),\n createFakeWitchAlivePlayer({ _id: witchPlayerId }),\n createFakePlayer(),\n ];\n const gameId = createFakeObjectId();\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay() }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordWitchUsePotionsPlay({\n targets: [createFakeGameHistoryRecordPlayTarget({ drankPotion: \"life\" })],\n source: createFakeGameHistoryRecordPlaySource({\n name: \"witch\",\n players,\n }),\n }),\n }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWitchUsePotionsPlay() }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay() }),\n ];\n await populate(gameHistoryRecords);\n const records = await repositories.gameHistoryRecord.getGameHistoryWitchUsesSpecificPotionRecords(gameId, witchPlayerId, \"death\");\n\n expect(toJSON(records)).toStrictEqual([]);\n });\n\n it(\"should get records of witch using death potion for this gameId when called.\", async() => {\n const witchPlayerId = createFakeObjectId();\n const players = [\n createFakePlayer(),\n createFakeWitchAlivePlayer({ _id: witchPlayerId }),\n createFakePlayer(),\n ];\n const gameId = createFakeObjectId();\n const otherGameId = createFakeObjectId();\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay() }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordWitchUsePotionsPlay({\n targets: [createFakeGameHistoryRecordPlayTarget({ drankPotion: \"death\" })],\n source: createFakeGameHistoryRecordPlaySource({\n name: \"witch\",\n players,\n }),\n }),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordWitchUsePotionsPlay({\n targets: [\n createFakeGameHistoryRecordPlayTarget({ drankPotion: \"life\" }),\n createFakeGameHistoryRecordPlayTarget({ drankPotion: \"death\" }),\n ],\n source: createFakeGameHistoryRecordPlaySource({\n name: \"witch\",\n players,\n }),\n }),\n }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWitchUsePotionsPlay() }),\n createFakeGameHistoryRecord({\n gameId: otherGameId,\n play: createFakeGameHistoryRecordWitchUsePotionsPlay({\n targets: [createFakeGameHistoryRecordPlayTarget({ drankPotion: \"death\" })],\n source: createFakeGameHistoryRecordPlaySource({\n name: \"witch\",\n players,\n }),\n }),\n }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay() }),\n ];\n await populate(gameHistoryRecords);\n const records = await repositories.gameHistoryRecord.getGameHistoryWitchUsesSpecificPotionRecords(gameId, witchPlayerId, \"death\");\n const expectedRecords = [gameHistoryRecords[1], gameHistoryRecords[2]];\n\n expect(toJSON(records)).toStrictEqual(toJSON(expectedRecords) as GameHistoryRecord[]);\n });\n });\n\n describe(\"getGameHistoryAccursedWolfFatherInfectsWithTargetRecords\", () => {\n it(\"should return no record when there is no infect play in the history.\", async() => {\n const accursedWolfFatherId = createFakeObjectId();\n const gameId = createFakeObjectId();\n await populate([\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordWerewolvesEatPlay({ targets: [createFakeGameHistoryRecordPlayTarget({ player: createFakePlayer() })] }),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordWitchUsePotionsPlay({ targets: [createFakeGameHistoryRecordPlayTarget({ player: createFakePlayer() })] }),\n }),\n ]);\n const records = await repositories.gameHistoryRecord.getGameHistoryAccursedWolfFatherInfectsWithTargetRecords(gameId, accursedWolfFatherId);\n\n expect(toJSON(records)).toStrictEqual([]);\n });\n\n it(\"should return no record when there gameId is not the good one.\", async() => {\n const accursedWolfFatherId = createFakeObjectId();\n const players = [\n createFakePlayer(),\n createFakePlayer({ _id: accursedWolfFatherId }),\n createFakePlayer(),\n ];\n const gameId = createFakeObjectId();\n const otherGameId = createFakeObjectId();\n await populate([\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordAccursedWolfFatherInfectsPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"accursed-wolf-father\",\n players: [players[1]],\n }),\n targets: [createFakeGameHistoryRecordPlayTarget({ player: players[2] })],\n }),\n }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWitchUsePotionsPlay() }),\n ]);\n const records = await repositories.gameHistoryRecord.getGameHistoryAccursedWolfFatherInfectsWithTargetRecords(otherGameId, accursedWolfFatherId);\n\n expect(toJSON(records)).toStrictEqual([]);\n });\n\n it(\"should return records of accursed wolf father infecting with target for this gameId when called.\", async() => {\n const accursedWolfFatherId = createFakeObjectId();\n const players = [\n createFakePlayer(),\n createFakePlayer({ _id: accursedWolfFatherId }),\n createFakePlayer(),\n ];\n const gameId = createFakeObjectId();\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordAccursedWolfFatherInfectsPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"accursed-wolf-father\",\n players: [players[1]],\n }),\n targets: [createFakeGameHistoryRecordPlayTarget({ player: players[2] })],\n }),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordWitchUsePotionsPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"witch\",\n players: [players[1]],\n }),\n targets: [createFakeGameHistoryRecordPlayTarget({ player: players[2] })],\n }),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordAccursedWolfFatherInfectsPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"accursed-wolf-father\",\n players: [players[1]],\n }),\n targets: [createFakeGameHistoryRecordPlayTarget({ player: players[2] })],\n }),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordWitchUsePotionsPlay(),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordAccursedWolfFatherInfectsPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"accursed-wolf-father\",\n players: [createFakePlayer()],\n }),\n targets: [createFakeGameHistoryRecordPlayTarget({ player: createFakePlayer() })],\n }),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordAccursedWolfFatherInfectsPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"accursed-wolf-father\",\n players: [players[1]],\n }),\n }),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordAccursedWolfFatherInfectsPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"accursed-wolf-father\",\n players: [players[1]],\n }),\n targets: [],\n }),\n }),\n ];\n await populate(gameHistoryRecords);\n const records = await repositories.gameHistoryRecord.getGameHistoryAccursedWolfFatherInfectsWithTargetRecords(gameId, accursedWolfFatherId);\n const expectedRecords = [gameHistoryRecords[0], gameHistoryRecords[2]];\n\n expect(toJSON(records)).toStrictEqual(toJSON(expectedRecords) as GameHistoryRecord[]);\n });\n });\n\n describe(\"getLastGameHistoryAccursedWolfFatherInfectsRecord\", () => {\n it(\"should return no record when there is no infect play in the history.\", async() => {\n const accursedWolfFatherId = createFakeObjectId();\n const gameId = createFakeObjectId();\n await populate([\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWerewolvesEatPlay() }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWitchUsePotionsPlay() }),\n ]);\n\n await expect(repositories.gameHistoryRecord.getLastGameHistoryAccursedWolfFatherInfectsRecord(gameId, accursedWolfFatherId)).resolves.toBeNull();\n });\n\n it(\"should return no record when there gameId is not the good one.\", async() => {\n const accursedWolfFatherId = createFakeObjectId();\n const players = [\n createFakePlayer(),\n createFakePlayer({ _id: accursedWolfFatherId }),\n createFakePlayer(),\n ];\n const gameId = createFakeObjectId();\n const otherGameId = createFakeObjectId();\n await populate([\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordAccursedWolfFatherInfectsPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"accursed-wolf-father\",\n players,\n }),\n }),\n }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWitchUsePotionsPlay() }),\n ]);\n\n await expect(repositories.gameHistoryRecord.getLastGameHistoryAccursedWolfFatherInfectsRecord(otherGameId, accursedWolfFatherId)).resolves.toBeNull();\n });\n\n it(\"should return the last accursed wolf father infects game history play record when called.\", async() => {\n const accursedWolfFatherId = createFakeObjectId();\n const players = [\n createFakePlayer(),\n createFakePlayer({ _id: accursedWolfFatherId }),\n createFakePlayer(),\n ];\n const gameId = createFakeObjectId();\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordAccursedWolfFatherInfectsPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"accursed-wolf-father\",\n players,\n }),\n }),\n createdAt: new Date(\"2020-01-01\"),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordWitchUsePotionsPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"witch\",\n players,\n }),\n }),\n createdAt: new Date(\"2021-01-01\"),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordAccursedWolfFatherInfectsPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"accursed-wolf-father\",\n players,\n }),\n }),\n createdAt: new Date(\"2022-01-01\"),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordWitchUsePotionsPlay(),\n createdAt: new Date(\"2023-01-01\"),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordAccursedWolfFatherInfectsPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"accursed-wolf-father\",\n players: [createFakePlayer()],\n }),\n }),\n createdAt: new Date(\"2024-01-01\"),\n }),\n ];\n await populate(gameHistoryRecords);\n const record = await repositories.gameHistoryRecord.getLastGameHistoryAccursedWolfFatherInfectsRecord(gameId, accursedWolfFatherId);\n\n expect(toJSON(record)).toStrictEqual(toJSON(gameHistoryRecords[2]) as GameHistoryRecord);\n });\n });\n\n describe(\"getGameHistoryStutteringJudgeRequestsAnotherVoteRecords\", () => {\n it(\"should get no record when there are no vote with judge request play.\", async() => {\n const stutteringJudgePlayerId = createFakeObjectId();\n const players = [\n createFakePlayer(),\n createFakeStutteringJudgeAlivePlayer({ _id: stutteringJudgePlayerId }),\n createFakePlayer(),\n ];\n const gameId = createFakeObjectId();\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay({ didJudgeRequestAnotherVote: false }) }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWitchUsePotionsPlay() }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordDefenderProtectPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"survivors\",\n players: [\n players[1],\n players[2],\n ],\n }),\n }),\n }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay() }),\n ];\n await populate(gameHistoryRecords);\n const records = await repositories.gameHistoryRecord.getGameHistoryStutteringJudgeRequestsAnotherVoteRecords(gameId, stutteringJudgePlayerId);\n\n expect(toJSON(records)).toStrictEqual([]);\n });\n\n it(\"should get records of stuttering judge requesting another vote for this gameId when called.\", async() => {\n const stutteringJudgePlayerId = createFakeObjectId();\n const players = [\n createFakePlayer(),\n createFakeStutteringJudgeAlivePlayer({ _id: stutteringJudgePlayerId }),\n createFakePlayer(),\n ];\n const gameId = createFakeObjectId();\n const otherGameId = createFakeObjectId();\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordSurvivorsVotePlay({ didJudgeRequestAnotherVote: true }),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordStutteringJudgeRequestsAnotherVotePlay({\n didJudgeRequestAnotherVote: true,\n source: createFakeGameHistoryRecordPlaySource({\n name: \"stuttering-judge\",\n players,\n }),\n }),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordStutteringJudgeRequestsAnotherVotePlay({\n didJudgeRequestAnotherVote: false,\n source: createFakeGameHistoryRecordPlaySource({\n name: \"stuttering-judge\",\n players,\n }),\n }),\n }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWitchUsePotionsPlay() }),\n createFakeGameHistoryRecord({\n gameId: otherGameId,\n play: createFakeGameHistoryRecordStutteringJudgeRequestsAnotherVotePlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"stuttering-judge\",\n players,\n }),\n didJudgeRequestAnotherVote: true,\n }),\n }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay() }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordStutteringJudgeRequestsAnotherVotePlay({\n didJudgeRequestAnotherVote: true,\n source: createFakeGameHistoryRecordPlaySource({\n name: \"stuttering-judge\",\n players: [\n createFakePlayer(),\n createFakePlayer(),\n ],\n }),\n }),\n }),\n ];\n await populate(gameHistoryRecords);\n const records = await repositories.gameHistoryRecord.getGameHistoryStutteringJudgeRequestsAnotherVoteRecords(gameId, stutteringJudgePlayerId);\n const expectedRecords = [gameHistoryRecords[1]];\n\n expect(toJSON(records)).toStrictEqual(toJSON(expectedRecords) as GameHistoryRecord[]);\n });\n });\n\n describe(\"getGameHistoryWerewolvesEatElderRecords\", () => {\n it(\"should get no record when there are no eat play.\", async() => {\n const elderPlayerId = createFakeObjectId();\n const gameId = createFakeObjectId();\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay({ didJudgeRequestAnotherVote: false }) }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWitchUsePotionsPlay() }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordDefenderProtectPlay() }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay() }),\n ];\n await populate(gameHistoryRecords);\n const records = await repositories.gameHistoryRecord.getGameHistoryWerewolvesEatElderRecords(gameId, elderPlayerId);\n\n expect(toJSON(records)).toStrictEqual([]);\n });\n\n it(\"should get records of elder eaten by any kind of werewolves for this gameId when called.\", async() => {\n const elderPlayerId = createFakeObjectId();\n const players = [\n createFakePlayer(),\n createFakeElderAlivePlayer({ _id: elderPlayerId }),\n createFakePlayer(),\n ];\n const gameId = createFakeObjectId();\n const otherGameId = createFakeObjectId();\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay() }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordWerewolvesEatPlay({\n targets: [\n createFakeGameHistoryRecordPlayTarget({ player: players[1] }),\n createFakeGameHistoryRecordPlayTarget({ player: players[0] }),\n ],\n }),\n }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay({ didJudgeRequestAnotherVote: false }) }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordBigBadWolfEatPlay({ targets: [createFakeGameHistoryRecordPlayTarget({ player: players[1] })] }) }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWitchUsePotionsPlay() }),\n createFakeGameHistoryRecord({\n gameId: otherGameId,\n play: createFakeGameHistoryRecordWerewolvesEatPlay({\n targets: [\n createFakeGameHistoryRecordPlayTarget({ player: players[1] }),\n createFakeGameHistoryRecordPlayTarget({ player: players[0] }),\n ],\n }),\n }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordBigBadWolfEatPlay({ targets: [createFakeGameHistoryRecordPlayTarget({ player: players[0] })] }) }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay() }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordWerewolvesEatPlay({\n targets: [\n createFakeGameHistoryRecordPlayTarget({ player: players[2] }),\n createFakeGameHistoryRecordPlayTarget({ player: players[0] }),\n ],\n }),\n }),\n ];\n await populate(gameHistoryRecords);\n const records = await repositories.gameHistoryRecord.getGameHistoryWerewolvesEatElderRecords(gameId, elderPlayerId);\n const expectedRecords = [gameHistoryRecords[1], gameHistoryRecords[3]];\n\n expect(toJSON(records)).toStrictEqual(toJSON(expectedRecords) as GameHistoryRecord[]);\n });\n });\n\n describe(\"getGameHistoryElderProtectedFromWerewolvesRecords\", () => {\n it(\"should get game history where elder is protected from werewolves records for gameId when called.\", async() => {\n const elderPlayerId = createFakeObjectId();\n const players = [\n createFakePlayer(),\n createFakeElderAlivePlayer({ _id: elderPlayerId }),\n createFakePlayer(),\n ];\n const gameId = createFakeObjectId();\n const otherGameId = createFakeObjectId();\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay({ didJudgeRequestAnotherVote: false }), createdAt: new Date(\"2023-01-01\") }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordDefenderProtectPlay({\n targets: [\n createFakeGameHistoryRecordPlayTarget({ player: players[0] }),\n createFakeGameHistoryRecordPlayTarget({ player: players[1] }),\n ],\n }),\n }),\n createFakeGameHistoryRecord({\n gameId: otherGameId,\n play: createFakeGameHistoryRecordDefenderProtectPlay({ targets: [createFakeGameHistoryRecordPlayTarget({ player: players[1] })] }),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordDefenderProtectPlay({ targets: [createFakeGameHistoryRecordPlayTarget({ player: players[0] })] }),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordWitchUsePotionsPlay({\n targets: [\n createFakeGameHistoryRecordPlayTarget({ player: players[0], drankPotion: \"life\" }),\n createFakeGameHistoryRecordPlayTarget({ player: players[1], drankPotion: \"death\" }),\n ],\n }),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordWitchUsePotionsPlay({\n targets: [\n createFakeGameHistoryRecordPlayTarget({ player: players[0], drankPotion: \"death\" }),\n createFakeGameHistoryRecordPlayTarget({ player: players[1], drankPotion: \"life\" }),\n ],\n }),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordDefenderProtectPlay({\n targets: [\n createFakeGameHistoryRecordPlayTarget({ player: players[0] }),\n createFakeGameHistoryRecordPlayTarget({ player: players[2] }),\n ],\n }),\n }),\n ];\n await populate(gameHistoryRecords);\n const records = await repositories.gameHistoryRecord.getGameHistoryElderProtectedFromWerewolvesRecords(gameId, elderPlayerId);\n const expectedRecords = [gameHistoryRecords[1], gameHistoryRecords[5]];\n\n expect(toJSON(records)).toStrictEqual(toJSON(expectedRecords) as GameHistoryRecord[]);\n });\n });\n\n describe(\"getPreviousGameHistoryRecord\", () => {\n it(\"should get no record when game doesn't have history yet.\", async() => {\n const gameId = createFakeObjectId();\n const otherGameId = createFakeObjectId();\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ gameId: otherGameId, play: createFakeGameHistoryRecordSurvivorsVotePlay({ didJudgeRequestAnotherVote: false }) }),\n createFakeGameHistoryRecord({ gameId: otherGameId, play: createFakeGameHistoryRecordWitchUsePotionsPlay() }),\n createFakeGameHistoryRecord({ gameId: otherGameId, play: createFakeGameHistoryRecordDefenderProtectPlay() }),\n createFakeGameHistoryRecord({ gameId: otherGameId, play: createFakeGameHistoryRecordSurvivorsVotePlay() }),\n ];\n await populate(gameHistoryRecords);\n const records = await repositories.gameHistoryRecord.getPreviousGameHistoryRecord(gameId);\n\n expect(toJSON(records)).toBeNull();\n });\n\n it(\"should get previous game history record for gameId when called.\", async() => {\n const gameId = createFakeObjectId();\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay(), createdAt: new Date(\"2020-01-01\") }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWitchUsePotionsPlay(), createdAt: new Date(\"2021-01-01\") }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordDefenderProtectPlay(), createdAt: new Date(\"2022-01-01\") }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay(), createdAt: new Date(\"2023-01-01\") }),\n ];\n await populate(gameHistoryRecords);\n const record = await repositories.gameHistoryRecord.getPreviousGameHistoryRecord(gameId);\n\n expect(toJSON(record)).toStrictEqual(toJSON(gameHistoryRecords[3]) as GameHistoryRecord);\n });\n });\n\n describe(\"getGameHistoryRecordsForTurnAndPhases\", () => {\n it(\"should get 3 records when called with gameId, turn and day phase.\", async() => {\n const gameId = createFakeObjectId();\n const otherGameId = createFakeObjectId();\n const play = createFakeGameHistoryRecordPlay({ source: createFakeGameHistoryRecordPlaySource({ name: \"werewolves\" }) });\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ gameId, turn: 1, phase: createFakeGamePhase({ name: \"day\" }), play }),\n createFakeGameHistoryRecord({ gameId, turn: 1, phase: createFakeGamePhase({ name: \"night\" }), play }),\n createFakeGameHistoryRecord({ gameId, turn: 1, phase: createFakeGamePhase({ name: \"day\" }), play }),\n createFakeGameHistoryRecord({ gameId, turn: 1, phase: createFakeGamePhase({ name: \"twilight\" }), play }),\n createFakeGameHistoryRecord({ gameId, turn: 2, phase: createFakeGamePhase({ name: \"day\" }), play }),\n createFakeGameHistoryRecord({ gameId, turn: 1, phase: createFakeGamePhase({ name: \"day\" }), play }),\n createFakeGameHistoryRecord({ gameId: otherGameId, phase: createFakeGamePhase({ name: \"day\" }), turn: 1, play }),\n ];\n await populate(gameHistoryRecords);\n const records = await repositories.gameHistoryRecord.getGameHistoryRecordsForTurnAndPhases(gameId, 1, [\"day\"]);\n const expectedRecords = [gameHistoryRecords[0], gameHistoryRecords[2], gameHistoryRecords[5]];\n\n expect(toJSON(records)).toStrictEqual(toJSON(expectedRecords) as GameHistoryRecord[]);\n });\n\n it(\"should get 2 records when called with gameId, turn and night and twilight phases.\", async() => {\n const gameId = createFakeObjectId();\n const otherGameId = createFakeObjectId();\n const play = createFakeGameHistoryRecordPlay({ source: createFakeGameHistoryRecordPlaySource({ name: \"werewolves\" }) });\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ gameId, turn: 1, phase: createFakeGamePhase({ name: \"day\" }), play }),\n createFakeGameHistoryRecord({ gameId, turn: 1, phase: createFakeGamePhase({ name: \"night\" }), play }),\n createFakeGameHistoryRecord({ gameId, turn: 1, phase: createFakeGamePhase({ name: \"day\" }), play }),\n createFakeGameHistoryRecord({ gameId, turn: 1, phase: createFakeGamePhase({ name: \"twilight\" }), play }),\n createFakeGameHistoryRecord({ gameId, turn: 3, phase: createFakeGamePhase({ name: \"twilight\" }), play }),\n createFakeGameHistoryRecord({ gameId, turn: 2, phase: createFakeGamePhase({ name: \"day\" }), play }),\n createFakeGameHistoryRecord({ gameId, turn: 1, phase: createFakeGamePhase({ name: \"day\" }), play }),\n createFakeGameHistoryRecord({ gameId: otherGameId, turn: 1, phase: createFakeGamePhase({ name: \"night\" }), play }),\n createFakeGameHistoryRecord({ gameId: otherGameId, phase: createFakeGamePhase({ name: \"day\" }), turn: 1, play }),\n ];\n await populate(gameHistoryRecords);\n const records = await repositories.gameHistoryRecord.getGameHistoryRecordsForTurnAndPhases(gameId, 1, [\"night\", \"twilight\"]);\n const expectedRecords = [gameHistoryRecords[1], gameHistoryRecords[3]];\n\n expect(toJSON(records)).toStrictEqual(toJSON(expectedRecords) as GameHistoryRecord[]);\n });\n });\n\n describe(\"getGameHistoryGamePlayRecords\", () => {\n const gameId = createFakeObjectId();\n const otherGameId = createFakeObjectId();\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordPlay({\n action: \"charm\",\n source: createFakeGameHistoryRecordPlaySource({ name: \"cupid\" }),\n }),\n }),\n createFakeGameHistoryRecord({\n gameId: otherGameId,\n play: createFakeGameHistoryRecordPlay({\n action: \"charm\",\n source: createFakeGameHistoryRecordPlaySource({ name: \"pied-piper\" }),\n }),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordPlay({\n action: \"charm\",\n source: createFakeGameHistoryRecordPlaySource({ name: \"cupid\" }),\n causes: [\"angel-presence\"],\n }),\n }),\n ];\n\n beforeEach(async() => {\n await populate(gameHistoryRecords);\n });\n\n it.each<{\n test: string;\n gameId: Types.ObjectId;\n gamePlay: GamePlay;\n expectedRecords: GameHistoryRecord[];\n }>([\n {\n test: \"should get one record when cupid charming.\",\n gameId,\n gamePlay: createFakeGamePlayCupidCharms(),\n expectedRecords: [gameHistoryRecords[0]],\n },\n {\n test: \"should get no record when pied-piper charming but on wrong game.\",\n gameId,\n gamePlay: createFakeGamePlayPiedPiperCharms(),\n expectedRecords: [],\n },\n {\n test: \"should get one record when cupid charming because of angel presence.\",\n gameId,\n gamePlay: createFakeGamePlayCupidCharms({ causes: [\"angel-presence\"] }),\n expectedRecords: [gameHistoryRecords[2]],\n },\n ])(`$test`, async({ gameId: id, gamePlay, expectedRecords }) => {\n const records = await repositories.gameHistoryRecord.getGameHistoryGamePlayRecords(id, gamePlay);\n\n expect(toJSON(records)).toStrictEqual(toJSON(expectedRecords) as GameHistoryRecord[]);\n });\n });\n\n describe(\"getGameHistoryGamePlayMadeByPlayerRecords\", () => {\n const gameId = createFakeObjectId();\n const otherGameId = createFakeObjectId();\n const player = createFakePlayer();\n\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordPlay({\n action: \"charm\",\n source: createFakeGameHistoryRecordPlaySource({\n name: \"cupid\",\n players: [\n createFakePlayer(),\n player,\n createFakePlayer(),\n ],\n }),\n }),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordPlay({\n action: \"eat\",\n source: createFakeGameHistoryRecordPlaySource({\n name: \"werewolves\",\n players: [\n createFakePlayer(),\n createFakePlayer(),\n ],\n }),\n }),\n }),\n createFakeGameHistoryRecord({\n gameId: otherGameId,\n play: createFakeGameHistoryRecordPlay({\n action: \"charm\",\n source: createFakeGameHistoryRecordPlaySource({\n name: \"pied-piper\",\n players: [\n createFakePlayer(),\n player,\n createFakePlayer(),\n ],\n }),\n }),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordPlay({\n action: \"charm\",\n source: createFakeGameHistoryRecordPlaySource({\n name: \"cupid\",\n players: [\n createFakePlayer(),\n player,\n createFakePlayer(),\n ],\n }),\n causes: [\"angel-presence\"],\n }),\n }),\n ];\n\n beforeEach(async() => {\n await populate(gameHistoryRecords);\n });\n\n it.each<{\n test: string;\n gameId: Types.ObjectId;\n gamePlay: GamePlay;\n expectedRecords: GameHistoryRecord[];\n }>([\n {\n test: \"should get one record when cupid charming.\",\n gameId,\n gamePlay: createFakeGamePlayCupidCharms(),\n expectedRecords: [gameHistoryRecords[0]],\n },\n {\n test: \"should get no record when pied-piper charming but on wrong game.\",\n gameId,\n gamePlay: createFakeGamePlayPiedPiperCharms(),\n expectedRecords: [],\n },\n {\n test: \"should get no record when werewolves eating but player is not found in game play.\",\n gameId,\n gamePlay: createFakeGamePlayWerewolvesEat(),\n expectedRecords: [],\n },\n {\n test: \"should get one record when cupid charming because of angel presence.\",\n gameId,\n gamePlay: createFakeGamePlayCupidCharms({ causes: [\"angel-presence\"] }),\n expectedRecords: [gameHistoryRecords[3]],\n },\n ])(`$test`, async({ gameId: id, gamePlay, expectedRecords }) => {\n const records = await repositories.gameHistoryRecord.getGameHistoryGamePlayMadeByPlayerRecords(id, gamePlay, player);\n\n expect(toJSON(records)).toStrictEqual(toJSON(expectedRecords) as GameHistoryRecord[]);\n });\n });\n});" + "source": "import { getModelToken } from \"@nestjs/mongoose\";\nimport type { NestFastifyApplication } from \"@nestjs/platform-fastify\";\nimport type { TestingModule } from \"@nestjs/testing\";\nimport type { Model, Types } from \"mongoose\";\n\nimport { GameHistoryRecordRepository } from \"@/modules/game/providers/repositories/game-history-record/game-history-record.repository\";\nimport type { GamePhaseName } from \"@/modules/game/types/game-phase/game-phase.types\";\nimport type { RoleSide } from \"@/modules/role/types/role.types\";\nimport { GameHistoryRecord } from \"@/modules/game/schemas/game-history-record/game-history-record.schema\";\nimport type { GamePlay } from \"@/modules/game/schemas/game-play/game-play.schema\";\nimport type { GameHistoryRecordToInsert, GameHistoryRecordVotingResult } from \"@/modules/game/types/game-history-record/game-history-record.types\";\nimport type { GamePlaySourceName, WitchPotion } from \"@/modules/game/types/game-play/game-play.types\";\n\nimport { ApiSortOrder } from \"@/shared/api/enums/api.enums\";\nimport { toJSON } from \"@/shared/misc/helpers/object.helpers\";\n\nimport { createFakeGamePhase } from \"@tests/factories/game/schemas/game-phase/game-phase.schema.factory\";\nimport { truncateAllCollections } from \"@tests/e2e/helpers/mongoose.helpers\";\nimport { initNestApp } from \"@tests/e2e/helpers/nest-app.helpers\";\nimport { createFakeGetGameHistoryDto } from \"@tests/factories/game/dto/get-game-history/get-game-history.dto.factory\";\nimport { createFakeGameHistoryRecord, createFakeGameHistoryRecordAccursedWolfFatherInfectsPlay, createFakeGameHistoryRecordBigBadWolfEatPlay, createFakeGameHistoryRecordDefenderProtectPlay, createFakeGameHistoryRecordPlay, createFakeGameHistoryRecordPlaySource, createFakeGameHistoryRecordPlayTarget, createFakeGameHistoryRecordPlayVoting, createFakeGameHistoryRecordStutteringJudgeRequestsAnotherVotePlay, createFakeGameHistoryRecordSurvivorsElectSheriffPlay, createFakeGameHistoryRecordSurvivorsVotePlay, createFakeGameHistoryRecordWerewolvesEatPlay, createFakeGameHistoryRecordWitchUsePotionsPlay } from \"@tests/factories/game/schemas/game-history-record/game-history-record.schema.factory\";\nimport { createFakeGamePlayCupidCharms, createFakeGamePlayPiedPiperCharms, createFakeGamePlayWerewolvesEat } from \"@tests/factories/game/schemas/game-play/game-play.schema.factory\";\nimport { createFakeElderAlivePlayer, createFakeStutteringJudgeAlivePlayer, createFakeWitchAlivePlayer } from \"@tests/factories/game/schemas/player/player-with-role.schema.factory\";\nimport { createFakePlayer } from \"@tests/factories/game/schemas/player/player.schema.factory\";\nimport { createFakeGameHistoryRecordToInsert } from \"@tests/factories/game/types/game-history-record/game-history-record.type.factory\";\nimport { createFakeObjectId } from \"@tests/factories/shared/mongoose/mongoose.factory\";\n\ndescribe(\"Game History Record Repository\", () => {\n let app: NestFastifyApplication;\n let testingModule: TestingModule;\n let models: { gameHistoryRecord: Model };\n let repositories: { gameHistoryRecord: GameHistoryRecordRepository };\n\n beforeAll(async() => {\n const { app: server, module } = await initNestApp();\n app = server;\n testingModule = module;\n\n repositories = { gameHistoryRecord: app.get(GameHistoryRecordRepository) };\n models = { gameHistoryRecord: module.get>(getModelToken(GameHistoryRecord.name)) };\n });\n\n beforeEach(async() => {\n await truncateAllCollections(testingModule);\n });\n\n afterEach(async() => {\n await truncateAllCollections(testingModule);\n });\n\n afterAll(async() => {\n await app.close();\n });\n\n async function populate(gameHistoryRecords: GameHistoryRecord[]): Promise {\n return models.gameHistoryRecord.insertMany(gameHistoryRecords);\n }\n\n describe(\"getGameHistory\", () => {\n it(\"should get nothing when there are no record.\", async() => {\n const gameId = createFakeObjectId();\n const getGameHistoryDto = createFakeGetGameHistoryDto();\n\n await expect(repositories.gameHistoryRecord.getGameHistory(gameId, getGameHistoryDto)).resolves.toStrictEqual([]);\n });\n\n it(\"should get all ascending records when called with gameId with records with default get game history dto.\", async() => {\n const gameId = createFakeObjectId();\n const getGameHistoryDto = createFakeGetGameHistoryDto();\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWerewolvesEatPlay(), createdAt: new Date(\"2022-01-01\") }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWitchUsePotionsPlay(), createdAt: new Date(\"2023-01-01\") }),\n ];\n await populate(gameHistoryRecords);\n const records = await repositories.gameHistoryRecord.getGameHistory(gameId, getGameHistoryDto);\n\n expect(toJSON(records)).toStrictEqual(toJSON(gameHistoryRecords) as GameHistoryRecord[]);\n });\n\n it(\"should get only one record when called with get game history dto limit set to 1.\", async() => {\n const gameId = createFakeObjectId();\n const getGameHistoryDto = createFakeGetGameHistoryDto({ limit: 1 });\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsElectSheriffPlay(), createdAt: new Date(\"2022-01-01\") }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWerewolvesEatPlay(), createdAt: new Date(\"2023-01-01\") }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWitchUsePotionsPlay(), createdAt: new Date(\"2024-01-01\") }),\n ];\n await populate(gameHistoryRecords);\n const records = await repositories.gameHistoryRecord.getGameHistory(gameId, getGameHistoryDto);\n\n expect(toJSON(records)).toStrictEqual([toJSON(gameHistoryRecords[0]) as GameHistoryRecord]);\n });\n\n it(\"should get records in descending order when called with get game history dto order set to DESC.\", async() => {\n const gameId = createFakeObjectId();\n const getGameHistoryDto = createFakeGetGameHistoryDto({ order: ApiSortOrder.DESC });\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsElectSheriffPlay(), createdAt: new Date(\"2022-01-01\") }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWerewolvesEatPlay(), createdAt: new Date(\"2023-01-01\") }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWitchUsePotionsPlay(), createdAt: new Date(\"2024-01-01\") }),\n ];\n await populate(gameHistoryRecords);\n const records = await repositories.gameHistoryRecord.getGameHistory(gameId, getGameHistoryDto);\n\n expect(toJSON(records)).toStrictEqual(toJSON(gameHistoryRecords.reverse()) as GameHistoryRecord[]);\n });\n });\n\n describe(\"create\", () => {\n it.each<{\n test: string;\n toInsert: GameHistoryRecordToInsert;\n errorMessage: string;\n }>([\n {\n test: \"should not create history record when turn is lower than 1.\",\n toInsert: createFakeGameHistoryRecord({ turn: 0 }),\n errorMessage: \"GameHistoryRecord validation failed: turn: Path `turn` (0) is less than minimum allowed value (1).\",\n },\n {\n test: \"should not create history record when tick is lower than 1.\",\n toInsert: createFakeGameHistoryRecord({ tick: -1 }),\n errorMessage: \"GameHistoryRecord validation failed: tick: Path `tick` (-1) is less than minimum allowed value (1).\",\n },\n {\n test: \"should not create history record when phase name is not in enum.\",\n toInsert: createFakeGameHistoryRecord({ phase: createFakeGamePhase({ name: \"Noon\" as GamePhaseName }) }),\n errorMessage: \"GameHistoryRecord validation failed: phase.name: `Noon` is not a valid enum value for path `name`.\",\n },\n {\n test: \"should not create history record when phase tick is not greater than 0.\",\n toInsert: createFakeGameHistoryRecord({ phase: createFakeGamePhase({ tick: 0 }) }),\n errorMessage: \"GameHistoryRecord validation failed: phase.tick: Path `tick` (0) is less than minimum allowed value (1).\",\n },\n {\n test: \"should not create history record when players in play's source is empty.\",\n toInsert: createFakeGameHistoryRecord({ play: createFakeGameHistoryRecordPlay({ source: { name: \"sheriff\", players: [] } }) }),\n errorMessage: \"GameHistoryRecord validation failed: play.source.players: Path `play.source.players` length is less than minimum allowed value (1).\",\n },\n {\n test: \"should not create history record when source in play's source is not in enum.\",\n toInsert: createFakeGameHistoryRecord({ play: createFakeGameHistoryRecordPlay({ source: { name: \"Bad source\" as GamePlaySourceName, players: [createFakePlayer()] } }) }),\n errorMessage: \"GameHistoryRecord validation failed: play.source.name: `Bad source` is not a valid enum value for path `name`.\",\n },\n {\n test: \"should not create history record when potion in play's target is not in enum.\",\n toInsert: createFakeGameHistoryRecord({ play: createFakeGameHistoryRecordPlay({ targets: [{ player: createFakePlayer(), drankPotion: \"Love Potion\" as WitchPotion }] }) }),\n errorMessage: \"GameHistoryRecord validation failed: play.targets.0.drankPotion: `Love Potion` is not a valid enum value for path `drankPotion`.\",\n },\n {\n test: \"should not create history record when voting result is not in enum.\",\n toInsert: createFakeGameHistoryRecord({ play: createFakeGameHistoryRecordPlay({ voting: createFakeGameHistoryRecordPlayVoting({ result: \"President election\" as GameHistoryRecordVotingResult }) }) }),\n errorMessage: \"GameHistoryRecord validation failed: play.voting.result: `President election` is not a valid enum value for path `result`.\",\n },\n {\n test: \"should not create history record when chosen side is not in enum.\",\n toInsert: createFakeGameHistoryRecord({ play: createFakeGameHistoryRecordPlay({ chosenSide: \"Dark side\" as RoleSide }) }),\n errorMessage: \"GameHistoryRecord validation failed: play.chosenSide: `Dark side` is not a valid enum value for path `chosenSide`.\",\n },\n ])(\"$test\", async({ toInsert, errorMessage }) => {\n const gameHistoryRecordToInsert = createFakeGameHistoryRecordToInsert(toInsert);\n\n await expect(repositories.gameHistoryRecord.create(gameHistoryRecordToInsert)).rejects.toThrow(errorMessage);\n });\n\n it(\"should create history record when called.\", async() => {\n const gameHistoryRecordPlayToInsert = createFakeGameHistoryRecordPlay({ source: createFakeGameHistoryRecordPlaySource({ name: \"seer\", players: [createFakePlayer()] }) });\n const gameHistoryRecordToInsert = createFakeGameHistoryRecordToInsert({ play: gameHistoryRecordPlayToInsert });\n const gameHistoryRecord = await repositories.gameHistoryRecord.create(gameHistoryRecordToInsert);\n\n expect(toJSON(gameHistoryRecord)).toStrictEqual({\n ...(toJSON(gameHistoryRecordToInsert) as GameHistoryRecordToInsert),\n _id: expect.any(String) as Types.ObjectId,\n createdAt: expect.any(String) as Date,\n });\n });\n });\n\n describe(\"getLastGameHistoryDefenderProtectsRecord\", () => {\n it(\"should return no record when there is no defender play in the history.\", async() => {\n const defenderPlayerId = createFakeObjectId();\n const gameId = createFakeObjectId();\n await populate([\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWerewolvesEatPlay() }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWitchUsePotionsPlay() }),\n ]);\n\n await expect(repositories.gameHistoryRecord.getLastGameHistoryDefenderProtectsRecord(gameId, defenderPlayerId)).resolves.toBeNull();\n });\n\n it(\"should return no record when there gameId is not the good one.\", async() => {\n const defenderPlayerId = createFakeObjectId();\n const players = [\n createFakePlayer(),\n createFakePlayer({ _id: defenderPlayerId }),\n createFakePlayer(),\n ];\n const gameId = createFakeObjectId();\n const otherGameId = createFakeObjectId();\n await populate([\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordDefenderProtectPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"defender\",\n players,\n }),\n }),\n }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWitchUsePotionsPlay() }),\n ]);\n\n await expect(repositories.gameHistoryRecord.getLastGameHistoryDefenderProtectsRecord(otherGameId, defenderPlayerId)).resolves.toBeNull();\n });\n\n it(\"should return the last defender game history play record when called.\", async() => {\n const defenderPlayerId = createFakeObjectId();\n const players = [\n createFakePlayer(),\n createFakePlayer({ _id: defenderPlayerId }),\n createFakePlayer(),\n ];\n const gameId = createFakeObjectId();\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordDefenderProtectPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"defender\",\n players,\n }),\n }),\n createdAt: new Date(\"2020-01-01\"),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordWitchUsePotionsPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"witch\",\n players,\n }),\n }),\n createdAt: new Date(\"2021-01-01\"),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordDefenderProtectPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"defender\",\n players,\n }),\n }),\n createdAt: new Date(\"2022-01-01\"),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordWitchUsePotionsPlay(),\n createdAt: new Date(\"2023-01-01\"),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordDefenderProtectPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"defender\",\n players: [createFakePlayer()],\n }),\n }),\n createdAt: new Date(\"2024-01-01\"),\n }),\n ];\n await populate(gameHistoryRecords);\n const record = await repositories.gameHistoryRecord.getLastGameHistoryDefenderProtectsRecord(gameId, defenderPlayerId);\n\n expect(toJSON(record)).toStrictEqual(toJSON(gameHistoryRecords[2]) as GameHistoryRecord);\n });\n });\n\n describe(\"getLastGameHistorySurvivorsVoteRecord\", () => {\n it(\"should return no record when there is no defender play in the history.\", async() => {\n const gameId = createFakeObjectId();\n await populate([\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWerewolvesEatPlay() }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWitchUsePotionsPlay() }),\n ]);\n\n await expect(repositories.gameHistoryRecord.getLastGameHistorySurvivorsVoteRecord(gameId)).resolves.toBeNull();\n });\n\n it(\"should return no record when there gameId is not the good one.\", async() => {\n const gameId = createFakeObjectId();\n const otherGameId = createFakeObjectId();\n await populate([\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordSurvivorsVotePlay(),\n }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWitchUsePotionsPlay() }),\n ]);\n\n await expect(repositories.gameHistoryRecord.getLastGameHistorySurvivorsVoteRecord(otherGameId)).resolves.toBeNull();\n });\n\n it(\"should one record when game history contains one survivors vote.\", async() => {\n const gameId = createFakeObjectId();\n const otherGameId = createFakeObjectId();\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordWitchUsePotionsPlay(),\n createdAt: new Date(\"2019-01-01\"),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordSurvivorsVotePlay(),\n createdAt: new Date(\"2020-01-01\"),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordSurvivorsVotePlay(),\n createdAt: new Date(\"2021-01-01\"),\n }),\n createFakeGameHistoryRecord({\n gameId: otherGameId,\n play: createFakeGameHistoryRecordSurvivorsVotePlay(),\n createdAt: new Date(\"2022-01-01\"),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordSurvivorsElectSheriffPlay(),\n createdAt: new Date(\"2023-01-01\"),\n }),\n ];\n await populate(gameHistoryRecords);\n const record = await repositories.gameHistoryRecord.getLastGameHistorySurvivorsVoteRecord(gameId);\n\n expect(toJSON(record)).toStrictEqual(toJSON(gameHistoryRecords[2]) as GameHistoryRecord);\n });\n });\n\n describe(\"getLastGameHistoryTieInVotesRecord\", () => {\n it(\"should return no record when there is no vote play in the history.\", async() => {\n const gameId = createFakeObjectId();\n await populate([\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWerewolvesEatPlay() }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWitchUsePotionsPlay() }),\n ]);\n\n await expect(repositories.gameHistoryRecord.getLastGameHistoryTieInVotesRecord(gameId, \"vote\")).resolves.toBeNull();\n });\n\n it(\"should return no record when there is no tie in vote play in the history.\", async() => {\n const gameId = createFakeObjectId();\n const gameHistoryRecordPlayTieVoting = createFakeGameHistoryRecordPlayVoting({ result: \"death\" });\n await populate([\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay({ voting: gameHistoryRecordPlayTieVoting }) }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay() }),\n ]);\n\n await expect(repositories.gameHistoryRecord.getLastGameHistoryTieInVotesRecord(gameId, \"vote\")).resolves.toBeNull();\n });\n\n it(\"should return no record when there gameId is not the good one.\", async() => {\n const gameId = createFakeObjectId();\n const otherGameId = createFakeObjectId();\n const gameHistoryRecordPlayTieVoting = createFakeGameHistoryRecordPlayVoting({ result: \"tie\" });\n await populate([\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordDefenderProtectPlay() }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay({ voting: gameHistoryRecordPlayTieVoting }) }),\n ]);\n\n await expect(repositories.gameHistoryRecord.getLastGameHistoryTieInVotesRecord(otherGameId, \"vote\")).resolves.toBeNull();\n });\n\n it(\"should return the last tie in vote game history play record when called.\", async() => {\n const gameId = createFakeObjectId();\n const gameHistoryRecordPlayTieVoting = createFakeGameHistoryRecordPlayVoting({ result: \"tie\" });\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay({ voting: gameHistoryRecordPlayTieVoting }), createdAt: new Date(\"2020-01-01\") }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWitchUsePotionsPlay(), createdAt: new Date(\"2021-01-01\") }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordDefenderProtectPlay(), createdAt: new Date(\"2022-01-01\") }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay({ voting: gameHistoryRecordPlayTieVoting }), createdAt: new Date(\"2024-01-01\") }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsElectSheriffPlay({ voting: gameHistoryRecordPlayTieVoting }), createdAt: new Date(\"2025-01-01\") }),\n ];\n await populate(gameHistoryRecords);\n const record = await repositories.gameHistoryRecord.getLastGameHistoryTieInVotesRecord(gameId, \"vote\");\n\n expect(toJSON(record)).toStrictEqual(toJSON(gameHistoryRecords[3]) as GameHistoryRecord);\n });\n });\n\n describe(\"getGameHistoryWitchUsesSpecificPotionRecords\", () => {\n it(\"should get no record when there are no witch play.\", async() => {\n const witchPlayerId = createFakeObjectId();\n const players = [\n createFakePlayer(),\n createFakeWitchAlivePlayer({ _id: witchPlayerId }),\n createFakePlayer(),\n ];\n const gameId = createFakeObjectId();\n const gameHistoryRecordPlayTieVoting = createFakeGameHistoryRecordPlayVoting({ result: \"tie\" });\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay({ voting: gameHistoryRecordPlayTieVoting }) }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordWerewolvesEatPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"werewolves\",\n players,\n }),\n }),\n }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordDefenderProtectPlay() }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay({ voting: gameHistoryRecordPlayTieVoting }) }),\n ];\n await populate(gameHistoryRecords);\n const records = await repositories.gameHistoryRecord.getGameHistoryWitchUsesSpecificPotionRecords(gameId, witchPlayerId, \"life\");\n\n expect(toJSON(records)).toStrictEqual([]);\n });\n\n it(\"should get no record when there are no witch using life potion play.\", async() => {\n const witchPlayerId = createFakeObjectId();\n const players = [\n createFakePlayer(),\n createFakeWitchAlivePlayer({ _id: witchPlayerId }),\n createFakePlayer(),\n ];\n const gameId = createFakeObjectId();\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay() }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordWitchUsePotionsPlay({\n targets: [createFakeGameHistoryRecordPlayTarget({ drankPotion: \"death\" })],\n source: createFakeGameHistoryRecordPlaySource({\n name: \"witch\",\n players,\n }),\n }),\n }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWitchUsePotionsPlay() }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordWitchUsePotionsPlay({\n targets: [createFakeGameHistoryRecordPlayTarget({ drankPotion: \"life\" })],\n source: createFakeGameHistoryRecordPlaySource({\n name: \"witch\",\n players: [\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n ],\n }),\n }),\n }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay() }),\n ];\n await populate(gameHistoryRecords);\n const records = await repositories.gameHistoryRecord.getGameHistoryWitchUsesSpecificPotionRecords(gameId, witchPlayerId, \"life\");\n\n expect(toJSON(records)).toStrictEqual([]);\n });\n\n it(\"should get records of witch using life potion for this gameId when called.\", async() => {\n const witchPlayerId = createFakeObjectId();\n const players = [\n createFakePlayer(),\n createFakeWitchAlivePlayer({ _id: witchPlayerId }),\n createFakePlayer(),\n ];\n const gameId = createFakeObjectId();\n const otherGameId = createFakeObjectId();\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay() }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordWitchUsePotionsPlay({\n targets: [createFakeGameHistoryRecordPlayTarget({ drankPotion: \"life\" })],\n source: createFakeGameHistoryRecordPlaySource({\n name: \"witch\",\n players,\n }),\n }),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordWitchUsePotionsPlay({\n targets: [\n createFakeGameHistoryRecordPlayTarget({ drankPotion: \"life\" }),\n createFakeGameHistoryRecordPlayTarget({ drankPotion: \"death\" }),\n ],\n source: createFakeGameHistoryRecordPlaySource({\n name: \"witch\",\n players,\n }),\n }),\n }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWitchUsePotionsPlay() }),\n createFakeGameHistoryRecord({\n gameId: otherGameId,\n play: createFakeGameHistoryRecordWitchUsePotionsPlay({\n targets: [createFakeGameHistoryRecordPlayTarget({ drankPotion: \"life\" })],\n source: createFakeGameHistoryRecordPlaySource({\n name: \"witch\",\n players,\n }),\n }),\n }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay() }),\n ];\n await populate(gameHistoryRecords);\n const records = await repositories.gameHistoryRecord.getGameHistoryWitchUsesSpecificPotionRecords(gameId, witchPlayerId, \"life\");\n const expectedRecords = [gameHistoryRecords[1], gameHistoryRecords[2]];\n\n expect(toJSON(records)).toStrictEqual(toJSON(expectedRecords) as GameHistoryRecord[]);\n });\n\n it(\"should get no record when there are no witch using death potion play.\", async() => {\n const witchPlayerId = createFakeObjectId();\n const players = [\n createFakePlayer(),\n createFakeWitchAlivePlayer({ _id: witchPlayerId }),\n createFakePlayer(),\n ];\n const gameId = createFakeObjectId();\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay() }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordWitchUsePotionsPlay({\n targets: [createFakeGameHistoryRecordPlayTarget({ drankPotion: \"life\" })],\n source: createFakeGameHistoryRecordPlaySource({\n name: \"witch\",\n players,\n }),\n }),\n }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWitchUsePotionsPlay() }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay() }),\n ];\n await populate(gameHistoryRecords);\n const records = await repositories.gameHistoryRecord.getGameHistoryWitchUsesSpecificPotionRecords(gameId, witchPlayerId, \"death\");\n\n expect(toJSON(records)).toStrictEqual([]);\n });\n\n it(\"should get records of witch using death potion for this gameId when called.\", async() => {\n const witchPlayerId = createFakeObjectId();\n const players = [\n createFakePlayer(),\n createFakeWitchAlivePlayer({ _id: witchPlayerId }),\n createFakePlayer(),\n ];\n const gameId = createFakeObjectId();\n const otherGameId = createFakeObjectId();\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay() }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordWitchUsePotionsPlay({\n targets: [createFakeGameHistoryRecordPlayTarget({ drankPotion: \"death\" })],\n source: createFakeGameHistoryRecordPlaySource({\n name: \"witch\",\n players,\n }),\n }),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordWitchUsePotionsPlay({\n targets: [\n createFakeGameHistoryRecordPlayTarget({ drankPotion: \"life\" }),\n createFakeGameHistoryRecordPlayTarget({ drankPotion: \"death\" }),\n ],\n source: createFakeGameHistoryRecordPlaySource({\n name: \"witch\",\n players,\n }),\n }),\n }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWitchUsePotionsPlay() }),\n createFakeGameHistoryRecord({\n gameId: otherGameId,\n play: createFakeGameHistoryRecordWitchUsePotionsPlay({\n targets: [createFakeGameHistoryRecordPlayTarget({ drankPotion: \"death\" })],\n source: createFakeGameHistoryRecordPlaySource({\n name: \"witch\",\n players,\n }),\n }),\n }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay() }),\n ];\n await populate(gameHistoryRecords);\n const records = await repositories.gameHistoryRecord.getGameHistoryWitchUsesSpecificPotionRecords(gameId, witchPlayerId, \"death\");\n const expectedRecords = [gameHistoryRecords[1], gameHistoryRecords[2]];\n\n expect(toJSON(records)).toStrictEqual(toJSON(expectedRecords) as GameHistoryRecord[]);\n });\n });\n\n describe(\"getGameHistoryAccursedWolfFatherInfectsWithTargetRecords\", () => {\n it(\"should return no record when there is no infect play in the history.\", async() => {\n const accursedWolfFatherId = createFakeObjectId();\n const gameId = createFakeObjectId();\n await populate([\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordWerewolvesEatPlay({ targets: [createFakeGameHistoryRecordPlayTarget({ player: createFakePlayer() })] }),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordWitchUsePotionsPlay({ targets: [createFakeGameHistoryRecordPlayTarget({ player: createFakePlayer() })] }),\n }),\n ]);\n const records = await repositories.gameHistoryRecord.getGameHistoryAccursedWolfFatherInfectsWithTargetRecords(gameId, accursedWolfFatherId);\n\n expect(toJSON(records)).toStrictEqual([]);\n });\n\n it(\"should return no record when there gameId is not the good one.\", async() => {\n const accursedWolfFatherId = createFakeObjectId();\n const players = [\n createFakePlayer(),\n createFakePlayer({ _id: accursedWolfFatherId }),\n createFakePlayer(),\n ];\n const gameId = createFakeObjectId();\n const otherGameId = createFakeObjectId();\n await populate([\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordAccursedWolfFatherInfectsPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"accursed-wolf-father\",\n players: [players[1]],\n }),\n targets: [createFakeGameHistoryRecordPlayTarget({ player: players[2] })],\n }),\n }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWitchUsePotionsPlay() }),\n ]);\n const records = await repositories.gameHistoryRecord.getGameHistoryAccursedWolfFatherInfectsWithTargetRecords(otherGameId, accursedWolfFatherId);\n\n expect(toJSON(records)).toStrictEqual([]);\n });\n\n it(\"should return records of accursed wolf father infecting with target for this gameId when called.\", async() => {\n const accursedWolfFatherId = createFakeObjectId();\n const players = [\n createFakePlayer(),\n createFakePlayer({ _id: accursedWolfFatherId }),\n createFakePlayer(),\n ];\n const gameId = createFakeObjectId();\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordAccursedWolfFatherInfectsPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"accursed-wolf-father\",\n players: [players[1]],\n }),\n targets: [createFakeGameHistoryRecordPlayTarget({ player: players[2] })],\n }),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordWitchUsePotionsPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"witch\",\n players: [players[1]],\n }),\n targets: [createFakeGameHistoryRecordPlayTarget({ player: players[2] })],\n }),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordAccursedWolfFatherInfectsPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"accursed-wolf-father\",\n players: [players[1]],\n }),\n targets: [createFakeGameHistoryRecordPlayTarget({ player: players[2] })],\n }),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordWitchUsePotionsPlay(),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordAccursedWolfFatherInfectsPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"accursed-wolf-father\",\n players: [createFakePlayer()],\n }),\n targets: [createFakeGameHistoryRecordPlayTarget({ player: createFakePlayer() })],\n }),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordAccursedWolfFatherInfectsPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"accursed-wolf-father\",\n players: [players[1]],\n }),\n }),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordAccursedWolfFatherInfectsPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"accursed-wolf-father\",\n players: [players[1]],\n }),\n targets: [],\n }),\n }),\n ];\n await populate(gameHistoryRecords);\n const records = await repositories.gameHistoryRecord.getGameHistoryAccursedWolfFatherInfectsWithTargetRecords(gameId, accursedWolfFatherId);\n const expectedRecords = [gameHistoryRecords[0], gameHistoryRecords[2]];\n\n expect(toJSON(records)).toStrictEqual(toJSON(expectedRecords) as GameHistoryRecord[]);\n });\n });\n\n describe(\"getLastGameHistoryAccursedWolfFatherInfectsRecord\", () => {\n it(\"should return no record when there is no infect play in the history.\", async() => {\n const accursedWolfFatherId = createFakeObjectId();\n const gameId = createFakeObjectId();\n await populate([\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWerewolvesEatPlay() }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWitchUsePotionsPlay() }),\n ]);\n\n await expect(repositories.gameHistoryRecord.getLastGameHistoryAccursedWolfFatherInfectsRecord(gameId, accursedWolfFatherId)).resolves.toBeNull();\n });\n\n it(\"should return no record when there gameId is not the good one.\", async() => {\n const accursedWolfFatherId = createFakeObjectId();\n const players = [\n createFakePlayer(),\n createFakePlayer({ _id: accursedWolfFatherId }),\n createFakePlayer(),\n ];\n const gameId = createFakeObjectId();\n const otherGameId = createFakeObjectId();\n await populate([\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordAccursedWolfFatherInfectsPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"accursed-wolf-father\",\n players,\n }),\n }),\n }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWitchUsePotionsPlay() }),\n ]);\n\n await expect(repositories.gameHistoryRecord.getLastGameHistoryAccursedWolfFatherInfectsRecord(otherGameId, accursedWolfFatherId)).resolves.toBeNull();\n });\n\n it(\"should return the last accursed wolf father infects game history play record when called.\", async() => {\n const accursedWolfFatherId = createFakeObjectId();\n const players = [\n createFakePlayer(),\n createFakePlayer({ _id: accursedWolfFatherId }),\n createFakePlayer(),\n ];\n const gameId = createFakeObjectId();\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordAccursedWolfFatherInfectsPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"accursed-wolf-father\",\n players,\n }),\n }),\n createdAt: new Date(\"2020-01-01\"),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordWitchUsePotionsPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"witch\",\n players,\n }),\n }),\n createdAt: new Date(\"2021-01-01\"),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordAccursedWolfFatherInfectsPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"accursed-wolf-father\",\n players,\n }),\n }),\n createdAt: new Date(\"2022-01-01\"),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordWitchUsePotionsPlay(),\n createdAt: new Date(\"2023-01-01\"),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordAccursedWolfFatherInfectsPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"accursed-wolf-father\",\n players: [createFakePlayer()],\n }),\n }),\n createdAt: new Date(\"2024-01-01\"),\n }),\n ];\n await populate(gameHistoryRecords);\n const record = await repositories.gameHistoryRecord.getLastGameHistoryAccursedWolfFatherInfectsRecord(gameId, accursedWolfFatherId);\n\n expect(toJSON(record)).toStrictEqual(toJSON(gameHistoryRecords[2]) as GameHistoryRecord);\n });\n });\n\n describe(\"getGameHistoryStutteringJudgeRequestsAnotherVoteRecords\", () => {\n it(\"should get no record when there are no vote with judge request play.\", async() => {\n const stutteringJudgePlayerId = createFakeObjectId();\n const players = [\n createFakePlayer(),\n createFakeStutteringJudgeAlivePlayer({ _id: stutteringJudgePlayerId }),\n createFakePlayer(),\n ];\n const gameId = createFakeObjectId();\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay({ didJudgeRequestAnotherVote: false }) }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWitchUsePotionsPlay() }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordDefenderProtectPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"survivors\",\n players: [\n players[1],\n players[2],\n ],\n }),\n }),\n }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay() }),\n ];\n await populate(gameHistoryRecords);\n const records = await repositories.gameHistoryRecord.getGameHistoryStutteringJudgeRequestsAnotherVoteRecords(gameId, stutteringJudgePlayerId);\n\n expect(toJSON(records)).toStrictEqual([]);\n });\n\n it(\"should get records of stuttering judge requesting another vote for this gameId when called.\", async() => {\n const stutteringJudgePlayerId = createFakeObjectId();\n const players = [\n createFakePlayer(),\n createFakeStutteringJudgeAlivePlayer({ _id: stutteringJudgePlayerId }),\n createFakePlayer(),\n ];\n const gameId = createFakeObjectId();\n const otherGameId = createFakeObjectId();\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordSurvivorsVotePlay({ didJudgeRequestAnotherVote: true }),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordStutteringJudgeRequestsAnotherVotePlay({\n didJudgeRequestAnotherVote: true,\n source: createFakeGameHistoryRecordPlaySource({\n name: \"stuttering-judge\",\n players,\n }),\n }),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordStutteringJudgeRequestsAnotherVotePlay({\n didJudgeRequestAnotherVote: false,\n source: createFakeGameHistoryRecordPlaySource({\n name: \"stuttering-judge\",\n players,\n }),\n }),\n }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWitchUsePotionsPlay() }),\n createFakeGameHistoryRecord({\n gameId: otherGameId,\n play: createFakeGameHistoryRecordStutteringJudgeRequestsAnotherVotePlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"stuttering-judge\",\n players,\n }),\n didJudgeRequestAnotherVote: true,\n }),\n }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay() }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordStutteringJudgeRequestsAnotherVotePlay({\n didJudgeRequestAnotherVote: true,\n source: createFakeGameHistoryRecordPlaySource({\n name: \"stuttering-judge\",\n players: [\n createFakePlayer(),\n createFakePlayer(),\n ],\n }),\n }),\n }),\n ];\n await populate(gameHistoryRecords);\n const records = await repositories.gameHistoryRecord.getGameHistoryStutteringJudgeRequestsAnotherVoteRecords(gameId, stutteringJudgePlayerId);\n const expectedRecords = [gameHistoryRecords[1]];\n\n expect(toJSON(records)).toStrictEqual(toJSON(expectedRecords) as GameHistoryRecord[]);\n });\n });\n\n describe(\"getGameHistoryWerewolvesEatElderRecords\", () => {\n it(\"should get no record when there are no eat play.\", async() => {\n const elderPlayerId = createFakeObjectId();\n const gameId = createFakeObjectId();\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay({ didJudgeRequestAnotherVote: false }) }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWitchUsePotionsPlay() }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordDefenderProtectPlay() }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay() }),\n ];\n await populate(gameHistoryRecords);\n const records = await repositories.gameHistoryRecord.getGameHistoryWerewolvesEatElderRecords(gameId, elderPlayerId);\n\n expect(toJSON(records)).toStrictEqual([]);\n });\n\n it(\"should get records of elder eaten by any kind of werewolves for this gameId when called.\", async() => {\n const elderPlayerId = createFakeObjectId();\n const players = [\n createFakePlayer(),\n createFakeElderAlivePlayer({ _id: elderPlayerId }),\n createFakePlayer(),\n ];\n const gameId = createFakeObjectId();\n const otherGameId = createFakeObjectId();\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay() }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordWerewolvesEatPlay({\n targets: [\n createFakeGameHistoryRecordPlayTarget({ player: players[1] }),\n createFakeGameHistoryRecordPlayTarget({ player: players[0] }),\n ],\n }),\n }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay({ didJudgeRequestAnotherVote: false }) }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordBigBadWolfEatPlay({ targets: [createFakeGameHistoryRecordPlayTarget({ player: players[1] })] }) }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWitchUsePotionsPlay() }),\n createFakeGameHistoryRecord({\n gameId: otherGameId,\n play: createFakeGameHistoryRecordWerewolvesEatPlay({\n targets: [\n createFakeGameHistoryRecordPlayTarget({ player: players[1] }),\n createFakeGameHistoryRecordPlayTarget({ player: players[0] }),\n ],\n }),\n }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordBigBadWolfEatPlay({ targets: [createFakeGameHistoryRecordPlayTarget({ player: players[0] })] }) }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay() }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordWerewolvesEatPlay({\n targets: [\n createFakeGameHistoryRecordPlayTarget({ player: players[2] }),\n createFakeGameHistoryRecordPlayTarget({ player: players[0] }),\n ],\n }),\n }),\n ];\n await populate(gameHistoryRecords);\n const records = await repositories.gameHistoryRecord.getGameHistoryWerewolvesEatElderRecords(gameId, elderPlayerId);\n const expectedRecords = [gameHistoryRecords[1], gameHistoryRecords[3]];\n\n expect(toJSON(records)).toStrictEqual(toJSON(expectedRecords) as GameHistoryRecord[]);\n });\n });\n\n describe(\"getGameHistoryElderProtectedFromWerewolvesRecords\", () => {\n it(\"should get game history where elder is protected from werewolves records for gameId when called.\", async() => {\n const elderPlayerId = createFakeObjectId();\n const players = [\n createFakePlayer(),\n createFakeElderAlivePlayer({ _id: elderPlayerId }),\n createFakePlayer(),\n ];\n const gameId = createFakeObjectId();\n const otherGameId = createFakeObjectId();\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay({ didJudgeRequestAnotherVote: false }), createdAt: new Date(\"2023-01-01\") }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordDefenderProtectPlay({\n targets: [\n createFakeGameHistoryRecordPlayTarget({ player: players[0] }),\n createFakeGameHistoryRecordPlayTarget({ player: players[1] }),\n ],\n }),\n }),\n createFakeGameHistoryRecord({\n gameId: otherGameId,\n play: createFakeGameHistoryRecordDefenderProtectPlay({ targets: [createFakeGameHistoryRecordPlayTarget({ player: players[1] })] }),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordDefenderProtectPlay({ targets: [createFakeGameHistoryRecordPlayTarget({ player: players[0] })] }),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordWitchUsePotionsPlay({\n targets: [\n createFakeGameHistoryRecordPlayTarget({ player: players[0], drankPotion: \"life\" }),\n createFakeGameHistoryRecordPlayTarget({ player: players[1], drankPotion: \"death\" }),\n ],\n }),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordWitchUsePotionsPlay({\n targets: [\n createFakeGameHistoryRecordPlayTarget({ player: players[0], drankPotion: \"death\" }),\n createFakeGameHistoryRecordPlayTarget({ player: players[1], drankPotion: \"life\" }),\n ],\n }),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordDefenderProtectPlay({\n targets: [\n createFakeGameHistoryRecordPlayTarget({ player: players[0] }),\n createFakeGameHistoryRecordPlayTarget({ player: players[2] }),\n ],\n }),\n }),\n ];\n await populate(gameHistoryRecords);\n const records = await repositories.gameHistoryRecord.getGameHistoryElderProtectedFromWerewolvesRecords(gameId, elderPlayerId);\n const expectedRecords = [gameHistoryRecords[1], gameHistoryRecords[5]];\n\n expect(toJSON(records)).toStrictEqual(toJSON(expectedRecords) as GameHistoryRecord[]);\n });\n });\n\n describe(\"getPreviousGameHistoryRecord\", () => {\n it(\"should get no record when game doesn't have history yet.\", async() => {\n const gameId = createFakeObjectId();\n const otherGameId = createFakeObjectId();\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ gameId: otherGameId, play: createFakeGameHistoryRecordSurvivorsVotePlay({ didJudgeRequestAnotherVote: false }) }),\n createFakeGameHistoryRecord({ gameId: otherGameId, play: createFakeGameHistoryRecordWitchUsePotionsPlay() }),\n createFakeGameHistoryRecord({ gameId: otherGameId, play: createFakeGameHistoryRecordDefenderProtectPlay() }),\n createFakeGameHistoryRecord({ gameId: otherGameId, play: createFakeGameHistoryRecordSurvivorsVotePlay() }),\n ];\n await populate(gameHistoryRecords);\n const records = await repositories.gameHistoryRecord.getPreviousGameHistoryRecord(gameId);\n\n expect(toJSON(records)).toBeNull();\n });\n\n it(\"should get previous game history record for gameId when called.\", async() => {\n const gameId = createFakeObjectId();\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay(), createdAt: new Date(\"2020-01-01\") }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordWitchUsePotionsPlay(), createdAt: new Date(\"2021-01-01\") }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordDefenderProtectPlay(), createdAt: new Date(\"2022-01-01\") }),\n createFakeGameHistoryRecord({ gameId, play: createFakeGameHistoryRecordSurvivorsVotePlay(), createdAt: new Date(\"2023-01-01\") }),\n ];\n await populate(gameHistoryRecords);\n const record = await repositories.gameHistoryRecord.getPreviousGameHistoryRecord(gameId);\n\n expect(toJSON(record)).toStrictEqual(toJSON(gameHistoryRecords[3]) as GameHistoryRecord);\n });\n });\n\n describe(\"getGameHistoryRecordsForTurnAndPhases\", () => {\n it(\"should get 3 records when called with gameId, turn and day phase.\", async() => {\n const gameId = createFakeObjectId();\n const otherGameId = createFakeObjectId();\n const play = createFakeGameHistoryRecordPlay({ source: createFakeGameHistoryRecordPlaySource({ name: \"werewolves\" }) });\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ gameId, turn: 1, phase: createFakeGamePhase({ name: \"day\" }), play }),\n createFakeGameHistoryRecord({ gameId, turn: 1, phase: createFakeGamePhase({ name: \"night\" }), play }),\n createFakeGameHistoryRecord({ gameId, turn: 1, phase: createFakeGamePhase({ name: \"day\" }), play }),\n createFakeGameHistoryRecord({ gameId, turn: 1, phase: createFakeGamePhase({ name: \"twilight\" }), play }),\n createFakeGameHistoryRecord({ gameId, turn: 2, phase: createFakeGamePhase({ name: \"day\" }), play }),\n createFakeGameHistoryRecord({ gameId, turn: 1, phase: createFakeGamePhase({ name: \"day\" }), play }),\n createFakeGameHistoryRecord({ gameId: otherGameId, phase: createFakeGamePhase({ name: \"day\" }), turn: 1, play }),\n ];\n await populate(gameHistoryRecords);\n const records = await repositories.gameHistoryRecord.getGameHistoryRecordsForTurnAndPhases(gameId, 1, [\"day\"]);\n const expectedRecords = [gameHistoryRecords[0], gameHistoryRecords[2], gameHistoryRecords[5]];\n\n expect(toJSON(records)).toStrictEqual(toJSON(expectedRecords) as GameHistoryRecord[]);\n });\n\n it(\"should get 2 records when called with gameId, turn and night and twilight phases.\", async() => {\n const gameId = createFakeObjectId();\n const otherGameId = createFakeObjectId();\n const play = createFakeGameHistoryRecordPlay({ source: createFakeGameHistoryRecordPlaySource({ name: \"werewolves\" }) });\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({ gameId, turn: 1, phase: createFakeGamePhase({ name: \"day\" }), play }),\n createFakeGameHistoryRecord({ gameId, turn: 1, phase: createFakeGamePhase({ name: \"night\" }), play }),\n createFakeGameHistoryRecord({ gameId, turn: 1, phase: createFakeGamePhase({ name: \"day\" }), play }),\n createFakeGameHistoryRecord({ gameId, turn: 1, phase: createFakeGamePhase({ name: \"twilight\" }), play }),\n createFakeGameHistoryRecord({ gameId, turn: 3, phase: createFakeGamePhase({ name: \"twilight\" }), play }),\n createFakeGameHistoryRecord({ gameId, turn: 2, phase: createFakeGamePhase({ name: \"day\" }), play }),\n createFakeGameHistoryRecord({ gameId, turn: 1, phase: createFakeGamePhase({ name: \"day\" }), play }),\n createFakeGameHistoryRecord({ gameId: otherGameId, turn: 1, phase: createFakeGamePhase({ name: \"night\" }), play }),\n createFakeGameHistoryRecord({ gameId: otherGameId, phase: createFakeGamePhase({ name: \"day\" }), turn: 1, play }),\n ];\n await populate(gameHistoryRecords);\n const records = await repositories.gameHistoryRecord.getGameHistoryRecordsForTurnAndPhases(gameId, 1, [\"night\", \"twilight\"]);\n const expectedRecords = [gameHistoryRecords[1], gameHistoryRecords[3]];\n\n expect(toJSON(records)).toStrictEqual(toJSON(expectedRecords) as GameHistoryRecord[]);\n });\n });\n\n describe(\"getGameHistoryGamePlayRecords\", () => {\n const gameId = createFakeObjectId();\n const otherGameId = createFakeObjectId();\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordPlay({\n action: \"charm\",\n source: createFakeGameHistoryRecordPlaySource({ name: \"cupid\" }),\n }),\n }),\n createFakeGameHistoryRecord({\n gameId: otherGameId,\n play: createFakeGameHistoryRecordPlay({\n action: \"charm\",\n source: createFakeGameHistoryRecordPlaySource({ name: \"pied-piper\" }),\n }),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordPlay({\n action: \"charm\",\n source: createFakeGameHistoryRecordPlaySource({ name: \"cupid\" }),\n causes: [\"angel-presence\"],\n }),\n }),\n ];\n\n beforeEach(async() => {\n await populate(gameHistoryRecords);\n });\n\n it.each<{\n test: string;\n gameId: Types.ObjectId;\n gamePlay: GamePlay;\n expectedRecords: GameHistoryRecord[];\n }>([\n {\n test: \"should get one record when cupid charming.\",\n gameId,\n gamePlay: createFakeGamePlayCupidCharms(),\n expectedRecords: [gameHistoryRecords[0]],\n },\n {\n test: \"should get no record when pied-piper charming but on wrong game.\",\n gameId,\n gamePlay: createFakeGamePlayPiedPiperCharms(),\n expectedRecords: [],\n },\n {\n test: \"should get one record when cupid charming because of angel presence.\",\n gameId,\n gamePlay: createFakeGamePlayCupidCharms({ causes: [\"angel-presence\"] }),\n expectedRecords: [gameHistoryRecords[2]],\n },\n ])(`$test`, async({ gameId: id, gamePlay, expectedRecords }) => {\n const records = await repositories.gameHistoryRecord.getGameHistoryGamePlayRecords(id, gamePlay);\n\n expect(toJSON(records)).toStrictEqual(toJSON(expectedRecords) as GameHistoryRecord[]);\n });\n });\n\n describe(\"getGameHistoryGamePlayMadeByPlayerRecords\", () => {\n const gameId = createFakeObjectId();\n const otherGameId = createFakeObjectId();\n const player = createFakePlayer();\n\n const gameHistoryRecords = [\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordPlay({\n action: \"charm\",\n source: createFakeGameHistoryRecordPlaySource({\n name: \"cupid\",\n players: [\n createFakePlayer(),\n player,\n createFakePlayer(),\n ],\n }),\n }),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordPlay({\n action: \"eat\",\n source: createFakeGameHistoryRecordPlaySource({\n name: \"werewolves\",\n players: [\n createFakePlayer(),\n createFakePlayer(),\n ],\n }),\n }),\n }),\n createFakeGameHistoryRecord({\n gameId: otherGameId,\n play: createFakeGameHistoryRecordPlay({\n action: \"charm\",\n source: createFakeGameHistoryRecordPlaySource({\n name: \"pied-piper\",\n players: [\n createFakePlayer(),\n player,\n createFakePlayer(),\n ],\n }),\n }),\n }),\n createFakeGameHistoryRecord({\n gameId,\n play: createFakeGameHistoryRecordPlay({\n action: \"charm\",\n source: createFakeGameHistoryRecordPlaySource({\n name: \"cupid\",\n players: [\n createFakePlayer(),\n player,\n createFakePlayer(),\n ],\n }),\n causes: [\"angel-presence\"],\n }),\n }),\n ];\n\n beforeEach(async() => {\n await populate(gameHistoryRecords);\n });\n\n it.each<{\n test: string;\n gameId: Types.ObjectId;\n gamePlay: GamePlay;\n expectedRecords: GameHistoryRecord[];\n }>([\n {\n test: \"should get one record when cupid charming.\",\n gameId,\n gamePlay: createFakeGamePlayCupidCharms(),\n expectedRecords: [gameHistoryRecords[0]],\n },\n {\n test: \"should get no record when pied-piper charming but on wrong game.\",\n gameId,\n gamePlay: createFakeGamePlayPiedPiperCharms(),\n expectedRecords: [],\n },\n {\n test: \"should get no record when werewolves eating but player is not found in game play.\",\n gameId,\n gamePlay: createFakeGamePlayWerewolvesEat(),\n expectedRecords: [],\n },\n {\n test: \"should get one record when cupid charming because of angel presence.\",\n gameId,\n gamePlay: createFakeGamePlayCupidCharms({ causes: [\"angel-presence\"] }),\n expectedRecords: [gameHistoryRecords[3]],\n },\n ])(`$test`, async({ gameId: id, gamePlay, expectedRecords }) => {\n const records = await repositories.gameHistoryRecord.getGameHistoryGamePlayMadeByPlayerRecords(id, gamePlay, player);\n\n expect(toJSON(records)).toStrictEqual(toJSON(expectedRecords) as GameHistoryRecord[]);\n });\n });\n});" }, "tests/unit/specs/modules/game/providers/services/game-history/game-history-record-to-insert-generator.service.spec.ts": { "tests": [ @@ -193073,7 +193075,7 @@ "location": { "start": { "column": 6, - "line": 102 + "line": 105 } } }, @@ -193083,7 +193085,7 @@ "location": { "start": { "column": 6, - "line": 114 + "line": 117 } } }, @@ -193093,7 +193095,7 @@ "location": { "start": { "column": 6, - "line": 131 + "line": 134 } } }, @@ -193103,7 +193105,7 @@ "location": { "start": { "column": 6, - "line": 142 + "line": 145 } } }, @@ -193113,7 +193115,7 @@ "location": { "start": { "column": 6, - "line": 153 + "line": 156 } } }, @@ -193123,7 +193125,7 @@ "location": { "start": { "column": 6, - "line": 164 + "line": 167 } } }, @@ -193133,7 +193135,7 @@ "location": { "start": { "column": 6, - "line": 175 + "line": 178 } } }, @@ -193143,7 +193145,7 @@ "location": { "start": { "column": 6, - "line": 186 + "line": 189 } } }, @@ -193153,7 +193155,7 @@ "location": { "start": { "column": 6, - "line": 209 + "line": 212 } } }, @@ -193163,7 +193165,7 @@ "location": { "start": { "column": 6, - "line": 225 + "line": 228 } } }, @@ -193173,7 +193175,7 @@ "location": { "start": { "column": 6, - "line": 253 + "line": 256 } } }, @@ -193183,7 +193185,7 @@ "location": { "start": { "column": 6, - "line": 280 + "line": 283 } } }, @@ -193193,7 +193195,7 @@ "location": { "start": { "column": 6, - "line": 309 + "line": 312 } } }, @@ -193203,7 +193205,7 @@ "location": { "start": { "column": 6, - "line": 331 + "line": 334 } } }, @@ -193213,7 +193215,7 @@ "location": { "start": { "column": 6, - "line": 359 + "line": 362 } } }, @@ -193223,7 +193225,7 @@ "location": { "start": { "column": 6, - "line": 386 + "line": 389 } } }, @@ -193233,7 +193235,7 @@ "location": { "start": { "column": 6, - "line": 412 + "line": 415 } } }, @@ -193243,7 +193245,7 @@ "location": { "start": { "column": 6, - "line": 438 + "line": 441 } } }, @@ -193253,7 +193255,7 @@ "location": { "start": { "column": 6, - "line": 497 + "line": 500 } } }, @@ -193263,7 +193265,7 @@ "location": { "start": { "column": 6, - "line": 519 + "line": 522 } } }, @@ -193273,7 +193275,7 @@ "location": { "start": { "column": 6, - "line": 541 + "line": 544 } } }, @@ -193283,7 +193285,7 @@ "location": { "start": { "column": 6, - "line": 585 + "line": 588 } } }, @@ -193293,7 +193295,7 @@ "location": { "start": { "column": 6, - "line": 620 + "line": 623 } } }, @@ -193303,7 +193305,7 @@ "location": { "start": { "column": 6, - "line": 652 + "line": 655 } } }, @@ -193313,7 +193315,7 @@ "location": { "start": { "column": 6, - "line": 659 + "line": 662 } } }, @@ -193323,7 +193325,7 @@ "location": { "start": { "column": 6, - "line": 677 + "line": 680 } } }, @@ -193333,7 +193335,7 @@ "location": { "start": { "column": 6, - "line": 708 + "line": 711 } } }, @@ -193343,7 +193345,7 @@ "location": { "start": { "column": 6, - "line": 735 + "line": 738 } } }, @@ -193353,7 +193355,7 @@ "location": { "start": { "column": 6, - "line": 758 + "line": 761 } } }, @@ -193363,7 +193365,7 @@ "location": { "start": { "column": 6, - "line": 781 + "line": 784 } } }, @@ -193373,7 +193375,7 @@ "location": { "start": { "column": 6, - "line": 805 + "line": 808 } } }, @@ -193383,7 +193385,7 @@ "location": { "start": { "column": 6, - "line": 829 + "line": 832 } } }, @@ -193393,7 +193395,7 @@ "location": { "start": { "column": 6, - "line": 857 + "line": 860 } } }, @@ -193403,7 +193405,7 @@ "location": { "start": { "column": 6, - "line": 881 + "line": 884 } } }, @@ -193413,7 +193415,7 @@ "location": { "start": { "column": 6, - "line": 905 + "line": 908 } } }, @@ -193423,7 +193425,7 @@ "location": { "start": { "column": 6, - "line": 929 + "line": 932 } } }, @@ -193433,7 +193435,7 @@ "location": { "start": { "column": 6, - "line": 959 + "line": 962 } } }, @@ -193443,7 +193445,7 @@ "location": { "start": { "column": 6, - "line": 979 + "line": 982 } } }, @@ -193453,7 +193455,7 @@ "location": { "start": { "column": 6, - "line": 996 + "line": 999 } } }, @@ -193463,7 +193465,7 @@ "location": { "start": { "column": 6, - "line": 1013 + "line": 1016 } } }, @@ -193473,7 +193475,7 @@ "location": { "start": { "column": 6, - "line": 1030 + "line": 1033 } } }, @@ -193483,12 +193485,12 @@ "location": { "start": { "column": 6, - "line": 1049 + "line": 1052 } } } ], - "source": "import type { MakeGamePlayTargetWithRelationsDto } from \"@/modules/game/dto/make-game-play/make-game-play-target/make-game-play-target-with-relations.dto\";\nimport { createGamePlaySurvivorsElectSheriff } from \"@/modules/game/helpers/game-play/game-play.factory\";\nimport { GameHistoryRecordToInsertGeneratorService } from \"@/modules/game/providers/services/game-history/game-history-record-to-insert-generator.service\";\nimport { GamePlayVoteService } from \"@/modules/game/providers/services/game-play/game-play-vote/game-play-vote.service\";\nimport type { GameHistoryRecordPlaySource } from \"@/modules/game/schemas/game-history-record/game-history-record-play/game-history-record-play-source/game-history-record-play-source.schema\";\nimport type { GameHistoryRecordPlayVoting } from \"@/modules/game/schemas/game-history-record/game-history-record-play/game-history-record-play-voting/game-history-record-play-voting.schema\";\nimport type { GameHistoryRecordPlay } from \"@/modules/game/schemas/game-history-record/game-history-record-play/game-history-record-play.schema\";\nimport type { GameHistoryRecordPlayerAttributeAlteration } from \"@/modules/game/schemas/game-history-record/game-history-record-player-attribute-alteration/game-history-record-player-attribute-alteration.schema\";\nimport type { Player } from \"@/modules/game/schemas/player/player.schema\";\nimport type { GameHistoryRecordToInsert } from \"@/modules/game/types/game-history-record/game-history-record.types\";\nimport * as UnexpectedExceptionFactory from \"@/shared/exception/helpers/unexpected-exception.factory\";\nimport type { TestingModule } from \"@nestjs/testing\";\nimport { Test } from \"@nestjs/testing\";\nimport { createFakeMakeGamePlayTargetWithRelationsDto } from \"@tests/factories/game/dto/make-game-play/make-game-play-with-relations/make-game-play-target-with-relations.dto.factory\";\nimport { createFakeMakeGamePlayWithRelationsDto } from \"@tests/factories/game/dto/make-game-play/make-game-play-with-relations/make-game-play-with-relations.dto.factory\";\nimport { createFakeGameAdditionalCard } from \"@tests/factories/game/schemas/game-additional-card/game-additional-card.schema.factory\";\nimport { createFakeGameHistoryRecordPlay, createFakeGameHistoryRecordPlayerAttributeAlteration, createFakeGameHistoryRecordPlaySource, createFakeGameHistoryRecordPlayTarget, createFakeGameHistoryRecordPlayVote, createFakeGameHistoryRecordPlayVoting } from \"@tests/factories/game/schemas/game-history-record/game-history-record.schema.factory\";\nimport { createFakeGamePhase } from \"@tests/factories/game/schemas/game-phase/game-phase.schema.factory\";\nimport { createFakeGamePlaySource } from \"@tests/factories/game/schemas/game-play/game-play-source/game-play-source.schema.factory\";\nimport { createFakeGamePlayFoxSniffs, createFakeGamePlaySheriffDelegates, createFakeGamePlaySurvivorsElectSheriff, createFakeGamePlaySurvivorsVote } from \"@tests/factories/game/schemas/game-play/game-play.schema.factory\";\nimport { createFakeGame, createFakeGameWithCurrentPlay } from \"@tests/factories/game/schemas/game.schema.factory\";\nimport { createFakeCharmedByPiedPiperPlayerAttribute, createFakeDrankDeathPotionByWitchPlayerAttribute, createFakePlayerAttributeActivation, createFakeSeenBySeerPlayerAttribute, createFakeSheriffBySurvivorsPlayerAttribute } from \"@tests/factories/game/schemas/player/player-attribute/player-attribute.schema.factory\";\nimport { createFakePlayerDeathPotionByWitchDeath, createFakePlayerVoteBySurvivorsDeath, createFakePlayerVoteScapegoatedBySurvivorsDeath } from \"@tests/factories/game/schemas/player/player-death/player-death.schema.factory\";\nimport { createFakeAngelAlivePlayer, createFakeHunterAlivePlayer, createFakeSeerAlivePlayer, createFakeVillagerAlivePlayer, createFakeWerewolfAlivePlayer } from \"@tests/factories/game/schemas/player/player-with-role.schema.factory\";\nimport { createFakeDeadPlayer, createFakePlayer, createFakePlayerRole, createFakePlayerSide } from \"@tests/factories/game/schemas/player/player.schema.factory\";\nimport { createFakeGameHistoryRecordToInsert } from \"@tests/factories/game/types/game-history-record/game-history-record.type.factory\";\nimport { createFakeObjectId } from \"@tests/factories/shared/mongoose/mongoose.factory\";\n\ndescribe(\"Game History Record To Insert Generator Service\", () => {\n let mocks: {\n gameHistoryRecordToInsertGeneratorService: {\n generateCurrentGameHistoryRecordPlayToInsert: jest.SpyInstance;\n generateCurrentGameHistoryRecordRevealedPlayersToInsert: jest.SpyInstance;\n generateCurrentGameHistoryRecordSwitchedSidePlayersToInsert: jest.SpyInstance;\n generateCurrentGameHistoryRecordDeadPlayersToInsert: jest.SpyInstance;\n generateCurrentGameHistoryRecordPlayVotingToInsert: jest.SpyInstance;\n generateCurrentGameHistoryRecordPlayVotingResultToInsert: jest.SpyInstance;\n generateCurrentGameHistoryRecordPlayTargetsToInsert: jest.SpyInstance;\n generateCurrentGameHistoryRecordPlaySourceToInsert: jest.SpyInstance;\n generateCurrentGameHistoryRecordPlayerAttributeAlterationsToInsert: jest.SpyInstance;\n generateCurrentGameHistoryRecordAttachedPlayerAttributesToInsertForPlayer: jest.SpyInstance;\n generateCurrentGameHistoryRecordDetachedPlayerAttributesToInsertForPlayer: jest.SpyInstance;\n generateCurrentGameHistoryRecordActivatedPlayerAttributesToInsertForPlayer: jest.SpyInstance;\n };\n gamePlayVoteService: {\n getGamePlayVoting: jest.SpyInstance;\n getNominatedPlayers: jest.SpyInstance;\n };\n unexpectedExceptionFactory: {\n createNoCurrentGamePlayUnexpectedException: jest.SpyInstance;\n };\n };\n let services: { gameHistoryRecordToInsertGenerator: GameHistoryRecordToInsertGeneratorService };\n\n beforeEach(async() => {\n mocks = {\n gameHistoryRecordToInsertGeneratorService: {\n generateCurrentGameHistoryRecordPlayToInsert: jest.fn(),\n generateCurrentGameHistoryRecordRevealedPlayersToInsert: jest.fn(),\n generateCurrentGameHistoryRecordSwitchedSidePlayersToInsert: jest.fn(),\n generateCurrentGameHistoryRecordDeadPlayersToInsert: jest.fn(),\n generateCurrentGameHistoryRecordPlayVotingToInsert: jest.fn(),\n generateCurrentGameHistoryRecordPlayVotingResultToInsert: jest.fn(),\n generateCurrentGameHistoryRecordPlaySourceToInsert: jest.fn(),\n generateCurrentGameHistoryRecordPlayTargetsToInsert: jest.fn(),\n generateCurrentGameHistoryRecordPlayerAttributeAlterationsToInsert: jest.fn(),\n generateCurrentGameHistoryRecordAttachedPlayerAttributesToInsertForPlayer: jest.fn(),\n generateCurrentGameHistoryRecordDetachedPlayerAttributesToInsertForPlayer: jest.fn(),\n generateCurrentGameHistoryRecordActivatedPlayerAttributesToInsertForPlayer: jest.fn(),\n },\n gamePlayVoteService: {\n getGamePlayVoting: jest.fn(),\n getNominatedPlayers: jest.fn(),\n },\n unexpectedExceptionFactory: {\n createNoCurrentGamePlayUnexpectedException: jest.spyOn(UnexpectedExceptionFactory, \"createNoCurrentGamePlayUnexpectedException\").mockImplementation(),\n },\n };\n const module: TestingModule = await Test.createTestingModule({\n providers: [\n GameHistoryRecordToInsertGeneratorService,\n {\n provide: GamePlayVoteService,\n useValue: mocks.gamePlayVoteService,\n },\n ],\n }).compile();\n\n services = { gameHistoryRecordToInsertGenerator: module.get(GameHistoryRecordToInsertGeneratorService) };\n });\n\n describe(\"generateCurrentGameHistoryRecordToInsert\", () => {\n beforeEach(() => {\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayToInsert = jest.spyOn(services.gameHistoryRecordToInsertGenerator as unknown as { generateCurrentGameHistoryRecordPlayToInsert }, \"generateCurrentGameHistoryRecordPlayToInsert\").mockImplementation();\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordRevealedPlayersToInsert = jest.spyOn(services.gameHistoryRecordToInsertGenerator as unknown as { generateCurrentGameHistoryRecordRevealedPlayersToInsert }, \"generateCurrentGameHistoryRecordRevealedPlayersToInsert\").mockImplementation();\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordSwitchedSidePlayersToInsert = jest.spyOn(services.gameHistoryRecordToInsertGenerator as unknown as { generateCurrentGameHistoryRecordSwitchedSidePlayersToInsert }, \"generateCurrentGameHistoryRecordSwitchedSidePlayersToInsert\").mockImplementation();\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordDeadPlayersToInsert = jest.spyOn(services.gameHistoryRecordToInsertGenerator as unknown as { generateCurrentGameHistoryRecordDeadPlayersToInsert }, \"generateCurrentGameHistoryRecordDeadPlayersToInsert\").mockImplementation();\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayVotingToInsert = jest.spyOn(services.gameHistoryRecordToInsertGenerator as unknown as { generateCurrentGameHistoryRecordPlayVotingToInsert }, \"generateCurrentGameHistoryRecordPlayVotingToInsert\").mockImplementation();\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayerAttributeAlterationsToInsert = jest.spyOn(services.gameHistoryRecordToInsertGenerator as unknown as { generateCurrentGameHistoryRecordPlayerAttributeAlterationsToInsert }, \"generateCurrentGameHistoryRecordPlayerAttributeAlterationsToInsert\").mockImplementation();\n });\n\n it(\"should throw error when there is no current play for the game.\", () => {\n const baseGame = createFakeGame();\n const newGame = createFakeGame();\n const play = createFakeMakeGamePlayWithRelationsDto();\n const interpolations = { gameId: baseGame._id };\n const mockedError = \"error\";\n mocks.unexpectedExceptionFactory.createNoCurrentGamePlayUnexpectedException.mockReturnValue(mockedError);\n\n expect(() => services.gameHistoryRecordToInsertGenerator.generateCurrentGameHistoryRecordToInsert(baseGame, newGame, play)).toThrow(mockedError);\n expect(mocks.unexpectedExceptionFactory.createNoCurrentGamePlayUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"generateCurrentGameHistoryRecordToInsert\", interpolations);\n });\n\n it(\"should generate current game history to insert when called.\", () => {\n const baseGame = createFakeGameWithCurrentPlay();\n const newGame = createFakeGameWithCurrentPlay();\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedCurrentGameHistoryPlayToInsert = createFakeGameHistoryRecordPlay();\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayToInsert.mockReturnValue(expectedCurrentGameHistoryPlayToInsert);\n const expectedCurrentGameHistoryToInsert = createFakeGameHistoryRecordToInsert({\n gameId: baseGame._id,\n turn: baseGame.turn,\n phase: baseGame.phase,\n tick: baseGame.tick,\n play: expectedCurrentGameHistoryPlayToInsert,\n });\n\n expect(services.gameHistoryRecordToInsertGenerator.generateCurrentGameHistoryRecordToInsert(baseGame, newGame, play)).toStrictEqual(expectedCurrentGameHistoryToInsert);\n });\n\n it(\"should call generateCurrentGameHistoryRecordPlayToInsert method when called.\", () => {\n const baseGame = createFakeGameWithCurrentPlay();\n const newGame = createFakeGameWithCurrentPlay();\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedCurrentGameHistoryPlayToInsert = createFakeGameHistoryRecordPlay();\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayToInsert.mockReturnValue(expectedCurrentGameHistoryPlayToInsert);\n services.gameHistoryRecordToInsertGenerator.generateCurrentGameHistoryRecordToInsert(baseGame, newGame, play);\n\n expect(mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayToInsert).toHaveBeenCalledExactlyOnceWith(baseGame, play);\n });\n\n it(\"should call generateCurrentGameHistoryRecordRevealedPlayersToInsert method when called.\", () => {\n const baseGame = createFakeGameWithCurrentPlay();\n const newGame = createFakeGameWithCurrentPlay();\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedCurrentGameHistoryPlayToInsert = createFakeGameHistoryRecordPlay();\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayToInsert.mockReturnValue(expectedCurrentGameHistoryPlayToInsert);\n services.gameHistoryRecordToInsertGenerator.generateCurrentGameHistoryRecordToInsert(baseGame, newGame, play);\n\n expect(mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordRevealedPlayersToInsert).toHaveBeenCalledExactlyOnceWith(baseGame, newGame);\n });\n\n it(\"should call generateCurrentGameHistoryRecordSwitchedSidePlayersToInsert method when called.\", () => {\n const baseGame = createFakeGameWithCurrentPlay();\n const newGame = createFakeGameWithCurrentPlay();\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedCurrentGameHistoryPlayToInsert = createFakeGameHistoryRecordPlay();\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayToInsert.mockReturnValue(expectedCurrentGameHistoryPlayToInsert);\n services.gameHistoryRecordToInsertGenerator.generateCurrentGameHistoryRecordToInsert(baseGame, newGame, play);\n\n expect(mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordSwitchedSidePlayersToInsert).toHaveBeenCalledExactlyOnceWith(baseGame, newGame);\n });\n\n it(\"should call generateCurrentGameHistoryRecordDeadPlayersToInsert method when called.\", () => {\n const baseGame = createFakeGameWithCurrentPlay();\n const newGame = createFakeGameWithCurrentPlay();\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedCurrentGameHistoryPlayToInsert = createFakeGameHistoryRecordPlay();\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayToInsert.mockReturnValue(expectedCurrentGameHistoryPlayToInsert);\n services.gameHistoryRecordToInsertGenerator.generateCurrentGameHistoryRecordToInsert(baseGame, newGame, play);\n\n expect(mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordDeadPlayersToInsert).toHaveBeenCalledExactlyOnceWith(baseGame, newGame);\n });\n\n it(\"should call generateCurrentGameHistoryRecordPlayerAttributeAlterationsToInsert method when called.\", () => {\n const baseGame = createFakeGameWithCurrentPlay();\n const newGame = createFakeGameWithCurrentPlay();\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedCurrentGameHistoryPlayToInsert = createFakeGameHistoryRecordPlay();\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayToInsert.mockReturnValue(expectedCurrentGameHistoryPlayToInsert);\n services.gameHistoryRecordToInsertGenerator.generateCurrentGameHistoryRecordToInsert(baseGame, newGame, play);\n\n expect(mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayerAttributeAlterationsToInsert).toHaveBeenCalledExactlyOnceWith(baseGame, newGame);\n });\n\n it(\"should call generateCurrentGameHistoryRecordPlayVotingToInsert method when called with votes and play type is vote.\", () => {\n const baseGame = createFakeGameWithCurrentPlay();\n const newGame = createFakeGameWithCurrentPlay();\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedCurrentGameHistoryPlayToInsert = createFakeGameHistoryRecordPlay({\n type: \"vote\",\n votes: [],\n });\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayToInsert.mockReturnValue(expectedCurrentGameHistoryPlayToInsert);\n const gameHistoryRecordToInsert = {\n gameId: baseGame._id,\n turn: baseGame.turn,\n phase: baseGame.phase,\n tick: baseGame.tick,\n play: expectedCurrentGameHistoryPlayToInsert,\n revealedPlayers: undefined,\n deadPlayers: undefined,\n };\n services.gameHistoryRecordToInsertGenerator.generateCurrentGameHistoryRecordToInsert(baseGame, newGame, play);\n\n expect(mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayVotingToInsert).toHaveBeenCalledExactlyOnceWith(baseGame, newGame, gameHistoryRecordToInsert);\n });\n\n it(\"should not call generateCurrentGameHistoryRecordPlayVotingToInsert method when called with votes and play type is not vote.\", () => {\n const baseGame = createFakeGameWithCurrentPlay();\n const newGame = createFakeGameWithCurrentPlay();\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedCurrentGameHistoryPlayToInsert = createFakeGameHistoryRecordPlay({\n type: \"target\",\n votes: [],\n });\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayToInsert.mockReturnValue(expectedCurrentGameHistoryPlayToInsert);\n services.gameHistoryRecordToInsertGenerator.generateCurrentGameHistoryRecordToInsert(baseGame, newGame, play);\n\n expect(mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayVotingToInsert).not.toHaveBeenCalled();\n });\n });\n\n describe(\"generateCurrentGameHistoryRecordDeadPlayersToInsert\", () => {\n it(\"should generate current game history dead players when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeVillagerAlivePlayer(),\n ];\n const baseGame = createFakeGame({ players });\n const newPlayers = [\n createFakePlayer({ ...players[0], isAlive: false }),\n createFakePlayer({ ...players[1] }),\n createFakePlayer({ ...players[2], isAlive: false }),\n createFakePlayer({ ...players[3] }),\n createFakePlayer({ ...players[4] }),\n createFakeAngelAlivePlayer({ name: \"NotAGoodName\", isAlive: false }),\n ];\n const newGame = createFakeGame({\n ...baseGame,\n players: newPlayers,\n });\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordDeadPlayersToInsert\"](baseGame, newGame)).toStrictEqual([\n newPlayers[0],\n newPlayers[2],\n ]);\n });\n\n it(\"should return undefined when there is no dead players.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeVillagerAlivePlayer(),\n ];\n const baseGame = createFakeGame({ players });\n const newPlayers = [\n createFakePlayer({ ...players[0] }),\n createFakePlayer({ ...players[1] }),\n createFakePlayer({ ...players[2] }),\n createFakePlayer({ ...players[3] }),\n createFakePlayer({ ...players[4] }),\n createFakeAngelAlivePlayer({ name: \"NotAGoodName\", isAlive: false }),\n ];\n const newGame = createFakeGame({\n ...baseGame,\n players: newPlayers,\n });\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordDeadPlayersToInsert\"](baseGame, newGame)).toBeUndefined();\n });\n });\n\n describe(\"generateCurrentGameHistoryRecordSwitchedSidePlayersToInsert\", () => {\n it(\"should generate current game history switched side players when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const baseGame = createFakeGame({ players });\n const newPlayers = [\n createFakePlayer({\n ...players[0],\n side: createFakePlayerSide({ current: \"villagers\" }),\n }),\n createFakePlayer({\n ...players[1],\n side: createFakePlayerSide({ current: \"werewolves\" }),\n }),\n createFakePlayer({ ...players[2] }),\n ];\n const newGame = createFakeGame({\n ...baseGame,\n players: newPlayers,\n });\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordSwitchedSidePlayersToInsert\"](baseGame, newGame)).toStrictEqual([\n newPlayers[0],\n newPlayers[1],\n ]);\n });\n\n it(\"should return undefined when there is no switched side players.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const baseGame = createFakeGame({ players });\n const newPlayers = [\n createFakePlayer({ ...players[0] }),\n createFakePlayer({ ...players[1] }),\n createFakePlayer({ ...players[2] }),\n ];\n const newGame = createFakeGame({\n ...baseGame,\n players: newPlayers,\n });\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordSwitchedSidePlayersToInsert\"](baseGame, newGame)).toBeUndefined();\n });\n });\n\n describe(\"generateCurrentGameHistoryRecordRevealedPlayersToInsert\", () => {\n it(\"should generate current game history revealed players but alive when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ role: createFakePlayerRole({ isRevealed: false }) }),\n createFakeVillagerAlivePlayer({ role: createFakePlayerRole({ isRevealed: true }) }),\n createFakeWerewolfAlivePlayer({ role: createFakePlayerRole({ isRevealed: false }) }),\n createFakeVillagerAlivePlayer({ isAlive: false, role: createFakePlayerRole({ isRevealed: false }) }),\n createFakeVillagerAlivePlayer({ role: createFakePlayerRole({ isRevealed: false }) }),\n ];\n const baseGame = createFakeGame({ players });\n const newPlayers = [\n createFakePlayer({ ...players[0], role: createFakePlayerRole({ isRevealed: true }) }),\n createFakePlayer({ ...players[1], role: createFakePlayerRole({ isRevealed: true }) }),\n createFakePlayer({ ...players[2], role: createFakePlayerRole({ isRevealed: true }) }),\n createFakePlayer({ ...players[3], role: createFakePlayerRole({ isRevealed: true }) }),\n createFakePlayer({ ...players[4], role: createFakePlayerRole({ isRevealed: false }) }),\n createFakeAngelAlivePlayer({ role: createFakePlayerRole({ isRevealed: false }) }),\n ];\n const newGame = createFakeGame({\n ...baseGame,\n players: newPlayers,\n });\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordRevealedPlayersToInsert\"](baseGame, newGame)).toStrictEqual([\n newPlayers[0],\n newPlayers[2],\n ]);\n });\n\n it(\"should return undefined when there is no new revealed players.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ role: createFakePlayerRole({ isRevealed: false }) }),\n createFakeVillagerAlivePlayer({ role: createFakePlayerRole({ isRevealed: true }) }),\n createFakeWerewolfAlivePlayer({ role: createFakePlayerRole({ isRevealed: false }) }),\n createFakeVillagerAlivePlayer({ isAlive: false, role: createFakePlayerRole({ isRevealed: false }) }),\n createFakeVillagerAlivePlayer({ role: createFakePlayerRole({ isRevealed: false }) }),\n ];\n const baseGame = createFakeGame({ players });\n const newPlayers = [\n createFakePlayer({ ...players[0], role: createFakePlayerRole({ isRevealed: false }) }),\n createFakePlayer({ ...players[1], role: createFakePlayerRole({ isRevealed: true }) }),\n createFakePlayer({ ...players[2], role: createFakePlayerRole({ isRevealed: false }) }),\n createFakePlayer({ ...players[3], role: createFakePlayerRole({ isRevealed: true }) }),\n createFakePlayer({ ...players[4], role: createFakePlayerRole({ isRevealed: false }) }),\n createFakeAngelAlivePlayer({ role: createFakePlayerRole({ isRevealed: false }) }),\n ];\n const newGame = createFakeGame({\n ...baseGame,\n players: newPlayers,\n });\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordRevealedPlayersToInsert\"](baseGame, newGame)).toBeUndefined();\n });\n });\n\n describe(\"generateCurrentGameHistoryRecordAttachedPlayerAttributesToInsertForPlayer\", () => {\n it(\"should generate current game history attached player attributes for player when called.\", () => {\n const basePlayer = createFakePlayer({\n name: \"Antoine\",\n attributes: [createFakeSeenBySeerPlayerAttribute()],\n });\n const newPlayer = createFakePlayer({\n name: \"New Antoine\",\n attributes: [\n createFakeSeenBySeerPlayerAttribute(),\n createFakeDrankDeathPotionByWitchPlayerAttribute(),\n ],\n });\n const expectedAttachedPlayerAttributes = [\n createFakeGameHistoryRecordPlayerAttributeAlteration({\n playerName: newPlayer.name,\n name: \"drank-death-potion\",\n source: \"witch\",\n status: \"attached\",\n }),\n ];\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordAttachedPlayerAttributesToInsertForPlayer\"](basePlayer, newPlayer)).toStrictEqual(expectedAttachedPlayerAttributes);\n });\n });\n\n describe(\"generateCurrentGameHistoryRecordDetachedPlayerAttributesToInsertForPlayer\", () => {\n it(\"should generate current game history detached player attributes for player when called.\", () => {\n const basePlayer = createFakePlayer({\n name: \"Antoine\",\n attributes: [\n createFakeSeenBySeerPlayerAttribute(),\n createFakeDrankDeathPotionByWitchPlayerAttribute(),\n ],\n });\n const newPlayer = createFakePlayer({\n name: \"New Antoine\",\n attributes: [createFakeDrankDeathPotionByWitchPlayerAttribute()],\n });\n const expectedDetachedPlayerAttributes = [\n createFakeGameHistoryRecordPlayerAttributeAlteration({\n playerName: newPlayer.name,\n name: \"seen\",\n source: \"seer\",\n status: \"detached\",\n }),\n ];\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordDetachedPlayerAttributesToInsertForPlayer\"](basePlayer, newPlayer)).toStrictEqual(expectedDetachedPlayerAttributes);\n });\n });\n\n describe(\"generateCurrentGameHistoryRecordActivatedPlayerAttributesToInsertForPlayer\", () => {\n it(\"should generate current game history activated player attributes for player when called.\", () => {\n const attributes = [\n createFakeDrankDeathPotionByWitchPlayerAttribute({\n activeAt: createFakePlayerAttributeActivation({\n turn: 2,\n phaseName: \"night\",\n }),\n }),\n createFakeSeenBySeerPlayerAttribute({\n activeAt: createFakePlayerAttributeActivation({\n turn: 2,\n phaseName: \"day\",\n }),\n }),\n ];\n const baseGame = createFakeGame({\n turn: 1,\n phase: createFakeGamePhase({ name: \"day\" }),\n });\n const newGame = createFakeGame({\n turn: 2,\n phase: createFakeGamePhase({ name: \"night\" }),\n });\n const basePlayer = createFakePlayer({\n name: \"Antoine\",\n attributes,\n });\n const newPlayer = createFakePlayer({\n name: \"New Antoine\",\n attributes: [\n ...attributes,\n createFakeCharmedByPiedPiperPlayerAttribute({\n activeAt: createFakePlayerAttributeActivation({\n turn: 2,\n phaseName: \"night\",\n }),\n }),\n ],\n });\n const expectedActivatedPlayerAttributes = [\n createFakeGameHistoryRecordPlayerAttributeAlteration({\n playerName: newPlayer.name,\n name: \"drank-death-potion\",\n source: \"witch\",\n status: \"activated\",\n }),\n ];\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordActivatedPlayerAttributesToInsertForPlayer\"](baseGame, newGame, basePlayer, newPlayer)).toStrictEqual(expectedActivatedPlayerAttributes);\n });\n });\n\n describe(\"generateCurrentGameHistoryRecordPlayerAttributeAlterationsToInsert\", () => {\n beforeEach(() => {\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordAttachedPlayerAttributesToInsertForPlayer = jest.spyOn(services.gameHistoryRecordToInsertGenerator as unknown as { generateCurrentGameHistoryRecordAttachedPlayerAttributesToInsertForPlayer }, \"generateCurrentGameHistoryRecordAttachedPlayerAttributesToInsertForPlayer\").mockImplementation();\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordDetachedPlayerAttributesToInsertForPlayer = jest.spyOn(services.gameHistoryRecordToInsertGenerator as unknown as { generateCurrentGameHistoryRecordDetachedPlayerAttributesToInsertForPlayer }, \"generateCurrentGameHistoryRecordDetachedPlayerAttributesToInsertForPlayer\").mockImplementation();\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordActivatedPlayerAttributesToInsertForPlayer = jest.spyOn(services.gameHistoryRecordToInsertGenerator as unknown as { generateCurrentGameHistoryRecordActivatedPlayerAttributesToInsertForPlayer }, \"generateCurrentGameHistoryRecordActivatedPlayerAttributesToInsertForPlayer\").mockImplementation();\n });\n\n it(\"should generate attached for each matching from base game when called.\", () => {\n const goodId = createFakeObjectId();\n const matchingPlayer = createFakePlayer({\n _id: goodId,\n name: \"Antoine\",\n attributes: [createFakeSeenBySeerPlayerAttribute()],\n });\n const basePlayers = [\n matchingPlayer,\n createFakePlayer({\n name: \"New Antoine\",\n attributes: [createFakeDrankDeathPotionByWitchPlayerAttribute()],\n }),\n ];\n const newPlayers = [matchingPlayer];\n const baseGame = createFakeGame({ players: basePlayers });\n const newGame = createFakeGame({ players: newPlayers });\n services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayerAttributeAlterationsToInsert\"](baseGame, newGame);\n\n expect(mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordAttachedPlayerAttributesToInsertForPlayer).toHaveBeenCalledExactlyOnceWith(matchingPlayer, matchingPlayer);\n });\n\n it(\"should generate detached for each matching from new game when called.\", () => {\n const goodId = createFakeObjectId();\n const matchingPlayer = createFakePlayer({\n _id: goodId,\n name: \"Antoine\",\n attributes: [createFakeSeenBySeerPlayerAttribute()],\n });\n const basePlayers = [\n matchingPlayer,\n createFakePlayer({\n name: \"New Antoine\",\n attributes: [createFakeDrankDeathPotionByWitchPlayerAttribute()],\n }),\n ];\n const newPlayers = [matchingPlayer];\n const baseGame = createFakeGame({ players: basePlayers });\n const newGame = createFakeGame({ players: newPlayers });\n services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayerAttributeAlterationsToInsert\"](baseGame, newGame);\n\n expect(mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordDetachedPlayerAttributesToInsertForPlayer).toHaveBeenCalledExactlyOnceWith(matchingPlayer, matchingPlayer);\n });\n\n it(\"should generate activated for each matching from new game when called.\", () => {\n const goodId = createFakeObjectId();\n const matchingPlayer = createFakePlayer({\n _id: goodId,\n name: \"Antoine\",\n attributes: [\n createFakeSeenBySeerPlayerAttribute({\n activeAt: createFakePlayerAttributeActivation({\n turn: 2,\n phaseName: \"day\",\n }),\n }),\n ],\n });\n const basePlayers = [\n matchingPlayer,\n createFakePlayer({\n name: \"New Antoine\",\n attributes: [\n createFakeDrankDeathPotionByWitchPlayerAttribute({\n activeAt: createFakePlayerAttributeActivation({\n turn: 2,\n phaseName: \"night\",\n }),\n }),\n ],\n }),\n ];\n const newPlayers = [matchingPlayer];\n const baseGame = createFakeGame({\n turn: 1,\n phase: createFakeGamePhase({ name: \"day\" }),\n players: basePlayers,\n });\n const newGame = createFakeGame({\n turn: 2,\n phase: createFakeGamePhase({ name: \"night\" }),\n players: newPlayers,\n });\n services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayerAttributeAlterationsToInsert\"](baseGame, newGame);\n\n expect(mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordActivatedPlayerAttributesToInsertForPlayer).toHaveBeenCalledExactlyOnceWith(baseGame, newGame, matchingPlayer, matchingPlayer);\n });\n\n it(\"should concat all alterations for each matching player when called.\", () => {\n const attachedPlayerAttributes = [createFakeGameHistoryRecordPlayerAttributeAlteration()];\n const detachedPlayerAttributes = [createFakeGameHistoryRecordPlayerAttributeAlteration()];\n const activatedPlayerAttributes = [createFakeGameHistoryRecordPlayerAttributeAlteration()];\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordAttachedPlayerAttributesToInsertForPlayer.mockReturnValue(attachedPlayerAttributes);\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordDetachedPlayerAttributesToInsertForPlayer.mockReturnValue(detachedPlayerAttributes);\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordActivatedPlayerAttributesToInsertForPlayer.mockReturnValue(activatedPlayerAttributes);\n const goodId = createFakeObjectId();\n const matchingPlayer = createFakePlayer({\n _id: goodId,\n name: \"Antoine\",\n attributes: [\n createFakeSeenBySeerPlayerAttribute(),\n createFakeDrankDeathPotionByWitchPlayerAttribute(),\n ],\n });\n const basePlayers = [matchingPlayer];\n const newPlayers = [\n matchingPlayer,\n createFakePlayer({\n name: \"New Antoine\",\n attributes: [createFakeDrankDeathPotionByWitchPlayerAttribute()],\n }),\n ];\n const baseGame = createFakeGame({ players: basePlayers });\n const newGame = createFakeGame({ players: newPlayers });\n const expectedPlayerAttributeAlterations = [\n ...attachedPlayerAttributes,\n ...detachedPlayerAttributes,\n ...activatedPlayerAttributes,\n ];\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayerAttributeAlterationsToInsert\"](baseGame, newGame)).toStrictEqual(expectedPlayerAttributeAlterations);\n });\n\n it(\"should return undefined when there are no alterations for every players.\", () => {\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordAttachedPlayerAttributesToInsertForPlayer.mockReturnValue([]);\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordDetachedPlayerAttributesToInsertForPlayer.mockReturnValue([]);\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordActivatedPlayerAttributesToInsertForPlayer.mockReturnValue([]);\n const basePlayers = [\n createFakePlayer({\n name: \"Antoine\",\n attributes: [createFakeSeenBySeerPlayerAttribute()],\n }),\n createFakePlayer({\n name: \"New Antoine\",\n attributes: [createFakeDrankDeathPotionByWitchPlayerAttribute()],\n }),\n ];\n const newPlayers = [\n createFakePlayer({\n name: \"Antoine\",\n attributes: [createFakeSeenBySeerPlayerAttribute()],\n }),\n createFakePlayer({\n name: \"New Antoine\",\n attributes: [createFakeDrankDeathPotionByWitchPlayerAttribute()],\n }),\n ];\n const baseGame = createFakeGame({ players: basePlayers });\n const newGame = createFakeGame({ players: newPlayers });\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayerAttributeAlterationsToInsert\"](baseGame, newGame)).toBeUndefined();\n });\n });\n\n describe(\"generateCurrentGameHistoryRecordPlayTargetsToInsert\", () => {\n it(\"should return undefined when there are no targets.\", () => {\n const baseGame = createFakeGameWithCurrentPlay();\n const play = createFakeMakeGamePlayWithRelationsDto();\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayTargetsToInsert\"](baseGame, play)).toBeUndefined();\n });\n\n it(\"should return targets when there are targets and action is not sniff.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const baseGame = createFakeGameWithCurrentPlay({\n players,\n currentPlay: createFakeGamePlaySheriffDelegates(),\n });\n const targets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[0] })];\n const play = createFakeMakeGamePlayWithRelationsDto({\n targets,\n });\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayTargetsToInsert\"](baseGame, play)).toStrictEqual(targets);\n });\n\n it(\"should return group of 3 targets when action is sniff.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ position: 0 }),\n createFakeVillagerAlivePlayer({ position: 1 }),\n createFakeWerewolfAlivePlayer({ position: 2 }),\n createFakeWerewolfAlivePlayer({ position: 3 }),\n ];\n const baseGame = createFakeGameWithCurrentPlay({\n players,\n currentPlay: createFakeGamePlayFoxSniffs(),\n });\n const targets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1] })];\n const play = createFakeMakeGamePlayWithRelationsDto({\n targets,\n });\n const expectedTargets = [\n createFakeMakeGamePlayTargetWithRelationsDto({ player: players[0] }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1] }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: players[2] }),\n ];\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayTargetsToInsert\"](baseGame, play)).toStrictEqual(expectedTargets);\n });\n });\n\n describe(\"generateCurrentGameHistoryRecordPlayToInsert\", () => {\n beforeEach(() => {\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlaySourceToInsert = jest.spyOn(services.gameHistoryRecordToInsertGenerator as unknown as { generateCurrentGameHistoryRecordPlaySourceToInsert }, \"generateCurrentGameHistoryRecordPlaySourceToInsert\").mockImplementation();\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayTargetsToInsert = jest.spyOn(services.gameHistoryRecordToInsertGenerator as unknown as { generateCurrentGameHistoryRecordPlayTargetsToInsert }, \"generateCurrentGameHistoryRecordPlayTargetsToInsert\").mockImplementation();\n });\n\n it(\"should generate current game history record play to insert when called.\", () => {\n const game = createFakeGameWithCurrentPlay();\n const play = createFakeMakeGamePlayWithRelationsDto({\n doesJudgeRequestAnotherVote: true,\n targets: [createFakeGameHistoryRecordPlayTarget()],\n votes: [createFakeGameHistoryRecordPlayVote()],\n chosenCard: createFakeGameAdditionalCard(),\n chosenSide: \"villagers\",\n });\n const expectedGameHistoryRecordPlaySource = { name: undefined, players: undefined };\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlaySourceToInsert.mockReturnValue(expectedGameHistoryRecordPlaySource);\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayTargetsToInsert.mockReturnValue(play.targets);\n const expectedGameHistoryRecordPlay = createFakeGameHistoryRecordPlay({\n type: game.currentPlay.type,\n action: game.currentPlay.action,\n didJudgeRequestAnotherVote: play.doesJudgeRequestAnotherVote,\n targets: play.targets,\n votes: play.votes,\n chosenCard: play.chosenCard,\n chosenSide: play.chosenSide,\n }, { source: expectedGameHistoryRecordPlaySource });\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayToInsert\"](game, play)).toStrictEqual(expectedGameHistoryRecordPlay);\n });\n });\n\n describe(\"generateCurrentGameHistoryRecordPlayVotingResultToInsert\", () => {\n it(\"should return sheriff election when there is a sheriff in the game.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeHunterAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const nominatedPlayers = [players[2], players[3]];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlaySurvivorsElectSheriff() });\n const newGame = createFakeGame({\n ...game,\n players: [\n createFakePlayer(players[0]),\n createFakePlayer({ ...players[1], attributes: [createFakeSheriffBySurvivorsPlayerAttribute()] }),\n createFakePlayer(players[2]),\n createFakePlayer(players[3]),\n ],\n });\n const gameHistoryRecordToInsert = createFakeGameHistoryRecordToInsert();\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayVotingResultToInsert\"](game, newGame, nominatedPlayers, gameHistoryRecordToInsert)).toBe(\"sheriff-election\");\n });\n\n it(\"should return tie when there is no sheriff in the game after election.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeHunterAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const nominatedPlayers = [players[2], players[3]];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlaySurvivorsElectSheriff() });\n const newGame = createFakeGame({\n ...game,\n players: [\n createFakePlayer(players[0]),\n createFakePlayer(players[1]),\n createFakePlayer(players[2]),\n createFakePlayer(players[3]),\n ],\n });\n const gameHistoryRecordToInsert = createFakeGameHistoryRecordToInsert();\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayVotingResultToInsert\"](game, newGame, nominatedPlayers, gameHistoryRecordToInsert)).toBe(\"tie\");\n });\n\n it(\"should return skipped when there are no vote set.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeHunterAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const nominatedPlayers = [players[2], players[3]];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlaySurvivorsVote() });\n const newGame = createFakeGame({\n ...game,\n players: [\n createFakePlayer(players[0]),\n createFakePlayer(players[1]),\n createFakePlayer(players[2]),\n createFakePlayer(players[3]),\n ],\n });\n const gameHistoryRecordPlay = createFakeGameHistoryRecordPlay({ votes: undefined });\n const gameHistoryRecordToInsert = createFakeGameHistoryRecordToInsert({ play: gameHistoryRecordPlay, deadPlayers: [createFakeDeadPlayer({ ...players[1], isAlive: false, death: createFakePlayerVoteBySurvivorsDeath() })] });\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayVotingResultToInsert\"](game, newGame, nominatedPlayers, gameHistoryRecordToInsert)).toBe(\"skipped\");\n });\n\n it(\"should return skipped when votes are empty.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeHunterAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const nominatedPlayers = [players[2], players[3]];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlaySurvivorsVote() });\n const newGame = createFakeGame({\n ...game,\n players: [\n createFakePlayer(players[0]),\n createFakePlayer(players[1]),\n createFakePlayer(players[2]),\n createFakePlayer(players[3]),\n ],\n });\n const gameHistoryRecordPlay = createFakeGameHistoryRecordPlay({ votes: [] });\n const gameHistoryRecordToInsert = createFakeGameHistoryRecordToInsert({ play: gameHistoryRecordPlay, deadPlayers: [createFakeDeadPlayer({ ...players[1], isAlive: false, death: createFakePlayerVoteBySurvivorsDeath() })] });\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayVotingResultToInsert\"](game, newGame, nominatedPlayers, gameHistoryRecordToInsert)).toBe(\"skipped\");\n });\n\n it(\"should return death when there is at least one dead player from votes.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeHunterAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const nominatedPlayers = [players[2], players[3]];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlaySurvivorsVote() });\n const newGame = createFakeGame({\n ...game,\n players: [\n createFakePlayer(players[0]),\n createFakePlayer(players[1]),\n createFakePlayer(players[2]),\n createFakePlayer(players[3]),\n ],\n });\n const gameHistoryRecordPlay = createFakeGameHistoryRecordPlay({ votes: [createFakeGameHistoryRecordPlayVote()] });\n const deadPlayers = [\n createFakeDeadPlayer({ ...players[1], isAlive: false, death: createFakePlayerVoteBySurvivorsDeath() }),\n createFakeDeadPlayer({ ...players[1], isAlive: false, death: createFakePlayerDeathPotionByWitchDeath() }),\n ];\n const gameHistoryRecordToInsert = createFakeGameHistoryRecordToInsert({ play: gameHistoryRecordPlay, deadPlayers });\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayVotingResultToInsert\"](game, newGame, nominatedPlayers, gameHistoryRecordToInsert)).toBe(\"death\");\n });\n\n it(\"should return death when there is at least one dead player from scapegoat votes.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeHunterAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const nominatedPlayers = [players[2], players[3]];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlaySurvivorsVote() });\n const newGame = createFakeGame({\n ...game,\n players: [\n createFakePlayer(players[0]),\n createFakePlayer(players[1]),\n createFakePlayer(players[2]),\n createFakePlayer(players[3]),\n ],\n });\n const gameHistoryRecordPlay = createFakeGameHistoryRecordPlay({ votes: [createFakeGameHistoryRecordPlayVote()] });\n const gameHistoryRecordToInsert = createFakeGameHistoryRecordToInsert({ play: gameHistoryRecordPlay, deadPlayers: [createFakeDeadPlayer({ ...players[1], isAlive: false, death: createFakePlayerVoteScapegoatedBySurvivorsDeath() })] });\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayVotingResultToInsert\"](game, newGame, nominatedPlayers, gameHistoryRecordToInsert)).toBe(\"death\");\n });\n\n it(\"should return inconsequential when there is no death from votes and current play was already after a tie.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeHunterAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const nominatedPlayers = [players[2], players[3]];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlaySurvivorsVote({ causes: [\"previous-votes-were-in-ties\"] }) });\n const newGame = createFakeGame({\n ...game,\n players: [\n createFakePlayer(players[0]),\n createFakePlayer(players[1]),\n createFakePlayer(players[2]),\n createFakePlayer(players[3]),\n ],\n });\n const gameHistoryRecordPlay = createFakeGameHistoryRecordPlay({ votes: [createFakeGameHistoryRecordPlayVote()] });\n const gameHistoryRecordToInsert = createFakeGameHistoryRecordToInsert({ play: gameHistoryRecordPlay, deadPlayers: [createFakeDeadPlayer({ ...players[1], isAlive: false, death: createFakePlayerDeathPotionByWitchDeath() })] });\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayVotingResultToInsert\"](game, newGame, nominatedPlayers, gameHistoryRecordToInsert)).toBe(\"inconsequential\");\n });\n\n it(\"should return inconsequential when there is no death from votes, current play was not already after a tie but only one player was nominated.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeHunterAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const nominatedPlayers = [players[2]];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlaySurvivorsVote({ causes: [\"stuttering-judge-request\"] }) });\n const newGame = createFakeGame({\n ...game,\n players: [\n createFakePlayer(players[0]),\n createFakePlayer(players[1]),\n createFakePlayer(players[2]),\n createFakePlayer(players[3]),\n ],\n });\n const gameHistoryRecordPlay = createFakeGameHistoryRecordPlay({ votes: [createFakeGameHistoryRecordPlayVote()] });\n const gameHistoryRecordToInsert = createFakeGameHistoryRecordToInsert({ play: gameHistoryRecordPlay, deadPlayers: [createFakeDeadPlayer({ ...players[1], isAlive: false, death: createFakePlayerDeathPotionByWitchDeath() })] });\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayVotingResultToInsert\"](game, newGame, nominatedPlayers, gameHistoryRecordToInsert)).toBe(\"inconsequential\");\n });\n\n it(\"should return tie when there is no death from votes, current play was not after a tie and there are several nominated players.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeHunterAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const nominatedPlayers = [players[2], players[3]];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlaySurvivorsVote({ causes: [\"stuttering-judge-request\"] }) });\n const newGame = createFakeGame({\n ...game,\n players: [\n createFakePlayer(players[0]),\n createFakePlayer(players[1]),\n createFakePlayer(players[2]),\n createFakePlayer(players[3]),\n ],\n });\n const gameHistoryRecordPlay = createFakeGameHistoryRecordPlay({ votes: [createFakeGameHistoryRecordPlayVote()] });\n const gameHistoryRecordToInsert = createFakeGameHistoryRecordToInsert({ play: gameHistoryRecordPlay, deadPlayers: [createFakeDeadPlayer({ ...players[1], isAlive: false, death: createFakePlayerDeathPotionByWitchDeath() })] });\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayVotingResultToInsert\"](game, newGame, nominatedPlayers, gameHistoryRecordToInsert)).toBe(\"tie\");\n });\n });\n\n describe(\"generateCurrentGameHistoryRecordPlayVotingToInsert\", () => {\n beforeEach(() => {\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayVotingResultToInsert = jest.spyOn(services.gameHistoryRecordToInsertGenerator as unknown as { generateCurrentGameHistoryRecordPlayVotingResultToInsert }, \"generateCurrentGameHistoryRecordPlayVotingResultToInsert\").mockImplementation();\n });\n\n it(\"should generate current game history record play voting when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const newGame = createFakeGameWithCurrentPlay(game);\n const gameHistoryRecordToInsert = createFakeGameHistoryRecordToInsert();\n const nominatedPlayers = [players[2]];\n mocks.gamePlayVoteService.getNominatedPlayers.mockReturnValue(nominatedPlayers);\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayVotingResultToInsert.mockReturnValue(\"death\");\n const expectedCurrentGameHistoryRecordPlayVoting = createFakeGameHistoryRecordPlayVoting({\n result: \"death\",\n nominatedPlayers,\n });\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayVotingToInsert\"](game, newGame, gameHistoryRecordToInsert)).toStrictEqual(expectedCurrentGameHistoryRecordPlayVoting);\n });\n\n it(\"should generate current game history record play voting without nominated players when no nominated players are found.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const newGame = createFakeGameWithCurrentPlay(game);\n const gameHistoryRecordToInsert = createFakeGameHistoryRecordToInsert();\n const nominatedPlayers = [];\n mocks.gamePlayVoteService.getNominatedPlayers.mockReturnValue(nominatedPlayers);\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayVotingResultToInsert.mockReturnValue(\"death\");\n const expectedCurrentGameHistoryRecordPlayVoting = createFakeGameHistoryRecordPlayVoting({ result: \"death\" });\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayVotingToInsert\"](game, newGame, gameHistoryRecordToInsert)).toStrictEqual(expectedCurrentGameHistoryRecordPlayVoting);\n });\n\n it(\"should call getNominatedPlayers method with undefined votes when called without votes.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const newGame = createFakeGameWithCurrentPlay(game);\n const gameHistoryRecordToInsert = createFakeGameHistoryRecordToInsert();\n const nominatedPlayers = [players[2]];\n mocks.gamePlayVoteService.getNominatedPlayers.mockReturnValue(nominatedPlayers);\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayVotingResultToInsert.mockReturnValue(\"death\");\n services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayVotingToInsert\"](game, newGame, gameHistoryRecordToInsert);\n\n expect(mocks.gamePlayVoteService.getNominatedPlayers).toHaveBeenCalledExactlyOnceWith(undefined, game);\n });\n\n it(\"should call getNominatedPlayers method with votes when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const newGame = createFakeGameWithCurrentPlay(game);\n const gameHistoryRecordToInsert = createFakeGameHistoryRecordToInsert({ play: createFakeGameHistoryRecordPlay({ votes: [createFakeGameHistoryRecordPlayVote()] }) });\n const nominatedPlayers = [players[2]];\n mocks.gamePlayVoteService.getNominatedPlayers.mockReturnValue(nominatedPlayers);\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayVotingResultToInsert.mockReturnValue(\"death\");\n services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayVotingToInsert\"](game, newGame, gameHistoryRecordToInsert);\n\n expect(mocks.gamePlayVoteService.getNominatedPlayers).toHaveBeenCalledExactlyOnceWith(gameHistoryRecordToInsert.play.votes, game);\n });\n\n it(\"should call generateCurrentGameHistoryRecordPlayVotingResultToInsert method when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const newGame = createFakeGameWithCurrentPlay(game);\n const gameHistoryRecordToInsert = createFakeGameHistoryRecordToInsert({ play: createFakeGameHistoryRecordPlay({ votes: [createFakeGameHistoryRecordPlayVote()] }) });\n const nominatedPlayers = [players[2]];\n mocks.gamePlayVoteService.getNominatedPlayers.mockReturnValue(nominatedPlayers);\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayVotingResultToInsert.mockReturnValue(\"death\");\n services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayVotingToInsert\"](game, newGame, gameHistoryRecordToInsert);\n\n expect(mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayVotingResultToInsert).toHaveBeenCalledExactlyOnceWith(game, newGame, nominatedPlayers, gameHistoryRecordToInsert);\n });\n });\n\n describe(\"generateCurrentGameHistoryRecordPlaySourceToInsert\", () => {\n it(\"should generate current game history record play source when called.\", () => {\n const players = [\n createFakeHunterAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeVillagerAlivePlayer(),\n ];\n const expectedPlayers = [players[0], players[1], players[3]];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createGamePlaySurvivorsElectSheriff({ source: createFakeGamePlaySource({ name: \"survivors\", players: expectedPlayers }) }), players });\n const expectedGameHistoryRecordPlaySource = createFakeGameHistoryRecordPlaySource({\n name: game.currentPlay.source.name,\n players: expectedPlayers,\n });\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlaySourceToInsert\"](game)).toStrictEqual(expectedGameHistoryRecordPlaySource);\n });\n });\n});" + "source": "import type { TestingModule } from \"@nestjs/testing\";\nimport { Test } from \"@nestjs/testing\";\n\nimport type { MakeGamePlayTargetWithRelationsDto } from \"@/modules/game/dto/make-game-play/make-game-play-target/make-game-play-target-with-relations.dto\";\nimport { createGamePlaySurvivorsElectSheriff } from \"@/modules/game/helpers/game-play/game-play.factory\";\nimport { GameHistoryRecordToInsertGeneratorService } from \"@/modules/game/providers/services/game-history/game-history-record-to-insert-generator.service\";\nimport { GamePlayVoteService } from \"@/modules/game/providers/services/game-play/game-play-vote/game-play-vote.service\";\nimport type { GameHistoryRecordPlaySource } from \"@/modules/game/schemas/game-history-record/game-history-record-play/game-history-record-play-source/game-history-record-play-source.schema\";\nimport type { GameHistoryRecordPlayVoting } from \"@/modules/game/schemas/game-history-record/game-history-record-play/game-history-record-play-voting/game-history-record-play-voting.schema\";\nimport type { GameHistoryRecordPlay } from \"@/modules/game/schemas/game-history-record/game-history-record-play/game-history-record-play.schema\";\nimport type { GameHistoryRecordPlayerAttributeAlteration } from \"@/modules/game/schemas/game-history-record/game-history-record-player-attribute-alteration/game-history-record-player-attribute-alteration.schema\";\nimport type { Player } from \"@/modules/game/schemas/player/player.schema\";\nimport type { GameHistoryRecordToInsert } from \"@/modules/game/types/game-history-record/game-history-record.types\";\n\nimport * as UnexpectedExceptionFactory from \"@/shared/exception/helpers/unexpected-exception.factory\";\n\nimport { createFakeMakeGamePlayTargetWithRelationsDto } from \"@tests/factories/game/dto/make-game-play/make-game-play-with-relations/make-game-play-target-with-relations.dto.factory\";\nimport { createFakeMakeGamePlayWithRelationsDto } from \"@tests/factories/game/dto/make-game-play/make-game-play-with-relations/make-game-play-with-relations.dto.factory\";\nimport { createFakeGameAdditionalCard } from \"@tests/factories/game/schemas/game-additional-card/game-additional-card.schema.factory\";\nimport { createFakeGameHistoryRecordPlay, createFakeGameHistoryRecordPlayerAttributeAlteration, createFakeGameHistoryRecordPlaySource, createFakeGameHistoryRecordPlayTarget, createFakeGameHistoryRecordPlayVote, createFakeGameHistoryRecordPlayVoting } from \"@tests/factories/game/schemas/game-history-record/game-history-record.schema.factory\";\nimport { createFakeGamePhase } from \"@tests/factories/game/schemas/game-phase/game-phase.schema.factory\";\nimport { createFakeGamePlaySource } from \"@tests/factories/game/schemas/game-play/game-play-source/game-play-source.schema.factory\";\nimport { createFakeGamePlayFoxSniffs, createFakeGamePlaySheriffDelegates, createFakeGamePlaySurvivorsElectSheriff, createFakeGamePlaySurvivorsVote } from \"@tests/factories/game/schemas/game-play/game-play.schema.factory\";\nimport { createFakeGame, createFakeGameWithCurrentPlay } from \"@tests/factories/game/schemas/game.schema.factory\";\nimport { createFakeCharmedByPiedPiperPlayerAttribute, createFakeDrankDeathPotionByWitchPlayerAttribute, createFakePlayerAttributeActivation, createFakeSeenBySeerPlayerAttribute, createFakeSheriffBySurvivorsPlayerAttribute } from \"@tests/factories/game/schemas/player/player-attribute/player-attribute.schema.factory\";\nimport { createFakePlayerDeathPotionByWitchDeath, createFakePlayerVoteBySurvivorsDeath, createFakePlayerVoteScapegoatedBySurvivorsDeath } from \"@tests/factories/game/schemas/player/player-death/player-death.schema.factory\";\nimport { createFakeAngelAlivePlayer, createFakeHunterAlivePlayer, createFakeSeerAlivePlayer, createFakeVillagerAlivePlayer, createFakeWerewolfAlivePlayer } from \"@tests/factories/game/schemas/player/player-with-role.schema.factory\";\nimport { createFakeDeadPlayer, createFakePlayer, createFakePlayerRole, createFakePlayerSide } from \"@tests/factories/game/schemas/player/player.schema.factory\";\nimport { createFakeGameHistoryRecordToInsert } from \"@tests/factories/game/types/game-history-record/game-history-record.type.factory\";\nimport { createFakeObjectId } from \"@tests/factories/shared/mongoose/mongoose.factory\";\n\ndescribe(\"Game History Record To Insert Generator Service\", () => {\n let mocks: {\n gameHistoryRecordToInsertGeneratorService: {\n generateCurrentGameHistoryRecordPlayToInsert: jest.SpyInstance;\n generateCurrentGameHistoryRecordRevealedPlayersToInsert: jest.SpyInstance;\n generateCurrentGameHistoryRecordSwitchedSidePlayersToInsert: jest.SpyInstance;\n generateCurrentGameHistoryRecordDeadPlayersToInsert: jest.SpyInstance;\n generateCurrentGameHistoryRecordPlayVotingToInsert: jest.SpyInstance;\n generateCurrentGameHistoryRecordPlayVotingResultToInsert: jest.SpyInstance;\n generateCurrentGameHistoryRecordPlayTargetsToInsert: jest.SpyInstance;\n generateCurrentGameHistoryRecordPlaySourceToInsert: jest.SpyInstance;\n generateCurrentGameHistoryRecordPlayerAttributeAlterationsToInsert: jest.SpyInstance;\n generateCurrentGameHistoryRecordAttachedPlayerAttributesToInsertForPlayer: jest.SpyInstance;\n generateCurrentGameHistoryRecordDetachedPlayerAttributesToInsertForPlayer: jest.SpyInstance;\n generateCurrentGameHistoryRecordActivatedPlayerAttributesToInsertForPlayer: jest.SpyInstance;\n };\n gamePlayVoteService: {\n getGamePlayVoting: jest.SpyInstance;\n getNominatedPlayers: jest.SpyInstance;\n };\n unexpectedExceptionFactory: {\n createNoCurrentGamePlayUnexpectedException: jest.SpyInstance;\n };\n };\n let services: { gameHistoryRecordToInsertGenerator: GameHistoryRecordToInsertGeneratorService };\n\n beforeEach(async() => {\n mocks = {\n gameHistoryRecordToInsertGeneratorService: {\n generateCurrentGameHistoryRecordPlayToInsert: jest.fn(),\n generateCurrentGameHistoryRecordRevealedPlayersToInsert: jest.fn(),\n generateCurrentGameHistoryRecordSwitchedSidePlayersToInsert: jest.fn(),\n generateCurrentGameHistoryRecordDeadPlayersToInsert: jest.fn(),\n generateCurrentGameHistoryRecordPlayVotingToInsert: jest.fn(),\n generateCurrentGameHistoryRecordPlayVotingResultToInsert: jest.fn(),\n generateCurrentGameHistoryRecordPlaySourceToInsert: jest.fn(),\n generateCurrentGameHistoryRecordPlayTargetsToInsert: jest.fn(),\n generateCurrentGameHistoryRecordPlayerAttributeAlterationsToInsert: jest.fn(),\n generateCurrentGameHistoryRecordAttachedPlayerAttributesToInsertForPlayer: jest.fn(),\n generateCurrentGameHistoryRecordDetachedPlayerAttributesToInsertForPlayer: jest.fn(),\n generateCurrentGameHistoryRecordActivatedPlayerAttributesToInsertForPlayer: jest.fn(),\n },\n gamePlayVoteService: {\n getGamePlayVoting: jest.fn(),\n getNominatedPlayers: jest.fn(),\n },\n unexpectedExceptionFactory: {\n createNoCurrentGamePlayUnexpectedException: jest.spyOn(UnexpectedExceptionFactory, \"createNoCurrentGamePlayUnexpectedException\").mockImplementation(),\n },\n };\n const module: TestingModule = await Test.createTestingModule({\n providers: [\n GameHistoryRecordToInsertGeneratorService,\n {\n provide: GamePlayVoteService,\n useValue: mocks.gamePlayVoteService,\n },\n ],\n }).compile();\n\n services = { gameHistoryRecordToInsertGenerator: module.get(GameHistoryRecordToInsertGeneratorService) };\n });\n\n describe(\"generateCurrentGameHistoryRecordToInsert\", () => {\n beforeEach(() => {\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayToInsert = jest.spyOn(services.gameHistoryRecordToInsertGenerator as unknown as { generateCurrentGameHistoryRecordPlayToInsert }, \"generateCurrentGameHistoryRecordPlayToInsert\").mockImplementation();\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordRevealedPlayersToInsert = jest.spyOn(services.gameHistoryRecordToInsertGenerator as unknown as { generateCurrentGameHistoryRecordRevealedPlayersToInsert }, \"generateCurrentGameHistoryRecordRevealedPlayersToInsert\").mockImplementation();\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordSwitchedSidePlayersToInsert = jest.spyOn(services.gameHistoryRecordToInsertGenerator as unknown as { generateCurrentGameHistoryRecordSwitchedSidePlayersToInsert }, \"generateCurrentGameHistoryRecordSwitchedSidePlayersToInsert\").mockImplementation();\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordDeadPlayersToInsert = jest.spyOn(services.gameHistoryRecordToInsertGenerator as unknown as { generateCurrentGameHistoryRecordDeadPlayersToInsert }, \"generateCurrentGameHistoryRecordDeadPlayersToInsert\").mockImplementation();\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayVotingToInsert = jest.spyOn(services.gameHistoryRecordToInsertGenerator as unknown as { generateCurrentGameHistoryRecordPlayVotingToInsert }, \"generateCurrentGameHistoryRecordPlayVotingToInsert\").mockImplementation();\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayerAttributeAlterationsToInsert = jest.spyOn(services.gameHistoryRecordToInsertGenerator as unknown as { generateCurrentGameHistoryRecordPlayerAttributeAlterationsToInsert }, \"generateCurrentGameHistoryRecordPlayerAttributeAlterationsToInsert\").mockImplementation();\n });\n\n it(\"should throw error when there is no current play for the game.\", () => {\n const baseGame = createFakeGame();\n const newGame = createFakeGame();\n const play = createFakeMakeGamePlayWithRelationsDto();\n const interpolations = { gameId: baseGame._id };\n const mockedError = \"error\";\n mocks.unexpectedExceptionFactory.createNoCurrentGamePlayUnexpectedException.mockReturnValue(mockedError);\n\n expect(() => services.gameHistoryRecordToInsertGenerator.generateCurrentGameHistoryRecordToInsert(baseGame, newGame, play)).toThrow(mockedError);\n expect(mocks.unexpectedExceptionFactory.createNoCurrentGamePlayUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"generateCurrentGameHistoryRecordToInsert\", interpolations);\n });\n\n it(\"should generate current game history to insert when called.\", () => {\n const baseGame = createFakeGameWithCurrentPlay();\n const newGame = createFakeGameWithCurrentPlay();\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedCurrentGameHistoryPlayToInsert = createFakeGameHistoryRecordPlay();\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayToInsert.mockReturnValue(expectedCurrentGameHistoryPlayToInsert);\n const expectedCurrentGameHistoryToInsert = createFakeGameHistoryRecordToInsert({\n gameId: baseGame._id,\n turn: baseGame.turn,\n phase: baseGame.phase,\n tick: baseGame.tick,\n play: expectedCurrentGameHistoryPlayToInsert,\n });\n\n expect(services.gameHistoryRecordToInsertGenerator.generateCurrentGameHistoryRecordToInsert(baseGame, newGame, play)).toStrictEqual(expectedCurrentGameHistoryToInsert);\n });\n\n it(\"should call generateCurrentGameHistoryRecordPlayToInsert method when called.\", () => {\n const baseGame = createFakeGameWithCurrentPlay();\n const newGame = createFakeGameWithCurrentPlay();\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedCurrentGameHistoryPlayToInsert = createFakeGameHistoryRecordPlay();\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayToInsert.mockReturnValue(expectedCurrentGameHistoryPlayToInsert);\n services.gameHistoryRecordToInsertGenerator.generateCurrentGameHistoryRecordToInsert(baseGame, newGame, play);\n\n expect(mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayToInsert).toHaveBeenCalledExactlyOnceWith(baseGame, play);\n });\n\n it(\"should call generateCurrentGameHistoryRecordRevealedPlayersToInsert method when called.\", () => {\n const baseGame = createFakeGameWithCurrentPlay();\n const newGame = createFakeGameWithCurrentPlay();\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedCurrentGameHistoryPlayToInsert = createFakeGameHistoryRecordPlay();\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayToInsert.mockReturnValue(expectedCurrentGameHistoryPlayToInsert);\n services.gameHistoryRecordToInsertGenerator.generateCurrentGameHistoryRecordToInsert(baseGame, newGame, play);\n\n expect(mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordRevealedPlayersToInsert).toHaveBeenCalledExactlyOnceWith(baseGame, newGame);\n });\n\n it(\"should call generateCurrentGameHistoryRecordSwitchedSidePlayersToInsert method when called.\", () => {\n const baseGame = createFakeGameWithCurrentPlay();\n const newGame = createFakeGameWithCurrentPlay();\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedCurrentGameHistoryPlayToInsert = createFakeGameHistoryRecordPlay();\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayToInsert.mockReturnValue(expectedCurrentGameHistoryPlayToInsert);\n services.gameHistoryRecordToInsertGenerator.generateCurrentGameHistoryRecordToInsert(baseGame, newGame, play);\n\n expect(mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordSwitchedSidePlayersToInsert).toHaveBeenCalledExactlyOnceWith(baseGame, newGame);\n });\n\n it(\"should call generateCurrentGameHistoryRecordDeadPlayersToInsert method when called.\", () => {\n const baseGame = createFakeGameWithCurrentPlay();\n const newGame = createFakeGameWithCurrentPlay();\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedCurrentGameHistoryPlayToInsert = createFakeGameHistoryRecordPlay();\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayToInsert.mockReturnValue(expectedCurrentGameHistoryPlayToInsert);\n services.gameHistoryRecordToInsertGenerator.generateCurrentGameHistoryRecordToInsert(baseGame, newGame, play);\n\n expect(mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordDeadPlayersToInsert).toHaveBeenCalledExactlyOnceWith(baseGame, newGame);\n });\n\n it(\"should call generateCurrentGameHistoryRecordPlayerAttributeAlterationsToInsert method when called.\", () => {\n const baseGame = createFakeGameWithCurrentPlay();\n const newGame = createFakeGameWithCurrentPlay();\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedCurrentGameHistoryPlayToInsert = createFakeGameHistoryRecordPlay();\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayToInsert.mockReturnValue(expectedCurrentGameHistoryPlayToInsert);\n services.gameHistoryRecordToInsertGenerator.generateCurrentGameHistoryRecordToInsert(baseGame, newGame, play);\n\n expect(mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayerAttributeAlterationsToInsert).toHaveBeenCalledExactlyOnceWith(baseGame, newGame);\n });\n\n it(\"should call generateCurrentGameHistoryRecordPlayVotingToInsert method when called with votes and play type is vote.\", () => {\n const baseGame = createFakeGameWithCurrentPlay();\n const newGame = createFakeGameWithCurrentPlay();\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedCurrentGameHistoryPlayToInsert = createFakeGameHistoryRecordPlay({\n type: \"vote\",\n votes: [],\n });\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayToInsert.mockReturnValue(expectedCurrentGameHistoryPlayToInsert);\n const gameHistoryRecordToInsert = {\n gameId: baseGame._id,\n turn: baseGame.turn,\n phase: baseGame.phase,\n tick: baseGame.tick,\n play: expectedCurrentGameHistoryPlayToInsert,\n revealedPlayers: undefined,\n deadPlayers: undefined,\n };\n services.gameHistoryRecordToInsertGenerator.generateCurrentGameHistoryRecordToInsert(baseGame, newGame, play);\n\n expect(mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayVotingToInsert).toHaveBeenCalledExactlyOnceWith(baseGame, newGame, gameHistoryRecordToInsert);\n });\n\n it(\"should not call generateCurrentGameHistoryRecordPlayVotingToInsert method when called with votes and play type is not vote.\", () => {\n const baseGame = createFakeGameWithCurrentPlay();\n const newGame = createFakeGameWithCurrentPlay();\n const play = createFakeMakeGamePlayWithRelationsDto();\n const expectedCurrentGameHistoryPlayToInsert = createFakeGameHistoryRecordPlay({\n type: \"target\",\n votes: [],\n });\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayToInsert.mockReturnValue(expectedCurrentGameHistoryPlayToInsert);\n services.gameHistoryRecordToInsertGenerator.generateCurrentGameHistoryRecordToInsert(baseGame, newGame, play);\n\n expect(mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayVotingToInsert).not.toHaveBeenCalled();\n });\n });\n\n describe(\"generateCurrentGameHistoryRecordDeadPlayersToInsert\", () => {\n it(\"should generate current game history dead players when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeVillagerAlivePlayer(),\n ];\n const baseGame = createFakeGame({ players });\n const newPlayers = [\n createFakePlayer({ ...players[0], isAlive: false }),\n createFakePlayer({ ...players[1] }),\n createFakePlayer({ ...players[2], isAlive: false }),\n createFakePlayer({ ...players[3] }),\n createFakePlayer({ ...players[4] }),\n createFakeAngelAlivePlayer({ name: \"NotAGoodName\", isAlive: false }),\n ];\n const newGame = createFakeGame({\n ...baseGame,\n players: newPlayers,\n });\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordDeadPlayersToInsert\"](baseGame, newGame)).toStrictEqual([\n newPlayers[0],\n newPlayers[2],\n ]);\n });\n\n it(\"should return undefined when there is no dead players.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeVillagerAlivePlayer(),\n ];\n const baseGame = createFakeGame({ players });\n const newPlayers = [\n createFakePlayer({ ...players[0] }),\n createFakePlayer({ ...players[1] }),\n createFakePlayer({ ...players[2] }),\n createFakePlayer({ ...players[3] }),\n createFakePlayer({ ...players[4] }),\n createFakeAngelAlivePlayer({ name: \"NotAGoodName\", isAlive: false }),\n ];\n const newGame = createFakeGame({\n ...baseGame,\n players: newPlayers,\n });\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordDeadPlayersToInsert\"](baseGame, newGame)).toBeUndefined();\n });\n });\n\n describe(\"generateCurrentGameHistoryRecordSwitchedSidePlayersToInsert\", () => {\n it(\"should generate current game history switched side players when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const baseGame = createFakeGame({ players });\n const newPlayers = [\n createFakePlayer({\n ...players[0],\n side: createFakePlayerSide({ current: \"villagers\" }),\n }),\n createFakePlayer({\n ...players[1],\n side: createFakePlayerSide({ current: \"werewolves\" }),\n }),\n createFakePlayer({ ...players[2] }),\n ];\n const newGame = createFakeGame({\n ...baseGame,\n players: newPlayers,\n });\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordSwitchedSidePlayersToInsert\"](baseGame, newGame)).toStrictEqual([\n newPlayers[0],\n newPlayers[1],\n ]);\n });\n\n it(\"should return undefined when there is no switched side players.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const baseGame = createFakeGame({ players });\n const newPlayers = [\n createFakePlayer({ ...players[0] }),\n createFakePlayer({ ...players[1] }),\n createFakePlayer({ ...players[2] }),\n ];\n const newGame = createFakeGame({\n ...baseGame,\n players: newPlayers,\n });\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordSwitchedSidePlayersToInsert\"](baseGame, newGame)).toBeUndefined();\n });\n });\n\n describe(\"generateCurrentGameHistoryRecordRevealedPlayersToInsert\", () => {\n it(\"should generate current game history revealed players but alive when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ role: createFakePlayerRole({ isRevealed: false }) }),\n createFakeVillagerAlivePlayer({ role: createFakePlayerRole({ isRevealed: true }) }),\n createFakeWerewolfAlivePlayer({ role: createFakePlayerRole({ isRevealed: false }) }),\n createFakeVillagerAlivePlayer({ isAlive: false, role: createFakePlayerRole({ isRevealed: false }) }),\n createFakeVillagerAlivePlayer({ role: createFakePlayerRole({ isRevealed: false }) }),\n ];\n const baseGame = createFakeGame({ players });\n const newPlayers = [\n createFakePlayer({ ...players[0], role: createFakePlayerRole({ isRevealed: true }) }),\n createFakePlayer({ ...players[1], role: createFakePlayerRole({ isRevealed: true }) }),\n createFakePlayer({ ...players[2], role: createFakePlayerRole({ isRevealed: true }) }),\n createFakePlayer({ ...players[3], role: createFakePlayerRole({ isRevealed: true }) }),\n createFakePlayer({ ...players[4], role: createFakePlayerRole({ isRevealed: false }) }),\n createFakeAngelAlivePlayer({ role: createFakePlayerRole({ isRevealed: false }) }),\n ];\n const newGame = createFakeGame({\n ...baseGame,\n players: newPlayers,\n });\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordRevealedPlayersToInsert\"](baseGame, newGame)).toStrictEqual([\n newPlayers[0],\n newPlayers[2],\n ]);\n });\n\n it(\"should return undefined when there is no new revealed players.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ role: createFakePlayerRole({ isRevealed: false }) }),\n createFakeVillagerAlivePlayer({ role: createFakePlayerRole({ isRevealed: true }) }),\n createFakeWerewolfAlivePlayer({ role: createFakePlayerRole({ isRevealed: false }) }),\n createFakeVillagerAlivePlayer({ isAlive: false, role: createFakePlayerRole({ isRevealed: false }) }),\n createFakeVillagerAlivePlayer({ role: createFakePlayerRole({ isRevealed: false }) }),\n ];\n const baseGame = createFakeGame({ players });\n const newPlayers = [\n createFakePlayer({ ...players[0], role: createFakePlayerRole({ isRevealed: false }) }),\n createFakePlayer({ ...players[1], role: createFakePlayerRole({ isRevealed: true }) }),\n createFakePlayer({ ...players[2], role: createFakePlayerRole({ isRevealed: false }) }),\n createFakePlayer({ ...players[3], role: createFakePlayerRole({ isRevealed: true }) }),\n createFakePlayer({ ...players[4], role: createFakePlayerRole({ isRevealed: false }) }),\n createFakeAngelAlivePlayer({ role: createFakePlayerRole({ isRevealed: false }) }),\n ];\n const newGame = createFakeGame({\n ...baseGame,\n players: newPlayers,\n });\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordRevealedPlayersToInsert\"](baseGame, newGame)).toBeUndefined();\n });\n });\n\n describe(\"generateCurrentGameHistoryRecordAttachedPlayerAttributesToInsertForPlayer\", () => {\n it(\"should generate current game history attached player attributes for player when called.\", () => {\n const basePlayer = createFakePlayer({\n name: \"Antoine\",\n attributes: [createFakeSeenBySeerPlayerAttribute()],\n });\n const newPlayer = createFakePlayer({\n name: \"New Antoine\",\n attributes: [\n createFakeSeenBySeerPlayerAttribute(),\n createFakeDrankDeathPotionByWitchPlayerAttribute(),\n ],\n });\n const expectedAttachedPlayerAttributes = [\n createFakeGameHistoryRecordPlayerAttributeAlteration({\n playerName: newPlayer.name,\n name: \"drank-death-potion\",\n source: \"witch\",\n status: \"attached\",\n }),\n ];\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordAttachedPlayerAttributesToInsertForPlayer\"](basePlayer, newPlayer)).toStrictEqual(expectedAttachedPlayerAttributes);\n });\n });\n\n describe(\"generateCurrentGameHistoryRecordDetachedPlayerAttributesToInsertForPlayer\", () => {\n it(\"should generate current game history detached player attributes for player when called.\", () => {\n const basePlayer = createFakePlayer({\n name: \"Antoine\",\n attributes: [\n createFakeSeenBySeerPlayerAttribute(),\n createFakeDrankDeathPotionByWitchPlayerAttribute(),\n ],\n });\n const newPlayer = createFakePlayer({\n name: \"New Antoine\",\n attributes: [createFakeDrankDeathPotionByWitchPlayerAttribute()],\n });\n const expectedDetachedPlayerAttributes = [\n createFakeGameHistoryRecordPlayerAttributeAlteration({\n playerName: newPlayer.name,\n name: \"seen\",\n source: \"seer\",\n status: \"detached\",\n }),\n ];\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordDetachedPlayerAttributesToInsertForPlayer\"](basePlayer, newPlayer)).toStrictEqual(expectedDetachedPlayerAttributes);\n });\n });\n\n describe(\"generateCurrentGameHistoryRecordActivatedPlayerAttributesToInsertForPlayer\", () => {\n it(\"should generate current game history activated player attributes for player when called.\", () => {\n const attributes = [\n createFakeDrankDeathPotionByWitchPlayerAttribute({\n activeAt: createFakePlayerAttributeActivation({\n turn: 2,\n phaseName: \"night\",\n }),\n }),\n createFakeSeenBySeerPlayerAttribute({\n activeAt: createFakePlayerAttributeActivation({\n turn: 2,\n phaseName: \"day\",\n }),\n }),\n ];\n const baseGame = createFakeGame({\n turn: 1,\n phase: createFakeGamePhase({ name: \"day\" }),\n });\n const newGame = createFakeGame({\n turn: 2,\n phase: createFakeGamePhase({ name: \"night\" }),\n });\n const basePlayer = createFakePlayer({\n name: \"Antoine\",\n attributes,\n });\n const newPlayer = createFakePlayer({\n name: \"New Antoine\",\n attributes: [\n ...attributes,\n createFakeCharmedByPiedPiperPlayerAttribute({\n activeAt: createFakePlayerAttributeActivation({\n turn: 2,\n phaseName: \"night\",\n }),\n }),\n ],\n });\n const expectedActivatedPlayerAttributes = [\n createFakeGameHistoryRecordPlayerAttributeAlteration({\n playerName: newPlayer.name,\n name: \"drank-death-potion\",\n source: \"witch\",\n status: \"activated\",\n }),\n ];\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordActivatedPlayerAttributesToInsertForPlayer\"](baseGame, newGame, basePlayer, newPlayer)).toStrictEqual(expectedActivatedPlayerAttributes);\n });\n });\n\n describe(\"generateCurrentGameHistoryRecordPlayerAttributeAlterationsToInsert\", () => {\n beforeEach(() => {\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordAttachedPlayerAttributesToInsertForPlayer = jest.spyOn(services.gameHistoryRecordToInsertGenerator as unknown as { generateCurrentGameHistoryRecordAttachedPlayerAttributesToInsertForPlayer }, \"generateCurrentGameHistoryRecordAttachedPlayerAttributesToInsertForPlayer\").mockImplementation();\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordDetachedPlayerAttributesToInsertForPlayer = jest.spyOn(services.gameHistoryRecordToInsertGenerator as unknown as { generateCurrentGameHistoryRecordDetachedPlayerAttributesToInsertForPlayer }, \"generateCurrentGameHistoryRecordDetachedPlayerAttributesToInsertForPlayer\").mockImplementation();\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordActivatedPlayerAttributesToInsertForPlayer = jest.spyOn(services.gameHistoryRecordToInsertGenerator as unknown as { generateCurrentGameHistoryRecordActivatedPlayerAttributesToInsertForPlayer }, \"generateCurrentGameHistoryRecordActivatedPlayerAttributesToInsertForPlayer\").mockImplementation();\n });\n\n it(\"should generate attached for each matching from base game when called.\", () => {\n const goodId = createFakeObjectId();\n const matchingPlayer = createFakePlayer({\n _id: goodId,\n name: \"Antoine\",\n attributes: [createFakeSeenBySeerPlayerAttribute()],\n });\n const basePlayers = [\n matchingPlayer,\n createFakePlayer({\n name: \"New Antoine\",\n attributes: [createFakeDrankDeathPotionByWitchPlayerAttribute()],\n }),\n ];\n const newPlayers = [matchingPlayer];\n const baseGame = createFakeGame({ players: basePlayers });\n const newGame = createFakeGame({ players: newPlayers });\n services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayerAttributeAlterationsToInsert\"](baseGame, newGame);\n\n expect(mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordAttachedPlayerAttributesToInsertForPlayer).toHaveBeenCalledExactlyOnceWith(matchingPlayer, matchingPlayer);\n });\n\n it(\"should generate detached for each matching from new game when called.\", () => {\n const goodId = createFakeObjectId();\n const matchingPlayer = createFakePlayer({\n _id: goodId,\n name: \"Antoine\",\n attributes: [createFakeSeenBySeerPlayerAttribute()],\n });\n const basePlayers = [\n matchingPlayer,\n createFakePlayer({\n name: \"New Antoine\",\n attributes: [createFakeDrankDeathPotionByWitchPlayerAttribute()],\n }),\n ];\n const newPlayers = [matchingPlayer];\n const baseGame = createFakeGame({ players: basePlayers });\n const newGame = createFakeGame({ players: newPlayers });\n services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayerAttributeAlterationsToInsert\"](baseGame, newGame);\n\n expect(mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordDetachedPlayerAttributesToInsertForPlayer).toHaveBeenCalledExactlyOnceWith(matchingPlayer, matchingPlayer);\n });\n\n it(\"should generate activated for each matching from new game when called.\", () => {\n const goodId = createFakeObjectId();\n const matchingPlayer = createFakePlayer({\n _id: goodId,\n name: \"Antoine\",\n attributes: [\n createFakeSeenBySeerPlayerAttribute({\n activeAt: createFakePlayerAttributeActivation({\n turn: 2,\n phaseName: \"day\",\n }),\n }),\n ],\n });\n const basePlayers = [\n matchingPlayer,\n createFakePlayer({\n name: \"New Antoine\",\n attributes: [\n createFakeDrankDeathPotionByWitchPlayerAttribute({\n activeAt: createFakePlayerAttributeActivation({\n turn: 2,\n phaseName: \"night\",\n }),\n }),\n ],\n }),\n ];\n const newPlayers = [matchingPlayer];\n const baseGame = createFakeGame({\n turn: 1,\n phase: createFakeGamePhase({ name: \"day\" }),\n players: basePlayers,\n });\n const newGame = createFakeGame({\n turn: 2,\n phase: createFakeGamePhase({ name: \"night\" }),\n players: newPlayers,\n });\n services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayerAttributeAlterationsToInsert\"](baseGame, newGame);\n\n expect(mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordActivatedPlayerAttributesToInsertForPlayer).toHaveBeenCalledExactlyOnceWith(baseGame, newGame, matchingPlayer, matchingPlayer);\n });\n\n it(\"should concat all alterations for each matching player when called.\", () => {\n const attachedPlayerAttributes = [createFakeGameHistoryRecordPlayerAttributeAlteration()];\n const detachedPlayerAttributes = [createFakeGameHistoryRecordPlayerAttributeAlteration()];\n const activatedPlayerAttributes = [createFakeGameHistoryRecordPlayerAttributeAlteration()];\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordAttachedPlayerAttributesToInsertForPlayer.mockReturnValue(attachedPlayerAttributes);\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordDetachedPlayerAttributesToInsertForPlayer.mockReturnValue(detachedPlayerAttributes);\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordActivatedPlayerAttributesToInsertForPlayer.mockReturnValue(activatedPlayerAttributes);\n const goodId = createFakeObjectId();\n const matchingPlayer = createFakePlayer({\n _id: goodId,\n name: \"Antoine\",\n attributes: [\n createFakeSeenBySeerPlayerAttribute(),\n createFakeDrankDeathPotionByWitchPlayerAttribute(),\n ],\n });\n const basePlayers = [matchingPlayer];\n const newPlayers = [\n matchingPlayer,\n createFakePlayer({\n name: \"New Antoine\",\n attributes: [createFakeDrankDeathPotionByWitchPlayerAttribute()],\n }),\n ];\n const baseGame = createFakeGame({ players: basePlayers });\n const newGame = createFakeGame({ players: newPlayers });\n const expectedPlayerAttributeAlterations = [\n ...attachedPlayerAttributes,\n ...detachedPlayerAttributes,\n ...activatedPlayerAttributes,\n ];\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayerAttributeAlterationsToInsert\"](baseGame, newGame)).toStrictEqual(expectedPlayerAttributeAlterations);\n });\n\n it(\"should return undefined when there are no alterations for every players.\", () => {\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordAttachedPlayerAttributesToInsertForPlayer.mockReturnValue([]);\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordDetachedPlayerAttributesToInsertForPlayer.mockReturnValue([]);\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordActivatedPlayerAttributesToInsertForPlayer.mockReturnValue([]);\n const basePlayers = [\n createFakePlayer({\n name: \"Antoine\",\n attributes: [createFakeSeenBySeerPlayerAttribute()],\n }),\n createFakePlayer({\n name: \"New Antoine\",\n attributes: [createFakeDrankDeathPotionByWitchPlayerAttribute()],\n }),\n ];\n const newPlayers = [\n createFakePlayer({\n name: \"Antoine\",\n attributes: [createFakeSeenBySeerPlayerAttribute()],\n }),\n createFakePlayer({\n name: \"New Antoine\",\n attributes: [createFakeDrankDeathPotionByWitchPlayerAttribute()],\n }),\n ];\n const baseGame = createFakeGame({ players: basePlayers });\n const newGame = createFakeGame({ players: newPlayers });\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayerAttributeAlterationsToInsert\"](baseGame, newGame)).toBeUndefined();\n });\n });\n\n describe(\"generateCurrentGameHistoryRecordPlayTargetsToInsert\", () => {\n it(\"should return undefined when there are no targets.\", () => {\n const baseGame = createFakeGameWithCurrentPlay();\n const play = createFakeMakeGamePlayWithRelationsDto();\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayTargetsToInsert\"](baseGame, play)).toBeUndefined();\n });\n\n it(\"should return targets when there are targets and action is not sniff.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const baseGame = createFakeGameWithCurrentPlay({\n players,\n currentPlay: createFakeGamePlaySheriffDelegates(),\n });\n const targets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[0] })];\n const play = createFakeMakeGamePlayWithRelationsDto({\n targets,\n });\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayTargetsToInsert\"](baseGame, play)).toStrictEqual(targets);\n });\n\n it(\"should return group of 3 targets when action is sniff.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ position: 0 }),\n createFakeVillagerAlivePlayer({ position: 1 }),\n createFakeWerewolfAlivePlayer({ position: 2 }),\n createFakeWerewolfAlivePlayer({ position: 3 }),\n ];\n const baseGame = createFakeGameWithCurrentPlay({\n players,\n currentPlay: createFakeGamePlayFoxSniffs(),\n });\n const targets = [createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1] })];\n const play = createFakeMakeGamePlayWithRelationsDto({\n targets,\n });\n const expectedTargets = [\n createFakeMakeGamePlayTargetWithRelationsDto({ player: players[0] }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: players[1] }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: players[2] }),\n ];\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayTargetsToInsert\"](baseGame, play)).toStrictEqual(expectedTargets);\n });\n });\n\n describe(\"generateCurrentGameHistoryRecordPlayToInsert\", () => {\n beforeEach(() => {\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlaySourceToInsert = jest.spyOn(services.gameHistoryRecordToInsertGenerator as unknown as { generateCurrentGameHistoryRecordPlaySourceToInsert }, \"generateCurrentGameHistoryRecordPlaySourceToInsert\").mockImplementation();\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayTargetsToInsert = jest.spyOn(services.gameHistoryRecordToInsertGenerator as unknown as { generateCurrentGameHistoryRecordPlayTargetsToInsert }, \"generateCurrentGameHistoryRecordPlayTargetsToInsert\").mockImplementation();\n });\n\n it(\"should generate current game history record play to insert when called.\", () => {\n const game = createFakeGameWithCurrentPlay();\n const play = createFakeMakeGamePlayWithRelationsDto({\n doesJudgeRequestAnotherVote: true,\n targets: [createFakeGameHistoryRecordPlayTarget()],\n votes: [createFakeGameHistoryRecordPlayVote()],\n chosenCard: createFakeGameAdditionalCard(),\n chosenSide: \"villagers\",\n });\n const expectedGameHistoryRecordPlaySource = { name: undefined, players: undefined };\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlaySourceToInsert.mockReturnValue(expectedGameHistoryRecordPlaySource);\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayTargetsToInsert.mockReturnValue(play.targets);\n const expectedGameHistoryRecordPlay = createFakeGameHistoryRecordPlay({\n type: game.currentPlay.type,\n action: game.currentPlay.action,\n didJudgeRequestAnotherVote: play.doesJudgeRequestAnotherVote,\n targets: play.targets,\n votes: play.votes,\n chosenCard: play.chosenCard,\n chosenSide: play.chosenSide,\n }, { source: expectedGameHistoryRecordPlaySource });\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayToInsert\"](game, play)).toStrictEqual(expectedGameHistoryRecordPlay);\n });\n });\n\n describe(\"generateCurrentGameHistoryRecordPlayVotingResultToInsert\", () => {\n it(\"should return sheriff election when there is a sheriff in the game.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeHunterAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const nominatedPlayers = [players[2], players[3]];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlaySurvivorsElectSheriff() });\n const newGame = createFakeGame({\n ...game,\n players: [\n createFakePlayer(players[0]),\n createFakePlayer({ ...players[1], attributes: [createFakeSheriffBySurvivorsPlayerAttribute()] }),\n createFakePlayer(players[2]),\n createFakePlayer(players[3]),\n ],\n });\n const gameHistoryRecordToInsert = createFakeGameHistoryRecordToInsert();\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayVotingResultToInsert\"](game, newGame, nominatedPlayers, gameHistoryRecordToInsert)).toBe(\"sheriff-election\");\n });\n\n it(\"should return tie when there is no sheriff in the game after election.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeHunterAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const nominatedPlayers = [players[2], players[3]];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlaySurvivorsElectSheriff() });\n const newGame = createFakeGame({\n ...game,\n players: [\n createFakePlayer(players[0]),\n createFakePlayer(players[1]),\n createFakePlayer(players[2]),\n createFakePlayer(players[3]),\n ],\n });\n const gameHistoryRecordToInsert = createFakeGameHistoryRecordToInsert();\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayVotingResultToInsert\"](game, newGame, nominatedPlayers, gameHistoryRecordToInsert)).toBe(\"tie\");\n });\n\n it(\"should return skipped when there are no vote set.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeHunterAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const nominatedPlayers = [players[2], players[3]];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlaySurvivorsVote() });\n const newGame = createFakeGame({\n ...game,\n players: [\n createFakePlayer(players[0]),\n createFakePlayer(players[1]),\n createFakePlayer(players[2]),\n createFakePlayer(players[3]),\n ],\n });\n const gameHistoryRecordPlay = createFakeGameHistoryRecordPlay({ votes: undefined });\n const gameHistoryRecordToInsert = createFakeGameHistoryRecordToInsert({ play: gameHistoryRecordPlay, deadPlayers: [createFakeDeadPlayer({ ...players[1], isAlive: false, death: createFakePlayerVoteBySurvivorsDeath() })] });\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayVotingResultToInsert\"](game, newGame, nominatedPlayers, gameHistoryRecordToInsert)).toBe(\"skipped\");\n });\n\n it(\"should return skipped when votes are empty.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeHunterAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const nominatedPlayers = [players[2], players[3]];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlaySurvivorsVote() });\n const newGame = createFakeGame({\n ...game,\n players: [\n createFakePlayer(players[0]),\n createFakePlayer(players[1]),\n createFakePlayer(players[2]),\n createFakePlayer(players[3]),\n ],\n });\n const gameHistoryRecordPlay = createFakeGameHistoryRecordPlay({ votes: [] });\n const gameHistoryRecordToInsert = createFakeGameHistoryRecordToInsert({ play: gameHistoryRecordPlay, deadPlayers: [createFakeDeadPlayer({ ...players[1], isAlive: false, death: createFakePlayerVoteBySurvivorsDeath() })] });\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayVotingResultToInsert\"](game, newGame, nominatedPlayers, gameHistoryRecordToInsert)).toBe(\"skipped\");\n });\n\n it(\"should return death when there is at least one dead player from votes.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeHunterAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const nominatedPlayers = [players[2], players[3]];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlaySurvivorsVote() });\n const newGame = createFakeGame({\n ...game,\n players: [\n createFakePlayer(players[0]),\n createFakePlayer(players[1]),\n createFakePlayer(players[2]),\n createFakePlayer(players[3]),\n ],\n });\n const gameHistoryRecordPlay = createFakeGameHistoryRecordPlay({ votes: [createFakeGameHistoryRecordPlayVote()] });\n const deadPlayers = [\n createFakeDeadPlayer({ ...players[1], isAlive: false, death: createFakePlayerVoteBySurvivorsDeath() }),\n createFakeDeadPlayer({ ...players[1], isAlive: false, death: createFakePlayerDeathPotionByWitchDeath() }),\n ];\n const gameHistoryRecordToInsert = createFakeGameHistoryRecordToInsert({ play: gameHistoryRecordPlay, deadPlayers });\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayVotingResultToInsert\"](game, newGame, nominatedPlayers, gameHistoryRecordToInsert)).toBe(\"death\");\n });\n\n it(\"should return death when there is at least one dead player from scapegoat votes.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeHunterAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const nominatedPlayers = [players[2], players[3]];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlaySurvivorsVote() });\n const newGame = createFakeGame({\n ...game,\n players: [\n createFakePlayer(players[0]),\n createFakePlayer(players[1]),\n createFakePlayer(players[2]),\n createFakePlayer(players[3]),\n ],\n });\n const gameHistoryRecordPlay = createFakeGameHistoryRecordPlay({ votes: [createFakeGameHistoryRecordPlayVote()] });\n const gameHistoryRecordToInsert = createFakeGameHistoryRecordToInsert({ play: gameHistoryRecordPlay, deadPlayers: [createFakeDeadPlayer({ ...players[1], isAlive: false, death: createFakePlayerVoteScapegoatedBySurvivorsDeath() })] });\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayVotingResultToInsert\"](game, newGame, nominatedPlayers, gameHistoryRecordToInsert)).toBe(\"death\");\n });\n\n it(\"should return inconsequential when there is no death from votes and current play was already after a tie.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeHunterAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const nominatedPlayers = [players[2], players[3]];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlaySurvivorsVote({ causes: [\"previous-votes-were-in-ties\"] }) });\n const newGame = createFakeGame({\n ...game,\n players: [\n createFakePlayer(players[0]),\n createFakePlayer(players[1]),\n createFakePlayer(players[2]),\n createFakePlayer(players[3]),\n ],\n });\n const gameHistoryRecordPlay = createFakeGameHistoryRecordPlay({ votes: [createFakeGameHistoryRecordPlayVote()] });\n const gameHistoryRecordToInsert = createFakeGameHistoryRecordToInsert({ play: gameHistoryRecordPlay, deadPlayers: [createFakeDeadPlayer({ ...players[1], isAlive: false, death: createFakePlayerDeathPotionByWitchDeath() })] });\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayVotingResultToInsert\"](game, newGame, nominatedPlayers, gameHistoryRecordToInsert)).toBe(\"inconsequential\");\n });\n\n it(\"should return inconsequential when there is no death from votes, current play was not already after a tie but only one player was nominated.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeHunterAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const nominatedPlayers = [players[2]];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlaySurvivorsVote({ causes: [\"stuttering-judge-request\"] }) });\n const newGame = createFakeGame({\n ...game,\n players: [\n createFakePlayer(players[0]),\n createFakePlayer(players[1]),\n createFakePlayer(players[2]),\n createFakePlayer(players[3]),\n ],\n });\n const gameHistoryRecordPlay = createFakeGameHistoryRecordPlay({ votes: [createFakeGameHistoryRecordPlayVote()] });\n const gameHistoryRecordToInsert = createFakeGameHistoryRecordToInsert({ play: gameHistoryRecordPlay, deadPlayers: [createFakeDeadPlayer({ ...players[1], isAlive: false, death: createFakePlayerDeathPotionByWitchDeath() })] });\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayVotingResultToInsert\"](game, newGame, nominatedPlayers, gameHistoryRecordToInsert)).toBe(\"inconsequential\");\n });\n\n it(\"should return tie when there is no death from votes, current play was not after a tie and there are several nominated players.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeHunterAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ];\n const nominatedPlayers = [players[2], players[3]];\n const game = createFakeGameWithCurrentPlay({ players, currentPlay: createFakeGamePlaySurvivorsVote({ causes: [\"stuttering-judge-request\"] }) });\n const newGame = createFakeGame({\n ...game,\n players: [\n createFakePlayer(players[0]),\n createFakePlayer(players[1]),\n createFakePlayer(players[2]),\n createFakePlayer(players[3]),\n ],\n });\n const gameHistoryRecordPlay = createFakeGameHistoryRecordPlay({ votes: [createFakeGameHistoryRecordPlayVote()] });\n const gameHistoryRecordToInsert = createFakeGameHistoryRecordToInsert({ play: gameHistoryRecordPlay, deadPlayers: [createFakeDeadPlayer({ ...players[1], isAlive: false, death: createFakePlayerDeathPotionByWitchDeath() })] });\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayVotingResultToInsert\"](game, newGame, nominatedPlayers, gameHistoryRecordToInsert)).toBe(\"tie\");\n });\n });\n\n describe(\"generateCurrentGameHistoryRecordPlayVotingToInsert\", () => {\n beforeEach(() => {\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayVotingResultToInsert = jest.spyOn(services.gameHistoryRecordToInsertGenerator as unknown as { generateCurrentGameHistoryRecordPlayVotingResultToInsert }, \"generateCurrentGameHistoryRecordPlayVotingResultToInsert\").mockImplementation();\n });\n\n it(\"should generate current game history record play voting when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const newGame = createFakeGameWithCurrentPlay(game);\n const gameHistoryRecordToInsert = createFakeGameHistoryRecordToInsert();\n const nominatedPlayers = [players[2]];\n mocks.gamePlayVoteService.getNominatedPlayers.mockReturnValue(nominatedPlayers);\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayVotingResultToInsert.mockReturnValue(\"death\");\n const expectedCurrentGameHistoryRecordPlayVoting = createFakeGameHistoryRecordPlayVoting({\n result: \"death\",\n nominatedPlayers,\n });\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayVotingToInsert\"](game, newGame, gameHistoryRecordToInsert)).toStrictEqual(expectedCurrentGameHistoryRecordPlayVoting);\n });\n\n it(\"should generate current game history record play voting without nominated players when no nominated players are found.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const newGame = createFakeGameWithCurrentPlay(game);\n const gameHistoryRecordToInsert = createFakeGameHistoryRecordToInsert();\n const nominatedPlayers = [];\n mocks.gamePlayVoteService.getNominatedPlayers.mockReturnValue(nominatedPlayers);\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayVotingResultToInsert.mockReturnValue(\"death\");\n const expectedCurrentGameHistoryRecordPlayVoting = createFakeGameHistoryRecordPlayVoting({ result: \"death\" });\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayVotingToInsert\"](game, newGame, gameHistoryRecordToInsert)).toStrictEqual(expectedCurrentGameHistoryRecordPlayVoting);\n });\n\n it(\"should call getNominatedPlayers method with undefined votes when called without votes.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const newGame = createFakeGameWithCurrentPlay(game);\n const gameHistoryRecordToInsert = createFakeGameHistoryRecordToInsert();\n const nominatedPlayers = [players[2]];\n mocks.gamePlayVoteService.getNominatedPlayers.mockReturnValue(nominatedPlayers);\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayVotingResultToInsert.mockReturnValue(\"death\");\n services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayVotingToInsert\"](game, newGame, gameHistoryRecordToInsert);\n\n expect(mocks.gamePlayVoteService.getNominatedPlayers).toHaveBeenCalledExactlyOnceWith(undefined, game);\n });\n\n it(\"should call getNominatedPlayers method with votes when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const newGame = createFakeGameWithCurrentPlay(game);\n const gameHistoryRecordToInsert = createFakeGameHistoryRecordToInsert({ play: createFakeGameHistoryRecordPlay({ votes: [createFakeGameHistoryRecordPlayVote()] }) });\n const nominatedPlayers = [players[2]];\n mocks.gamePlayVoteService.getNominatedPlayers.mockReturnValue(nominatedPlayers);\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayVotingResultToInsert.mockReturnValue(\"death\");\n services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayVotingToInsert\"](game, newGame, gameHistoryRecordToInsert);\n\n expect(mocks.gamePlayVoteService.getNominatedPlayers).toHaveBeenCalledExactlyOnceWith(gameHistoryRecordToInsert.play.votes, game);\n });\n\n it(\"should call generateCurrentGameHistoryRecordPlayVotingResultToInsert method when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGameWithCurrentPlay({ players });\n const newGame = createFakeGameWithCurrentPlay(game);\n const gameHistoryRecordToInsert = createFakeGameHistoryRecordToInsert({ play: createFakeGameHistoryRecordPlay({ votes: [createFakeGameHistoryRecordPlayVote()] }) });\n const nominatedPlayers = [players[2]];\n mocks.gamePlayVoteService.getNominatedPlayers.mockReturnValue(nominatedPlayers);\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayVotingResultToInsert.mockReturnValue(\"death\");\n services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlayVotingToInsert\"](game, newGame, gameHistoryRecordToInsert);\n\n expect(mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordPlayVotingResultToInsert).toHaveBeenCalledExactlyOnceWith(game, newGame, nominatedPlayers, gameHistoryRecordToInsert);\n });\n });\n\n describe(\"generateCurrentGameHistoryRecordPlaySourceToInsert\", () => {\n it(\"should generate current game history record play source when called.\", () => {\n const players = [\n createFakeHunterAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeVillagerAlivePlayer(),\n ];\n const expectedPlayers = [players[0], players[1], players[3]];\n const game = createFakeGameWithCurrentPlay({ currentPlay: createGamePlaySurvivorsElectSheriff({ source: createFakeGamePlaySource({ name: \"survivors\", players: expectedPlayers }) }), players });\n const expectedGameHistoryRecordPlaySource = createFakeGameHistoryRecordPlaySource({\n name: game.currentPlay.source.name,\n players: expectedPlayers,\n });\n\n expect(services.gameHistoryRecordToInsertGenerator[\"generateCurrentGameHistoryRecordPlaySourceToInsert\"](game)).toStrictEqual(expectedGameHistoryRecordPlaySource);\n });\n });\n});" }, "tests/unit/specs/modules/game/providers/services/game-event/game-events-generator.service.spec.ts": { "tests": [ @@ -193498,7 +193500,7 @@ "location": { "start": { "column": 6, - "line": 78 + "line": 80 } } }, @@ -193508,7 +193510,7 @@ "location": { "start": { "column": 6, - "line": 86 + "line": 88 } } }, @@ -193518,7 +193520,7 @@ "location": { "start": { "column": 6, - "line": 94 + "line": 96 } } }, @@ -193528,7 +193530,7 @@ "location": { "start": { "column": 6, - "line": 102 + "line": 104 } } }, @@ -193538,7 +193540,7 @@ "location": { "start": { "column": 6, - "line": 110 + "line": 112 } } }, @@ -193548,7 +193550,7 @@ "location": { "start": { "column": 6, - "line": 118 + "line": 120 } } }, @@ -193558,7 +193560,7 @@ "location": { "start": { "column": 6, - "line": 126 + "line": 128 } } }, @@ -193568,7 +193570,7 @@ "location": { "start": { "column": 6, - "line": 134 + "line": 136 } } }, @@ -193578,7 +193580,7 @@ "location": { "start": { "column": 6, - "line": 142 + "line": 144 } } }, @@ -193588,7 +193590,7 @@ "location": { "start": { "column": 6, - "line": 152 + "line": 154 } } }, @@ -193598,7 +193600,7 @@ "location": { "start": { "column": 6, - "line": 163 + "line": 165 } } }, @@ -193608,7 +193610,7 @@ "location": { "start": { "column": 6, - "line": 188 + "line": 190 } } }, @@ -193618,7 +193620,7 @@ "location": { "start": { "column": 6, - "line": 213 + "line": 215 } } }, @@ -193628,7 +193630,7 @@ "location": { "start": { "column": 6, - "line": 240 + "line": 242 } } }, @@ -193638,7 +193640,7 @@ "location": { "start": { "column": 6, - "line": 254 + "line": 256 } } }, @@ -193648,7 +193650,7 @@ "location": { "start": { "column": 6, - "line": 265 + "line": 267 } } }, @@ -193658,7 +193660,7 @@ "location": { "start": { "column": 6, - "line": 279 + "line": 281 } } }, @@ -193668,7 +193670,7 @@ "location": { "start": { "column": 6, - "line": 290 + "line": 292 } } }, @@ -193678,7 +193680,7 @@ "location": { "start": { "column": 6, - "line": 304 + "line": 306 } } }, @@ -193688,7 +193690,7 @@ "location": { "start": { "column": 6, - "line": 315 + "line": 317 } } }, @@ -193698,7 +193700,7 @@ "location": { "start": { "column": 6, - "line": 331 + "line": 333 } } }, @@ -193708,7 +193710,7 @@ "location": { "start": { "column": 6, - "line": 345 + "line": 347 } } }, @@ -193718,7 +193720,7 @@ "location": { "start": { "column": 6, - "line": 356 + "line": 358 } } }, @@ -193728,7 +193730,7 @@ "location": { "start": { "column": 6, - "line": 370 + "line": 372 } } }, @@ -193738,7 +193740,7 @@ "location": { "start": { "column": 6, - "line": 381 + "line": 383 } } }, @@ -193748,7 +193750,7 @@ "location": { "start": { "column": 6, - "line": 395 + "line": 397 } } }, @@ -193758,7 +193760,7 @@ "location": { "start": { "column": 6, - "line": 406 + "line": 408 } } }, @@ -193768,7 +193770,7 @@ "location": { "start": { "column": 6, - "line": 419 + "line": 421 } } }, @@ -193778,7 +193780,7 @@ "location": { "start": { "column": 6, - "line": 444 + "line": 446 } } }, @@ -193788,7 +193790,7 @@ "location": { "start": { "column": 6, - "line": 451 + "line": 453 } } }, @@ -193798,7 +193800,7 @@ "location": { "start": { "column": 6, - "line": 473 + "line": 475 } } }, @@ -193808,7 +193810,7 @@ "location": { "start": { "column": 6, - "line": 487 + "line": 489 } } }, @@ -193818,7 +193820,7 @@ "location": { "start": { "column": 6, - "line": 501 + "line": 503 } } }, @@ -193828,7 +193830,7 @@ "location": { "start": { "column": 6, - "line": 517 + "line": 519 } } }, @@ -193838,7 +193840,7 @@ "location": { "start": { "column": 6, - "line": 531 + "line": 533 } } }, @@ -193848,7 +193850,7 @@ "location": { "start": { "column": 6, - "line": 545 + "line": 547 } } }, @@ -193858,7 +193860,7 @@ "location": { "start": { "column": 6, - "line": 563 + "line": 565 } } }, @@ -193868,7 +193870,7 @@ "location": { "start": { "column": 6, - "line": 581 + "line": 583 } } }, @@ -193878,7 +193880,7 @@ "location": { "start": { "column": 6, - "line": 596 + "line": 598 } } }, @@ -193888,7 +193890,7 @@ "location": { "start": { "column": 6, - "line": 611 + "line": 613 } } }, @@ -193898,7 +193900,7 @@ "location": { "start": { "column": 6, - "line": 627 + "line": 629 } } }, @@ -193908,7 +193910,7 @@ "location": { "start": { "column": 6, - "line": 634 + "line": 636 } } }, @@ -193918,7 +193920,7 @@ "location": { "start": { "column": 6, - "line": 653 + "line": 655 } } }, @@ -193928,7 +193930,7 @@ "location": { "start": { "column": 6, - "line": 681 + "line": 683 } } }, @@ -193938,7 +193940,7 @@ "location": { "start": { "column": 6, - "line": 688 + "line": 690 } } }, @@ -193948,7 +193950,7 @@ "location": { "start": { "column": 6, - "line": 694 + "line": 696 } } }, @@ -193958,7 +193960,7 @@ "location": { "start": { "column": 6, - "line": 708 + "line": 710 } } }, @@ -193968,7 +193970,7 @@ "location": { "start": { "column": 6, - "line": 720 + "line": 722 } } }, @@ -193978,7 +193980,7 @@ "location": { "start": { "column": 6, - "line": 727 + "line": 729 } } }, @@ -193988,7 +193990,7 @@ "location": { "start": { "column": 6, - "line": 733 + "line": 735 } } }, @@ -193998,7 +194000,7 @@ "location": { "start": { "column": 6, - "line": 750 + "line": 752 } } }, @@ -194008,7 +194010,7 @@ "location": { "start": { "column": 6, - "line": 763 + "line": 765 } } }, @@ -194018,7 +194020,7 @@ "location": { "start": { "column": 6, - "line": 778 + "line": 780 } } }, @@ -194028,7 +194030,7 @@ "location": { "start": { "column": 6, - "line": 785 + "line": 787 } } }, @@ -194038,7 +194040,7 @@ "location": { "start": { "column": 6, - "line": 791 + "line": 793 } } }, @@ -194048,7 +194050,7 @@ "location": { "start": { "column": 6, - "line": 810 + "line": 812 } } }, @@ -194058,7 +194060,7 @@ "location": { "start": { "column": 6, - "line": 829 + "line": 831 } } }, @@ -194068,7 +194070,7 @@ "location": { "start": { "column": 6, - "line": 848 + "line": 850 } } }, @@ -194078,7 +194080,7 @@ "location": { "start": { "column": 6, - "line": 867 + "line": 869 } } }, @@ -194088,7 +194090,7 @@ "location": { "start": { "column": 6, - "line": 886 + "line": 888 } } }, @@ -194098,7 +194100,7 @@ "location": { "start": { "column": 6, - "line": 905 + "line": 907 } } }, @@ -194108,7 +194110,7 @@ "location": { "start": { "column": 6, - "line": 926 + "line": 928 } } }, @@ -194118,7 +194120,7 @@ "location": { "start": { "column": 6, - "line": 954 + "line": 956 } } }, @@ -194128,7 +194130,7 @@ "location": { "start": { "column": 6, - "line": 966 + "line": 968 } } }, @@ -194138,7 +194140,7 @@ "location": { "start": { "column": 6, - "line": 978 + "line": 980 } } }, @@ -194148,7 +194150,7 @@ "location": { "start": { "column": 6, - "line": 993 + "line": 995 } } }, @@ -194158,7 +194160,7 @@ "location": { "start": { "column": 6, - "line": 1012 + "line": 1014 } } }, @@ -194168,7 +194170,7 @@ "location": { "start": { "column": 6, - "line": 1031 + "line": 1033 } } }, @@ -194178,7 +194180,7 @@ "location": { "start": { "column": 6, - "line": 1052 + "line": 1054 } } }, @@ -194188,7 +194190,7 @@ "location": { "start": { "column": 6, - "line": 1073 + "line": 1075 } } }, @@ -194198,7 +194200,7 @@ "location": { "start": { "column": 6, - "line": 1085 + "line": 1087 } } }, @@ -194208,7 +194210,7 @@ "location": { "start": { "column": 6, - "line": 1096 + "line": 1098 } } }, @@ -194218,7 +194220,7 @@ "location": { "start": { "column": 6, - "line": 1120 + "line": 1122 } } }, @@ -194228,7 +194230,7 @@ "location": { "start": { "column": 6, - "line": 1145 + "line": 1147 } } }, @@ -194238,7 +194240,7 @@ "location": { "start": { "column": 6, - "line": 1167 + "line": 1169 } } }, @@ -194248,7 +194250,7 @@ "location": { "start": { "column": 6, - "line": 1177 + "line": 1179 } } }, @@ -194258,7 +194260,7 @@ "location": { "start": { "column": 6, - "line": 1203 + "line": 1205 } } }, @@ -194268,7 +194270,7 @@ "location": { "start": { "column": 6, - "line": 1221 + "line": 1223 } } }, @@ -194278,12 +194280,12 @@ "location": { "start": { "column": 6, - "line": 1241 + "line": 1243 } } } ], - "source": "import { DEFAULT_GAME_OPTIONS } from \"@/modules/game/constants/game-options/game-options.constants\";\nimport { GameEventsGeneratorService } from \"@/modules/game/providers/services/game-event/game-events-generator.service\";\nimport type { GameEvent } from \"@/modules/game/schemas/game-event/game-event.schema\";\nimport type { TestingModule } from \"@nestjs/testing\";\nimport { Test } from \"@nestjs/testing\";\nimport { createFakeGameEvent } from \"@tests/factories/game/schemas/game-event/game-event.schema.factory\";\nimport { createFakeGameHistoryRecord, createFakeGameHistoryRecordPlay, createFakeGameHistoryRecordPlayerAttributeAlteration, createFakeGameHistoryRecordPlaySource, createFakeGameHistoryRecordPlayTarget } from \"@tests/factories/game/schemas/game-history-record/game-history-record.schema.factory\";\nimport { createFakeGamePhase } from \"@tests/factories/game/schemas/game-phase/game-phase.schema.factory\";\nimport { createFakeGamePlaySurvivorsVote, createFakeGamePlayWerewolvesEat } from \"@tests/factories/game/schemas/game-play/game-play.schema.factory\";\nimport { createFakeGame } from \"@tests/factories/game/schemas/game.schema.factory\";\nimport { createFakePlayerAttribute, createFakeScandalmongerMarkedByScandalmongerPlayerAttribute } from \"@tests/factories/game/schemas/player/player-attribute/player-attribute.schema.factory\";\nimport { createFakeActorAlivePlayer, createFakeBearTamerAlivePlayer, createFakeElderAlivePlayer, createFakeIdiotAlivePlayer, createFakeScandalmongerAlivePlayer, createFakeThiefAlivePlayer, createFakeVillagerAlivePlayer, createFakeVillagerVillagerAlivePlayer, createFakeWerewolfAlivePlayer, createFakeWildChildAlivePlayer, createFakeWolfHoundAlivePlayer } from \"@tests/factories/game/schemas/player/player-with-role.schema.factory\";\nimport { createFakeDeadPlayer, createFakePlayerSide } from \"@tests/factories/game/schemas/player/player.schema.factory\";\n\ndescribe(\"Game Events Generator Service\", () => {\n let mocks: {\n gameEventsGeneratorService: {\n generateSeerHasSeenGameEvent: jest.SpyInstance;\n generateScandalmongerHayHaveMarkedGameEvent: jest.SpyInstance;\n generateAccursedWolfFatherMayHaveInfectedGameEvent: jest.SpyInstance;\n generateWolfHoundHasChosenSideGameEvent: jest.SpyInstance;\n generatePiedPiperHasCharmedGameEvent: jest.SpyInstance;\n generateCupidHasCharmedGameEvent: jest.SpyInstance;\n generateFoxMayHaveSniffedGameEvent: jest.SpyInstance;\n generateThiefMayHaveChosenCardGameEvent: jest.SpyInstance;\n generateActorMayHaveChosenCardGameEvent: jest.SpyInstance;\n generateLastGamePlaySourceGameEvent: jest.SpyInstance;\n generateFirstTickGameEvents: jest.SpyInstance;\n generateRevealedPlayersGameEvents: jest.SpyInstance;\n generateSwitchedSidePlayersGameEvents: jest.SpyInstance;\n generateDeadPlayersGameEvents: jest.SpyInstance;\n generateBearGrowlsOrSleepsGameEvent: jest.SpyInstance;\n generatePlayerAttributeAlterationsEvents: jest.SpyInstance;\n generateTurnStartsGameEvents: jest.SpyInstance;\n };\n };\n let services: { gameEventsGenerator: GameEventsGeneratorService };\n\n beforeEach(async() => {\n mocks = {\n gameEventsGeneratorService: {\n generateSeerHasSeenGameEvent: jest.fn(),\n generateScandalmongerHayHaveMarkedGameEvent: jest.fn(),\n generateAccursedWolfFatherMayHaveInfectedGameEvent: jest.fn(),\n generateWolfHoundHasChosenSideGameEvent: jest.fn(),\n generatePiedPiperHasCharmedGameEvent: jest.fn(),\n generateCupidHasCharmedGameEvent: jest.fn(),\n generateFoxMayHaveSniffedGameEvent: jest.fn(),\n generateThiefMayHaveChosenCardGameEvent: jest.fn(),\n generateActorMayHaveChosenCardGameEvent: jest.fn(),\n generateLastGamePlaySourceGameEvent: jest.fn(),\n generateFirstTickGameEvents: jest.fn(),\n generateRevealedPlayersGameEvents: jest.fn(),\n generateSwitchedSidePlayersGameEvents: jest.fn(),\n generateDeadPlayersGameEvents: jest.fn(),\n generateBearGrowlsOrSleepsGameEvent: jest.fn(),\n generatePlayerAttributeAlterationsEvents: jest.fn(),\n generateTurnStartsGameEvents: jest.fn(),\n },\n };\n const module: TestingModule = await Test.createTestingModule({ providers: [GameEventsGeneratorService] }).compile();\n\n services = { gameEventsGenerator: module.get(GameEventsGeneratorService) };\n });\n\n describe(\"generateGameEventsFromGameAndLastRecord\", () => {\n beforeEach(() => {\n mocks.gameEventsGeneratorService.generateFirstTickGameEvents = jest.spyOn(services.gameEventsGenerator as unknown as { generateFirstTickGameEvents }, \"generateFirstTickGameEvents\").mockReturnValue([]);\n mocks.gameEventsGeneratorService.generateRevealedPlayersGameEvents = jest.spyOn(services.gameEventsGenerator as unknown as { generateRevealedPlayersGameEvents }, \"generateRevealedPlayersGameEvents\").mockReturnValue([]);\n mocks.gameEventsGeneratorService.generateSwitchedSidePlayersGameEvents = jest.spyOn(services.gameEventsGenerator as unknown as { generateSwitchedSidePlayersGameEvents }, \"generateSwitchedSidePlayersGameEvents\").mockReturnValue([]);\n mocks.gameEventsGeneratorService.generateDeadPlayersGameEvents = jest.spyOn(services.gameEventsGenerator as unknown as { generateDeadPlayersGameEvents }, \"generateDeadPlayersGameEvents\").mockReturnValue([]);\n mocks.gameEventsGeneratorService.generateBearGrowlsOrSleepsGameEvent = jest.spyOn(services.gameEventsGenerator as unknown as { generateBearGrowlsOrSleepsGameEvent }, \"generateBearGrowlsOrSleepsGameEvent\").mockReturnValue([]);\n mocks.gameEventsGeneratorService.generatePlayerAttributeAlterationsEvents = jest.spyOn(services.gameEventsGenerator as unknown as { generatePlayerAttributeAlterationsEvents }, \"generatePlayerAttributeAlterationsEvents\").mockReturnValue([]);\n mocks.gameEventsGeneratorService.generateTurnStartsGameEvents = jest.spyOn(services.gameEventsGenerator as unknown as { generateTurnStartsGameEvents }, \"generateTurnStartsGameEvents\").mockReturnValue([]);\n mocks.gameEventsGeneratorService.generateLastGamePlaySourceGameEvent = jest.spyOn(services.gameEventsGenerator as unknown as { generateLastGamePlaySourceGameEvent }, \"generateLastGamePlaySourceGameEvent\").mockReturnValue(undefined);\n });\n\n it(\"should generate first tick game events when called.\", () => {\n const gameHistoryRecord = createFakeGameHistoryRecord();\n const game = createFakeGame();\n services.gameEventsGenerator.generateGameEventsFromGameAndLastRecord(game, gameHistoryRecord);\n\n expect(mocks.gameEventsGeneratorService.generateFirstTickGameEvents).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should generate revealed players game events when called.\", () => {\n const gameHistoryRecord = createFakeGameHistoryRecord();\n const game = createFakeGame();\n services.gameEventsGenerator.generateGameEventsFromGameAndLastRecord(game, gameHistoryRecord);\n\n expect(mocks.gameEventsGeneratorService.generateRevealedPlayersGameEvents).toHaveBeenCalledExactlyOnceWith(gameHistoryRecord);\n });\n\n it(\"should generate last game play source game event when called.\", () => {\n const gameHistoryRecord = createFakeGameHistoryRecord();\n const game = createFakeGame();\n services.gameEventsGenerator.generateGameEventsFromGameAndLastRecord(game, gameHistoryRecord);\n\n expect(mocks.gameEventsGeneratorService.generateLastGamePlaySourceGameEvent).toHaveBeenCalledExactlyOnceWith(game, gameHistoryRecord);\n });\n\n it(\"should generate switched side players game events when called.\", () => {\n const gameHistoryRecord = createFakeGameHistoryRecord();\n const game = createFakeGame();\n services.gameEventsGenerator.generateGameEventsFromGameAndLastRecord(game, gameHistoryRecord);\n\n expect(mocks.gameEventsGeneratorService.generateSwitchedSidePlayersGameEvents).toHaveBeenCalledExactlyOnceWith(gameHistoryRecord);\n });\n\n it(\"should generate dead players game events when called.\", () => {\n const gameHistoryRecord = createFakeGameHistoryRecord();\n const game = createFakeGame();\n services.gameEventsGenerator.generateGameEventsFromGameAndLastRecord(game, gameHistoryRecord);\n\n expect(mocks.gameEventsGeneratorService.generateDeadPlayersGameEvents).toHaveBeenCalledExactlyOnceWith(gameHistoryRecord);\n });\n\n it(\"should generate player attribute alterations events when called.\", () => {\n const gameHistoryRecord = createFakeGameHistoryRecord();\n const game = createFakeGame();\n services.gameEventsGenerator.generateGameEventsFromGameAndLastRecord(game, gameHistoryRecord);\n\n expect(mocks.gameEventsGeneratorService.generatePlayerAttributeAlterationsEvents).toHaveBeenCalledExactlyOnceWith(game, gameHistoryRecord);\n });\n\n it(\"should generate starting game phase tick game events when called.\", () => {\n const gameHistoryRecord = createFakeGameHistoryRecord();\n const game = createFakeGame();\n services.gameEventsGenerator.generateGameEventsFromGameAndLastRecord(game, gameHistoryRecord);\n\n expect(mocks.gameEventsGeneratorService.generateTurnStartsGameEvents).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should generate turn start game events when called.\", () => {\n const gameHistoryRecord = createFakeGameHistoryRecord();\n const game = createFakeGame();\n services.gameEventsGenerator.generateGameEventsFromGameAndLastRecord(game, gameHistoryRecord);\n\n expect(mocks.gameEventsGeneratorService.generateTurnStartsGameEvents).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should return generated events with last game play source event when there is a last game play source event.\", () => {\n const gameHistoryRecord = createFakeGameHistoryRecord();\n const game = createFakeGame();\n const gameEvent = createFakeGameEvent();\n mocks.gameEventsGeneratorService.generateLastGamePlaySourceGameEvent.mockReturnValue(gameEvent);\n const gameEvents = services.gameEventsGenerator.generateGameEventsFromGameAndLastRecord(game, gameHistoryRecord);\n\n expect(gameEvents).toStrictEqual([gameEvent]);\n });\n\n it(\"should return generated events without last game play source event when there is no last game play source event.\", () => {\n const gameHistoryRecord = createFakeGameHistoryRecord();\n const game = createFakeGame();\n mocks.gameEventsGeneratorService.generateLastGamePlaySourceGameEvent.mockReturnValue(undefined);\n const gameEvents = services.gameEventsGenerator.generateGameEventsFromGameAndLastRecord(game, gameHistoryRecord);\n\n expect(gameEvents).toStrictEqual([]);\n });\n });\n\n describe(\"sortGameEventsByGamePhase\", () => {\n it(\"should sort events for day phase when game phase is day.\", () => {\n const game = createFakeGame({\n phase: createFakeGamePhase({ name: \"day\" }),\n });\n const gameEvents = [\n createFakeGameEvent({ type: \"elder-has-taken-revenge\" }),\n createFakeGameEvent({ type: \"death\" }),\n createFakeGameEvent({ type: \"game-starts\" }),\n createFakeGameEvent({ type: \"game-phase-starts\" }),\n createFakeGameEvent({ type: \"game-turn-starts\" }),\n createFakeGameEvent({ type: \"seer-has-seen\" }),\n ];\n const sortedGameEvents = services.gameEventsGenerator[\"sortGameEventsByGamePhase\"](gameEvents, game);\n const expectedSortedGameEvents = [\n gameEvents[2],\n gameEvents[3],\n gameEvents[1],\n gameEvents[0],\n gameEvents[4],\n gameEvents[5],\n ];\n\n expect(sortedGameEvents).toStrictEqual(expectedSortedGameEvents);\n });\n\n it(\"should sort events for night phase when game phase is night.\", () => {\n const game = createFakeGame({\n phase: createFakeGamePhase({ name: \"night\" }),\n });\n const gameEvents = [\n createFakeGameEvent({ type: \"elder-has-taken-revenge\" }),\n createFakeGameEvent({ type: \"death\" }),\n createFakeGameEvent({ type: \"game-starts\" }),\n createFakeGameEvent({ type: \"game-phase-starts\" }),\n createFakeGameEvent({ type: \"game-turn-starts\" }),\n createFakeGameEvent({ type: \"seer-has-seen\" }),\n ];\n const sortedGameEvents = services.gameEventsGenerator[\"sortGameEventsByGamePhase\"](gameEvents, game);\n const expectedSortedGameEvents = [\n gameEvents[2],\n gameEvents[1],\n gameEvents[5],\n gameEvents[0],\n gameEvents[3],\n gameEvents[4],\n ];\n\n expect(sortedGameEvents).toStrictEqual(expectedSortedGameEvents);\n });\n\n it(\"should sort events for night phase when game phase is twilight.\", () => {\n const game = createFakeGame({\n phase: createFakeGamePhase({ name: \"twilight\" }),\n });\n const gameEvents = [\n createFakeGameEvent({ type: \"elder-has-taken-revenge\" }),\n createFakeGameEvent({ type: \"death\" }),\n createFakeGameEvent({ type: \"game-starts\" }),\n createFakeGameEvent({ type: \"game-phase-starts\" }),\n createFakeGameEvent({ type: \"game-turn-starts\" }),\n createFakeGameEvent({ type: \"seer-has-seen\" }),\n ];\n const sortedGameEvents = services.gameEventsGenerator[\"sortGameEventsByGamePhase\"](gameEvents, game);\n const expectedSortedGameEvents = [\n gameEvents[2],\n gameEvents[1],\n gameEvents[5],\n gameEvents[0],\n gameEvents[3],\n gameEvents[4],\n ];\n\n expect(sortedGameEvents).toStrictEqual(expectedSortedGameEvents);\n });\n });\n\n describe(\"generateSeerHasSeenGameEvent\", () => {\n it(\"should return seer has seen game event with targets when there are targets in last game history record.\", () => {\n const targetedPlayers = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const gameEvent = services.gameEventsGenerator[\"generateSeerHasSeenGameEvent\"](targetedPlayers);\n const expectedGameEvent = createFakeGameEvent({\n type: \"seer-has-seen\",\n players: targetedPlayers,\n });\n\n expect(gameEvent).toStrictEqual(expectedGameEvent);\n });\n\n it(\"should return seer has seen game event without targets when there are no targets in last game history record.\", () => {\n const gameEvent = services.gameEventsGenerator[\"generateSeerHasSeenGameEvent\"]();\n const expectedGameEvent = createFakeGameEvent({\n type: \"seer-has-seen\",\n });\n\n expect(gameEvent).toStrictEqual(expectedGameEvent);\n });\n });\n\n describe(\"generateScandalmongerHayHaveMarkedGameEvent\", () => {\n it(\"should return scandalmonger has marked game event with targets when there are targets in last game history record.\", () => {\n const targetedPlayers = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const gameEvent = services.gameEventsGenerator[\"generateScandalmongerHayHaveMarkedGameEvent\"](targetedPlayers);\n const expectedGameEvent = createFakeGameEvent({\n type: \"scandalmonger-may-have-marked\",\n players: targetedPlayers,\n });\n\n expect(gameEvent).toStrictEqual(expectedGameEvent);\n });\n\n it(\"should return scandalmonger has marked game event without targets when there are no targets in last game history record.\", () => {\n const gameEvent = services.gameEventsGenerator[\"generateScandalmongerHayHaveMarkedGameEvent\"]();\n const expectedGameEvent = createFakeGameEvent({\n type: \"scandalmonger-may-have-marked\",\n });\n\n expect(gameEvent).toStrictEqual(expectedGameEvent);\n });\n });\n\n describe(\"generateAccursedWolfFatherMayHaveInfectedGameEvent\", () => {\n it(\"should return accursed wolf father may have infected game event with targets when there are targets in last game history record.\", () => {\n const targetedPlayers = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const gameEvent = services.gameEventsGenerator[\"generateAccursedWolfFatherMayHaveInfectedGameEvent\"](targetedPlayers);\n const expectedGameEvent = createFakeGameEvent({\n type: \"accursed-wolf-father-may-have-infected\",\n players: targetedPlayers,\n });\n\n expect(gameEvent).toStrictEqual(expectedGameEvent);\n });\n\n it(\"should return accursed wolf father may have infected game event without targets when there are no targets in last game history record.\", () => {\n const gameEvent = services.gameEventsGenerator[\"generateAccursedWolfFatherMayHaveInfectedGameEvent\"]();\n const expectedGameEvent = createFakeGameEvent({\n type: \"accursed-wolf-father-may-have-infected\",\n });\n\n expect(gameEvent).toStrictEqual(expectedGameEvent);\n });\n });\n\n describe(\"generateWolfHoundHasChosenSideGameEvent\", () => {\n it(\"should return wolf hound has chosen side game event when called.\", () => {\n const wolfHoundPlayer = createFakeWolfHoundAlivePlayer();\n const game = createFakeGame({\n players: [wolfHoundPlayer],\n });\n const gameEvent = services.gameEventsGenerator[\"generateWolfHoundHasChosenSideGameEvent\"](game);\n const expectedGameEvent = createFakeGameEvent({\n type: \"wolf-hound-has-chosen-side\",\n players: [wolfHoundPlayer],\n });\n\n expect(gameEvent).toStrictEqual(expectedGameEvent);\n });\n });\n\n describe(\"generatePiedPiperHasCharmedGameEvent\", () => {\n it(\"should return pied piper has charmed game event with targets when there are targets in last game history record.\", () => {\n const targetedPlayers = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const gameEvent = services.gameEventsGenerator[\"generatePiedPiperHasCharmedGameEvent\"](targetedPlayers);\n const expectedGameEvent = createFakeGameEvent({\n type: \"pied-piper-has-charmed\",\n players: targetedPlayers,\n });\n\n expect(gameEvent).toStrictEqual(expectedGameEvent);\n });\n\n it(\"should return pied piper has charmed game event without targets when there are no targets in last game history record.\", () => {\n const gameEvent = services.gameEventsGenerator[\"generatePiedPiperHasCharmedGameEvent\"]();\n const expectedGameEvent = createFakeGameEvent({\n type: \"pied-piper-has-charmed\",\n });\n\n expect(gameEvent).toStrictEqual(expectedGameEvent);\n });\n });\n\n describe(\"generateCupidHasCharmedGameEvent\", () => {\n it(\"should return cupid has charmed game event with targets when there are targets in last game history record.\", () => {\n const targetedPlayers = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const gameEvent = services.gameEventsGenerator[\"generateCupidHasCharmedGameEvent\"](targetedPlayers);\n const expectedGameEvent = createFakeGameEvent({\n type: \"cupid-has-charmed\",\n players: targetedPlayers,\n });\n\n expect(gameEvent).toStrictEqual(expectedGameEvent);\n });\n\n it(\"should return cupid has charmed game event without targets when there are no targets in last game history record.\", () => {\n const gameEvent = services.gameEventsGenerator[\"generateCupidHasCharmedGameEvent\"]();\n const expectedGameEvent = createFakeGameEvent({\n type: \"cupid-has-charmed\",\n });\n\n expect(gameEvent).toStrictEqual(expectedGameEvent);\n });\n });\n\n describe(\"generateFoxMayHaveSniffedGameEvent\", () => {\n it(\"should return fox may have sniffed game event with targets when there are targets in last game history record.\", () => {\n const targetedPlayers = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const gameEvent = services.gameEventsGenerator[\"generateFoxMayHaveSniffedGameEvent\"](targetedPlayers);\n const expectedGameEvent = createFakeGameEvent({\n type: \"fox-may-have-sniffed\",\n players: targetedPlayers,\n });\n\n expect(gameEvent).toStrictEqual(expectedGameEvent);\n });\n\n it(\"should return fox may have sniffed game event without targets when there are no targets in last game history record.\", () => {\n const gameEvent = services.gameEventsGenerator[\"generateFoxMayHaveSniffedGameEvent\"]();\n const expectedGameEvent = createFakeGameEvent({\n type: \"fox-may-have-sniffed\",\n });\n\n expect(gameEvent).toStrictEqual(expectedGameEvent);\n });\n });\n\n describe(\"generateThiefMayHaveChosenCardGameEvent\", () => {\n it(\"should return thief may have chosen card game event when called.\", () => {\n const players = [createFakeThiefAlivePlayer()];\n const gameEvent = services.gameEventsGenerator[\"generateThiefMayHaveChosenCardGameEvent\"](players);\n const expectedGameEvent = createFakeGameEvent({\n type: \"thief-may-have-chosen-card\",\n players,\n });\n\n expect(gameEvent).toStrictEqual(expectedGameEvent);\n });\n });\n\n describe(\"generateActorMayHaveChosenCardGameEvent\", () => {\n it(\"should return actor may have chosen card game event when called.\", () => {\n const players = [createFakeActorAlivePlayer()];\n const gameEvent = services.gameEventsGenerator[\"generateActorMayHaveChosenCardGameEvent\"](players);\n const expectedGameEvent = createFakeGameEvent({\n type: \"actor-may-have-chosen-card\",\n players,\n });\n\n expect(gameEvent).toStrictEqual(expectedGameEvent);\n });\n });\n\n describe(\"generateLastGamePlaySourceGameEvent\", () => {\n beforeEach(() => {\n mocks.gameEventsGeneratorService.generateSeerHasSeenGameEvent = jest.spyOn(services.gameEventsGenerator as unknown as { generateSeerHasSeenGameEvent }, \"generateSeerHasSeenGameEvent\").mockImplementation();\n mocks.gameEventsGeneratorService.generateScandalmongerHayHaveMarkedGameEvent = jest.spyOn(services.gameEventsGenerator as unknown as { generateScandalmongerHayHaveMarkedGameEvent }, \"generateScandalmongerHayHaveMarkedGameEvent\").mockImplementation();\n mocks.gameEventsGeneratorService.generateAccursedWolfFatherMayHaveInfectedGameEvent = jest.spyOn(services.gameEventsGenerator as unknown as { generateAccursedWolfFatherMayHaveInfectedGameEvent }, \"generateAccursedWolfFatherMayHaveInfectedGameEvent\").mockImplementation();\n mocks.gameEventsGeneratorService.generateWolfHoundHasChosenSideGameEvent = jest.spyOn(services.gameEventsGenerator as unknown as { generateWolfHoundHasChosenSideGameEvent }, \"generateWolfHoundHasChosenSideGameEvent\").mockImplementation();\n mocks.gameEventsGeneratorService.generatePiedPiperHasCharmedGameEvent = jest.spyOn(services.gameEventsGenerator as unknown as { generatePiedPiperHasCharmedGameEvent }, \"generatePiedPiperHasCharmedGameEvent\").mockImplementation();\n mocks.gameEventsGeneratorService.generateCupidHasCharmedGameEvent = jest.spyOn(services.gameEventsGenerator as unknown as { generateCupidHasCharmedGameEvent }, \"generateCupidHasCharmedGameEvent\").mockImplementation();\n mocks.gameEventsGeneratorService.generateFoxMayHaveSniffedGameEvent = jest.spyOn(services.gameEventsGenerator as unknown as { generateFoxMayHaveSniffedGameEvent }, \"generateFoxMayHaveSniffedGameEvent\").mockImplementation();\n mocks.gameEventsGeneratorService.generateThiefMayHaveChosenCardGameEvent = jest.spyOn(services.gameEventsGenerator as unknown as { generateThiefMayHaveChosenCardGameEvent }, \"generateThiefMayHaveChosenCardGameEvent\").mockImplementation();\n mocks.gameEventsGeneratorService.generateActorMayHaveChosenCardGameEvent = jest.spyOn(services.gameEventsGenerator as unknown as { generateActorMayHaveChosenCardGameEvent }, \"generateActorMayHaveChosenCardGameEvent\").mockImplementation();\n });\n\n it(\"should return undefined when game history record is undefined.\", () => {\n const game = createFakeGame();\n const gameEvent = services.gameEventsGenerator[\"generateLastGamePlaySourceGameEvent\"](game, undefined);\n\n expect(gameEvent).toBeUndefined();\n });\n\n it(\"should generate seer has seen game event when the last game play source is seer.\", () => {\n const targetedPlayers = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGame({ players: targetedPlayers });\n const gameHistoryRecord = createFakeGameHistoryRecord({\n play: createFakeGameHistoryRecordPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"seer\",\n }),\n targets: [\n createFakeGameHistoryRecordPlayTarget({ player: targetedPlayers[0] }),\n createFakeGameHistoryRecordPlayTarget({ player: targetedPlayers[1] }),\n ],\n }),\n });\n services.gameEventsGenerator[\"generateLastGamePlaySourceGameEvent\"](game, gameHistoryRecord);\n\n expect(mocks.gameEventsGeneratorService.generateSeerHasSeenGameEvent).toHaveBeenCalledExactlyOnceWith(targetedPlayers);\n });\n\n it(\"should generate scandalmonger may have marked game event when the last game play source is scandalmonger.\", () => {\n const game = createFakeGame();\n const gameHistoryRecord = createFakeGameHistoryRecord({\n play: createFakeGameHistoryRecordPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"scandalmonger\",\n }),\n }),\n });\n services.gameEventsGenerator[\"generateLastGamePlaySourceGameEvent\"](game, gameHistoryRecord);\n\n expect(mocks.gameEventsGeneratorService.generateScandalmongerHayHaveMarkedGameEvent).toHaveBeenCalledExactlyOnceWith();\n });\n\n it(\"should generate accursed wolf father may have infected game event when the last game play source is accursed wolf father.\", () => {\n const game = createFakeGame();\n const gameHistoryRecord = createFakeGameHistoryRecord({\n play: createFakeGameHistoryRecordPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"accursed-wolf-father\",\n }),\n }),\n });\n services.gameEventsGenerator[\"generateLastGamePlaySourceGameEvent\"](game, gameHistoryRecord);\n\n expect(mocks.gameEventsGeneratorService.generateAccursedWolfFatherMayHaveInfectedGameEvent).toHaveBeenCalledExactlyOnceWith();\n });\n\n it(\"should generate wolf hound has chosen side game event when the last game play source is wolf hound.\", () => {\n const game = createFakeGame();\n const wolfHoundPlayer = createFakeWolfHoundAlivePlayer();\n const gameHistoryRecord = createFakeGameHistoryRecord({\n play: createFakeGameHistoryRecordPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"wolf-hound\",\n players: [wolfHoundPlayer],\n }),\n }),\n });\n services.gameEventsGenerator[\"generateLastGamePlaySourceGameEvent\"](game, gameHistoryRecord);\n\n expect(mocks.gameEventsGeneratorService.generateWolfHoundHasChosenSideGameEvent).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should generate pied piper has charmed game event when the last game play source is pied piper.\", () => {\n const game = createFakeGame();\n const gameHistoryRecord = createFakeGameHistoryRecord({\n play: createFakeGameHistoryRecordPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"pied-piper\",\n }),\n }),\n });\n services.gameEventsGenerator[\"generateLastGamePlaySourceGameEvent\"](game, gameHistoryRecord);\n\n expect(mocks.gameEventsGeneratorService.generatePiedPiperHasCharmedGameEvent).toHaveBeenCalledExactlyOnceWith();\n });\n\n it(\"should generate cupid has charmed game event when the last game play source is cupid.\", () => {\n const game = createFakeGame();\n const gameHistoryRecord = createFakeGameHistoryRecord({\n play: createFakeGameHistoryRecordPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"cupid\",\n }),\n }),\n });\n services.gameEventsGenerator[\"generateLastGamePlaySourceGameEvent\"](game, gameHistoryRecord);\n\n expect(mocks.gameEventsGeneratorService.generateCupidHasCharmedGameEvent).toHaveBeenCalledExactlyOnceWith();\n });\n\n it(\"should generate fox may have sniffed game event when the last game play source is fox.\", () => {\n const game = createFakeGame();\n const gameHistoryRecord = createFakeGameHistoryRecord({\n play: createFakeGameHistoryRecordPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"fox\",\n }),\n targets: [\n createFakeGameHistoryRecordPlayTarget({ player: createFakeWerewolfAlivePlayer() }),\n createFakeGameHistoryRecordPlayTarget({ player: createFakeWerewolfAlivePlayer() }),\n ],\n }),\n });\n services.gameEventsGenerator[\"generateLastGamePlaySourceGameEvent\"](game, gameHistoryRecord);\n\n expect(mocks.gameEventsGeneratorService.generateFoxMayHaveSniffedGameEvent).toHaveBeenCalledExactlyOnceWith([]);\n });\n\n it(\"should generate thief may have chosen card game event when the last game play source is thief.\", () => {\n const thiefPlayer = createFakeThiefAlivePlayer();\n const game = createFakeGame({\n players: [thiefPlayer],\n });\n const gameHistoryRecord = createFakeGameHistoryRecord({\n play: createFakeGameHistoryRecordPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"thief\",\n players: [thiefPlayer],\n }),\n }),\n });\n services.gameEventsGenerator[\"generateLastGamePlaySourceGameEvent\"](game, gameHistoryRecord);\n\n expect(mocks.gameEventsGeneratorService.generateThiefMayHaveChosenCardGameEvent).toHaveBeenCalledExactlyOnceWith([thiefPlayer]);\n });\n\n it(\"should generate actor may have chosen card game event when the last game play source is actor.\", () => {\n const game = createFakeGame();\n const gameHistoryRecord = createFakeGameHistoryRecord({\n play: createFakeGameHistoryRecordPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"actor\",\n players: [createFakeActorAlivePlayer()],\n }),\n }),\n });\n services.gameEventsGenerator[\"generateLastGamePlaySourceGameEvent\"](game, gameHistoryRecord);\n\n expect(mocks.gameEventsGeneratorService.generateActorMayHaveChosenCardGameEvent).toHaveBeenCalledExactlyOnceWith([]);\n });\n\n it(\"should generate actor may have chosen card game event without actor when the last game play source is actor.\", () => {\n const game = createFakeGame();\n const gameHistoryRecord = createFakeGameHistoryRecord({\n play: createFakeGameHistoryRecordPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"actor\",\n }),\n }),\n });\n gameHistoryRecord.play.source.players = undefined;\n services.gameEventsGenerator[\"generateLastGamePlaySourceGameEvent\"](game, gameHistoryRecord);\n\n expect(mocks.gameEventsGeneratorService.generateActorMayHaveChosenCardGameEvent).toHaveBeenCalledExactlyOnceWith();\n });\n\n it(\"should return undefined when the last game play source is not a special role.\", () => {\n const game = createFakeGame();\n const gameHistoryRecord = createFakeGameHistoryRecord({\n play: createFakeGameHistoryRecordPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"defender\",\n }),\n }),\n });\n const gameEvent = services.gameEventsGenerator[\"generateLastGamePlaySourceGameEvent\"](game, gameHistoryRecord);\n\n expect(gameEvent).toBeUndefined();\n });\n });\n\n describe(\"generateFirstTickGameEvents\", () => {\n it(\"should return empty array when it's not the first tick of the game..\", () => {\n const game = createFakeGame({ tick: 2 });\n const gameEvents = services.gameEventsGenerator[\"generateFirstTickGameEvents\"](game);\n\n expect(gameEvents).toStrictEqual([]);\n });\n\n it(\"should return game starts game event when it's the first tick of the game.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGame({\n tick: 1,\n players,\n });\n const gameEvents = services.gameEventsGenerator[\"generateFirstTickGameEvents\"](game);\n const expectedGameEvent = createFakeGameEvent({\n type: \"game-starts\",\n players,\n });\n\n expect(gameEvents).toStrictEqual([expectedGameEvent]);\n });\n\n it(\"should return game starts event with villager villager introduction event when it's the first tick of the game and there is a villager villager.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerVillagerAlivePlayer(),\n ];\n const game = createFakeGame({\n tick: 1,\n players,\n });\n const gameEvents = services.gameEventsGenerator[\"generateFirstTickGameEvents\"](game);\n const expectedGameEvents = [\n createFakeGameEvent({\n type: \"game-starts\",\n players,\n }),\n createFakeGameEvent({\n type: \"villager-villager-introduction\",\n players: [players[3]],\n }),\n ];\n\n expect(gameEvents).toStrictEqual(expectedGameEvents);\n });\n });\n\n describe(\"generateRevealedPlayersGameEvents\", () => {\n it(\"should return empty array when there are no revealed players.\", () => {\n const gameHistoryRecord = createFakeGameHistoryRecord();\n const gameEvents = services.gameEventsGenerator[\"generateRevealedPlayersGameEvents\"](gameHistoryRecord);\n\n expect(gameEvents).toStrictEqual([]);\n });\n\n it(\"should return empty array when game history record is undefined.\", () => {\n const gameEvents = services.gameEventsGenerator[\"generateRevealedPlayersGameEvents\"](undefined);\n\n expect(gameEvents).toStrictEqual([]);\n });\n\n it(\"should return idiot is spared game event when the revealed player is idiot.\", () => {\n const revealedPlayer = createFakeIdiotAlivePlayer();\n const gameHistoryRecord = createFakeGameHistoryRecord({\n revealedPlayers: [revealedPlayer],\n });\n const gameEvents = services.gameEventsGenerator[\"generateRevealedPlayersGameEvents\"](gameHistoryRecord);\n const expectedGameEvent = createFakeGameEvent({\n type: \"idiot-is-spared\",\n players: [revealedPlayer],\n });\n\n expect(gameEvents).toStrictEqual([expectedGameEvent]);\n });\n\n it(\"should return empty array when the revealed player is not idiot.\", () => {\n const revealedPlayer = createFakeWerewolfAlivePlayer();\n const gameHistoryRecord = createFakeGameHistoryRecord({\n revealedPlayers: [revealedPlayer],\n });\n const gameEvents = services.gameEventsGenerator[\"generateRevealedPlayersGameEvents\"](gameHistoryRecord);\n\n expect(gameEvents).toStrictEqual([]);\n });\n });\n\n describe(\"generateSwitchedSidePlayersGameEvents\", () => {\n it(\"should return empty array when there are no switched side players.\", () => {\n const gameHistoryRecord = createFakeGameHistoryRecord();\n const gameEvents = services.gameEventsGenerator[\"generateSwitchedSidePlayersGameEvents\"](gameHistoryRecord);\n\n expect(gameEvents).toStrictEqual([]);\n });\n\n it(\"should return empty array when game history record is undefined.\", () => {\n const gameEvents = services.gameEventsGenerator[\"generateSwitchedSidePlayersGameEvents\"](undefined);\n\n expect(gameEvents).toStrictEqual([]);\n });\n\n it(\"should return wild child has transformed game event when the switched side player is wild child and last game play action is bury dead bodies.\", () => {\n const switchedSidePlayer = createFakeWildChildAlivePlayer();\n const gameHistoryRecord = createFakeGameHistoryRecord({\n switchedSidePlayers: [switchedSidePlayer],\n play: createFakeGameHistoryRecordPlay({\n action: \"bury-dead-bodies\",\n }),\n });\n const gameEvents = services.gameEventsGenerator[\"generateSwitchedSidePlayersGameEvents\"](gameHistoryRecord);\n const expectedGameEvent = createFakeGameEvent({\n type: \"wild-child-has-transformed\",\n players: [switchedSidePlayer],\n });\n\n expect(gameEvents).toStrictEqual([expectedGameEvent]);\n });\n\n it(\"should return empty array when the switched side player is wild child and last game play action is not bury dead bodies.\", () => {\n const switchedSidePlayer = createFakeWildChildAlivePlayer();\n const gameHistoryRecord = createFakeGameHistoryRecord({\n switchedSidePlayers: [switchedSidePlayer],\n play: createFakeGameHistoryRecordPlay({\n action: \"vote\",\n }),\n });\n const gameEvents = services.gameEventsGenerator[\"generateSwitchedSidePlayersGameEvents\"](gameHistoryRecord);\n\n expect(gameEvents).toStrictEqual([]);\n });\n\n it(\"should return empty array when the switched side player is not wild child.\", () => {\n const switchedSidePlayer = createFakeWerewolfAlivePlayer();\n const gameHistoryRecord = createFakeGameHistoryRecord({\n switchedSidePlayers: [switchedSidePlayer],\n play: createFakeGameHistoryRecordPlay({\n action: \"bury-dead-bodies\",\n }),\n });\n const gameEvents = services.gameEventsGenerator[\"generateSwitchedSidePlayersGameEvents\"](gameHistoryRecord);\n\n expect(gameEvents).toStrictEqual([]);\n });\n });\n\n describe(\"generateDeadPlayersGameEvents\", () => {\n it(\"should return empty array when there are no dead players.\", () => {\n const gameHistoryRecord = createFakeGameHistoryRecord();\n const gameEvents = services.gameEventsGenerator[\"generateDeadPlayersGameEvents\"](gameHistoryRecord);\n\n expect(gameEvents).toStrictEqual([]);\n });\n\n it(\"should return empty array when game history record is undefined.\", () => {\n const gameEvents = services.gameEventsGenerator[\"generateDeadPlayersGameEvents\"](undefined);\n\n expect(gameEvents).toStrictEqual([]);\n });\n\n it(\"should return player dies game event with all dead players when there are dead players.\", () => {\n const deadPlayers = [\n createFakeDeadPlayer({ isAlive: false }),\n createFakeDeadPlayer({ isAlive: false }),\n ];\n const gameHistoryRecord = createFakeGameHistoryRecord({\n deadPlayers,\n });\n const gameEvents = services.gameEventsGenerator[\"generateDeadPlayersGameEvents\"](gameHistoryRecord);\n const expectedGameEvent = createFakeGameEvent({\n type: \"death\",\n players: deadPlayers,\n });\n\n expect(gameEvents).toStrictEqual([expectedGameEvent]);\n });\n });\n\n describe(\"generateBearGrowlsOrSleepsGameEvent\", () => {\n it(\"should generate bear growls game event when left neighbor is a werewolf.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ position: 1 }),\n createFakeBearTamerAlivePlayer({ position: 2 }),\n createFakeVillagerAlivePlayer({ position: 3 }),\n ];\n const game = createFakeGame({\n players,\n options: DEFAULT_GAME_OPTIONS,\n });\n const gameEvent = services.gameEventsGenerator[\"generateBearGrowlsOrSleepsGameEvent\"](game, players[1]);\n const expectedGameEvent = createFakeGameEvent({\n type: \"bear-growls\",\n players: [players[1]],\n });\n\n expect(gameEvent).toStrictEqual(expectedGameEvent);\n });\n\n it(\"should generate bear sleeps game event when left neighbor is not a werewolf.\", () => {\n const players = [\n createFakeVillagerAlivePlayer({ position: 1 }),\n createFakeBearTamerAlivePlayer({ position: 2 }),\n createFakeVillagerAlivePlayer({ position: 3 }),\n ];\n const game = createFakeGame({\n players,\n options: DEFAULT_GAME_OPTIONS,\n });\n const gameEvent = services.gameEventsGenerator[\"generateBearGrowlsOrSleepsGameEvent\"](game, players[1]);\n const expectedGameEvent = createFakeGameEvent({\n type: \"bear-sleeps\",\n players: [players[1]],\n });\n\n expect(gameEvent).toStrictEqual(expectedGameEvent);\n });\n\n it(\"should generate bear growls when right neighbor is a werewolf.\", () => {\n const players = [\n createFakeVillagerAlivePlayer({ position: 1 }),\n createFakeBearTamerAlivePlayer({ position: 2 }),\n createFakeWerewolfAlivePlayer({ position: 3 }),\n ];\n const game = createFakeGame({\n players,\n options: DEFAULT_GAME_OPTIONS,\n });\n const gameEvent = services.gameEventsGenerator[\"generateBearGrowlsOrSleepsGameEvent\"](game, players[1]);\n const expectedGameEvent = createFakeGameEvent({\n type: \"bear-growls\",\n players: [players[1]],\n });\n\n expect(gameEvent).toStrictEqual(expectedGameEvent);\n });\n\n it(\"should generate bear sleeps when right neighbor is not a werewolf.\", () => {\n const players = [\n createFakeVillagerAlivePlayer({ position: 1 }),\n createFakeBearTamerAlivePlayer({ position: 2 }),\n createFakeVillagerAlivePlayer({ position: 3 }),\n ];\n const game = createFakeGame({\n players,\n options: DEFAULT_GAME_OPTIONS,\n });\n const gameEvent = services.gameEventsGenerator[\"generateBearGrowlsOrSleepsGameEvent\"](game, players[1]);\n const expectedGameEvent = createFakeGameEvent({\n type: \"bear-sleeps\",\n players: [players[1]],\n });\n\n expect(gameEvent).toStrictEqual(expectedGameEvent);\n });\n\n it(\"should generate bear growls when both neighbors are werewolves.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ position: 1 }),\n createFakeBearTamerAlivePlayer({ position: 2 }),\n createFakeWerewolfAlivePlayer({ position: 3 }),\n ];\n const game = createFakeGame({\n players,\n options: DEFAULT_GAME_OPTIONS,\n });\n const gameEvent = services.gameEventsGenerator[\"generateBearGrowlsOrSleepsGameEvent\"](game, players[1]);\n const expectedGameEvent = createFakeGameEvent({\n type: \"bear-growls\",\n players: [players[1]],\n });\n\n expect(gameEvent).toStrictEqual(expectedGameEvent);\n });\n\n it(\"should generate bear growls when bear tamer is infected but both neighbors are not werewolves.\", () => {\n const players = [\n createFakeVillagerAlivePlayer(),\n createFakeBearTamerAlivePlayer({\n side: createFakePlayerSide({ current: \"werewolves\" }),\n }),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({\n players,\n options: DEFAULT_GAME_OPTIONS,\n });\n const gameEvent = services.gameEventsGenerator[\"generateBearGrowlsOrSleepsGameEvent\"](game, players[1]);\n const expectedGameEvent = createFakeGameEvent({\n type: \"bear-growls\",\n players: [players[1]],\n });\n\n expect(gameEvent).toStrictEqual(expectedGameEvent);\n });\n\n it(\"should generate bear sleeps when bear tamer is infected and both neighbors are not werewolves but game options doesn't make the infected bear tamer to growl.\", () => {\n const players = [\n createFakeVillagerAlivePlayer(),\n createFakeBearTamerAlivePlayer({\n side: createFakePlayerSide({ current: \"werewolves\" }),\n }),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({\n players,\n options: DEFAULT_GAME_OPTIONS,\n });\n game.options.roles.bearTamer.doesGrowlOnWerewolvesSide = false;\n const gameEvent = services.gameEventsGenerator[\"generateBearGrowlsOrSleepsGameEvent\"](game, players[1]);\n const expectedGameEvent = createFakeGameEvent({\n type: \"bear-sleeps\",\n players: [players[1]],\n });\n\n expect(gameEvent).toStrictEqual(expectedGameEvent);\n });\n });\n\n describe(\"generateGamePhaseStartsGameEvents\", () => {\n beforeEach(() => {\n mocks.gameEventsGeneratorService.generateBearGrowlsOrSleepsGameEvent = jest.spyOn(services.gameEventsGenerator as unknown as { generateBearGrowlsOrSleepsGameEvent }, \"generateBearGrowlsOrSleepsGameEvent\").mockReturnValue(createFakeGameEvent());\n });\n\n it(\"should return empty array when game phase tick is not 1.\", () => {\n const game = createFakeGame({\n phase: createFakeGamePhase({\n tick: 2,\n name: \"day\",\n }),\n });\n const gameEvents = services.gameEventsGenerator[\"generateGamePhaseStartsGameEvents\"](game);\n\n expect(gameEvents).toStrictEqual([]);\n });\n\n it(\"should return empty array when game phase name is twilight.\", () => {\n const game = createFakeGame({\n phase: createFakeGamePhase({\n tick: 1,\n name: \"twilight\",\n }),\n });\n const gameEvents = services.gameEventsGenerator[\"generateGamePhaseStartsGameEvents\"](game);\n\n expect(gameEvents).toStrictEqual([]);\n });\n\n it(\"should return game phase starts game event when game phase tick is 1 and not twilight.\", () => {\n const game = createFakeGame({\n phase: createFakeGamePhase({\n tick: 1,\n name: \"night\",\n }),\n });\n const gameEvents = services.gameEventsGenerator[\"generateGamePhaseStartsGameEvents\"](game);\n const expectedGameEvent = createFakeGameEvent({\n type: \"game-phase-starts\",\n });\n\n expect(gameEvents).toStrictEqual([expectedGameEvent]);\n });\n\n it(\"should generate bear growls or sleeps game event when game phase tick is 1 and day and bear tamer is in game and alive and powerful.\", () => {\n const players = [\n createFakeVillagerAlivePlayer(),\n createFakeBearTamerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({\n phase: createFakeGamePhase({\n tick: 1,\n name: \"day\",\n }),\n players,\n options: DEFAULT_GAME_OPTIONS,\n });\n services.gameEventsGenerator[\"generateGamePhaseStartsGameEvents\"](game);\n\n expect(mocks.gameEventsGeneratorService.generateBearGrowlsOrSleepsGameEvent).toHaveBeenCalledExactlyOnceWith(game, players[1]);\n });\n\n it(\"should not generate bear growls or sleeps game event when game phase tick is 1 and day and bear tamer is not in game.\", () => {\n const players = [\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({\n phase: createFakeGamePhase({\n tick: 1,\n name: \"day\",\n }),\n players,\n options: DEFAULT_GAME_OPTIONS,\n });\n services.gameEventsGenerator[\"generateGamePhaseStartsGameEvents\"](game);\n\n expect(mocks.gameEventsGeneratorService.generateBearGrowlsOrSleepsGameEvent).not.toHaveBeenCalled();\n });\n\n it(\"should not generate bear growls or sleeps game event when game phase tick is 1 and day and bear tamer is not alive.\", () => {\n const players = [\n createFakeVillagerAlivePlayer(),\n createFakeBearTamerAlivePlayer({\n isAlive: false,\n }),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({\n phase: createFakeGamePhase({\n tick: 1,\n name: \"day\",\n }),\n players,\n options: DEFAULT_GAME_OPTIONS,\n });\n services.gameEventsGenerator[\"generateGamePhaseStartsGameEvents\"](game);\n\n expect(mocks.gameEventsGeneratorService.generateBearGrowlsOrSleepsGameEvent).not.toHaveBeenCalled();\n });\n\n it(\"should not generate bear growls or sleeps game event when game phase tick is 1 and bear tamer is in game and alive and powerful but phase is night.\", () => {\n const players = [\n createFakeVillagerAlivePlayer(),\n createFakeBearTamerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({\n phase: createFakeGamePhase({\n tick: 1,\n name: \"night\",\n }),\n players,\n options: DEFAULT_GAME_OPTIONS,\n });\n services.gameEventsGenerator[\"generateGamePhaseStartsGameEvents\"](game);\n\n expect(mocks.gameEventsGeneratorService.generateBearGrowlsOrSleepsGameEvent).not.toHaveBeenCalled();\n });\n });\n\n describe(\"generatePlayerAttributeAlterationsEvents\", () => {\n it(\"should return empty array when there are no player attribute alterations.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const gameHistoryRecord = createFakeGameHistoryRecord();\n const gameEvents = services.gameEventsGenerator[\"generatePlayerAttributeAlterationsEvents\"](game, gameHistoryRecord);\n\n expect(gameEvents).toStrictEqual([]);\n });\n\n it(\"should return empty array when game history record is undefined.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const gameEvents = services.gameEventsGenerator[\"generatePlayerAttributeAlterationsEvents\"](game, undefined);\n\n expect(gameEvents).toStrictEqual([]);\n });\n\n it(\"should return elder has taken revenge game event when elder has taken revenge.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeElderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const gameHistoryRecord = createFakeGameHistoryRecord({\n playerAttributeAlterations: [\n createFakeGameHistoryRecordPlayerAttributeAlteration({\n source: \"elder\",\n name: \"powerless\",\n status: \"attached\",\n }),\n ],\n });\n const gameEvents = services.gameEventsGenerator[\"generatePlayerAttributeAlterationsEvents\"](game, gameHistoryRecord);\n const expectedGameEvent = createFakeGameEvent({\n type: \"elder-has-taken-revenge\",\n players: [players[1]],\n });\n\n expect(gameEvents).toStrictEqual([expectedGameEvent]);\n });\n\n it(\"should return sheriff promotion game event when sheriff has been promoted.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({\n attributes: [createFakePlayerAttribute({ name: \"sheriff\" })],\n }),\n ];\n const game = createFakeGame({ players });\n const gameHistoryRecord = createFakeGameHistoryRecord({\n playerAttributeAlterations: [\n createFakeGameHistoryRecordPlayerAttributeAlteration({\n name: \"sheriff\",\n status: \"attached\",\n }),\n ],\n });\n const gameEvents = services.gameEventsGenerator[\"generatePlayerAttributeAlterationsEvents\"](game, gameHistoryRecord);\n const expectedGameEvent = createFakeGameEvent({\n type: \"sheriff-promotion\",\n players: [players[1]],\n });\n\n expect(gameEvents).toStrictEqual([expectedGameEvent]);\n });\n\n it(\"should return empty array when sheriff is not promoted or elder has not taken revenge.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const gameHistoryRecord = createFakeGameHistoryRecord({\n playerAttributeAlterations: [\n createFakeGameHistoryRecordPlayerAttributeAlteration({\n source: \"elder\",\n name: \"powerless\",\n status: \"detached\",\n }),\n ],\n });\n const gameEvents = services.gameEventsGenerator[\"generatePlayerAttributeAlterationsEvents\"](game, gameHistoryRecord);\n\n expect(gameEvents).toStrictEqual([]);\n });\n });\n\n describe(\"generateTurnStartsGameEvents\", () => {\n it(\"should return game turn starts when called.\", () => {\n const game = createFakeGame();\n const gameEvents = services.gameEventsGenerator[\"generateTurnStartsGameEvents\"](game);\n const expectedGameEvent = createFakeGameEvent({\n type: \"game-turn-starts\",\n });\n\n expect(gameEvents).toStrictEqual([expectedGameEvent]);\n });\n\n it(\"should generate game turn starts and scandalmonger mark is active game events when current play is vote and one player has the mark.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeVillagerAlivePlayer({\n attributes: [createFakeScandalmongerMarkedByScandalmongerPlayerAttribute()],\n }),\n ];\n const game = createFakeGame({\n players,\n currentPlay: createFakeGamePlaySurvivorsVote(),\n });\n const gameEvents = services.gameEventsGenerator[\"generateTurnStartsGameEvents\"](game);\n const expectedGameEvents = [\n createFakeGameEvent({\n type: \"scandalmonger-mark-is-active\",\n players: [players[2]],\n }),\n createFakeGameEvent({\n type: \"game-turn-starts\",\n }),\n ];\n\n expect(gameEvents).toStrictEqual(expectedGameEvents);\n });\n\n it(\"should generate only game turn starts game event when current play is vote and no player has the mark.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({\n players,\n currentPlay: createFakeGamePlaySurvivorsVote(),\n });\n const gameEvents = services.gameEventsGenerator[\"generateTurnStartsGameEvents\"](game);\n const expectedGameEvent = createFakeGameEvent({\n type: \"game-turn-starts\",\n });\n\n expect(gameEvents).toStrictEqual([expectedGameEvent]);\n });\n\n it(\"should generate only game turn starts game event when current play is not vote and one player is marked.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeVillagerAlivePlayer({\n attributes: [createFakeScandalmongerMarkedByScandalmongerPlayerAttribute()],\n }),\n ];\n const game = createFakeGame({\n players,\n currentPlay: createFakeGamePlayWerewolvesEat(),\n });\n const gameEvents = services.gameEventsGenerator[\"generateTurnStartsGameEvents\"](game);\n const expectedGameEvent = createFakeGameEvent({\n type: \"game-turn-starts\",\n });\n\n expect(gameEvents).toStrictEqual([expectedGameEvent]);\n });\n\n it(\"should generate only game turn starts game event when current play is null and one player is marked.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeVillagerAlivePlayer({\n attributes: [createFakeScandalmongerMarkedByScandalmongerPlayerAttribute()],\n }),\n ];\n const game = createFakeGame({\n players,\n currentPlay: null,\n });\n const gameEvents = services.gameEventsGenerator[\"generateTurnStartsGameEvents\"](game);\n const expectedGameEvent = createFakeGameEvent({\n type: \"game-turn-starts\",\n });\n\n expect(gameEvents).toStrictEqual([expectedGameEvent]);\n });\n });\n});" + "source": "import type { TestingModule } from \"@nestjs/testing\";\nimport { Test } from \"@nestjs/testing\";\n\nimport { DEFAULT_GAME_OPTIONS } from \"@/modules/game/constants/game-options/game-options.constants\";\nimport { GameEventsGeneratorService } from \"@/modules/game/providers/services/game-event/game-events-generator.service\";\nimport type { GameEvent } from \"@/modules/game/schemas/game-event/game-event.schema\";\n\nimport { createFakeGameEvent } from \"@tests/factories/game/schemas/game-event/game-event.schema.factory\";\nimport { createFakeGameHistoryRecord, createFakeGameHistoryRecordPlay, createFakeGameHistoryRecordPlayerAttributeAlteration, createFakeGameHistoryRecordPlaySource, createFakeGameHistoryRecordPlayTarget } from \"@tests/factories/game/schemas/game-history-record/game-history-record.schema.factory\";\nimport { createFakeGamePhase } from \"@tests/factories/game/schemas/game-phase/game-phase.schema.factory\";\nimport { createFakeGamePlaySurvivorsVote, createFakeGamePlayWerewolvesEat } from \"@tests/factories/game/schemas/game-play/game-play.schema.factory\";\nimport { createFakeGame } from \"@tests/factories/game/schemas/game.schema.factory\";\nimport { createFakePlayerAttribute, createFakeScandalmongerMarkedByScandalmongerPlayerAttribute } from \"@tests/factories/game/schemas/player/player-attribute/player-attribute.schema.factory\";\nimport { createFakeActorAlivePlayer, createFakeBearTamerAlivePlayer, createFakeElderAlivePlayer, createFakeIdiotAlivePlayer, createFakeScandalmongerAlivePlayer, createFakeThiefAlivePlayer, createFakeVillagerAlivePlayer, createFakeVillagerVillagerAlivePlayer, createFakeWerewolfAlivePlayer, createFakeWildChildAlivePlayer, createFakeWolfHoundAlivePlayer } from \"@tests/factories/game/schemas/player/player-with-role.schema.factory\";\nimport { createFakeDeadPlayer, createFakePlayerSide } from \"@tests/factories/game/schemas/player/player.schema.factory\";\n\ndescribe(\"Game Events Generator Service\", () => {\n let mocks: {\n gameEventsGeneratorService: {\n generateSeerHasSeenGameEvent: jest.SpyInstance;\n generateScandalmongerHayHaveMarkedGameEvent: jest.SpyInstance;\n generateAccursedWolfFatherMayHaveInfectedGameEvent: jest.SpyInstance;\n generateWolfHoundHasChosenSideGameEvent: jest.SpyInstance;\n generatePiedPiperHasCharmedGameEvent: jest.SpyInstance;\n generateCupidHasCharmedGameEvent: jest.SpyInstance;\n generateFoxMayHaveSniffedGameEvent: jest.SpyInstance;\n generateThiefMayHaveChosenCardGameEvent: jest.SpyInstance;\n generateActorMayHaveChosenCardGameEvent: jest.SpyInstance;\n generateLastGamePlaySourceGameEvent: jest.SpyInstance;\n generateFirstTickGameEvents: jest.SpyInstance;\n generateRevealedPlayersGameEvents: jest.SpyInstance;\n generateSwitchedSidePlayersGameEvents: jest.SpyInstance;\n generateDeadPlayersGameEvents: jest.SpyInstance;\n generateBearGrowlsOrSleepsGameEvent: jest.SpyInstance;\n generatePlayerAttributeAlterationsEvents: jest.SpyInstance;\n generateTurnStartsGameEvents: jest.SpyInstance;\n };\n };\n let services: { gameEventsGenerator: GameEventsGeneratorService };\n\n beforeEach(async() => {\n mocks = {\n gameEventsGeneratorService: {\n generateSeerHasSeenGameEvent: jest.fn(),\n generateScandalmongerHayHaveMarkedGameEvent: jest.fn(),\n generateAccursedWolfFatherMayHaveInfectedGameEvent: jest.fn(),\n generateWolfHoundHasChosenSideGameEvent: jest.fn(),\n generatePiedPiperHasCharmedGameEvent: jest.fn(),\n generateCupidHasCharmedGameEvent: jest.fn(),\n generateFoxMayHaveSniffedGameEvent: jest.fn(),\n generateThiefMayHaveChosenCardGameEvent: jest.fn(),\n generateActorMayHaveChosenCardGameEvent: jest.fn(),\n generateLastGamePlaySourceGameEvent: jest.fn(),\n generateFirstTickGameEvents: jest.fn(),\n generateRevealedPlayersGameEvents: jest.fn(),\n generateSwitchedSidePlayersGameEvents: jest.fn(),\n generateDeadPlayersGameEvents: jest.fn(),\n generateBearGrowlsOrSleepsGameEvent: jest.fn(),\n generatePlayerAttributeAlterationsEvents: jest.fn(),\n generateTurnStartsGameEvents: jest.fn(),\n },\n };\n const module: TestingModule = await Test.createTestingModule({ providers: [GameEventsGeneratorService] }).compile();\n\n services = { gameEventsGenerator: module.get(GameEventsGeneratorService) };\n });\n\n describe(\"generateGameEventsFromGameAndLastRecord\", () => {\n beforeEach(() => {\n mocks.gameEventsGeneratorService.generateFirstTickGameEvents = jest.spyOn(services.gameEventsGenerator as unknown as { generateFirstTickGameEvents }, \"generateFirstTickGameEvents\").mockReturnValue([]);\n mocks.gameEventsGeneratorService.generateRevealedPlayersGameEvents = jest.spyOn(services.gameEventsGenerator as unknown as { generateRevealedPlayersGameEvents }, \"generateRevealedPlayersGameEvents\").mockReturnValue([]);\n mocks.gameEventsGeneratorService.generateSwitchedSidePlayersGameEvents = jest.spyOn(services.gameEventsGenerator as unknown as { generateSwitchedSidePlayersGameEvents }, \"generateSwitchedSidePlayersGameEvents\").mockReturnValue([]);\n mocks.gameEventsGeneratorService.generateDeadPlayersGameEvents = jest.spyOn(services.gameEventsGenerator as unknown as { generateDeadPlayersGameEvents }, \"generateDeadPlayersGameEvents\").mockReturnValue([]);\n mocks.gameEventsGeneratorService.generateBearGrowlsOrSleepsGameEvent = jest.spyOn(services.gameEventsGenerator as unknown as { generateBearGrowlsOrSleepsGameEvent }, \"generateBearGrowlsOrSleepsGameEvent\").mockReturnValue([]);\n mocks.gameEventsGeneratorService.generatePlayerAttributeAlterationsEvents = jest.spyOn(services.gameEventsGenerator as unknown as { generatePlayerAttributeAlterationsEvents }, \"generatePlayerAttributeAlterationsEvents\").mockReturnValue([]);\n mocks.gameEventsGeneratorService.generateTurnStartsGameEvents = jest.spyOn(services.gameEventsGenerator as unknown as { generateTurnStartsGameEvents }, \"generateTurnStartsGameEvents\").mockReturnValue([]);\n mocks.gameEventsGeneratorService.generateLastGamePlaySourceGameEvent = jest.spyOn(services.gameEventsGenerator as unknown as { generateLastGamePlaySourceGameEvent }, \"generateLastGamePlaySourceGameEvent\").mockReturnValue(undefined);\n });\n\n it(\"should generate first tick game events when called.\", () => {\n const gameHistoryRecord = createFakeGameHistoryRecord();\n const game = createFakeGame();\n services.gameEventsGenerator.generateGameEventsFromGameAndLastRecord(game, gameHistoryRecord);\n\n expect(mocks.gameEventsGeneratorService.generateFirstTickGameEvents).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should generate revealed players game events when called.\", () => {\n const gameHistoryRecord = createFakeGameHistoryRecord();\n const game = createFakeGame();\n services.gameEventsGenerator.generateGameEventsFromGameAndLastRecord(game, gameHistoryRecord);\n\n expect(mocks.gameEventsGeneratorService.generateRevealedPlayersGameEvents).toHaveBeenCalledExactlyOnceWith(gameHistoryRecord);\n });\n\n it(\"should generate last game play source game event when called.\", () => {\n const gameHistoryRecord = createFakeGameHistoryRecord();\n const game = createFakeGame();\n services.gameEventsGenerator.generateGameEventsFromGameAndLastRecord(game, gameHistoryRecord);\n\n expect(mocks.gameEventsGeneratorService.generateLastGamePlaySourceGameEvent).toHaveBeenCalledExactlyOnceWith(game, gameHistoryRecord);\n });\n\n it(\"should generate switched side players game events when called.\", () => {\n const gameHistoryRecord = createFakeGameHistoryRecord();\n const game = createFakeGame();\n services.gameEventsGenerator.generateGameEventsFromGameAndLastRecord(game, gameHistoryRecord);\n\n expect(mocks.gameEventsGeneratorService.generateSwitchedSidePlayersGameEvents).toHaveBeenCalledExactlyOnceWith(gameHistoryRecord);\n });\n\n it(\"should generate dead players game events when called.\", () => {\n const gameHistoryRecord = createFakeGameHistoryRecord();\n const game = createFakeGame();\n services.gameEventsGenerator.generateGameEventsFromGameAndLastRecord(game, gameHistoryRecord);\n\n expect(mocks.gameEventsGeneratorService.generateDeadPlayersGameEvents).toHaveBeenCalledExactlyOnceWith(gameHistoryRecord);\n });\n\n it(\"should generate player attribute alterations events when called.\", () => {\n const gameHistoryRecord = createFakeGameHistoryRecord();\n const game = createFakeGame();\n services.gameEventsGenerator.generateGameEventsFromGameAndLastRecord(game, gameHistoryRecord);\n\n expect(mocks.gameEventsGeneratorService.generatePlayerAttributeAlterationsEvents).toHaveBeenCalledExactlyOnceWith(game, gameHistoryRecord);\n });\n\n it(\"should generate starting game phase tick game events when called.\", () => {\n const gameHistoryRecord = createFakeGameHistoryRecord();\n const game = createFakeGame();\n services.gameEventsGenerator.generateGameEventsFromGameAndLastRecord(game, gameHistoryRecord);\n\n expect(mocks.gameEventsGeneratorService.generateTurnStartsGameEvents).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should generate turn start game events when called.\", () => {\n const gameHistoryRecord = createFakeGameHistoryRecord();\n const game = createFakeGame();\n services.gameEventsGenerator.generateGameEventsFromGameAndLastRecord(game, gameHistoryRecord);\n\n expect(mocks.gameEventsGeneratorService.generateTurnStartsGameEvents).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should return generated events with last game play source event when there is a last game play source event.\", () => {\n const gameHistoryRecord = createFakeGameHistoryRecord();\n const game = createFakeGame();\n const gameEvent = createFakeGameEvent();\n mocks.gameEventsGeneratorService.generateLastGamePlaySourceGameEvent.mockReturnValue(gameEvent);\n const gameEvents = services.gameEventsGenerator.generateGameEventsFromGameAndLastRecord(game, gameHistoryRecord);\n\n expect(gameEvents).toStrictEqual([gameEvent]);\n });\n\n it(\"should return generated events without last game play source event when there is no last game play source event.\", () => {\n const gameHistoryRecord = createFakeGameHistoryRecord();\n const game = createFakeGame();\n mocks.gameEventsGeneratorService.generateLastGamePlaySourceGameEvent.mockReturnValue(undefined);\n const gameEvents = services.gameEventsGenerator.generateGameEventsFromGameAndLastRecord(game, gameHistoryRecord);\n\n expect(gameEvents).toStrictEqual([]);\n });\n });\n\n describe(\"sortGameEventsByGamePhase\", () => {\n it(\"should sort events for day phase when game phase is day.\", () => {\n const game = createFakeGame({\n phase: createFakeGamePhase({ name: \"day\" }),\n });\n const gameEvents = [\n createFakeGameEvent({ type: \"elder-has-taken-revenge\" }),\n createFakeGameEvent({ type: \"death\" }),\n createFakeGameEvent({ type: \"game-starts\" }),\n createFakeGameEvent({ type: \"game-phase-starts\" }),\n createFakeGameEvent({ type: \"game-turn-starts\" }),\n createFakeGameEvent({ type: \"seer-has-seen\" }),\n ];\n const sortedGameEvents = services.gameEventsGenerator[\"sortGameEventsByGamePhase\"](gameEvents, game);\n const expectedSortedGameEvents = [\n gameEvents[2],\n gameEvents[3],\n gameEvents[1],\n gameEvents[0],\n gameEvents[4],\n gameEvents[5],\n ];\n\n expect(sortedGameEvents).toStrictEqual(expectedSortedGameEvents);\n });\n\n it(\"should sort events for night phase when game phase is night.\", () => {\n const game = createFakeGame({\n phase: createFakeGamePhase({ name: \"night\" }),\n });\n const gameEvents = [\n createFakeGameEvent({ type: \"elder-has-taken-revenge\" }),\n createFakeGameEvent({ type: \"death\" }),\n createFakeGameEvent({ type: \"game-starts\" }),\n createFakeGameEvent({ type: \"game-phase-starts\" }),\n createFakeGameEvent({ type: \"game-turn-starts\" }),\n createFakeGameEvent({ type: \"seer-has-seen\" }),\n ];\n const sortedGameEvents = services.gameEventsGenerator[\"sortGameEventsByGamePhase\"](gameEvents, game);\n const expectedSortedGameEvents = [\n gameEvents[2],\n gameEvents[1],\n gameEvents[5],\n gameEvents[0],\n gameEvents[3],\n gameEvents[4],\n ];\n\n expect(sortedGameEvents).toStrictEqual(expectedSortedGameEvents);\n });\n\n it(\"should sort events for night phase when game phase is twilight.\", () => {\n const game = createFakeGame({\n phase: createFakeGamePhase({ name: \"twilight\" }),\n });\n const gameEvents = [\n createFakeGameEvent({ type: \"elder-has-taken-revenge\" }),\n createFakeGameEvent({ type: \"death\" }),\n createFakeGameEvent({ type: \"game-starts\" }),\n createFakeGameEvent({ type: \"game-phase-starts\" }),\n createFakeGameEvent({ type: \"game-turn-starts\" }),\n createFakeGameEvent({ type: \"seer-has-seen\" }),\n ];\n const sortedGameEvents = services.gameEventsGenerator[\"sortGameEventsByGamePhase\"](gameEvents, game);\n const expectedSortedGameEvents = [\n gameEvents[2],\n gameEvents[1],\n gameEvents[5],\n gameEvents[0],\n gameEvents[3],\n gameEvents[4],\n ];\n\n expect(sortedGameEvents).toStrictEqual(expectedSortedGameEvents);\n });\n });\n\n describe(\"generateSeerHasSeenGameEvent\", () => {\n it(\"should return seer has seen game event with targets when there are targets in last game history record.\", () => {\n const targetedPlayers = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const gameEvent = services.gameEventsGenerator[\"generateSeerHasSeenGameEvent\"](targetedPlayers);\n const expectedGameEvent = createFakeGameEvent({\n type: \"seer-has-seen\",\n players: targetedPlayers,\n });\n\n expect(gameEvent).toStrictEqual(expectedGameEvent);\n });\n\n it(\"should return seer has seen game event without targets when there are no targets in last game history record.\", () => {\n const gameEvent = services.gameEventsGenerator[\"generateSeerHasSeenGameEvent\"]();\n const expectedGameEvent = createFakeGameEvent({\n type: \"seer-has-seen\",\n });\n\n expect(gameEvent).toStrictEqual(expectedGameEvent);\n });\n });\n\n describe(\"generateScandalmongerHayHaveMarkedGameEvent\", () => {\n it(\"should return scandalmonger has marked game event with targets when there are targets in last game history record.\", () => {\n const targetedPlayers = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const gameEvent = services.gameEventsGenerator[\"generateScandalmongerHayHaveMarkedGameEvent\"](targetedPlayers);\n const expectedGameEvent = createFakeGameEvent({\n type: \"scandalmonger-may-have-marked\",\n players: targetedPlayers,\n });\n\n expect(gameEvent).toStrictEqual(expectedGameEvent);\n });\n\n it(\"should return scandalmonger has marked game event without targets when there are no targets in last game history record.\", () => {\n const gameEvent = services.gameEventsGenerator[\"generateScandalmongerHayHaveMarkedGameEvent\"]();\n const expectedGameEvent = createFakeGameEvent({\n type: \"scandalmonger-may-have-marked\",\n });\n\n expect(gameEvent).toStrictEqual(expectedGameEvent);\n });\n });\n\n describe(\"generateAccursedWolfFatherMayHaveInfectedGameEvent\", () => {\n it(\"should return accursed wolf father may have infected game event with targets when there are targets in last game history record.\", () => {\n const targetedPlayers = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const gameEvent = services.gameEventsGenerator[\"generateAccursedWolfFatherMayHaveInfectedGameEvent\"](targetedPlayers);\n const expectedGameEvent = createFakeGameEvent({\n type: \"accursed-wolf-father-may-have-infected\",\n players: targetedPlayers,\n });\n\n expect(gameEvent).toStrictEqual(expectedGameEvent);\n });\n\n it(\"should return accursed wolf father may have infected game event without targets when there are no targets in last game history record.\", () => {\n const gameEvent = services.gameEventsGenerator[\"generateAccursedWolfFatherMayHaveInfectedGameEvent\"]();\n const expectedGameEvent = createFakeGameEvent({\n type: \"accursed-wolf-father-may-have-infected\",\n });\n\n expect(gameEvent).toStrictEqual(expectedGameEvent);\n });\n });\n\n describe(\"generateWolfHoundHasChosenSideGameEvent\", () => {\n it(\"should return wolf hound has chosen side game event when called.\", () => {\n const wolfHoundPlayer = createFakeWolfHoundAlivePlayer();\n const game = createFakeGame({\n players: [wolfHoundPlayer],\n });\n const gameEvent = services.gameEventsGenerator[\"generateWolfHoundHasChosenSideGameEvent\"](game);\n const expectedGameEvent = createFakeGameEvent({\n type: \"wolf-hound-has-chosen-side\",\n players: [wolfHoundPlayer],\n });\n\n expect(gameEvent).toStrictEqual(expectedGameEvent);\n });\n });\n\n describe(\"generatePiedPiperHasCharmedGameEvent\", () => {\n it(\"should return pied piper has charmed game event with targets when there are targets in last game history record.\", () => {\n const targetedPlayers = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const gameEvent = services.gameEventsGenerator[\"generatePiedPiperHasCharmedGameEvent\"](targetedPlayers);\n const expectedGameEvent = createFakeGameEvent({\n type: \"pied-piper-has-charmed\",\n players: targetedPlayers,\n });\n\n expect(gameEvent).toStrictEqual(expectedGameEvent);\n });\n\n it(\"should return pied piper has charmed game event without targets when there are no targets in last game history record.\", () => {\n const gameEvent = services.gameEventsGenerator[\"generatePiedPiperHasCharmedGameEvent\"]();\n const expectedGameEvent = createFakeGameEvent({\n type: \"pied-piper-has-charmed\",\n });\n\n expect(gameEvent).toStrictEqual(expectedGameEvent);\n });\n });\n\n describe(\"generateCupidHasCharmedGameEvent\", () => {\n it(\"should return cupid has charmed game event with targets when there are targets in last game history record.\", () => {\n const targetedPlayers = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const gameEvent = services.gameEventsGenerator[\"generateCupidHasCharmedGameEvent\"](targetedPlayers);\n const expectedGameEvent = createFakeGameEvent({\n type: \"cupid-has-charmed\",\n players: targetedPlayers,\n });\n\n expect(gameEvent).toStrictEqual(expectedGameEvent);\n });\n\n it(\"should return cupid has charmed game event without targets when there are no targets in last game history record.\", () => {\n const gameEvent = services.gameEventsGenerator[\"generateCupidHasCharmedGameEvent\"]();\n const expectedGameEvent = createFakeGameEvent({\n type: \"cupid-has-charmed\",\n });\n\n expect(gameEvent).toStrictEqual(expectedGameEvent);\n });\n });\n\n describe(\"generateFoxMayHaveSniffedGameEvent\", () => {\n it(\"should return fox may have sniffed game event with targets when there are targets in last game history record.\", () => {\n const targetedPlayers = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const gameEvent = services.gameEventsGenerator[\"generateFoxMayHaveSniffedGameEvent\"](targetedPlayers);\n const expectedGameEvent = createFakeGameEvent({\n type: \"fox-may-have-sniffed\",\n players: targetedPlayers,\n });\n\n expect(gameEvent).toStrictEqual(expectedGameEvent);\n });\n\n it(\"should return fox may have sniffed game event without targets when there are no targets in last game history record.\", () => {\n const gameEvent = services.gameEventsGenerator[\"generateFoxMayHaveSniffedGameEvent\"]();\n const expectedGameEvent = createFakeGameEvent({\n type: \"fox-may-have-sniffed\",\n });\n\n expect(gameEvent).toStrictEqual(expectedGameEvent);\n });\n });\n\n describe(\"generateThiefMayHaveChosenCardGameEvent\", () => {\n it(\"should return thief may have chosen card game event when called.\", () => {\n const players = [createFakeThiefAlivePlayer()];\n const gameEvent = services.gameEventsGenerator[\"generateThiefMayHaveChosenCardGameEvent\"](players);\n const expectedGameEvent = createFakeGameEvent({\n type: \"thief-may-have-chosen-card\",\n players,\n });\n\n expect(gameEvent).toStrictEqual(expectedGameEvent);\n });\n });\n\n describe(\"generateActorMayHaveChosenCardGameEvent\", () => {\n it(\"should return actor may have chosen card game event when called.\", () => {\n const players = [createFakeActorAlivePlayer()];\n const gameEvent = services.gameEventsGenerator[\"generateActorMayHaveChosenCardGameEvent\"](players);\n const expectedGameEvent = createFakeGameEvent({\n type: \"actor-may-have-chosen-card\",\n players,\n });\n\n expect(gameEvent).toStrictEqual(expectedGameEvent);\n });\n });\n\n describe(\"generateLastGamePlaySourceGameEvent\", () => {\n beforeEach(() => {\n mocks.gameEventsGeneratorService.generateSeerHasSeenGameEvent = jest.spyOn(services.gameEventsGenerator as unknown as { generateSeerHasSeenGameEvent }, \"generateSeerHasSeenGameEvent\").mockImplementation();\n mocks.gameEventsGeneratorService.generateScandalmongerHayHaveMarkedGameEvent = jest.spyOn(services.gameEventsGenerator as unknown as { generateScandalmongerHayHaveMarkedGameEvent }, \"generateScandalmongerHayHaveMarkedGameEvent\").mockImplementation();\n mocks.gameEventsGeneratorService.generateAccursedWolfFatherMayHaveInfectedGameEvent = jest.spyOn(services.gameEventsGenerator as unknown as { generateAccursedWolfFatherMayHaveInfectedGameEvent }, \"generateAccursedWolfFatherMayHaveInfectedGameEvent\").mockImplementation();\n mocks.gameEventsGeneratorService.generateWolfHoundHasChosenSideGameEvent = jest.spyOn(services.gameEventsGenerator as unknown as { generateWolfHoundHasChosenSideGameEvent }, \"generateWolfHoundHasChosenSideGameEvent\").mockImplementation();\n mocks.gameEventsGeneratorService.generatePiedPiperHasCharmedGameEvent = jest.spyOn(services.gameEventsGenerator as unknown as { generatePiedPiperHasCharmedGameEvent }, \"generatePiedPiperHasCharmedGameEvent\").mockImplementation();\n mocks.gameEventsGeneratorService.generateCupidHasCharmedGameEvent = jest.spyOn(services.gameEventsGenerator as unknown as { generateCupidHasCharmedGameEvent }, \"generateCupidHasCharmedGameEvent\").mockImplementation();\n mocks.gameEventsGeneratorService.generateFoxMayHaveSniffedGameEvent = jest.spyOn(services.gameEventsGenerator as unknown as { generateFoxMayHaveSniffedGameEvent }, \"generateFoxMayHaveSniffedGameEvent\").mockImplementation();\n mocks.gameEventsGeneratorService.generateThiefMayHaveChosenCardGameEvent = jest.spyOn(services.gameEventsGenerator as unknown as { generateThiefMayHaveChosenCardGameEvent }, \"generateThiefMayHaveChosenCardGameEvent\").mockImplementation();\n mocks.gameEventsGeneratorService.generateActorMayHaveChosenCardGameEvent = jest.spyOn(services.gameEventsGenerator as unknown as { generateActorMayHaveChosenCardGameEvent }, \"generateActorMayHaveChosenCardGameEvent\").mockImplementation();\n });\n\n it(\"should return undefined when game history record is undefined.\", () => {\n const game = createFakeGame();\n const gameEvent = services.gameEventsGenerator[\"generateLastGamePlaySourceGameEvent\"](game, undefined);\n\n expect(gameEvent).toBeUndefined();\n });\n\n it(\"should generate seer has seen game event when the last game play source is seer.\", () => {\n const targetedPlayers = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGame({ players: targetedPlayers });\n const gameHistoryRecord = createFakeGameHistoryRecord({\n play: createFakeGameHistoryRecordPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"seer\",\n }),\n targets: [\n createFakeGameHistoryRecordPlayTarget({ player: targetedPlayers[0] }),\n createFakeGameHistoryRecordPlayTarget({ player: targetedPlayers[1] }),\n ],\n }),\n });\n services.gameEventsGenerator[\"generateLastGamePlaySourceGameEvent\"](game, gameHistoryRecord);\n\n expect(mocks.gameEventsGeneratorService.generateSeerHasSeenGameEvent).toHaveBeenCalledExactlyOnceWith(targetedPlayers);\n });\n\n it(\"should generate scandalmonger may have marked game event when the last game play source is scandalmonger.\", () => {\n const game = createFakeGame();\n const gameHistoryRecord = createFakeGameHistoryRecord({\n play: createFakeGameHistoryRecordPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"scandalmonger\",\n }),\n }),\n });\n services.gameEventsGenerator[\"generateLastGamePlaySourceGameEvent\"](game, gameHistoryRecord);\n\n expect(mocks.gameEventsGeneratorService.generateScandalmongerHayHaveMarkedGameEvent).toHaveBeenCalledExactlyOnceWith();\n });\n\n it(\"should generate accursed wolf father may have infected game event when the last game play source is accursed wolf father.\", () => {\n const game = createFakeGame();\n const gameHistoryRecord = createFakeGameHistoryRecord({\n play: createFakeGameHistoryRecordPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"accursed-wolf-father\",\n }),\n }),\n });\n services.gameEventsGenerator[\"generateLastGamePlaySourceGameEvent\"](game, gameHistoryRecord);\n\n expect(mocks.gameEventsGeneratorService.generateAccursedWolfFatherMayHaveInfectedGameEvent).toHaveBeenCalledExactlyOnceWith();\n });\n\n it(\"should generate wolf hound has chosen side game event when the last game play source is wolf hound.\", () => {\n const game = createFakeGame();\n const wolfHoundPlayer = createFakeWolfHoundAlivePlayer();\n const gameHistoryRecord = createFakeGameHistoryRecord({\n play: createFakeGameHistoryRecordPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"wolf-hound\",\n players: [wolfHoundPlayer],\n }),\n }),\n });\n services.gameEventsGenerator[\"generateLastGamePlaySourceGameEvent\"](game, gameHistoryRecord);\n\n expect(mocks.gameEventsGeneratorService.generateWolfHoundHasChosenSideGameEvent).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should generate pied piper has charmed game event when the last game play source is pied piper.\", () => {\n const game = createFakeGame();\n const gameHistoryRecord = createFakeGameHistoryRecord({\n play: createFakeGameHistoryRecordPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"pied-piper\",\n }),\n }),\n });\n services.gameEventsGenerator[\"generateLastGamePlaySourceGameEvent\"](game, gameHistoryRecord);\n\n expect(mocks.gameEventsGeneratorService.generatePiedPiperHasCharmedGameEvent).toHaveBeenCalledExactlyOnceWith();\n });\n\n it(\"should generate cupid has charmed game event when the last game play source is cupid.\", () => {\n const game = createFakeGame();\n const gameHistoryRecord = createFakeGameHistoryRecord({\n play: createFakeGameHistoryRecordPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"cupid\",\n }),\n }),\n });\n services.gameEventsGenerator[\"generateLastGamePlaySourceGameEvent\"](game, gameHistoryRecord);\n\n expect(mocks.gameEventsGeneratorService.generateCupidHasCharmedGameEvent).toHaveBeenCalledExactlyOnceWith();\n });\n\n it(\"should generate fox may have sniffed game event when the last game play source is fox.\", () => {\n const game = createFakeGame();\n const gameHistoryRecord = createFakeGameHistoryRecord({\n play: createFakeGameHistoryRecordPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"fox\",\n }),\n targets: [\n createFakeGameHistoryRecordPlayTarget({ player: createFakeWerewolfAlivePlayer() }),\n createFakeGameHistoryRecordPlayTarget({ player: createFakeWerewolfAlivePlayer() }),\n ],\n }),\n });\n services.gameEventsGenerator[\"generateLastGamePlaySourceGameEvent\"](game, gameHistoryRecord);\n\n expect(mocks.gameEventsGeneratorService.generateFoxMayHaveSniffedGameEvent).toHaveBeenCalledExactlyOnceWith([]);\n });\n\n it(\"should generate thief may have chosen card game event when the last game play source is thief.\", () => {\n const thiefPlayer = createFakeThiefAlivePlayer();\n const game = createFakeGame({\n players: [thiefPlayer],\n });\n const gameHistoryRecord = createFakeGameHistoryRecord({\n play: createFakeGameHistoryRecordPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"thief\",\n players: [thiefPlayer],\n }),\n }),\n });\n services.gameEventsGenerator[\"generateLastGamePlaySourceGameEvent\"](game, gameHistoryRecord);\n\n expect(mocks.gameEventsGeneratorService.generateThiefMayHaveChosenCardGameEvent).toHaveBeenCalledExactlyOnceWith([thiefPlayer]);\n });\n\n it(\"should generate actor may have chosen card game event when the last game play source is actor.\", () => {\n const game = createFakeGame();\n const gameHistoryRecord = createFakeGameHistoryRecord({\n play: createFakeGameHistoryRecordPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"actor\",\n players: [createFakeActorAlivePlayer()],\n }),\n }),\n });\n services.gameEventsGenerator[\"generateLastGamePlaySourceGameEvent\"](game, gameHistoryRecord);\n\n expect(mocks.gameEventsGeneratorService.generateActorMayHaveChosenCardGameEvent).toHaveBeenCalledExactlyOnceWith([]);\n });\n\n it(\"should generate actor may have chosen card game event without actor when the last game play source is actor.\", () => {\n const game = createFakeGame();\n const gameHistoryRecord = createFakeGameHistoryRecord({\n play: createFakeGameHistoryRecordPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"actor\",\n }),\n }),\n });\n gameHistoryRecord.play.source.players = undefined;\n services.gameEventsGenerator[\"generateLastGamePlaySourceGameEvent\"](game, gameHistoryRecord);\n\n expect(mocks.gameEventsGeneratorService.generateActorMayHaveChosenCardGameEvent).toHaveBeenCalledExactlyOnceWith();\n });\n\n it(\"should return undefined when the last game play source is not a special role.\", () => {\n const game = createFakeGame();\n const gameHistoryRecord = createFakeGameHistoryRecord({\n play: createFakeGameHistoryRecordPlay({\n source: createFakeGameHistoryRecordPlaySource({\n name: \"defender\",\n }),\n }),\n });\n const gameEvent = services.gameEventsGenerator[\"generateLastGamePlaySourceGameEvent\"](game, gameHistoryRecord);\n\n expect(gameEvent).toBeUndefined();\n });\n });\n\n describe(\"generateFirstTickGameEvents\", () => {\n it(\"should return empty array when it's not the first tick of the game..\", () => {\n const game = createFakeGame({ tick: 2 });\n const gameEvents = services.gameEventsGenerator[\"generateFirstTickGameEvents\"](game);\n\n expect(gameEvents).toStrictEqual([]);\n });\n\n it(\"should return game starts game event when it's the first tick of the game.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGame({\n tick: 1,\n players,\n });\n const gameEvents = services.gameEventsGenerator[\"generateFirstTickGameEvents\"](game);\n const expectedGameEvent = createFakeGameEvent({\n type: \"game-starts\",\n players,\n });\n\n expect(gameEvents).toStrictEqual([expectedGameEvent]);\n });\n\n it(\"should return game starts event with villager villager introduction event when it's the first tick of the game and there is a villager villager.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerVillagerAlivePlayer(),\n ];\n const game = createFakeGame({\n tick: 1,\n players,\n });\n const gameEvents = services.gameEventsGenerator[\"generateFirstTickGameEvents\"](game);\n const expectedGameEvents = [\n createFakeGameEvent({\n type: \"game-starts\",\n players,\n }),\n createFakeGameEvent({\n type: \"villager-villager-introduction\",\n players: [players[3]],\n }),\n ];\n\n expect(gameEvents).toStrictEqual(expectedGameEvents);\n });\n });\n\n describe(\"generateRevealedPlayersGameEvents\", () => {\n it(\"should return empty array when there are no revealed players.\", () => {\n const gameHistoryRecord = createFakeGameHistoryRecord();\n const gameEvents = services.gameEventsGenerator[\"generateRevealedPlayersGameEvents\"](gameHistoryRecord);\n\n expect(gameEvents).toStrictEqual([]);\n });\n\n it(\"should return empty array when game history record is undefined.\", () => {\n const gameEvents = services.gameEventsGenerator[\"generateRevealedPlayersGameEvents\"](undefined);\n\n expect(gameEvents).toStrictEqual([]);\n });\n\n it(\"should return idiot is spared game event when the revealed player is idiot.\", () => {\n const revealedPlayer = createFakeIdiotAlivePlayer();\n const gameHistoryRecord = createFakeGameHistoryRecord({\n revealedPlayers: [revealedPlayer],\n });\n const gameEvents = services.gameEventsGenerator[\"generateRevealedPlayersGameEvents\"](gameHistoryRecord);\n const expectedGameEvent = createFakeGameEvent({\n type: \"idiot-is-spared\",\n players: [revealedPlayer],\n });\n\n expect(gameEvents).toStrictEqual([expectedGameEvent]);\n });\n\n it(\"should return empty array when the revealed player is not idiot.\", () => {\n const revealedPlayer = createFakeWerewolfAlivePlayer();\n const gameHistoryRecord = createFakeGameHistoryRecord({\n revealedPlayers: [revealedPlayer],\n });\n const gameEvents = services.gameEventsGenerator[\"generateRevealedPlayersGameEvents\"](gameHistoryRecord);\n\n expect(gameEvents).toStrictEqual([]);\n });\n });\n\n describe(\"generateSwitchedSidePlayersGameEvents\", () => {\n it(\"should return empty array when there are no switched side players.\", () => {\n const gameHistoryRecord = createFakeGameHistoryRecord();\n const gameEvents = services.gameEventsGenerator[\"generateSwitchedSidePlayersGameEvents\"](gameHistoryRecord);\n\n expect(gameEvents).toStrictEqual([]);\n });\n\n it(\"should return empty array when game history record is undefined.\", () => {\n const gameEvents = services.gameEventsGenerator[\"generateSwitchedSidePlayersGameEvents\"](undefined);\n\n expect(gameEvents).toStrictEqual([]);\n });\n\n it(\"should return wild child has transformed game event when the switched side player is wild child and last game play action is bury dead bodies.\", () => {\n const switchedSidePlayer = createFakeWildChildAlivePlayer();\n const gameHistoryRecord = createFakeGameHistoryRecord({\n switchedSidePlayers: [switchedSidePlayer],\n play: createFakeGameHistoryRecordPlay({\n action: \"bury-dead-bodies\",\n }),\n });\n const gameEvents = services.gameEventsGenerator[\"generateSwitchedSidePlayersGameEvents\"](gameHistoryRecord);\n const expectedGameEvent = createFakeGameEvent({\n type: \"wild-child-has-transformed\",\n players: [switchedSidePlayer],\n });\n\n expect(gameEvents).toStrictEqual([expectedGameEvent]);\n });\n\n it(\"should return empty array when the switched side player is wild child and last game play action is not bury dead bodies.\", () => {\n const switchedSidePlayer = createFakeWildChildAlivePlayer();\n const gameHistoryRecord = createFakeGameHistoryRecord({\n switchedSidePlayers: [switchedSidePlayer],\n play: createFakeGameHistoryRecordPlay({\n action: \"vote\",\n }),\n });\n const gameEvents = services.gameEventsGenerator[\"generateSwitchedSidePlayersGameEvents\"](gameHistoryRecord);\n\n expect(gameEvents).toStrictEqual([]);\n });\n\n it(\"should return empty array when the switched side player is not wild child.\", () => {\n const switchedSidePlayer = createFakeWerewolfAlivePlayer();\n const gameHistoryRecord = createFakeGameHistoryRecord({\n switchedSidePlayers: [switchedSidePlayer],\n play: createFakeGameHistoryRecordPlay({\n action: \"bury-dead-bodies\",\n }),\n });\n const gameEvents = services.gameEventsGenerator[\"generateSwitchedSidePlayersGameEvents\"](gameHistoryRecord);\n\n expect(gameEvents).toStrictEqual([]);\n });\n });\n\n describe(\"generateDeadPlayersGameEvents\", () => {\n it(\"should return empty array when there are no dead players.\", () => {\n const gameHistoryRecord = createFakeGameHistoryRecord();\n const gameEvents = services.gameEventsGenerator[\"generateDeadPlayersGameEvents\"](gameHistoryRecord);\n\n expect(gameEvents).toStrictEqual([]);\n });\n\n it(\"should return empty array when game history record is undefined.\", () => {\n const gameEvents = services.gameEventsGenerator[\"generateDeadPlayersGameEvents\"](undefined);\n\n expect(gameEvents).toStrictEqual([]);\n });\n\n it(\"should return player dies game event with all dead players when there are dead players.\", () => {\n const deadPlayers = [\n createFakeDeadPlayer({ isAlive: false }),\n createFakeDeadPlayer({ isAlive: false }),\n ];\n const gameHistoryRecord = createFakeGameHistoryRecord({\n deadPlayers,\n });\n const gameEvents = services.gameEventsGenerator[\"generateDeadPlayersGameEvents\"](gameHistoryRecord);\n const expectedGameEvent = createFakeGameEvent({\n type: \"death\",\n players: deadPlayers,\n });\n\n expect(gameEvents).toStrictEqual([expectedGameEvent]);\n });\n });\n\n describe(\"generateBearGrowlsOrSleepsGameEvent\", () => {\n it(\"should generate bear growls game event when left neighbor is a werewolf.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ position: 1 }),\n createFakeBearTamerAlivePlayer({ position: 2 }),\n createFakeVillagerAlivePlayer({ position: 3 }),\n ];\n const game = createFakeGame({\n players,\n options: DEFAULT_GAME_OPTIONS,\n });\n const gameEvent = services.gameEventsGenerator[\"generateBearGrowlsOrSleepsGameEvent\"](game, players[1]);\n const expectedGameEvent = createFakeGameEvent({\n type: \"bear-growls\",\n players: [players[1]],\n });\n\n expect(gameEvent).toStrictEqual(expectedGameEvent);\n });\n\n it(\"should generate bear sleeps game event when left neighbor is not a werewolf.\", () => {\n const players = [\n createFakeVillagerAlivePlayer({ position: 1 }),\n createFakeBearTamerAlivePlayer({ position: 2 }),\n createFakeVillagerAlivePlayer({ position: 3 }),\n ];\n const game = createFakeGame({\n players,\n options: DEFAULT_GAME_OPTIONS,\n });\n const gameEvent = services.gameEventsGenerator[\"generateBearGrowlsOrSleepsGameEvent\"](game, players[1]);\n const expectedGameEvent = createFakeGameEvent({\n type: \"bear-sleeps\",\n players: [players[1]],\n });\n\n expect(gameEvent).toStrictEqual(expectedGameEvent);\n });\n\n it(\"should generate bear growls when right neighbor is a werewolf.\", () => {\n const players = [\n createFakeVillagerAlivePlayer({ position: 1 }),\n createFakeBearTamerAlivePlayer({ position: 2 }),\n createFakeWerewolfAlivePlayer({ position: 3 }),\n ];\n const game = createFakeGame({\n players,\n options: DEFAULT_GAME_OPTIONS,\n });\n const gameEvent = services.gameEventsGenerator[\"generateBearGrowlsOrSleepsGameEvent\"](game, players[1]);\n const expectedGameEvent = createFakeGameEvent({\n type: \"bear-growls\",\n players: [players[1]],\n });\n\n expect(gameEvent).toStrictEqual(expectedGameEvent);\n });\n\n it(\"should generate bear sleeps when right neighbor is not a werewolf.\", () => {\n const players = [\n createFakeVillagerAlivePlayer({ position: 1 }),\n createFakeBearTamerAlivePlayer({ position: 2 }),\n createFakeVillagerAlivePlayer({ position: 3 }),\n ];\n const game = createFakeGame({\n players,\n options: DEFAULT_GAME_OPTIONS,\n });\n const gameEvent = services.gameEventsGenerator[\"generateBearGrowlsOrSleepsGameEvent\"](game, players[1]);\n const expectedGameEvent = createFakeGameEvent({\n type: \"bear-sleeps\",\n players: [players[1]],\n });\n\n expect(gameEvent).toStrictEqual(expectedGameEvent);\n });\n\n it(\"should generate bear growls when both neighbors are werewolves.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ position: 1 }),\n createFakeBearTamerAlivePlayer({ position: 2 }),\n createFakeWerewolfAlivePlayer({ position: 3 }),\n ];\n const game = createFakeGame({\n players,\n options: DEFAULT_GAME_OPTIONS,\n });\n const gameEvent = services.gameEventsGenerator[\"generateBearGrowlsOrSleepsGameEvent\"](game, players[1]);\n const expectedGameEvent = createFakeGameEvent({\n type: \"bear-growls\",\n players: [players[1]],\n });\n\n expect(gameEvent).toStrictEqual(expectedGameEvent);\n });\n\n it(\"should generate bear growls when bear tamer is infected but both neighbors are not werewolves.\", () => {\n const players = [\n createFakeVillagerAlivePlayer(),\n createFakeBearTamerAlivePlayer({\n side: createFakePlayerSide({ current: \"werewolves\" }),\n }),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({\n players,\n options: DEFAULT_GAME_OPTIONS,\n });\n const gameEvent = services.gameEventsGenerator[\"generateBearGrowlsOrSleepsGameEvent\"](game, players[1]);\n const expectedGameEvent = createFakeGameEvent({\n type: \"bear-growls\",\n players: [players[1]],\n });\n\n expect(gameEvent).toStrictEqual(expectedGameEvent);\n });\n\n it(\"should generate bear sleeps when bear tamer is infected and both neighbors are not werewolves but game options doesn't make the infected bear tamer to growl.\", () => {\n const players = [\n createFakeVillagerAlivePlayer(),\n createFakeBearTamerAlivePlayer({\n side: createFakePlayerSide({ current: \"werewolves\" }),\n }),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({\n players,\n options: DEFAULT_GAME_OPTIONS,\n });\n game.options.roles.bearTamer.doesGrowlOnWerewolvesSide = false;\n const gameEvent = services.gameEventsGenerator[\"generateBearGrowlsOrSleepsGameEvent\"](game, players[1]);\n const expectedGameEvent = createFakeGameEvent({\n type: \"bear-sleeps\",\n players: [players[1]],\n });\n\n expect(gameEvent).toStrictEqual(expectedGameEvent);\n });\n });\n\n describe(\"generateGamePhaseStartsGameEvents\", () => {\n beforeEach(() => {\n mocks.gameEventsGeneratorService.generateBearGrowlsOrSleepsGameEvent = jest.spyOn(services.gameEventsGenerator as unknown as { generateBearGrowlsOrSleepsGameEvent }, \"generateBearGrowlsOrSleepsGameEvent\").mockReturnValue(createFakeGameEvent());\n });\n\n it(\"should return empty array when game phase tick is not 1.\", () => {\n const game = createFakeGame({\n phase: createFakeGamePhase({\n tick: 2,\n name: \"day\",\n }),\n });\n const gameEvents = services.gameEventsGenerator[\"generateGamePhaseStartsGameEvents\"](game);\n\n expect(gameEvents).toStrictEqual([]);\n });\n\n it(\"should return empty array when game phase name is twilight.\", () => {\n const game = createFakeGame({\n phase: createFakeGamePhase({\n tick: 1,\n name: \"twilight\",\n }),\n });\n const gameEvents = services.gameEventsGenerator[\"generateGamePhaseStartsGameEvents\"](game);\n\n expect(gameEvents).toStrictEqual([]);\n });\n\n it(\"should return game phase starts game event when game phase tick is 1 and not twilight.\", () => {\n const game = createFakeGame({\n phase: createFakeGamePhase({\n tick: 1,\n name: \"night\",\n }),\n });\n const gameEvents = services.gameEventsGenerator[\"generateGamePhaseStartsGameEvents\"](game);\n const expectedGameEvent = createFakeGameEvent({\n type: \"game-phase-starts\",\n });\n\n expect(gameEvents).toStrictEqual([expectedGameEvent]);\n });\n\n it(\"should generate bear growls or sleeps game event when game phase tick is 1 and day and bear tamer is in game and alive and powerful.\", () => {\n const players = [\n createFakeVillagerAlivePlayer(),\n createFakeBearTamerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({\n phase: createFakeGamePhase({\n tick: 1,\n name: \"day\",\n }),\n players,\n options: DEFAULT_GAME_OPTIONS,\n });\n services.gameEventsGenerator[\"generateGamePhaseStartsGameEvents\"](game);\n\n expect(mocks.gameEventsGeneratorService.generateBearGrowlsOrSleepsGameEvent).toHaveBeenCalledExactlyOnceWith(game, players[1]);\n });\n\n it(\"should not generate bear growls or sleeps game event when game phase tick is 1 and day and bear tamer is not in game.\", () => {\n const players = [\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({\n phase: createFakeGamePhase({\n tick: 1,\n name: \"day\",\n }),\n players,\n options: DEFAULT_GAME_OPTIONS,\n });\n services.gameEventsGenerator[\"generateGamePhaseStartsGameEvents\"](game);\n\n expect(mocks.gameEventsGeneratorService.generateBearGrowlsOrSleepsGameEvent).not.toHaveBeenCalled();\n });\n\n it(\"should not generate bear growls or sleeps game event when game phase tick is 1 and day and bear tamer is not alive.\", () => {\n const players = [\n createFakeVillagerAlivePlayer(),\n createFakeBearTamerAlivePlayer({\n isAlive: false,\n }),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({\n phase: createFakeGamePhase({\n tick: 1,\n name: \"day\",\n }),\n players,\n options: DEFAULT_GAME_OPTIONS,\n });\n services.gameEventsGenerator[\"generateGamePhaseStartsGameEvents\"](game);\n\n expect(mocks.gameEventsGeneratorService.generateBearGrowlsOrSleepsGameEvent).not.toHaveBeenCalled();\n });\n\n it(\"should not generate bear growls or sleeps game event when game phase tick is 1 and bear tamer is in game and alive and powerful but phase is night.\", () => {\n const players = [\n createFakeVillagerAlivePlayer(),\n createFakeBearTamerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({\n phase: createFakeGamePhase({\n tick: 1,\n name: \"night\",\n }),\n players,\n options: DEFAULT_GAME_OPTIONS,\n });\n services.gameEventsGenerator[\"generateGamePhaseStartsGameEvents\"](game);\n\n expect(mocks.gameEventsGeneratorService.generateBearGrowlsOrSleepsGameEvent).not.toHaveBeenCalled();\n });\n });\n\n describe(\"generatePlayerAttributeAlterationsEvents\", () => {\n it(\"should return empty array when there are no player attribute alterations.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const gameHistoryRecord = createFakeGameHistoryRecord();\n const gameEvents = services.gameEventsGenerator[\"generatePlayerAttributeAlterationsEvents\"](game, gameHistoryRecord);\n\n expect(gameEvents).toStrictEqual([]);\n });\n\n it(\"should return empty array when game history record is undefined.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const gameEvents = services.gameEventsGenerator[\"generatePlayerAttributeAlterationsEvents\"](game, undefined);\n\n expect(gameEvents).toStrictEqual([]);\n });\n\n it(\"should return elder has taken revenge game event when elder has taken revenge.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeElderAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const gameHistoryRecord = createFakeGameHistoryRecord({\n playerAttributeAlterations: [\n createFakeGameHistoryRecordPlayerAttributeAlteration({\n source: \"elder\",\n name: \"powerless\",\n status: \"attached\",\n }),\n ],\n });\n const gameEvents = services.gameEventsGenerator[\"generatePlayerAttributeAlterationsEvents\"](game, gameHistoryRecord);\n const expectedGameEvent = createFakeGameEvent({\n type: \"elder-has-taken-revenge\",\n players: [players[1]],\n });\n\n expect(gameEvents).toStrictEqual([expectedGameEvent]);\n });\n\n it(\"should return sheriff promotion game event when sheriff has been promoted.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({\n attributes: [createFakePlayerAttribute({ name: \"sheriff\" })],\n }),\n ];\n const game = createFakeGame({ players });\n const gameHistoryRecord = createFakeGameHistoryRecord({\n playerAttributeAlterations: [\n createFakeGameHistoryRecordPlayerAttributeAlteration({\n name: \"sheriff\",\n status: \"attached\",\n }),\n ],\n });\n const gameEvents = services.gameEventsGenerator[\"generatePlayerAttributeAlterationsEvents\"](game, gameHistoryRecord);\n const expectedGameEvent = createFakeGameEvent({\n type: \"sheriff-promotion\",\n players: [players[1]],\n });\n\n expect(gameEvents).toStrictEqual([expectedGameEvent]);\n });\n\n it(\"should return empty array when sheriff is not promoted or elder has not taken revenge.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n const gameHistoryRecord = createFakeGameHistoryRecord({\n playerAttributeAlterations: [\n createFakeGameHistoryRecordPlayerAttributeAlteration({\n source: \"elder\",\n name: \"powerless\",\n status: \"detached\",\n }),\n ],\n });\n const gameEvents = services.gameEventsGenerator[\"generatePlayerAttributeAlterationsEvents\"](game, gameHistoryRecord);\n\n expect(gameEvents).toStrictEqual([]);\n });\n });\n\n describe(\"generateTurnStartsGameEvents\", () => {\n it(\"should return game turn starts when called.\", () => {\n const game = createFakeGame();\n const gameEvents = services.gameEventsGenerator[\"generateTurnStartsGameEvents\"](game);\n const expectedGameEvent = createFakeGameEvent({\n type: \"game-turn-starts\",\n });\n\n expect(gameEvents).toStrictEqual([expectedGameEvent]);\n });\n\n it(\"should generate game turn starts and scandalmonger mark is active game events when current play is vote and one player has the mark.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeVillagerAlivePlayer({\n attributes: [createFakeScandalmongerMarkedByScandalmongerPlayerAttribute()],\n }),\n ];\n const game = createFakeGame({\n players,\n currentPlay: createFakeGamePlaySurvivorsVote(),\n });\n const gameEvents = services.gameEventsGenerator[\"generateTurnStartsGameEvents\"](game);\n const expectedGameEvents = [\n createFakeGameEvent({\n type: \"scandalmonger-mark-is-active\",\n players: [players[2]],\n }),\n createFakeGameEvent({\n type: \"game-turn-starts\",\n }),\n ];\n\n expect(gameEvents).toStrictEqual(expectedGameEvents);\n });\n\n it(\"should generate only game turn starts game event when current play is vote and no player has the mark.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({\n players,\n currentPlay: createFakeGamePlaySurvivorsVote(),\n });\n const gameEvents = services.gameEventsGenerator[\"generateTurnStartsGameEvents\"](game);\n const expectedGameEvent = createFakeGameEvent({\n type: \"game-turn-starts\",\n });\n\n expect(gameEvents).toStrictEqual([expectedGameEvent]);\n });\n\n it(\"should generate only game turn starts game event when current play is not vote and one player is marked.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeVillagerAlivePlayer({\n attributes: [createFakeScandalmongerMarkedByScandalmongerPlayerAttribute()],\n }),\n ];\n const game = createFakeGame({\n players,\n currentPlay: createFakeGamePlayWerewolvesEat(),\n });\n const gameEvents = services.gameEventsGenerator[\"generateTurnStartsGameEvents\"](game);\n const expectedGameEvent = createFakeGameEvent({\n type: \"game-turn-starts\",\n });\n\n expect(gameEvents).toStrictEqual([expectedGameEvent]);\n });\n\n it(\"should generate only game turn starts game event when current play is null and one player is marked.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeScandalmongerAlivePlayer(),\n createFakeVillagerAlivePlayer({\n attributes: [createFakeScandalmongerMarkedByScandalmongerPlayerAttribute()],\n }),\n ];\n const game = createFakeGame({\n players,\n currentPlay: null,\n });\n const gameEvents = services.gameEventsGenerator[\"generateTurnStartsGameEvents\"](game);\n const expectedGameEvent = createFakeGameEvent({\n type: \"game-turn-starts\",\n });\n\n expect(gameEvents).toStrictEqual([expectedGameEvent]);\n });\n });\n});" }, "tests/unit/specs/modules/game/helpers/game.helpers.spec.ts": { "tests": [ @@ -195088,7 +195090,7 @@ } } ], - "source": "import { DEFAULT_GAME_OPTIONS } from \"@/modules/game/constants/game-options/game-options.constants\";\nimport type { Types } from \"mongoose\";\n\nimport type { CreateGamePlayerDto } from \"@/modules/game/dto/create-game/create-game-player/create-game-player.dto\";\nimport { areAllPlayersDead, areAllVillagersAlive, areAllWerewolvesAlive, doesGameHaveCurrentOrUpcomingPlaySourceAndAction, doesGameHaveUpcomingPlaySourceAndAction, getAdditionalCardWithId, getAlivePlayers, getAliveVillagerSidedPlayers, getAliveWerewolfSidedPlayers, getAllowedToVotePlayers, getDistinctPlayerGroups, getEligibleBigBadWolfTargets, getEligibleCupidTargets, getEligiblePiedPiperTargets, getEligibleWerewolvesTargets, getEligibleWhiteWerewolfTargets, getFoxSniffedPlayers, getGroupOfPlayers, getNearestAliveNeighbor, getNonexistentPlayer, getNonexistentPlayerId, getPlayerDtoWithRole, getPlayersWithActiveAttributeName, getPlayersWithCurrentRole, getPlayersWithCurrentSide, getPlayersWithIds, getPlayerWithActiveAttributeName, getPlayerWithCurrentRole, getPlayerWithId, getPlayerWithIdOrThrow, getPlayerWithName, getPlayerWithNameOrThrow, isGameSourceGroup, isGameSourceRole } from \"@/modules/game/helpers/game.helpers\";\nimport type { GameAdditionalCard } from \"@/modules/game/schemas/game-additional-card/game-additional-card.schema\";\nimport type { Game } from \"@/modules/game/schemas/game.schema\";\nimport type { Player } from \"@/modules/game/schemas/player/player.schema\";\nimport type { GamePlayAction } from \"@/modules/game/types/game-play/game-play.types\";\nimport type { GetNearestPlayerOptions } from \"@/modules/game/types/game.types\";\nimport type { PlayerGroup } from \"@/modules/game/types/player/player.types\";\nimport type { RoleName } from \"@/modules/role/types/role.types\";\n\nimport { UnexpectedExceptionReasons } from \"@/shared/exception/enums/unexpected-exception.enum\";\nimport type { ExceptionInterpolations } from \"@/shared/exception/types/exception.types\";\nimport { UnexpectedException } from \"@/shared/exception/types/unexpected-exception.types\";\n\nimport { createFakeCreateGamePlayerDto } from \"@tests/factories/game/dto/create-game/create-game-player/create-game-player.dto.factory\";\nimport { createFakeCreateGameDto } from \"@tests/factories/game/dto/create-game/create-game.dto.factory\";\nimport { createFakeGameAdditionalCard } from \"@tests/factories/game/schemas/game-additional-card/game-additional-card.schema.factory\";\nimport { createFakeGameOptions } from \"@tests/factories/game/schemas/game-options/game-options.schema.factory\";\nimport { createFakeCupidGameOptions, createFakeRolesGameOptions, createFakeWerewolfGameOptions } from \"@tests/factories/game/schemas/game-options/game-roles-options/game-roles-options.schema.factory\";\nimport { createFakeGamePlayHunterShoots, createFakeGamePlayWerewolvesEat } from \"@tests/factories/game/schemas/game-play/game-play.schema.factory\";\nimport { createFakeGame } from \"@tests/factories/game/schemas/game.schema.factory\";\nimport { createFakeCantVoteBySurvivorsPlayerAttribute, createFakeCharmedByPiedPiperPlayerAttribute, createFakeEatenByWerewolvesPlayerAttribute, createFakeEatenByWhiteWerewolfPlayerAttribute, createFakeInLoveByCupidPlayerAttribute } from \"@tests/factories/game/schemas/player/player-attribute/player-attribute.schema.factory\";\nimport { createFakeBigBadWolfAlivePlayer, createFakeCupidAlivePlayer, createFakePiedPiperAlivePlayer, createFakeSeerAlivePlayer, createFakeVillagerAlivePlayer, createFakeVillagerVillagerAlivePlayer, createFakeWerewolfAlivePlayer, createFakeWhiteWerewolfAlivePlayer } from \"@tests/factories/game/schemas/player/player-with-role.schema.factory\";\nimport { createFakePlayer } from \"@tests/factories/game/schemas/player/player.schema.factory\";\nimport { createFakeObjectId } from \"@tests/factories/shared/mongoose/mongoose.factory\";\n\ndescribe(\"Game Helper\", () => {\n describe(\"getPlayerDtoWithRole\", () => {\n const players = [\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"seer\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"two-sisters\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"two-sisters\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"idiot\" } }),\n ];\n const game = createFakeCreateGameDto({ players });\n\n it(\"should return player with role when a player has this role.\", () => {\n expect(getPlayerDtoWithRole(game, \"werewolf\")).toStrictEqual(game.players[2]);\n });\n\n it(\"should return undefined when player with role is not found.\", () => {\n expect(getPlayerDtoWithRole(game, \"three-brothers\")).toBeUndefined();\n });\n });\n\n describe(\"getPlayerWithCurrentRole\", () => {\n const players = [\n createFakePlayer({ role: { current: \"witch\", original: \"witch\", isRevealed: false } }),\n createFakePlayer({ role: { current: \"seer\", original: \"seer\", isRevealed: false } }),\n createFakePlayer({ role: { current: \"werewolf\", original: \"werewolf\", isRevealed: false } }),\n createFakePlayer({ role: { current: \"two-sisters\", original: \"two-sisters\", isRevealed: false } }),\n createFakePlayer({ role: { current: \"two-sisters\", original: \"two-sisters\", isRevealed: false } }),\n createFakePlayer({ role: { current: \"idiot\", original: \"idiot\", isRevealed: false } }),\n ];\n const game = createFakeGame({ players });\n\n it(\"should return player with role when a player has this role.\", () => {\n expect(getPlayerWithCurrentRole(game, \"seer\")).toStrictEqual(players[1]);\n });\n\n it(\"should return undefined when player with role is not found.\", () => {\n expect(getPlayerWithCurrentRole(game, \"big-bad-wolf\")).toBeUndefined();\n });\n });\n\n describe(\"getPlayersWithCurrentRole\", () => {\n const players = [\n createFakePlayer({ role: { current: \"three-brothers\", original: \"witch\", isRevealed: false } }),\n createFakePlayer({ role: { current: \"three-brothers\", original: \"seer\", isRevealed: false } }),\n createFakePlayer({ role: { current: \"three-brothers\", original: \"werewolf\", isRevealed: false } }),\n createFakePlayer({ role: { current: \"two-sisters\", original: \"two-sisters\", isRevealed: false } }),\n createFakePlayer({ role: { current: \"two-sisters\", original: \"two-sisters\", isRevealed: false } }),\n createFakePlayer({ role: { current: \"idiot\", original: \"idiot\", isRevealed: false } }),\n ];\n const game = createFakeGame({ players });\n\n it(\"should return players when they have this role.\", () => {\n expect(getPlayersWithCurrentRole(game, \"three-brothers\")).toStrictEqual([players[0], players[1], players[2]]);\n });\n\n it(\"should return empty array when no one has the role.\", () => {\n expect(getPlayersWithCurrentRole(game, \"werewolf\")).toStrictEqual([]);\n });\n });\n\n describe(\"getPlayersWithCurrentSide\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n it(\"should return werewolves when they have this side.\", () => {\n expect(getPlayersWithCurrentSide(game, \"werewolves\")).toStrictEqual([players[0], players[1], players[4], players[5]]);\n });\n\n it(\"should return villagers when they have this side.\", () => {\n expect(getPlayersWithCurrentSide(game, \"villagers\")).toStrictEqual([players[2], players[3]]);\n });\n });\n\n describe(\"getPlayerWithId\", () => {\n it(\"should get player with specific id when called with this id.\", () => {\n const players = [\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(getPlayerWithId(game, players[2]._id)).toStrictEqual(players[2]);\n });\n\n it(\"should return undefined when called with unknown id.\", () => {\n const players = [\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(getPlayerWithId(game, createFakeObjectId())).toBeUndefined();\n });\n });\n\n describe(\"getPlayerWithIdOrThrow\", () => {\n it(\"should get player with specific id when called with this id.\", () => {\n const players = [\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n ];\n const game = createFakeGame({ players });\n const exceptionInterpolations: ExceptionInterpolations = { gameId: game._id.toString(), playerId: players[2]._id.toString() };\n const exception = new UnexpectedException(\"killPlayer\", UnexpectedExceptionReasons.CANT_FIND_PLAYER_WITH_ID_IN_GAME, exceptionInterpolations);\n\n expect(getPlayerWithIdOrThrow(players[2]._id, game, exception)).toStrictEqual(players[2]);\n });\n\n it(\"should throw error when called with unknown id.\", () => {\n const players = [\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n ];\n const game = createFakeGame({ players });\n const unknownPlayerId = createFakeObjectId();\n const exceptionInterpolations: ExceptionInterpolations = { gameId: game._id.toString(), playerId: unknownPlayerId.toString() };\n const exception = new UnexpectedException(\"killPlayer\", UnexpectedExceptionReasons.CANT_FIND_PLAYER_WITH_ID_IN_GAME, exceptionInterpolations);\n\n expect(() => getPlayerWithIdOrThrow(unknownPlayerId, game, exception)).toThrow(exception);\n });\n });\n\n describe(\"getPlayersWithIds\", () => {\n it(\"should get players with specific ids when called with these ids.\", () => {\n const players = [\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n ];\n const game = createFakeGame({ players });\n const idsToFind = [players[1]._id, players[3]._id, createFakeObjectId(), players[5]._id];\n const expectedPlayers = [players[1], players[3], players[5]];\n\n expect(getPlayersWithIds(idsToFind, game)).toStrictEqual(expectedPlayers);\n });\n });\n\n describe(\"getPlayerWithName\", () => {\n it(\"should get player with specific name when called with this name.\", () => {\n const players = [\n createFakePlayer({ name: \"player1\" }),\n createFakePlayer({ name: \"player2\" }),\n createFakePlayer({ name: \"player3\" }),\n createFakePlayer({ name: \"player4\" }),\n createFakePlayer({ name: \"player5\" }),\n ];\n const game = createFakeGame({ players });\n\n expect(getPlayerWithName(game, \"player3\")).toStrictEqual(players[2]);\n });\n\n it(\"should return undefined when called with unknown name.\", () => {\n const players = [\n createFakePlayer({ name: \"player1\" }),\n createFakePlayer({ name: \"player2\" }),\n createFakePlayer({ name: \"player3\" }),\n createFakePlayer({ name: \"player4\" }),\n createFakePlayer({ name: \"player5\" }),\n ];\n const game = createFakeGame({ players });\n\n expect(getPlayerWithName(game, \"i-cant-be-a-valid-name-that-is-bad\")).toBeUndefined();\n });\n });\n\n describe(\"getPlayerWithNameOrThrow\", () => {\n it(\"should get player with specific name when called with this id.\", () => {\n const players = [\n createFakePlayer({ name: \"player1\" }),\n createFakePlayer({ name: \"player2\" }),\n createFakePlayer({ name: \"player5\" }),\n createFakePlayer({ name: \"player3\" }),\n createFakePlayer({ name: \"player4\" }),\n createFakePlayer({ name: \"player6\" }),\n ];\n const game = createFakeGame({ players });\n const error = new Error(\"Can't find player with name…\");\n\n expect(getPlayerWithNameOrThrow(\"player5\", game, error)).toStrictEqual(players[2]);\n });\n\n it(\"should throw error when called with unknown name.\", () => {\n const players = [\n createFakePlayer({ name: \"player1\" }),\n createFakePlayer({ name: \"player2\" }),\n createFakePlayer({ name: \"player5\" }),\n createFakePlayer({ name: \"player3\" }),\n createFakePlayer({ name: \"player4\" }),\n createFakePlayer({ name: \"player6\" }),\n ];\n const game = createFakeGame({ players });\n const unknownPlayerName = \"i-cant-be-a-valid-name-that-is-bad\";\n const error = new Error(`Can't find player with name \"${unknownPlayerName}\" in game \"${game._id.toString()}\"`);\n\n expect(() => getPlayerWithNameOrThrow(unknownPlayerName, game, error)).toThrow(error);\n });\n });\n\n describe(\"getDistinctPlayerGroups\", () => {\n it(\"should return distinct player groups when called.\", () => {\n const players = [\n createFakeCreateGamePlayerDto({ group: \"group1\" }),\n createFakeCreateGamePlayerDto({ group: \"group2\" }),\n createFakeCreateGamePlayerDto({ group: \"group1\" }),\n createFakeCreateGamePlayerDto({ group: \"group3\" }),\n createFakeCreateGamePlayerDto({ group: \"group2\" }),\n createFakeCreateGamePlayerDto({ group: \"group4\" }),\n ];\n const game = createFakeCreateGameDto({ players });\n\n expect(getDistinctPlayerGroups(game)).toStrictEqual([\"group1\", \"group2\", \"group3\", \"group4\"]);\n });\n\n it(\"should return empty array when no player groups are provided.\", () => {\n const game = createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto(),\n createFakeCreateGamePlayerDto(),\n createFakeCreateGamePlayerDto(),\n ],\n });\n\n expect(getDistinctPlayerGroups(game)).toStrictEqual([]);\n });\n });\n\n describe(\"getAdditionalCardWithId\", () => {\n it(\"should get card with specific id when called with this id.\", () => {\n const cards = [\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n ];\n\n expect(getAdditionalCardWithId(cards, cards[3]._id)).toStrictEqual(cards[3]);\n });\n\n it(\"should return undefined when cards are undefined.\", () => {\n expect(getAdditionalCardWithId(undefined, createFakeObjectId())).toBeUndefined();\n });\n\n it(\"should return undefined when called with unknown id.\", () => {\n const cards = [\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n ];\n\n expect(getAdditionalCardWithId(cards, createFakeObjectId())).toBeUndefined();\n });\n });\n\n describe(\"areAllWerewolvesAlive\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n it(\"should return false when empty array is provided.\", () => {\n expect(areAllWerewolvesAlive(createFakeGame())).toBe(false);\n });\n\n it(\"should return true when all werewolves are alive.\", () => {\n expect(areAllWerewolvesAlive(game)).toBe(true);\n });\n\n it(\"should return true when at least one werewolf is dead.\", () => {\n const notAllAlivePlayers = players.map(player => createFakePlayer(player));\n notAllAlivePlayers[0].isAlive = false;\n const notAllAliveGame = createFakeGame({ players: notAllAlivePlayers });\n\n expect(areAllWerewolvesAlive(notAllAliveGame)).toBe(false);\n });\n });\n\n describe(\"areAllVillagersAlive\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n it(\"should return false when empty array is provided.\", () => {\n expect(areAllVillagersAlive(createFakeGame())).toBe(false);\n });\n\n it(\"should return true when all villagers are alive.\", () => {\n expect(areAllVillagersAlive(game)).toBe(true);\n });\n\n it(\"should return true when at least one villager is dead.\", () => {\n const clonedPlayers = players.map(player => createFakePlayer(player));\n clonedPlayers[1].isAlive = false;\n const notAllAlivePlayersGame = createFakeGame({ players: clonedPlayers });\n\n expect(areAllVillagersAlive(notAllAlivePlayersGame)).toBe(false);\n });\n });\n\n describe(\"areAllPlayersDead\", () => {\n const players = [\n createFakePlayer({ isAlive: false }),\n createFakePlayer({ isAlive: false }),\n createFakePlayer({ isAlive: true }),\n createFakePlayer({ isAlive: false }),\n ];\n const game = createFakeGame({ players });\n\n it(\"should return false when empty array is provided.\", () => {\n expect(areAllPlayersDead(createFakeGame())).toBe(false);\n });\n\n it(\"should return false when at least one player is alive.\", () => {\n expect(areAllPlayersDead(game)).toBe(false);\n });\n\n it(\"should return true when all players are dead.\", () => {\n const clonedGame = createFakeGame(game);\n clonedGame.players[2].isAlive = false;\n\n expect(areAllPlayersDead(clonedGame)).toBe(true);\n });\n });\n\n describe(\"getPlayerWithActiveAttributeName\", () => {\n it(\"should return first player with attribute when called.\", () => {\n const players = [\n createFakePlayer({ attributes: [] }),\n createFakePlayer({ attributes: [createFakeEatenByWerewolvesPlayerAttribute()] }),\n createFakePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n ];\n const game = createFakeGame({ players });\n\n expect(getPlayerWithActiveAttributeName(game, \"charmed\")).toStrictEqual(players[2]);\n });\n\n it(\"should return undefined when player with attribute is not found.\", () => {\n const players = [\n createFakePlayer({ attributes: [] }),\n createFakePlayer({ attributes: [createFakeEatenByWerewolvesPlayerAttribute()] }),\n createFakePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n ];\n const game = createFakeGame({ players });\n\n expect(getPlayerWithActiveAttributeName(game, \"seen\")).toBeUndefined();\n });\n });\n\n describe(\"getPlayersWithActiveAttributeName\", () => {\n const players = [\n createFakePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakePlayer({ attributes: [] }),\n createFakePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakePlayer({ attributes: [createFakeEatenByWerewolvesPlayerAttribute()] }),\n ];\n const game = createFakeGame({ players });\n\n it(\"should return players when they have the attribute.\", () => {\n expect(getPlayersWithActiveAttributeName(game, \"charmed\")).toStrictEqual([players[0], players[2]]);\n });\n\n it(\"should return empty array when none has the attribute.\", () => {\n expect(getPlayersWithActiveAttributeName(game, \"seen\")).toStrictEqual([]);\n });\n });\n\n describe(\"getAlivePlayers\", () => {\n it(\"should get all alive players when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(getAlivePlayers(game)).toStrictEqual([players[0], players[1], players[3]]);\n });\n });\n\n describe(\"getAliveVillagerSidedPlayers\", () => {\n it(\"should get all alive villager sided players when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(getAliveVillagerSidedPlayers(game)).toStrictEqual([players[1]]);\n });\n });\n\n describe(\"getAliveWerewolfSidedPlayers\", () => {\n it(\"should get all alive werewolf sided players when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n ];\n const game = createFakeGame({ players });\n\n expect(getAliveWerewolfSidedPlayers(game)).toStrictEqual([players[0]]);\n });\n });\n\n describe(\"getEligiblePiedPiperTargets\", () => {\n it(\"should get left to charm by pied piper players when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakePiedPiperAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer({ isAlive: false, attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(getEligiblePiedPiperTargets(game)).toStrictEqual([players[2], players[4]]);\n });\n });\n\n describe(\"getEligibleWerewolvesTargets\", () => {\n it(\"should return alive and not already eaten villagers players when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakePiedPiperAlivePlayer(),\n createFakeVillagerAlivePlayer({ attributes: [createFakeEatenByWerewolvesPlayerAttribute()] }),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGame({\n players,\n options: DEFAULT_GAME_OPTIONS,\n });\n\n expect(getEligibleWerewolvesTargets(game)).toStrictEqual([players[1]]);\n });\n\n it(\"should return alive and not already eaten villagers and werewolves players when werewolves can eat each other.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakePiedPiperAlivePlayer(),\n createFakeVillagerAlivePlayer({ attributes: [createFakeEatenByWerewolvesPlayerAttribute()] }),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeEatenByWhiteWerewolfPlayerAttribute()] }),\n ];\n const game = createFakeGame({\n players,\n options: createFakeGameOptions({\n roles: createFakeRolesGameOptions({\n werewolf: createFakeWerewolfGameOptions({ canEatEachOther: true }),\n }),\n }),\n });\n\n expect(getEligibleWerewolvesTargets(game)).toStrictEqual([\n players[0],\n players[1],\n players[4],\n ]);\n });\n\n it(\"should return alive and not already eaten villagers when werewolves can eat each other but only one werewolf is alive.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakePiedPiperAlivePlayer(),\n createFakeVillagerAlivePlayer({ attributes: [createFakeEatenByWerewolvesPlayerAttribute()] }),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n ];\n const game = createFakeGame({\n players,\n options: createFakeGameOptions({\n roles: createFakeRolesGameOptions({\n werewolf: createFakeWerewolfGameOptions({ canEatEachOther: true }),\n }),\n }),\n });\n\n expect(getEligibleWerewolvesTargets(game)).toStrictEqual([players[1]]);\n });\n });\n\n describe(\"getEligibleBigBadWolfTargets\", () => {\n it(\"should return eligible targets without the big bad wolf when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakePiedPiperAlivePlayer(),\n createFakeVillagerAlivePlayer({ attributes: [createFakeEatenByWerewolvesPlayerAttribute()] }),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer(),\n createFakePiedPiperAlivePlayer(),\n createFakeBigBadWolfAlivePlayer(),\n ];\n const game = createFakeGame({\n players,\n options: createFakeGameOptions({\n roles: createFakeRolesGameOptions({\n werewolf: createFakeWerewolfGameOptions({ canEatEachOther: true }),\n }),\n }),\n });\n\n expect(getEligibleBigBadWolfTargets(game)).toStrictEqual([\n players[0],\n players[1],\n players[4],\n players[5],\n ]);\n });\n });\n\n describe(\"getEligibleWhiteWerewolfTargets\", () => {\n it(\"should return left to eat by white werewolf players when called.\", () => {\n const players = [\n createFakeWhiteWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeVillagerAlivePlayer({ attributes: [createFakeEatenByWerewolvesPlayerAttribute()] }),\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(getEligibleWhiteWerewolfTargets(game)).toStrictEqual([players[4]]);\n });\n });\n\n describe(\"getEligibleCupidTargets\", () => {\n it(\"should return left to charm by cupid players when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeCupidAlivePlayer(),\n createFakeVillagerAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ cupid: createFakeCupidGameOptions({ mustWinWithLovers: false }) }) });\n const game = createFakeGame({ players, options });\n\n expect(getEligibleCupidTargets(game)).toStrictEqual([\n players[0],\n players[1],\n players[2],\n players[4],\n ]);\n });\n\n it(\"should return left to charm by cupid players without cupid himself when called with cupid must win with lovers option.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeCupidAlivePlayer(),\n createFakeVillagerAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ cupid: createFakeCupidGameOptions({ mustWinWithLovers: true }) }) });\n const game = createFakeGame({ players, options });\n\n expect(getEligibleCupidTargets(game)).toStrictEqual([\n players[0],\n players[2],\n players[4],\n ]);\n });\n });\n\n describe(\"getGroupOfPlayers\", () => {\n const players = [\n createFakeVillagerAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n createFakeWhiteWerewolfAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakeVillagerAlivePlayer({ attributes: [createFakeEatenByWerewolvesPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n createFakeVillagerVillagerAlivePlayer({ isAlive: false }),\n ];\n const game = createFakeGame({ players });\n\n it.each<{\n test: string;\n group: PlayerGroup;\n expected: Player[];\n }>([\n {\n test: \"should return all alive players when group is survivors.\",\n group: \"survivors\",\n expected: [\n players[0],\n players[1],\n players[2],\n players[3],\n players[4],\n players[5],\n ],\n },\n {\n test: \"should return players in love when group is lovers.\",\n group: \"lovers\",\n expected: [players[2], players[5]],\n },\n {\n test: \"should return charmed players when group is charmed.\",\n group: \"charmed\",\n expected: [players[0], players[3]],\n },\n {\n test: \"should return villagers when group is villagers.\",\n group: \"villagers\",\n expected: [players[0], players[2], players[4], players[6]],\n },\n {\n test: \"should return werewolves when group is werewolves.\",\n group: \"werewolves\",\n expected: [players[1], players[3], players[5]],\n },\n ])(\"$test\", ({ group, expected }) => {\n expect(getGroupOfPlayers(game, group)).toStrictEqual(expected);\n });\n });\n\n describe(\"isGameSourceRole\", () => {\n it(\"should return true when source is role.\", () => {\n expect(isGameSourceRole(\"witch\")).toBe(true);\n });\n\n it(\"should return false when source is group.\", () => {\n expect(isGameSourceRole(\"survivors\")).toBe(false);\n });\n });\n\n describe(\"isGameSourceGroup\", () => {\n it(\"should return true when source is group.\", () => {\n expect(isGameSourceGroup(\"werewolves\")).toBe(true);\n });\n\n it(\"should return false when source is role.\", () => {\n expect(isGameSourceGroup(\"seer\")).toBe(false);\n });\n });\n\n describe(\"getNonexistentPlayerId\", () => {\n it(\"should return undefined when all candidate ids are found.\", () => {\n const players = [\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(getNonexistentPlayerId(game, players.map(player => player._id))).toBeUndefined();\n });\n\n it(\"should return unknown id when one candidate id is not found.\", () => {\n const players = [\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n ];\n const ids = players.map(player => player._id);\n const unknownId = createFakeObjectId();\n const game = createFakeGame({ players });\n\n expect(getNonexistentPlayerId(game, [...ids, unknownId])).toStrictEqual(unknownId);\n });\n });\n\n describe(\"getNonexistentPlayer\", () => {\n it(\"should return undefined when all candidate ids are found.\", () => {\n const players = [\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(getNonexistentPlayer(game, players)).toBeUndefined();\n });\n\n it(\"should return unknown id when one candidate id is not found.\", () => {\n const players = [\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n ];\n const otherPlayer = createFakePlayer();\n const game = createFakeGame({ players });\n\n expect(getNonexistentPlayer(game, [...players, otherPlayer])).toStrictEqual(otherPlayer);\n });\n });\n\n describe(\"getFoxSniffedPlayers\", () => {\n it(\"should get 3 targets with left and right neighbors when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ position: 0 }),\n createFakeVillagerAlivePlayer({ position: 1 }),\n createFakeWerewolfAlivePlayer({ position: 2 }),\n createFakeVillagerAlivePlayer({ position: 3 }),\n ];\n const game = createFakeGame({ players });\n const expectedPlayers = [\n createFakePlayer(players[2]),\n createFakePlayer(players[3]),\n createFakePlayer(players[0]),\n ];\n\n expect(getFoxSniffedPlayers(players[3]._id, game)).toStrictEqual(expectedPlayers);\n });\n\n it(\"should get 3 targets with left neighbor when right is dead.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ position: 0, isAlive: false }),\n createFakeVillagerAlivePlayer({ position: 1 }),\n createFakeWerewolfAlivePlayer({ position: 2 }),\n createFakeVillagerAlivePlayer({ position: 3 }),\n ];\n const game = createFakeGame({ players });\n const expectedPlayers = [\n createFakePlayer(players[2]),\n createFakePlayer(players[3]),\n createFakePlayer(players[1]),\n ];\n\n expect(getFoxSniffedPlayers(players[3]._id, game)).toStrictEqual(expectedPlayers);\n });\n\n it(\"should get 2 targets with left neighbor when all rights are dead.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ position: 0, isAlive: false }),\n createFakeVillagerAlivePlayer({ position: 1, isAlive: false }),\n createFakeWerewolfAlivePlayer({ position: 2 }),\n createFakeVillagerAlivePlayer({ position: 3 }),\n ];\n const game = createFakeGame({ players });\n const expectedPlayers = [\n createFakePlayer(players[2]),\n createFakePlayer(players[3]),\n ];\n\n expect(getFoxSniffedPlayers(players[3]._id, game)).toStrictEqual(expectedPlayers);\n });\n\n it(\"should get only 1 target when all neighbors.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ position: 0, isAlive: false }),\n createFakeVillagerAlivePlayer({ position: 1, isAlive: false }),\n createFakeWerewolfAlivePlayer({ position: 2 }),\n createFakeVillagerAlivePlayer({ position: 3, isAlive: false }),\n ];\n const game = createFakeGame({ players });\n const expectedPlayers = [createFakePlayer(players[2])];\n\n expect(getFoxSniffedPlayers(players[2]._id, game)).toStrictEqual(expectedPlayers);\n });\n\n it(\"should throw error when player is not found in game.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ position: 0 }),\n createFakeVillagerAlivePlayer({ position: 1 }),\n createFakeWerewolfAlivePlayer({ position: 2 }),\n createFakeVillagerAlivePlayer({ position: 3 }),\n ];\n const game = createFakeGame({ players });\n const unknownPlayerId = createFakeObjectId();\n const exceptionInterpolations: ExceptionInterpolations = { gameId: game._id.toString(), playerId: unknownPlayerId.toString() };\n const exception = new UnexpectedException(\"getFoxSniffedTargets\", UnexpectedExceptionReasons.CANT_FIND_PLAYER_WITH_ID_IN_GAME, exceptionInterpolations);\n\n expect(() => getFoxSniffedPlayers(unknownPlayerId, game)).toThrow(exception);\n });\n });\n\n describe(\"getNearestAliveNeighbor\", () => {\n it(\"should throw error when player is not found in game.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ position: 0 }),\n createFakeVillagerAlivePlayer({ position: 1 }),\n createFakeWerewolfAlivePlayer({ position: 2 }),\n createFakeVillagerAlivePlayer({ position: 3 }),\n createFakeWerewolfAlivePlayer({ position: 4 }),\n createFakeVillagerAlivePlayer({ position: 5 }),\n ];\n const game = createFakeGame({ players });\n const options: GetNearestPlayerOptions = { direction: \"right\" };\n const unknownPlayerId = createFakeObjectId();\n const exceptionInterpolations: ExceptionInterpolations = { gameId: game._id.toString(), playerId: unknownPlayerId.toString() };\n const exception = new UnexpectedException(\"getNearestAliveNeighbor\", UnexpectedExceptionReasons.CANT_FIND_PLAYER_WITH_ID_IN_GAME, exceptionInterpolations);\n\n expect(() => getNearestAliveNeighbor(unknownPlayerId, game, options)).toThrow(exception);\n });\n\n it(\"should get the nearest right alive player when called with right direction.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ position: 2 }),\n createFakeVillagerAlivePlayer({ position: 1 }),\n createFakeWerewolfAlivePlayer({ position: 0, isAlive: false }),\n createFakeVillagerAlivePlayer({ position: 3 }),\n createFakeVillagerAlivePlayer({ position: 5, isAlive: false }),\n createFakeWerewolfAlivePlayer({ position: 4 }),\n ];\n const game = createFakeGame({ players });\n const options: GetNearestPlayerOptions = { direction: \"right\" };\n\n expect(getNearestAliveNeighbor(players[5]._id, game, options)).toStrictEqual(players[1]);\n });\n\n it(\"should get the nearest left alive player when called with left direction.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ position: 2 }),\n createFakeWerewolfAlivePlayer({ position: 0, isAlive: false }),\n createFakeVillagerAlivePlayer({ position: 3 }),\n createFakeVillagerAlivePlayer({ position: 5, isAlive: false }),\n createFakeWerewolfAlivePlayer({ position: 4 }),\n createFakeVillagerAlivePlayer({ position: 1 }),\n ];\n const game = createFakeGame({ players });\n const options: GetNearestPlayerOptions = { direction: \"left\" };\n\n expect(getNearestAliveNeighbor(players[5]._id, game, options)).toStrictEqual(players[4]);\n });\n\n it(\"should get the nearest left alive villager player when called with left direction and villager side.\", () => {\n const players = [\n createFakeVillagerAlivePlayer({ position: 5, isAlive: false }),\n createFakeVillagerAlivePlayer({ position: 3 }),\n createFakeWerewolfAlivePlayer({ position: 0, isAlive: false }),\n createFakeVillagerAlivePlayer({ position: 1 }),\n createFakeWerewolfAlivePlayer({ position: 4 }),\n createFakeWerewolfAlivePlayer({ position: 2 }),\n ];\n const game = createFakeGame({ players });\n const options: GetNearestPlayerOptions = { direction: \"left\", playerSide: \"villagers\" };\n\n expect(getNearestAliveNeighbor(players[3]._id, game, options)).toStrictEqual(players[1]);\n });\n\n it(\"should get the nearest left alive werewolf player when called with left direction and werewolf side.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ position: 0 }),\n createFakeVillagerAlivePlayer({ position: 1 }),\n createFakeWerewolfAlivePlayer({ position: 2 }),\n createFakeVillagerAlivePlayer({ position: 3 }),\n createFakeWerewolfAlivePlayer({ position: 4 }),\n createFakeVillagerAlivePlayer({ position: 5, isAlive: false }),\n ];\n const game = createFakeGame({ players });\n const options: GetNearestPlayerOptions = { direction: \"left\", playerSide: \"werewolves\" };\n\n expect(getNearestAliveNeighbor(players[1]._id, game, options)).toStrictEqual(players[0]);\n });\n\n it(\"should return the other alive player when there are only two alive players.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ position: 0 }),\n createFakeVillagerAlivePlayer({ position: 1 }),\n createFakeVillagerAlivePlayer({ position: 2, isAlive: false }),\n ];\n const game = createFakeGame({ players });\n const options: GetNearestPlayerOptions = { direction: \"left\" };\n\n expect(getNearestAliveNeighbor(players[0]._id, game, options)).toStrictEqual(players[1]);\n });\n\n it(\"should return undefined when can't find player with conditions.\", () => {\n const players = [\n createFakeVillagerAlivePlayer({ position: 5, isAlive: false }),\n createFakeVillagerAlivePlayer({ position: 3 }),\n createFakeWerewolfAlivePlayer({ position: 0, isAlive: false }),\n createFakeVillagerAlivePlayer({ position: 1 }),\n createFakeWerewolfAlivePlayer({ position: 4 }),\n createFakeWerewolfAlivePlayer({ position: 2, isAlive: false }),\n ];\n const game = createFakeGame({ players });\n const options: GetNearestPlayerOptions = { direction: \"left\", playerSide: \"werewolves\" };\n\n expect(getNearestAliveNeighbor(players[4]._id, game, options)).toBeUndefined();\n });\n\n it(\"should return undefined when there are no alive players.\", () => {\n const players = [\n createFakeVillagerAlivePlayer({ position: 5, isAlive: false }),\n createFakeVillagerAlivePlayer({ position: 3, isAlive: false }),\n createFakeWerewolfAlivePlayer({ position: 0, isAlive: false }),\n createFakeVillagerAlivePlayer({ position: 1, isAlive: false }),\n createFakeWerewolfAlivePlayer({ position: 4, isAlive: false }),\n createFakeWerewolfAlivePlayer({ position: 2, isAlive: false }),\n ];\n const game = createFakeGame({ players });\n const options: GetNearestPlayerOptions = { direction: \"left\", playerSide: \"werewolves\" };\n\n expect(getNearestAliveNeighbor(players[4]._id, game, options)).toBeUndefined();\n });\n\n it(\"should return undefined when there is no alive werewolf to find.\", () => {\n const players = [\n createFakeVillagerAlivePlayer({ position: 5, isAlive: false }),\n createFakeVillagerAlivePlayer({ position: 3 }),\n createFakeWerewolfAlivePlayer({ position: 0, isAlive: false }),\n createFakeVillagerAlivePlayer({ position: 1 }),\n createFakeWerewolfAlivePlayer({ position: 4 }),\n createFakeWerewolfAlivePlayer({ position: 2, isAlive: false }),\n ];\n const game = createFakeGame({ players });\n const options: GetNearestPlayerOptions = { direction: \"left\", playerSide: \"werewolves\" };\n\n expect(getNearestAliveNeighbor(players[4]._id, game, options)).toBeUndefined();\n });\n\n it(\"should return undefined when player is alone.\", () => {\n const players = [createFakeVillagerAlivePlayer({ position: 1 })];\n const game = createFakeGame({ players });\n const options: GetNearestPlayerOptions = { direction: \"left\", playerSide: \"werewolves\" };\n\n expect(getNearestAliveNeighbor(players[0]._id, game, options)).toBeUndefined();\n });\n });\n\n describe(\"getAllowedToVotePlayers\", () => {\n it(\"should return all alive players which can vote when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeCantVoteBySurvivorsPlayerAttribute()] }),\n createFakeVillagerAlivePlayer({ attributes: [] }),\n ];\n const game = createFakeGame({ players });\n const expectedAllowedToVotePlayers = [players[0], players[3]];\n\n expect(getAllowedToVotePlayers(game)).toStrictEqual(expectedAllowedToVotePlayers);\n });\n });\n\n describe(\"doesGameHaveUpcomingPlaySourceAndAction\", () => {\n it.each<{\n test: string;\n game: Game;\n role: RoleName;\n action: GamePlayAction;\n expected: boolean;\n }>([\n {\n test: \"should return true when game has upcoming play source and action.\",\n game: createFakeGame({ upcomingPlays: [createFakeGamePlayHunterShoots()] }),\n role: \"hunter\",\n action: \"shoot\",\n expected: true,\n },\n {\n test: \"should return false when game has no upcoming play source and action.\",\n game: createFakeGame({\n upcomingPlays: [\n createFakeGamePlayHunterShoots(),\n createFakeGamePlayWerewolvesEat(),\n ],\n }),\n role: \"hunter\",\n action: \"eat\",\n expected: false,\n },\n ])(`$test`, ({ game, role, action, expected }) => {\n expect(doesGameHaveUpcomingPlaySourceAndAction(game, role, action)).toBe(expected);\n });\n });\n\n describe(\"doesGameHaveCurrentOrUpcomingPlaySourceAndAction\", () => {\n it.each<{\n test: string;\n game: Game;\n role: RoleName;\n action: GamePlayAction;\n expected: boolean;\n }>([\n {\n test: \"should return true when game has current play source and action.\",\n game: createFakeGame({ currentPlay: createFakeGamePlayHunterShoots() }),\n role: \"hunter\",\n action: \"shoot\",\n expected: true,\n },\n {\n test: \"should return true when game has upcoming play source and action.\",\n game: createFakeGame({ upcomingPlays: [createFakeGamePlayHunterShoots()] }),\n role: \"hunter\",\n action: \"shoot\",\n expected: true,\n },\n {\n test: \"should return false when game has no current or upcoming play source and action.\",\n game: createFakeGame({ currentPlay: createFakeGamePlayHunterShoots(), upcomingPlays: [createFakeGamePlayHunterShoots()] }),\n role: \"hunter\",\n action: \"eat\",\n expected: false,\n },\n ])(`$test`, ({ game, role, action, expected }) => {\n expect(doesGameHaveCurrentOrUpcomingPlaySourceAndAction(game, role, action)).toBe(expected);\n });\n });\n});" + "source": "import type { Types } from \"mongoose\";\n\nimport { DEFAULT_GAME_OPTIONS } from \"@/modules/game/constants/game-options/game-options.constants\";\nimport type { CreateGamePlayerDto } from \"@/modules/game/dto/create-game/create-game-player/create-game-player.dto\";\nimport { areAllPlayersDead, areAllVillagersAlive, areAllWerewolvesAlive, doesGameHaveCurrentOrUpcomingPlaySourceAndAction, doesGameHaveUpcomingPlaySourceAndAction, getAdditionalCardWithId, getAlivePlayers, getAliveVillagerSidedPlayers, getAliveWerewolfSidedPlayers, getAllowedToVotePlayers, getDistinctPlayerGroups, getEligibleBigBadWolfTargets, getEligibleCupidTargets, getEligiblePiedPiperTargets, getEligibleWerewolvesTargets, getEligibleWhiteWerewolfTargets, getFoxSniffedPlayers, getGroupOfPlayers, getNearestAliveNeighbor, getNonexistentPlayer, getNonexistentPlayerId, getPlayerDtoWithRole, getPlayersWithActiveAttributeName, getPlayersWithCurrentRole, getPlayersWithCurrentSide, getPlayersWithIds, getPlayerWithActiveAttributeName, getPlayerWithCurrentRole, getPlayerWithId, getPlayerWithIdOrThrow, getPlayerWithName, getPlayerWithNameOrThrow, isGameSourceGroup, isGameSourceRole } from \"@/modules/game/helpers/game.helpers\";\nimport type { GameAdditionalCard } from \"@/modules/game/schemas/game-additional-card/game-additional-card.schema\";\nimport type { Game } from \"@/modules/game/schemas/game.schema\";\nimport type { Player } from \"@/modules/game/schemas/player/player.schema\";\nimport type { GamePlayAction } from \"@/modules/game/types/game-play/game-play.types\";\nimport type { GetNearestPlayerOptions } from \"@/modules/game/types/game.types\";\nimport type { PlayerGroup } from \"@/modules/game/types/player/player.types\";\nimport type { RoleName } from \"@/modules/role/types/role.types\";\n\nimport { UnexpectedExceptionReasons } from \"@/shared/exception/enums/unexpected-exception.enums\";\nimport type { ExceptionInterpolations } from \"@/shared/exception/types/exception.types\";\nimport { UnexpectedException } from \"@/shared/exception/types/unexpected-exception.types\";\n\nimport { createFakeCreateGamePlayerDto } from \"@tests/factories/game/dto/create-game/create-game-player/create-game-player.dto.factory\";\nimport { createFakeCreateGameDto } from \"@tests/factories/game/dto/create-game/create-game.dto.factory\";\nimport { createFakeGameAdditionalCard } from \"@tests/factories/game/schemas/game-additional-card/game-additional-card.schema.factory\";\nimport { createFakeGameOptions } from \"@tests/factories/game/schemas/game-options/game-options.schema.factory\";\nimport { createFakeCupidGameOptions, createFakeRolesGameOptions, createFakeWerewolfGameOptions } from \"@tests/factories/game/schemas/game-options/game-roles-options/game-roles-options.schema.factory\";\nimport { createFakeGamePlayHunterShoots, createFakeGamePlayWerewolvesEat } from \"@tests/factories/game/schemas/game-play/game-play.schema.factory\";\nimport { createFakeGame } from \"@tests/factories/game/schemas/game.schema.factory\";\nimport { createFakeCantVoteBySurvivorsPlayerAttribute, createFakeCharmedByPiedPiperPlayerAttribute, createFakeEatenByWerewolvesPlayerAttribute, createFakeEatenByWhiteWerewolfPlayerAttribute, createFakeInLoveByCupidPlayerAttribute } from \"@tests/factories/game/schemas/player/player-attribute/player-attribute.schema.factory\";\nimport { createFakeBigBadWolfAlivePlayer, createFakeCupidAlivePlayer, createFakePiedPiperAlivePlayer, createFakeSeerAlivePlayer, createFakeVillagerAlivePlayer, createFakeVillagerVillagerAlivePlayer, createFakeWerewolfAlivePlayer, createFakeWhiteWerewolfAlivePlayer } from \"@tests/factories/game/schemas/player/player-with-role.schema.factory\";\nimport { createFakePlayer } from \"@tests/factories/game/schemas/player/player.schema.factory\";\nimport { createFakeObjectId } from \"@tests/factories/shared/mongoose/mongoose.factory\";\n\ndescribe(\"Game Helper\", () => {\n describe(\"getPlayerDtoWithRole\", () => {\n const players = [\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"seer\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"two-sisters\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"two-sisters\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"idiot\" } }),\n ];\n const game = createFakeCreateGameDto({ players });\n\n it(\"should return player with role when a player has this role.\", () => {\n expect(getPlayerDtoWithRole(game, \"werewolf\")).toStrictEqual(game.players[2]);\n });\n\n it(\"should return undefined when player with role is not found.\", () => {\n expect(getPlayerDtoWithRole(game, \"three-brothers\")).toBeUndefined();\n });\n });\n\n describe(\"getPlayerWithCurrentRole\", () => {\n const players = [\n createFakePlayer({ role: { current: \"witch\", original: \"witch\", isRevealed: false } }),\n createFakePlayer({ role: { current: \"seer\", original: \"seer\", isRevealed: false } }),\n createFakePlayer({ role: { current: \"werewolf\", original: \"werewolf\", isRevealed: false } }),\n createFakePlayer({ role: { current: \"two-sisters\", original: \"two-sisters\", isRevealed: false } }),\n createFakePlayer({ role: { current: \"two-sisters\", original: \"two-sisters\", isRevealed: false } }),\n createFakePlayer({ role: { current: \"idiot\", original: \"idiot\", isRevealed: false } }),\n ];\n const game = createFakeGame({ players });\n\n it(\"should return player with role when a player has this role.\", () => {\n expect(getPlayerWithCurrentRole(game, \"seer\")).toStrictEqual(players[1]);\n });\n\n it(\"should return undefined when player with role is not found.\", () => {\n expect(getPlayerWithCurrentRole(game, \"big-bad-wolf\")).toBeUndefined();\n });\n });\n\n describe(\"getPlayersWithCurrentRole\", () => {\n const players = [\n createFakePlayer({ role: { current: \"three-brothers\", original: \"witch\", isRevealed: false } }),\n createFakePlayer({ role: { current: \"three-brothers\", original: \"seer\", isRevealed: false } }),\n createFakePlayer({ role: { current: \"three-brothers\", original: \"werewolf\", isRevealed: false } }),\n createFakePlayer({ role: { current: \"two-sisters\", original: \"two-sisters\", isRevealed: false } }),\n createFakePlayer({ role: { current: \"two-sisters\", original: \"two-sisters\", isRevealed: false } }),\n createFakePlayer({ role: { current: \"idiot\", original: \"idiot\", isRevealed: false } }),\n ];\n const game = createFakeGame({ players });\n\n it(\"should return players when they have this role.\", () => {\n expect(getPlayersWithCurrentRole(game, \"three-brothers\")).toStrictEqual([players[0], players[1], players[2]]);\n });\n\n it(\"should return empty array when no one has the role.\", () => {\n expect(getPlayersWithCurrentRole(game, \"werewolf\")).toStrictEqual([]);\n });\n });\n\n describe(\"getPlayersWithCurrentSide\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n it(\"should return werewolves when they have this side.\", () => {\n expect(getPlayersWithCurrentSide(game, \"werewolves\")).toStrictEqual([players[0], players[1], players[4], players[5]]);\n });\n\n it(\"should return villagers when they have this side.\", () => {\n expect(getPlayersWithCurrentSide(game, \"villagers\")).toStrictEqual([players[2], players[3]]);\n });\n });\n\n describe(\"getPlayerWithId\", () => {\n it(\"should get player with specific id when called with this id.\", () => {\n const players = [\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(getPlayerWithId(game, players[2]._id)).toStrictEqual(players[2]);\n });\n\n it(\"should return undefined when called with unknown id.\", () => {\n const players = [\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(getPlayerWithId(game, createFakeObjectId())).toBeUndefined();\n });\n });\n\n describe(\"getPlayerWithIdOrThrow\", () => {\n it(\"should get player with specific id when called with this id.\", () => {\n const players = [\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n ];\n const game = createFakeGame({ players });\n const exceptionInterpolations: ExceptionInterpolations = { gameId: game._id.toString(), playerId: players[2]._id.toString() };\n const exception = new UnexpectedException(\"killPlayer\", UnexpectedExceptionReasons.CANT_FIND_PLAYER_WITH_ID_IN_GAME, exceptionInterpolations);\n\n expect(getPlayerWithIdOrThrow(players[2]._id, game, exception)).toStrictEqual(players[2]);\n });\n\n it(\"should throw error when called with unknown id.\", () => {\n const players = [\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n ];\n const game = createFakeGame({ players });\n const unknownPlayerId = createFakeObjectId();\n const exceptionInterpolations: ExceptionInterpolations = { gameId: game._id.toString(), playerId: unknownPlayerId.toString() };\n const exception = new UnexpectedException(\"killPlayer\", UnexpectedExceptionReasons.CANT_FIND_PLAYER_WITH_ID_IN_GAME, exceptionInterpolations);\n\n expect(() => getPlayerWithIdOrThrow(unknownPlayerId, game, exception)).toThrow(exception);\n });\n });\n\n describe(\"getPlayersWithIds\", () => {\n it(\"should get players with specific ids when called with these ids.\", () => {\n const players = [\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n ];\n const game = createFakeGame({ players });\n const idsToFind = [players[1]._id, players[3]._id, createFakeObjectId(), players[5]._id];\n const expectedPlayers = [players[1], players[3], players[5]];\n\n expect(getPlayersWithIds(idsToFind, game)).toStrictEqual(expectedPlayers);\n });\n });\n\n describe(\"getPlayerWithName\", () => {\n it(\"should get player with specific name when called with this name.\", () => {\n const players = [\n createFakePlayer({ name: \"player1\" }),\n createFakePlayer({ name: \"player2\" }),\n createFakePlayer({ name: \"player3\" }),\n createFakePlayer({ name: \"player4\" }),\n createFakePlayer({ name: \"player5\" }),\n ];\n const game = createFakeGame({ players });\n\n expect(getPlayerWithName(game, \"player3\")).toStrictEqual(players[2]);\n });\n\n it(\"should return undefined when called with unknown name.\", () => {\n const players = [\n createFakePlayer({ name: \"player1\" }),\n createFakePlayer({ name: \"player2\" }),\n createFakePlayer({ name: \"player3\" }),\n createFakePlayer({ name: \"player4\" }),\n createFakePlayer({ name: \"player5\" }),\n ];\n const game = createFakeGame({ players });\n\n expect(getPlayerWithName(game, \"i-cant-be-a-valid-name-that-is-bad\")).toBeUndefined();\n });\n });\n\n describe(\"getPlayerWithNameOrThrow\", () => {\n it(\"should get player with specific name when called with this id.\", () => {\n const players = [\n createFakePlayer({ name: \"player1\" }),\n createFakePlayer({ name: \"player2\" }),\n createFakePlayer({ name: \"player5\" }),\n createFakePlayer({ name: \"player3\" }),\n createFakePlayer({ name: \"player4\" }),\n createFakePlayer({ name: \"player6\" }),\n ];\n const game = createFakeGame({ players });\n const error = new Error(\"Can't find player with name…\");\n\n expect(getPlayerWithNameOrThrow(\"player5\", game, error)).toStrictEqual(players[2]);\n });\n\n it(\"should throw error when called with unknown name.\", () => {\n const players = [\n createFakePlayer({ name: \"player1\" }),\n createFakePlayer({ name: \"player2\" }),\n createFakePlayer({ name: \"player5\" }),\n createFakePlayer({ name: \"player3\" }),\n createFakePlayer({ name: \"player4\" }),\n createFakePlayer({ name: \"player6\" }),\n ];\n const game = createFakeGame({ players });\n const unknownPlayerName = \"i-cant-be-a-valid-name-that-is-bad\";\n const error = new Error(`Can't find player with name \"${unknownPlayerName}\" in game \"${game._id.toString()}\"`);\n\n expect(() => getPlayerWithNameOrThrow(unknownPlayerName, game, error)).toThrow(error);\n });\n });\n\n describe(\"getDistinctPlayerGroups\", () => {\n it(\"should return distinct player groups when called.\", () => {\n const players = [\n createFakeCreateGamePlayerDto({ group: \"group1\" }),\n createFakeCreateGamePlayerDto({ group: \"group2\" }),\n createFakeCreateGamePlayerDto({ group: \"group1\" }),\n createFakeCreateGamePlayerDto({ group: \"group3\" }),\n createFakeCreateGamePlayerDto({ group: \"group2\" }),\n createFakeCreateGamePlayerDto({ group: \"group4\" }),\n ];\n const game = createFakeCreateGameDto({ players });\n\n expect(getDistinctPlayerGroups(game)).toStrictEqual([\"group1\", \"group2\", \"group3\", \"group4\"]);\n });\n\n it(\"should return empty array when no player groups are provided.\", () => {\n const game = createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto(),\n createFakeCreateGamePlayerDto(),\n createFakeCreateGamePlayerDto(),\n ],\n });\n\n expect(getDistinctPlayerGroups(game)).toStrictEqual([]);\n });\n });\n\n describe(\"getAdditionalCardWithId\", () => {\n it(\"should get card with specific id when called with this id.\", () => {\n const cards = [\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n ];\n\n expect(getAdditionalCardWithId(cards, cards[3]._id)).toStrictEqual(cards[3]);\n });\n\n it(\"should return undefined when cards are undefined.\", () => {\n expect(getAdditionalCardWithId(undefined, createFakeObjectId())).toBeUndefined();\n });\n\n it(\"should return undefined when called with unknown id.\", () => {\n const cards = [\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n ];\n\n expect(getAdditionalCardWithId(cards, createFakeObjectId())).toBeUndefined();\n });\n });\n\n describe(\"areAllWerewolvesAlive\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n it(\"should return false when empty array is provided.\", () => {\n expect(areAllWerewolvesAlive(createFakeGame())).toBe(false);\n });\n\n it(\"should return true when all werewolves are alive.\", () => {\n expect(areAllWerewolvesAlive(game)).toBe(true);\n });\n\n it(\"should return true when at least one werewolf is dead.\", () => {\n const notAllAlivePlayers = players.map(player => createFakePlayer(player));\n notAllAlivePlayers[0].isAlive = false;\n const notAllAliveGame = createFakeGame({ players: notAllAlivePlayers });\n\n expect(areAllWerewolvesAlive(notAllAliveGame)).toBe(false);\n });\n });\n\n describe(\"areAllVillagersAlive\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n it(\"should return false when empty array is provided.\", () => {\n expect(areAllVillagersAlive(createFakeGame())).toBe(false);\n });\n\n it(\"should return true when all villagers are alive.\", () => {\n expect(areAllVillagersAlive(game)).toBe(true);\n });\n\n it(\"should return true when at least one villager is dead.\", () => {\n const clonedPlayers = players.map(player => createFakePlayer(player));\n clonedPlayers[1].isAlive = false;\n const notAllAlivePlayersGame = createFakeGame({ players: clonedPlayers });\n\n expect(areAllVillagersAlive(notAllAlivePlayersGame)).toBe(false);\n });\n });\n\n describe(\"areAllPlayersDead\", () => {\n const players = [\n createFakePlayer({ isAlive: false }),\n createFakePlayer({ isAlive: false }),\n createFakePlayer({ isAlive: true }),\n createFakePlayer({ isAlive: false }),\n ];\n const game = createFakeGame({ players });\n\n it(\"should return false when empty array is provided.\", () => {\n expect(areAllPlayersDead(createFakeGame())).toBe(false);\n });\n\n it(\"should return false when at least one player is alive.\", () => {\n expect(areAllPlayersDead(game)).toBe(false);\n });\n\n it(\"should return true when all players are dead.\", () => {\n const clonedGame = createFakeGame(game);\n clonedGame.players[2].isAlive = false;\n\n expect(areAllPlayersDead(clonedGame)).toBe(true);\n });\n });\n\n describe(\"getPlayerWithActiveAttributeName\", () => {\n it(\"should return first player with attribute when called.\", () => {\n const players = [\n createFakePlayer({ attributes: [] }),\n createFakePlayer({ attributes: [createFakeEatenByWerewolvesPlayerAttribute()] }),\n createFakePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n ];\n const game = createFakeGame({ players });\n\n expect(getPlayerWithActiveAttributeName(game, \"charmed\")).toStrictEqual(players[2]);\n });\n\n it(\"should return undefined when player with attribute is not found.\", () => {\n const players = [\n createFakePlayer({ attributes: [] }),\n createFakePlayer({ attributes: [createFakeEatenByWerewolvesPlayerAttribute()] }),\n createFakePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n ];\n const game = createFakeGame({ players });\n\n expect(getPlayerWithActiveAttributeName(game, \"seen\")).toBeUndefined();\n });\n });\n\n describe(\"getPlayersWithActiveAttributeName\", () => {\n const players = [\n createFakePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakePlayer({ attributes: [] }),\n createFakePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakePlayer({ attributes: [createFakeEatenByWerewolvesPlayerAttribute()] }),\n ];\n const game = createFakeGame({ players });\n\n it(\"should return players when they have the attribute.\", () => {\n expect(getPlayersWithActiveAttributeName(game, \"charmed\")).toStrictEqual([players[0], players[2]]);\n });\n\n it(\"should return empty array when none has the attribute.\", () => {\n expect(getPlayersWithActiveAttributeName(game, \"seen\")).toStrictEqual([]);\n });\n });\n\n describe(\"getAlivePlayers\", () => {\n it(\"should get all alive players when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(getAlivePlayers(game)).toStrictEqual([players[0], players[1], players[3]]);\n });\n });\n\n describe(\"getAliveVillagerSidedPlayers\", () => {\n it(\"should get all alive villager sided players when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(getAliveVillagerSidedPlayers(game)).toStrictEqual([players[1]]);\n });\n });\n\n describe(\"getAliveWerewolfSidedPlayers\", () => {\n it(\"should get all alive werewolf sided players when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n ];\n const game = createFakeGame({ players });\n\n expect(getAliveWerewolfSidedPlayers(game)).toStrictEqual([players[0]]);\n });\n });\n\n describe(\"getEligiblePiedPiperTargets\", () => {\n it(\"should get left to charm by pied piper players when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakePiedPiperAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer({ isAlive: false, attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(getEligiblePiedPiperTargets(game)).toStrictEqual([players[2], players[4]]);\n });\n });\n\n describe(\"getEligibleWerewolvesTargets\", () => {\n it(\"should return alive and not already eaten villagers players when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakePiedPiperAlivePlayer(),\n createFakeVillagerAlivePlayer({ attributes: [createFakeEatenByWerewolvesPlayerAttribute()] }),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGame({\n players,\n options: DEFAULT_GAME_OPTIONS,\n });\n\n expect(getEligibleWerewolvesTargets(game)).toStrictEqual([players[1]]);\n });\n\n it(\"should return alive and not already eaten villagers and werewolves players when werewolves can eat each other.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakePiedPiperAlivePlayer(),\n createFakeVillagerAlivePlayer({ attributes: [createFakeEatenByWerewolvesPlayerAttribute()] }),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeEatenByWhiteWerewolfPlayerAttribute()] }),\n ];\n const game = createFakeGame({\n players,\n options: createFakeGameOptions({\n roles: createFakeRolesGameOptions({\n werewolf: createFakeWerewolfGameOptions({ canEatEachOther: true }),\n }),\n }),\n });\n\n expect(getEligibleWerewolvesTargets(game)).toStrictEqual([\n players[0],\n players[1],\n players[4],\n ]);\n });\n\n it(\"should return alive and not already eaten villagers when werewolves can eat each other but only one werewolf is alive.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakePiedPiperAlivePlayer(),\n createFakeVillagerAlivePlayer({ attributes: [createFakeEatenByWerewolvesPlayerAttribute()] }),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n ];\n const game = createFakeGame({\n players,\n options: createFakeGameOptions({\n roles: createFakeRolesGameOptions({\n werewolf: createFakeWerewolfGameOptions({ canEatEachOther: true }),\n }),\n }),\n });\n\n expect(getEligibleWerewolvesTargets(game)).toStrictEqual([players[1]]);\n });\n });\n\n describe(\"getEligibleBigBadWolfTargets\", () => {\n it(\"should return eligible targets without the big bad wolf when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakePiedPiperAlivePlayer(),\n createFakeVillagerAlivePlayer({ attributes: [createFakeEatenByWerewolvesPlayerAttribute()] }),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer(),\n createFakePiedPiperAlivePlayer(),\n createFakeBigBadWolfAlivePlayer(),\n ];\n const game = createFakeGame({\n players,\n options: createFakeGameOptions({\n roles: createFakeRolesGameOptions({\n werewolf: createFakeWerewolfGameOptions({ canEatEachOther: true }),\n }),\n }),\n });\n\n expect(getEligibleBigBadWolfTargets(game)).toStrictEqual([\n players[0],\n players[1],\n players[4],\n players[5],\n ]);\n });\n });\n\n describe(\"getEligibleWhiteWerewolfTargets\", () => {\n it(\"should return left to eat by white werewolf players when called.\", () => {\n const players = [\n createFakeWhiteWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeVillagerAlivePlayer({ attributes: [createFakeEatenByWerewolvesPlayerAttribute()] }),\n createFakeVillagerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(getEligibleWhiteWerewolfTargets(game)).toStrictEqual([players[4]]);\n });\n });\n\n describe(\"getEligibleCupidTargets\", () => {\n it(\"should return left to charm by cupid players when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeCupidAlivePlayer(),\n createFakeVillagerAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ cupid: createFakeCupidGameOptions({ mustWinWithLovers: false }) }) });\n const game = createFakeGame({ players, options });\n\n expect(getEligibleCupidTargets(game)).toStrictEqual([\n players[0],\n players[1],\n players[2],\n players[4],\n ]);\n });\n\n it(\"should return left to charm by cupid players without cupid himself when called with cupid must win with lovers option.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeCupidAlivePlayer(),\n createFakeVillagerAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ cupid: createFakeCupidGameOptions({ mustWinWithLovers: true }) }) });\n const game = createFakeGame({ players, options });\n\n expect(getEligibleCupidTargets(game)).toStrictEqual([\n players[0],\n players[2],\n players[4],\n ]);\n });\n });\n\n describe(\"getGroupOfPlayers\", () => {\n const players = [\n createFakeVillagerAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n createFakeWhiteWerewolfAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakeVillagerAlivePlayer({ attributes: [createFakeEatenByWerewolvesPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n createFakeVillagerVillagerAlivePlayer({ isAlive: false }),\n ];\n const game = createFakeGame({ players });\n\n it.each<{\n test: string;\n group: PlayerGroup;\n expected: Player[];\n }>([\n {\n test: \"should return all alive players when group is survivors.\",\n group: \"survivors\",\n expected: [\n players[0],\n players[1],\n players[2],\n players[3],\n players[4],\n players[5],\n ],\n },\n {\n test: \"should return players in love when group is lovers.\",\n group: \"lovers\",\n expected: [players[2], players[5]],\n },\n {\n test: \"should return charmed players when group is charmed.\",\n group: \"charmed\",\n expected: [players[0], players[3]],\n },\n {\n test: \"should return villagers when group is villagers.\",\n group: \"villagers\",\n expected: [players[0], players[2], players[4], players[6]],\n },\n {\n test: \"should return werewolves when group is werewolves.\",\n group: \"werewolves\",\n expected: [players[1], players[3], players[5]],\n },\n ])(\"$test\", ({ group, expected }) => {\n expect(getGroupOfPlayers(game, group)).toStrictEqual(expected);\n });\n });\n\n describe(\"isGameSourceRole\", () => {\n it(\"should return true when source is role.\", () => {\n expect(isGameSourceRole(\"witch\")).toBe(true);\n });\n\n it(\"should return false when source is group.\", () => {\n expect(isGameSourceRole(\"survivors\")).toBe(false);\n });\n });\n\n describe(\"isGameSourceGroup\", () => {\n it(\"should return true when source is group.\", () => {\n expect(isGameSourceGroup(\"werewolves\")).toBe(true);\n });\n\n it(\"should return false when source is role.\", () => {\n expect(isGameSourceGroup(\"seer\")).toBe(false);\n });\n });\n\n describe(\"getNonexistentPlayerId\", () => {\n it(\"should return undefined when all candidate ids are found.\", () => {\n const players = [\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(getNonexistentPlayerId(game, players.map(player => player._id))).toBeUndefined();\n });\n\n it(\"should return unknown id when one candidate id is not found.\", () => {\n const players = [\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n ];\n const ids = players.map(player => player._id);\n const unknownId = createFakeObjectId();\n const game = createFakeGame({ players });\n\n expect(getNonexistentPlayerId(game, [...ids, unknownId])).toStrictEqual(unknownId);\n });\n });\n\n describe(\"getNonexistentPlayer\", () => {\n it(\"should return undefined when all candidate ids are found.\", () => {\n const players = [\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(getNonexistentPlayer(game, players)).toBeUndefined();\n });\n\n it(\"should return unknown id when one candidate id is not found.\", () => {\n const players = [\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n ];\n const otherPlayer = createFakePlayer();\n const game = createFakeGame({ players });\n\n expect(getNonexistentPlayer(game, [...players, otherPlayer])).toStrictEqual(otherPlayer);\n });\n });\n\n describe(\"getFoxSniffedPlayers\", () => {\n it(\"should get 3 targets with left and right neighbors when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ position: 0 }),\n createFakeVillagerAlivePlayer({ position: 1 }),\n createFakeWerewolfAlivePlayer({ position: 2 }),\n createFakeVillagerAlivePlayer({ position: 3 }),\n ];\n const game = createFakeGame({ players });\n const expectedPlayers = [\n createFakePlayer(players[2]),\n createFakePlayer(players[3]),\n createFakePlayer(players[0]),\n ];\n\n expect(getFoxSniffedPlayers(players[3]._id, game)).toStrictEqual(expectedPlayers);\n });\n\n it(\"should get 3 targets with left neighbor when right is dead.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ position: 0, isAlive: false }),\n createFakeVillagerAlivePlayer({ position: 1 }),\n createFakeWerewolfAlivePlayer({ position: 2 }),\n createFakeVillagerAlivePlayer({ position: 3 }),\n ];\n const game = createFakeGame({ players });\n const expectedPlayers = [\n createFakePlayer(players[2]),\n createFakePlayer(players[3]),\n createFakePlayer(players[1]),\n ];\n\n expect(getFoxSniffedPlayers(players[3]._id, game)).toStrictEqual(expectedPlayers);\n });\n\n it(\"should get 2 targets with left neighbor when all rights are dead.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ position: 0, isAlive: false }),\n createFakeVillagerAlivePlayer({ position: 1, isAlive: false }),\n createFakeWerewolfAlivePlayer({ position: 2 }),\n createFakeVillagerAlivePlayer({ position: 3 }),\n ];\n const game = createFakeGame({ players });\n const expectedPlayers = [\n createFakePlayer(players[2]),\n createFakePlayer(players[3]),\n ];\n\n expect(getFoxSniffedPlayers(players[3]._id, game)).toStrictEqual(expectedPlayers);\n });\n\n it(\"should get only 1 target when all neighbors.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ position: 0, isAlive: false }),\n createFakeVillagerAlivePlayer({ position: 1, isAlive: false }),\n createFakeWerewolfAlivePlayer({ position: 2 }),\n createFakeVillagerAlivePlayer({ position: 3, isAlive: false }),\n ];\n const game = createFakeGame({ players });\n const expectedPlayers = [createFakePlayer(players[2])];\n\n expect(getFoxSniffedPlayers(players[2]._id, game)).toStrictEqual(expectedPlayers);\n });\n\n it(\"should throw error when player is not found in game.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ position: 0 }),\n createFakeVillagerAlivePlayer({ position: 1 }),\n createFakeWerewolfAlivePlayer({ position: 2 }),\n createFakeVillagerAlivePlayer({ position: 3 }),\n ];\n const game = createFakeGame({ players });\n const unknownPlayerId = createFakeObjectId();\n const exceptionInterpolations: ExceptionInterpolations = { gameId: game._id.toString(), playerId: unknownPlayerId.toString() };\n const exception = new UnexpectedException(\"getFoxSniffedTargets\", UnexpectedExceptionReasons.CANT_FIND_PLAYER_WITH_ID_IN_GAME, exceptionInterpolations);\n\n expect(() => getFoxSniffedPlayers(unknownPlayerId, game)).toThrow(exception);\n });\n });\n\n describe(\"getNearestAliveNeighbor\", () => {\n it(\"should throw error when player is not found in game.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ position: 0 }),\n createFakeVillagerAlivePlayer({ position: 1 }),\n createFakeWerewolfAlivePlayer({ position: 2 }),\n createFakeVillagerAlivePlayer({ position: 3 }),\n createFakeWerewolfAlivePlayer({ position: 4 }),\n createFakeVillagerAlivePlayer({ position: 5 }),\n ];\n const game = createFakeGame({ players });\n const options: GetNearestPlayerOptions = { direction: \"right\" };\n const unknownPlayerId = createFakeObjectId();\n const exceptionInterpolations: ExceptionInterpolations = { gameId: game._id.toString(), playerId: unknownPlayerId.toString() };\n const exception = new UnexpectedException(\"getNearestAliveNeighbor\", UnexpectedExceptionReasons.CANT_FIND_PLAYER_WITH_ID_IN_GAME, exceptionInterpolations);\n\n expect(() => getNearestAliveNeighbor(unknownPlayerId, game, options)).toThrow(exception);\n });\n\n it(\"should get the nearest right alive player when called with right direction.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ position: 2 }),\n createFakeVillagerAlivePlayer({ position: 1 }),\n createFakeWerewolfAlivePlayer({ position: 0, isAlive: false }),\n createFakeVillagerAlivePlayer({ position: 3 }),\n createFakeVillagerAlivePlayer({ position: 5, isAlive: false }),\n createFakeWerewolfAlivePlayer({ position: 4 }),\n ];\n const game = createFakeGame({ players });\n const options: GetNearestPlayerOptions = { direction: \"right\" };\n\n expect(getNearestAliveNeighbor(players[5]._id, game, options)).toStrictEqual(players[1]);\n });\n\n it(\"should get the nearest left alive player when called with left direction.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ position: 2 }),\n createFakeWerewolfAlivePlayer({ position: 0, isAlive: false }),\n createFakeVillagerAlivePlayer({ position: 3 }),\n createFakeVillagerAlivePlayer({ position: 5, isAlive: false }),\n createFakeWerewolfAlivePlayer({ position: 4 }),\n createFakeVillagerAlivePlayer({ position: 1 }),\n ];\n const game = createFakeGame({ players });\n const options: GetNearestPlayerOptions = { direction: \"left\" };\n\n expect(getNearestAliveNeighbor(players[5]._id, game, options)).toStrictEqual(players[4]);\n });\n\n it(\"should get the nearest left alive villager player when called with left direction and villager side.\", () => {\n const players = [\n createFakeVillagerAlivePlayer({ position: 5, isAlive: false }),\n createFakeVillagerAlivePlayer({ position: 3 }),\n createFakeWerewolfAlivePlayer({ position: 0, isAlive: false }),\n createFakeVillagerAlivePlayer({ position: 1 }),\n createFakeWerewolfAlivePlayer({ position: 4 }),\n createFakeWerewolfAlivePlayer({ position: 2 }),\n ];\n const game = createFakeGame({ players });\n const options: GetNearestPlayerOptions = { direction: \"left\", playerSide: \"villagers\" };\n\n expect(getNearestAliveNeighbor(players[3]._id, game, options)).toStrictEqual(players[1]);\n });\n\n it(\"should get the nearest left alive werewolf player when called with left direction and werewolf side.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ position: 0 }),\n createFakeVillagerAlivePlayer({ position: 1 }),\n createFakeWerewolfAlivePlayer({ position: 2 }),\n createFakeVillagerAlivePlayer({ position: 3 }),\n createFakeWerewolfAlivePlayer({ position: 4 }),\n createFakeVillagerAlivePlayer({ position: 5, isAlive: false }),\n ];\n const game = createFakeGame({ players });\n const options: GetNearestPlayerOptions = { direction: \"left\", playerSide: \"werewolves\" };\n\n expect(getNearestAliveNeighbor(players[1]._id, game, options)).toStrictEqual(players[0]);\n });\n\n it(\"should return the other alive player when there are only two alive players.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ position: 0 }),\n createFakeVillagerAlivePlayer({ position: 1 }),\n createFakeVillagerAlivePlayer({ position: 2, isAlive: false }),\n ];\n const game = createFakeGame({ players });\n const options: GetNearestPlayerOptions = { direction: \"left\" };\n\n expect(getNearestAliveNeighbor(players[0]._id, game, options)).toStrictEqual(players[1]);\n });\n\n it(\"should return undefined when can't find player with conditions.\", () => {\n const players = [\n createFakeVillagerAlivePlayer({ position: 5, isAlive: false }),\n createFakeVillagerAlivePlayer({ position: 3 }),\n createFakeWerewolfAlivePlayer({ position: 0, isAlive: false }),\n createFakeVillagerAlivePlayer({ position: 1 }),\n createFakeWerewolfAlivePlayer({ position: 4 }),\n createFakeWerewolfAlivePlayer({ position: 2, isAlive: false }),\n ];\n const game = createFakeGame({ players });\n const options: GetNearestPlayerOptions = { direction: \"left\", playerSide: \"werewolves\" };\n\n expect(getNearestAliveNeighbor(players[4]._id, game, options)).toBeUndefined();\n });\n\n it(\"should return undefined when there are no alive players.\", () => {\n const players = [\n createFakeVillagerAlivePlayer({ position: 5, isAlive: false }),\n createFakeVillagerAlivePlayer({ position: 3, isAlive: false }),\n createFakeWerewolfAlivePlayer({ position: 0, isAlive: false }),\n createFakeVillagerAlivePlayer({ position: 1, isAlive: false }),\n createFakeWerewolfAlivePlayer({ position: 4, isAlive: false }),\n createFakeWerewolfAlivePlayer({ position: 2, isAlive: false }),\n ];\n const game = createFakeGame({ players });\n const options: GetNearestPlayerOptions = { direction: \"left\", playerSide: \"werewolves\" };\n\n expect(getNearestAliveNeighbor(players[4]._id, game, options)).toBeUndefined();\n });\n\n it(\"should return undefined when there is no alive werewolf to find.\", () => {\n const players = [\n createFakeVillagerAlivePlayer({ position: 5, isAlive: false }),\n createFakeVillagerAlivePlayer({ position: 3 }),\n createFakeWerewolfAlivePlayer({ position: 0, isAlive: false }),\n createFakeVillagerAlivePlayer({ position: 1 }),\n createFakeWerewolfAlivePlayer({ position: 4 }),\n createFakeWerewolfAlivePlayer({ position: 2, isAlive: false }),\n ];\n const game = createFakeGame({ players });\n const options: GetNearestPlayerOptions = { direction: \"left\", playerSide: \"werewolves\" };\n\n expect(getNearestAliveNeighbor(players[4]._id, game, options)).toBeUndefined();\n });\n\n it(\"should return undefined when player is alone.\", () => {\n const players = [createFakeVillagerAlivePlayer({ position: 1 })];\n const game = createFakeGame({ players });\n const options: GetNearestPlayerOptions = { direction: \"left\", playerSide: \"werewolves\" };\n\n expect(getNearestAliveNeighbor(players[0]._id, game, options)).toBeUndefined();\n });\n });\n\n describe(\"getAllowedToVotePlayers\", () => {\n it(\"should return all alive players which can vote when called.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeCantVoteBySurvivorsPlayerAttribute()] }),\n createFakeVillagerAlivePlayer({ attributes: [] }),\n ];\n const game = createFakeGame({ players });\n const expectedAllowedToVotePlayers = [players[0], players[3]];\n\n expect(getAllowedToVotePlayers(game)).toStrictEqual(expectedAllowedToVotePlayers);\n });\n });\n\n describe(\"doesGameHaveUpcomingPlaySourceAndAction\", () => {\n it.each<{\n test: string;\n game: Game;\n role: RoleName;\n action: GamePlayAction;\n expected: boolean;\n }>([\n {\n test: \"should return true when game has upcoming play source and action.\",\n game: createFakeGame({ upcomingPlays: [createFakeGamePlayHunterShoots()] }),\n role: \"hunter\",\n action: \"shoot\",\n expected: true,\n },\n {\n test: \"should return false when game has no upcoming play source and action.\",\n game: createFakeGame({\n upcomingPlays: [\n createFakeGamePlayHunterShoots(),\n createFakeGamePlayWerewolvesEat(),\n ],\n }),\n role: \"hunter\",\n action: \"eat\",\n expected: false,\n },\n ])(`$test`, ({ game, role, action, expected }) => {\n expect(doesGameHaveUpcomingPlaySourceAndAction(game, role, action)).toBe(expected);\n });\n });\n\n describe(\"doesGameHaveCurrentOrUpcomingPlaySourceAndAction\", () => {\n it.each<{\n test: string;\n game: Game;\n role: RoleName;\n action: GamePlayAction;\n expected: boolean;\n }>([\n {\n test: \"should return true when game has current play source and action.\",\n game: createFakeGame({ currentPlay: createFakeGamePlayHunterShoots() }),\n role: \"hunter\",\n action: \"shoot\",\n expected: true,\n },\n {\n test: \"should return true when game has upcoming play source and action.\",\n game: createFakeGame({ upcomingPlays: [createFakeGamePlayHunterShoots()] }),\n role: \"hunter\",\n action: \"shoot\",\n expected: true,\n },\n {\n test: \"should return false when game has no current or upcoming play source and action.\",\n game: createFakeGame({ currentPlay: createFakeGamePlayHunterShoots(), upcomingPlays: [createFakeGamePlayHunterShoots()] }),\n role: \"hunter\",\n action: \"eat\",\n expected: false,\n },\n ])(`$test`, ({ game, role, action, expected }) => {\n expect(doesGameHaveCurrentOrUpcomingPlaySourceAndAction(game, role, action)).toBe(expected);\n });\n });\n});" }, "tests/unit/specs/modules/game/providers/services/game-victory/game-victory.service.spec.ts": { "tests": [ @@ -195338,7 +195340,7 @@ "location": { "start": { "column": 6, - "line": 427 + "line": 428 } } }, @@ -195348,7 +195350,7 @@ "location": { "start": { "column": 6, - "line": 437 + "line": 438 } } }, @@ -195358,7 +195360,7 @@ "location": { "start": { "column": 6, - "line": 449 + "line": 450 } } }, @@ -195368,7 +195370,7 @@ "location": { "start": { "column": 8, - "line": 525 + "line": 526 } } }, @@ -195378,7 +195380,7 @@ "location": { "start": { "column": 8, - "line": 525 + "line": 526 } } }, @@ -195388,7 +195390,7 @@ "location": { "start": { "column": 8, - "line": 525 + "line": 526 } } }, @@ -195398,7 +195400,7 @@ "location": { "start": { "column": 8, - "line": 525 + "line": 526 } } }, @@ -195408,7 +195410,7 @@ "location": { "start": { "column": 8, - "line": 525 + "line": 526 } } }, @@ -195418,7 +195420,7 @@ "location": { "start": { "column": 8, - "line": 584 + "line": 585 } } }, @@ -195428,7 +195430,7 @@ "location": { "start": { "column": 8, - "line": 584 + "line": 585 } } }, @@ -195438,7 +195440,7 @@ "location": { "start": { "column": 8, - "line": 584 + "line": 585 } } }, @@ -195448,7 +195450,7 @@ "location": { "start": { "column": 8, - "line": 584 + "line": 585 } } }, @@ -195458,7 +195460,7 @@ "location": { "start": { "column": 8, - "line": 584 + "line": 585 } } }, @@ -195468,7 +195470,7 @@ "location": { "start": { "column": 8, - "line": 685 + "line": 686 } } }, @@ -195478,7 +195480,7 @@ "location": { "start": { "column": 8, - "line": 685 + "line": 686 } } }, @@ -195488,7 +195490,7 @@ "location": { "start": { "column": 8, - "line": 685 + "line": 686 } } }, @@ -195498,7 +195500,7 @@ "location": { "start": { "column": 8, - "line": 685 + "line": 686 } } }, @@ -195508,7 +195510,7 @@ "location": { "start": { "column": 8, - "line": 685 + "line": 686 } } }, @@ -195518,7 +195520,7 @@ "location": { "start": { "column": 8, - "line": 685 + "line": 686 } } }, @@ -195528,7 +195530,7 @@ "location": { "start": { "column": 8, - "line": 685 + "line": 686 } } }, @@ -195538,7 +195540,7 @@ "location": { "start": { "column": 8, - "line": 685 + "line": 686 } } }, @@ -195548,7 +195550,7 @@ "location": { "start": { "column": 8, - "line": 829 + "line": 830 } } }, @@ -195558,7 +195560,7 @@ "location": { "start": { "column": 8, - "line": 829 + "line": 830 } } }, @@ -195568,7 +195570,7 @@ "location": { "start": { "column": 8, - "line": 829 + "line": 830 } } }, @@ -195578,7 +195580,7 @@ "location": { "start": { "column": 8, - "line": 829 + "line": 830 } } }, @@ -195588,7 +195590,7 @@ "location": { "start": { "column": 8, - "line": 829 + "line": 830 } } }, @@ -195598,7 +195600,7 @@ "location": { "start": { "column": 8, - "line": 829 + "line": 830 } } }, @@ -195608,7 +195610,7 @@ "location": { "start": { "column": 8, - "line": 829 + "line": 830 } } }, @@ -195618,7 +195620,7 @@ "location": { "start": { "column": 8, - "line": 829 + "line": 830 } } }, @@ -195628,7 +195630,7 @@ "location": { "start": { "column": 8, - "line": 829 + "line": 830 } } }, @@ -195638,7 +195640,7 @@ "location": { "start": { "column": 8, - "line": 829 + "line": 830 } } }, @@ -195648,7 +195650,7 @@ "location": { "start": { "column": 8, - "line": 829 + "line": 830 } } }, @@ -195658,7 +195660,7 @@ "location": { "start": { "column": 8, - "line": 905 + "line": 906 } } }, @@ -195668,7 +195670,7 @@ "location": { "start": { "column": 8, - "line": 905 + "line": 906 } } }, @@ -195678,7 +195680,7 @@ "location": { "start": { "column": 8, - "line": 905 + "line": 906 } } }, @@ -195688,7 +195690,7 @@ "location": { "start": { "column": 8, - "line": 905 + "line": 906 } } }, @@ -195698,7 +195700,7 @@ "location": { "start": { "column": 8, - "line": 905 + "line": 906 } } }, @@ -195708,12 +195710,12 @@ "location": { "start": { "column": 8, - "line": 905 + "line": 906 } } } ], - "source": "import type { TestingModule } from \"@nestjs/testing\";\nimport { Test } from \"@nestjs/testing\";\n\nimport { GameVictoryService } from \"@/modules/game/providers/services/game-victory/game-victory.service\";\nimport type { GameVictory } from \"@/modules/game/schemas/game-victory/game-victory.schema\";\nimport type { Game } from \"@/modules/game/schemas/game.schema\";\n\nimport { UnexpectedExceptionReasons } from \"@/shared/exception/enums/unexpected-exception.enum\";\nimport * as UnexpectedExceptionFactory from \"@/shared/exception/helpers/unexpected-exception.factory\";\nimport { UnexpectedException } from \"@/shared/exception/types/unexpected-exception.types\";\n\nimport { createFakeGameOptions } from \"@tests/factories/game/schemas/game-options/game-options.schema.factory\";\nimport { createFakeCupidGameOptions, createFakePiedPiperGameOptions, createFakeRolesGameOptions } from \"@tests/factories/game/schemas/game-options/game-roles-options/game-roles-options.schema.factory\";\nimport { createFakeGamePhase } from \"@tests/factories/game/schemas/game-phase/game-phase.schema.factory\";\nimport { createFakeGamePlaySource } from \"@tests/factories/game/schemas/game-play/game-play-source/game-play-source.schema.factory\";\nimport { createFakeGamePlayHunterShoots, createFakeGamePlaySurvivorsVote, createFakeGamePlayWerewolvesEat } from \"@tests/factories/game/schemas/game-play/game-play.schema.factory\";\nimport { createFakeGameVictory } from \"@tests/factories/game/schemas/game-victory/game-victory.schema.factory\";\nimport { createFakeGame } from \"@tests/factories/game/schemas/game.schema.factory\";\nimport { createFakeCharmedByPiedPiperPlayerAttribute, createFakeInLoveByCupidPlayerAttribute, createFakePowerlessByElderPlayerAttribute } from \"@tests/factories/game/schemas/player/player-attribute/player-attribute.schema.factory\";\nimport { createFakePlayerBrokenHeartByCupidDeath, createFakePlayerEatenByWerewolvesDeath, createFakePlayerShotByHunterDeath, createFakePlayerVoteBySurvivorsDeath } from \"@tests/factories/game/schemas/player/player-death/player-death.schema.factory\";\nimport { createFakeAngelAlivePlayer, createFakeCupidAlivePlayer, createFakePiedPiperAlivePlayer, createFakePrejudicedManipulatorAlivePlayer, createFakeSeerAlivePlayer, createFakeVillagerAlivePlayer, createFakeWerewolfAlivePlayer, createFakeWhiteWerewolfAlivePlayer } from \"@tests/factories/game/schemas/player/player-with-role.schema.factory\";\nimport { createFakePlayerSide } from \"@tests/factories/game/schemas/player/player.schema.factory\";\n\ndescribe(\"Game Victory Service\", () => {\n let services: { gameVictory: GameVictoryService };\n let mocks: {\n unexpectedExceptionFactory: {\n createNoCurrentGamePlayUnexpectedException: jest.SpyInstance;\n };\n };\n\n beforeEach(async() => {\n const module: TestingModule = await Test.createTestingModule({ providers: [GameVictoryService] }).compile();\n mocks = { unexpectedExceptionFactory: { createNoCurrentGamePlayUnexpectedException: jest.spyOn(UnexpectedExceptionFactory, \"createNoCurrentGamePlayUnexpectedException\").mockImplementation() } };\n services = { gameVictory: module.get(GameVictoryService) };\n });\n\n describe(\"isGameOver\", () => {\n it(\"should throw error when game's current play is not set.\", () => {\n const game = createFakeGame();\n const expectedError = new UnexpectedException(\"isGameOver\", UnexpectedExceptionReasons.NO_CURRENT_GAME_PLAY, { gameId: game._id.toString() });\n mocks.unexpectedExceptionFactory.createNoCurrentGamePlayUnexpectedException.mockReturnValueOnce(expectedError);\n\n expect(() => services.gameVictory.isGameOver(game)).toThrow(expectedError);\n expect(mocks.unexpectedExceptionFactory.createNoCurrentGamePlayUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"isGameOver\", { gameId: game._id });\n });\n\n it(\"should return true when all players are dead.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeSeerAlivePlayer({ isAlive: false }),\n ];\n const upcomingPlays = [\n createFakeGamePlayHunterShoots({ source: createFakeGamePlaySource({ name: \"hunter\" }) }),\n createFakeGamePlayWerewolvesEat(),\n ];\n const currentPlay = createFakeGamePlaySurvivorsVote();\n const game = createFakeGame({ players, upcomingPlays, currentPlay });\n\n expect(services.gameVictory.isGameOver(game)).toBe(true);\n });\n\n it(\"should return false when there is a incoming shoot by hunter play.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer({ isAlive: false }),\n ];\n const upcomingPlays = [\n createFakeGamePlayHunterShoots(),\n createFakeGamePlayWerewolvesEat(),\n ];\n const currentPlay = createFakeGamePlaySurvivorsVote();\n const game = createFakeGame({ players, upcomingPlays, currentPlay });\n\n expect(services.gameVictory.isGameOver(game)).toBe(false);\n });\n\n it(\"should return false when current play is shoot by hunter play.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer({ isAlive: false }),\n ];\n const upcomingPlays = [\n createFakeGamePlaySurvivorsVote(),\n createFakeGamePlayWerewolvesEat(),\n ];\n const currentPlay = createFakeGamePlayHunterShoots();\n const game = createFakeGame({ players, upcomingPlays, currentPlay });\n\n expect(services.gameVictory.isGameOver(game)).toBe(false);\n });\n\n it(\"should return true when werewolves win.\", () => {\n const players = [\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeSeerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const upcomingPlays = [\n createFakeGamePlayHunterShoots({ action: \"look\" }),\n createFakeGamePlayWerewolvesEat(),\n ];\n const currentPlay = createFakeGamePlaySurvivorsVote();\n const game = createFakeGame({ players, currentPlay, upcomingPlays });\n\n expect(services.gameVictory.isGameOver(game)).toBe(true);\n });\n\n it(\"should return true when villagers win.\", () => {\n const players = [\n createFakeVillagerAlivePlayer(),\n createFakeSeerAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n ];\n const upcomingPlays = [\n createFakeGamePlayHunterShoots({ source: createFakeGamePlaySource({ name: \"thief\" }) }),\n createFakeGamePlaySurvivorsVote(),\n createFakeGamePlayWerewolvesEat(),\n ];\n const currentPlay = createFakeGamePlaySurvivorsVote();\n const game = createFakeGame({ players, currentPlay, upcomingPlays });\n\n expect(services.gameVictory.isGameOver(game)).toBe(true);\n });\n\n it(\"should return true when lovers win.\", () => {\n const players = [\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeSeerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n ];\n const upcomingPlays = [\n createFakeGamePlaySurvivorsVote(),\n createFakeGamePlayWerewolvesEat(),\n ];\n const currentPlay = createFakeGamePlaySurvivorsVote();\n const game = createFakeGame({ players, upcomingPlays, currentPlay });\n\n expect(services.gameVictory.isGameOver(game)).toBe(true);\n });\n\n it(\"should return true when white werewolf wins.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeSeerAlivePlayer({ isAlive: false }),\n createFakeWhiteWerewolfAlivePlayer({ isAlive: true }),\n ];\n const upcomingPlays = [\n createFakeGamePlaySurvivorsVote(),\n createFakeGamePlayWerewolvesEat(),\n ];\n const currentPlay = createFakeGamePlaySurvivorsVote();\n const game = createFakeGame({ players, upcomingPlays, currentPlay });\n\n expect(services.gameVictory.isGameOver(game)).toBe(true);\n });\n\n it(\"should return true when pied piper wins.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakeSeerAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakeVillagerAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakePiedPiperAlivePlayer({ side: createFakePlayerSide({ current: \"werewolves\" }) }),\n ];\n const upcomingPlays = [\n createFakeGamePlaySurvivorsVote(),\n createFakeGamePlayWerewolvesEat(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ piedPiper: createFakePiedPiperGameOptions({ isPowerlessOnWerewolvesSide: false }) }) });\n const currentPlay = createFakeGamePlaySurvivorsVote();\n const game = createFakeGame({ players, upcomingPlays, currentPlay, options });\n\n expect(services.gameVictory.isGameOver(game)).toBe(true);\n });\n\n it(\"should return true when angel wins.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeAngelAlivePlayer({ isAlive: false, death: createFakePlayerVoteBySurvivorsDeath() }),\n ];\n const upcomingPlays = [\n createFakeGamePlaySurvivorsVote(),\n createFakeGamePlayWerewolvesEat(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ piedPiper: createFakePiedPiperGameOptions({ isPowerlessOnWerewolvesSide: false }) }) });\n const currentPlay = createFakeGamePlaySurvivorsVote();\n const game = createFakeGame({\n players,\n upcomingPlays,\n currentPlay,\n options,\n turn: 1,\n phase: createFakeGamePhase({ name: \"night\" }),\n });\n\n expect(services.gameVictory.isGameOver(game)).toBe(true);\n });\n });\n\n describe(\"generateGameVictoryData\", () => {\n it(\"should return no winners when all players are dead.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeSeerAlivePlayer({ isAlive: false }),\n ];\n const upcomingPlays = [\n createFakeGamePlayHunterShoots({ source: createFakeGamePlaySource({ name: \"hunter\" }) }),\n createFakeGamePlayWerewolvesEat(),\n ];\n const game = createFakeGame({ players, upcomingPlays });\n const expectedGameVictory = createFakeGameVictory({ type: \"none\" });\n\n expect(services.gameVictory.generateGameVictoryData(game)).toStrictEqual(expectedGameVictory);\n });\n\n it(\"should return angel victory when angel wins.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeAngelAlivePlayer({ isAlive: false, death: createFakePlayerVoteBySurvivorsDeath() }),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ piedPiper: createFakePiedPiperGameOptions({ isPowerlessOnWerewolvesSide: false }) }) });\n const game = createFakeGame({\n players,\n options,\n phase: createFakeGamePhase({ name: \"night\" }),\n turn: 1,\n });\n const expectedGameVictory = createFakeGameVictory({ type: \"angel\", winners: [players[3]] });\n\n expect(services.gameVictory.generateGameVictoryData(game)).toStrictEqual(expectedGameVictory);\n });\n\n it(\"should return lovers victory when lovers win.\", () => {\n const players = [\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeSeerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n ];\n const game = createFakeGame({ players });\n const expectedGameVictory = createFakeGameVictory({ type: \"lovers\", winners: [players[2], players[3]] });\n\n expect(services.gameVictory.generateGameVictoryData(game)).toStrictEqual(expectedGameVictory);\n });\n\n it(\"should return pied piper victory when pied piper wins.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakeSeerAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakeVillagerAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakePiedPiperAlivePlayer({ side: createFakePlayerSide({ current: \"werewolves\" }) }),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ piedPiper: createFakePiedPiperGameOptions({ isPowerlessOnWerewolvesSide: false }) }) });\n const game = createFakeGame({ players, options });\n const expectedGameVictory = createFakeGameVictory({ type: \"pied-piper\", winners: [players[3]] });\n\n expect(services.gameVictory.generateGameVictoryData(game)).toStrictEqual(expectedGameVictory);\n });\n\n it(\"should return white werewolf victory when white werewolf wins.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeSeerAlivePlayer({ isAlive: false }),\n createFakeWhiteWerewolfAlivePlayer({ isAlive: true }),\n ];\n const game = createFakeGame({ players });\n const expectedGameVictory = createFakeGameVictory({ type: \"white-werewolf\", winners: [players[2]] });\n\n expect(services.gameVictory.generateGameVictoryData(game)).toStrictEqual(expectedGameVictory);\n });\n\n it(\"should return prejudiced manipulator victory when prejudiced manipulator wins.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ isAlive: false, group: \"girl\" }),\n createFakeSeerAlivePlayer({ isAlive: false, group: \"girl\" }),\n createFakePrejudicedManipulatorAlivePlayer({ group: \"boy\" }),\n createFakeWerewolfAlivePlayer({ group: \"boy\" }),\n ];\n const game = createFakeGame({ players });\n const expectedGameVictory = createFakeGameVictory({ type: \"prejudiced-manipulator\", winners: [players[2]] });\n\n expect(services.gameVictory.generateGameVictoryData(game)).toStrictEqual(expectedGameVictory);\n });\n\n it(\"should return werewolves victory when werewolves win.\", () => {\n const players = [\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeSeerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n ];\n const game = createFakeGame({ players });\n const expectedGameVictory = createFakeGameVictory({ type: \"werewolves\", winners: [players[2], players[3]] });\n\n expect(services.gameVictory.generateGameVictoryData(game)).toStrictEqual(expectedGameVictory);\n });\n\n it(\"should return villagers victory when villagers win.\", () => {\n const players = [\n createFakeVillagerAlivePlayer(),\n createFakeSeerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n ];\n const game = createFakeGame({ players });\n const expectedGameVictory = createFakeGameVictory({ type: \"villagers\", winners: [players[0], players[1]] });\n\n expect(services.gameVictory.generateGameVictoryData(game)).toStrictEqual(expectedGameVictory);\n });\n\n it(\"should return undefined when no victory can't be generated.\", () => {\n const players = [\n createFakeVillagerAlivePlayer(),\n createFakeSeerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n ];\n const game = createFakeGame({ players });\n\n expect(services.gameVictory.generateGameVictoryData(game)).toBeUndefined();\n });\n });\n\n describe(\"doWerewolvesWin\", () => {\n it.each<{\n test: string;\n game: Game;\n expected: boolean;\n }>([\n {\n test: \"should return false when there are no players provided.\",\n game: createFakeGame(),\n expected: false,\n },\n {\n test: \"should return false when there are no werewolves among players.\",\n game: createFakeGame({\n players: [\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeSeerAlivePlayer({ isAlive: false }),\n ],\n }),\n expected: false,\n },\n {\n test: \"should return false when there are at least one alive villager among players.\",\n game: createFakeGame({\n players: [\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeSeerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ],\n }),\n expected: false,\n },\n {\n test: \"should return true when all villagers are dead.\",\n game: createFakeGame({\n players: [\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeSeerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ],\n }),\n expected: true,\n },\n ])(\"$test\", ({ game, expected }) => {\n expect(services.gameVictory[\"doWerewolvesWin\"](game)).toBe(expected);\n });\n\n it(\"should return false when there are no players provided.\", () => {\n const game = createFakeGame();\n\n expect(services.gameVictory[\"doWerewolvesWin\"](game)).toBe(false);\n });\n\n it(\"should return false when there are no werewolves among players.\", () => {\n const players = [\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeSeerAlivePlayer({ isAlive: false }),\n ];\n const game = createFakeGame({ players });\n\n expect(services.gameVictory[\"doWerewolvesWin\"](game)).toBe(false);\n });\n\n it(\"should return false when there are at least one alive villager among players.\", () => {\n const players = [\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeSeerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(services.gameVictory[\"doWerewolvesWin\"](game)).toBe(false);\n });\n\n it(\"should return true when all villagers are dead.\", () => {\n const players = [\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeSeerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(services.gameVictory[\"doWerewolvesWin\"](game)).toBe(true);\n });\n });\n\n describe(\"doVillagersWin\", () => {\n it(\"should return false when there are no players provided.\", () => {\n const game = createFakeGame();\n expect(services.gameVictory[\"doVillagersWin\"](game)).toBe(false);\n });\n\n it(\"should return false when there are no villagers among players.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeWhiteWerewolfAlivePlayer({ isAlive: false }),\n ];\n const game = createFakeGame({ players });\n\n expect(services.gameVictory[\"doVillagersWin\"](game)).toBe(false);\n });\n\n it(\"should return false when there are at least one alive werewolf among players.\", () => {\n const players = [\n createFakeVillagerAlivePlayer(),\n createFakeSeerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n ];\n const game = createFakeGame({ players });\n\n expect(services.gameVictory[\"doVillagersWin\"](game)).toBe(false);\n });\n\n it(\"should return true when all werewolves are dead.\", () => {\n const players = [\n createFakeVillagerAlivePlayer(),\n createFakeSeerAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n ];\n const game = createFakeGame({ players });\n\n expect(services.gameVictory[\"doVillagersWin\"](game)).toBe(true);\n });\n });\n\n describe(\"doLoversWin\", () => {\n it.each<{\n test: string;\n game: Game;\n expected: boolean;\n }>([\n {\n test: \"should return false when there are no players provided.\",\n game: createFakeGame(),\n expected: false,\n },\n {\n test: \"should return false when there are no lovers among players.\",\n game: createFakeGame({\n players: [\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeSeerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ],\n options: createFakeGameOptions({ roles: createFakeRolesGameOptions({ cupid: createFakeCupidGameOptions({ mustWinWithLovers: false }) }) }),\n }),\n expected: false,\n },\n {\n test: \"should return false when there are at least one alive non-lover player among players.\",\n game: createFakeGame({\n players: [\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeSeerAlivePlayer(),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n ],\n options: createFakeGameOptions({ roles: createFakeRolesGameOptions({ cupid: createFakeCupidGameOptions({ mustWinWithLovers: true }) }) }),\n }),\n expected: false,\n },\n {\n test: \"should return true when all non-lover players are dead.\",\n game: createFakeGame({\n players: [\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeCupidAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n ],\n options: createFakeGameOptions({ roles: createFakeRolesGameOptions({ cupid: createFakeCupidGameOptions({ mustWinWithLovers: false }) }) }),\n }),\n expected: true,\n },\n {\n test: \"should return true when all non-lover players are dead and cupid can win with lovers.\",\n game: createFakeGame({\n players: [\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeCupidAlivePlayer(),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n ],\n options: createFakeGameOptions({ roles: createFakeRolesGameOptions({ cupid: createFakeCupidGameOptions({ mustWinWithLovers: true }) }) }),\n }),\n expected: true,\n },\n ])(\"$test\", ({ game, expected }) => {\n expect(services.gameVictory[\"doLoversWin\"](game)).toBe(expected);\n });\n });\n\n describe(\"doesWhiteWerewolfWin\", () => {\n it.each<{\n test: string;\n game: Game;\n expected: boolean;\n }>([\n {\n test: \"should return false when no players are provided.\",\n game: createFakeGame(),\n expected: false,\n },\n {\n test: \"should return false when there is no white werewolf among players.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ],\n }),\n expected: false,\n },\n {\n test: \"should return false when there is at least one alive players among players except white werewolf himself.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer({ isAlive: false }),\n createFakeWhiteWerewolfAlivePlayer(),\n ],\n }),\n expected: false,\n },\n {\n test: \"should return false when all players are dead even white werewolf himself.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeSeerAlivePlayer({ isAlive: false }),\n createFakeWhiteWerewolfAlivePlayer({ isAlive: false }),\n ],\n }),\n expected: false,\n },\n {\n test: \"should return true when all players are dead except white werewolf.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeSeerAlivePlayer({ isAlive: false }),\n createFakeWhiteWerewolfAlivePlayer({ isAlive: true }),\n ],\n }),\n expected: true,\n },\n ])(\"$test\", ({ game, expected }) => {\n expect(services.gameVictory[\"doesWhiteWerewolfWin\"](game)).toBe(expected);\n });\n });\n\n describe(\"doesPiedPiperWin\", () => {\n it.each<{\n test: string;\n game: Game;\n expected: boolean;\n }>([\n {\n test: \"should return false when no players are provided.\",\n game: createFakeGame(),\n expected: false,\n },\n {\n test: \"should return false when there is no pied piper among players.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ],\n }),\n expected: false,\n },\n {\n test: \"should return false when pied piper is dead but all are charmed.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakeSeerAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakeVillagerAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakePiedPiperAlivePlayer({ isAlive: false }),\n ],\n }),\n expected: false,\n },\n {\n test: \"should return false when pied piper is powerless but all are charmed.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakeSeerAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakeVillagerAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakePiedPiperAlivePlayer({ attributes: [createFakePowerlessByElderPlayerAttribute()] }),\n ],\n }),\n expected: false,\n },\n {\n test: \"should return false when there are still left to charm players.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakeSeerAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakeVillagerAlivePlayer({ attributes: [] }),\n createFakePiedPiperAlivePlayer({ attributes: [createFakePowerlessByElderPlayerAttribute()] }),\n ],\n }),\n expected: false,\n },\n {\n test: \"should return false when all are charmed but pied piper is powerless because infected.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakeSeerAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakeVillagerAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakePiedPiperAlivePlayer({ side: createFakePlayerSide({ current: \"werewolves\" }) }),\n ],\n options: createFakeGameOptions({ roles: createFakeRolesGameOptions({ piedPiper: createFakePiedPiperGameOptions({ isPowerlessOnWerewolvesSide: true }) }) }),\n }),\n expected: false,\n },\n {\n test: \"should return true when all are charmed but pied piper is not powerless because infected.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakeSeerAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakeVillagerAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakePiedPiperAlivePlayer({ side: createFakePlayerSide({ current: \"werewolves\" }) }),\n ],\n options: createFakeGameOptions({ roles: createFakeRolesGameOptions({ piedPiper: createFakePiedPiperGameOptions({ isPowerlessOnWerewolvesSide: false }) }) }),\n }),\n expected: true,\n },\n {\n test: \"should return true when all are charmed and pied piper is not infected anyway.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakeSeerAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakeVillagerAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakePiedPiperAlivePlayer(),\n ],\n options: createFakeGameOptions({ roles: createFakeRolesGameOptions({ piedPiper: createFakePiedPiperGameOptions({ isPowerlessOnWerewolvesSide: true }) }) }),\n }),\n expected: true,\n },\n ])(\"$test\", ({ game, expected }) => {\n expect(services.gameVictory[\"doesPiedPiperWin\"](game)).toBe(expected);\n });\n });\n\n describe(\"doesAngelWin\", () => {\n it.each<{\n test: string;\n game: Game;\n expected: boolean;\n }>([\n {\n test: \"should return false when no players are provided.\",\n game: createFakeGame(),\n expected: false,\n },\n {\n test: \"should return false when there is no angel among players.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ],\n }),\n expected: false,\n },\n {\n test: \"should return false when angel is still alive.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeAngelAlivePlayer(),\n ],\n }),\n expected: false,\n },\n {\n test: \"should return false when angel is dead but has no death cause.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeAngelAlivePlayer({ isAlive: false }),\n ],\n }),\n expected: false,\n },\n {\n test: \"should return false when angel is dead but powerless.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeAngelAlivePlayer({ isAlive: false, attributes: [createFakePowerlessByElderPlayerAttribute()] }),\n ],\n }),\n expected: false,\n },\n {\n test: \"should return false when it's not first turn of the game.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeAngelAlivePlayer({ isAlive: false, death: createFakePlayerEatenByWerewolvesDeath() }),\n ],\n turn: 2,\n }),\n expected: false,\n },\n {\n test: \"should return false when angel is not dead from vote or eaten cause.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeAngelAlivePlayer({ isAlive: false, death: createFakePlayerBrokenHeartByCupidDeath() }),\n ],\n turn: 1,\n }),\n expected: false,\n },\n {\n test: \"should return false when angel dead for shot cause on night phase.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeAngelAlivePlayer({ isAlive: false, death: createFakePlayerShotByHunterDeath() }),\n ],\n turn: 1,\n phase: createFakeGamePhase({ name: \"night\" }),\n }),\n expected: false,\n },\n {\n test: \"should return false when angel dead for vote cause but on phase day.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeAngelAlivePlayer({ isAlive: false, death: createFakePlayerVoteBySurvivorsDeath() }),\n ],\n turn: 1,\n phase: createFakeGamePhase({ name: \"day\" }),\n }),\n expected: false,\n },\n {\n test: \"should return true when angel is dead from eaten cause.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeAngelAlivePlayer({ isAlive: false, death: createFakePlayerEatenByWerewolvesDeath() }),\n ],\n turn: 1,\n }),\n expected: true,\n },\n {\n test: \"should return true when angel is dead from vote cause.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeAngelAlivePlayer({ isAlive: false, death: createFakePlayerVoteBySurvivorsDeath() }),\n ],\n turn: 1,\n phase: createFakeGamePhase({ name: \"night\" }),\n }),\n expected: true,\n },\n ])(\"$test\", ({ game, expected }) => {\n expect(services.gameVictory[\"doesAngelWin\"](game)).toBe(expected);\n });\n });\n\n describe(\"doesPrejudicedManipulatorWin\", () => {\n it.each<{\n test: string;\n game: Game;\n expected: boolean;\n }>([\n {\n test: \"should return false when no players are provided.\",\n game: createFakeGame(),\n expected: false,\n },\n {\n test: \"should return false when there is no prejudiced manipulator among players.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer({ group: \"boy\" }),\n createFakeSeerAlivePlayer({ group: \"boy\" }),\n createFakeVillagerAlivePlayer({ group: \"boy\" }),\n createFakeVillagerAlivePlayer({ group: \"girl\", isAlive: false }),\n ],\n }),\n expected: false,\n },\n {\n test: \"should return false when prejudiced manipulator is dead.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer({ group: \"boy\" }),\n createFakeSeerAlivePlayer({ group: \"boy\" }),\n createFakePrejudicedManipulatorAlivePlayer({ group: \"boy\", isAlive: false }),\n createFakeVillagerAlivePlayer({ group: \"girl\", isAlive: false }),\n ],\n }),\n expected: false,\n },\n {\n test: \"should return false when prejudiced manipulator is powerless.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer({ group: \"boy\" }),\n createFakeSeerAlivePlayer({ group: \"boy\" }),\n createFakePrejudicedManipulatorAlivePlayer({ group: \"boy\", attributes: [createFakePowerlessByElderPlayerAttribute()] }),\n createFakeVillagerAlivePlayer({ group: \"girl\", isAlive: false }),\n ],\n }),\n expected: false,\n },\n {\n test: \"should return false when one of the prejudiced manipulator's other group is still alive.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer({ group: \"boy\" }),\n createFakeSeerAlivePlayer({ group: \"girl\" }),\n createFakePrejudicedManipulatorAlivePlayer({ group: \"boy\" }),\n createFakeVillagerAlivePlayer({ group: \"girl\", isAlive: false }),\n ],\n }),\n expected: false,\n },\n {\n test: \"should return true when every one of the prejudiced manipulator's other group is dead.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer({ group: \"boy\" }),\n createFakeSeerAlivePlayer({ group: \"girl\", isAlive: false }),\n createFakePrejudicedManipulatorAlivePlayer({ group: \"boy\" }),\n createFakeVillagerAlivePlayer({ group: \"girl\", isAlive: false }),\n ],\n }),\n expected: true,\n },\n ])(\"$test\", ({ game, expected }) => {\n expect(services.gameVictory[\"doesPrejudicedManipulatorWin\"](game)).toBe(expected);\n });\n });\n});" + "source": "import type { TestingModule } from \"@nestjs/testing\";\nimport { Test } from \"@nestjs/testing\";\n\nimport { GameVictoryService } from \"@/modules/game/providers/services/game-victory/game-victory.service\";\nimport type { GameVictory } from \"@/modules/game/schemas/game-victory/game-victory.schema\";\nimport type { Game } from \"@/modules/game/schemas/game.schema\";\n\nimport { UnexpectedExceptionReasons } from \"@/shared/exception/enums/unexpected-exception.enums\";\nimport * as UnexpectedExceptionFactory from \"@/shared/exception/helpers/unexpected-exception.factory\";\nimport { UnexpectedException } from \"@/shared/exception/types/unexpected-exception.types\";\n\nimport { createFakeGameOptions } from \"@tests/factories/game/schemas/game-options/game-options.schema.factory\";\nimport { createFakeCupidGameOptions, createFakePiedPiperGameOptions, createFakeRolesGameOptions } from \"@tests/factories/game/schemas/game-options/game-roles-options/game-roles-options.schema.factory\";\nimport { createFakeGamePhase } from \"@tests/factories/game/schemas/game-phase/game-phase.schema.factory\";\nimport { createFakeGamePlaySource } from \"@tests/factories/game/schemas/game-play/game-play-source/game-play-source.schema.factory\";\nimport { createFakeGamePlayHunterShoots, createFakeGamePlaySurvivorsVote, createFakeGamePlayWerewolvesEat } from \"@tests/factories/game/schemas/game-play/game-play.schema.factory\";\nimport { createFakeGameVictory } from \"@tests/factories/game/schemas/game-victory/game-victory.schema.factory\";\nimport { createFakeGame } from \"@tests/factories/game/schemas/game.schema.factory\";\nimport { createFakeCharmedByPiedPiperPlayerAttribute, createFakeInLoveByCupidPlayerAttribute, createFakePowerlessByElderPlayerAttribute } from \"@tests/factories/game/schemas/player/player-attribute/player-attribute.schema.factory\";\nimport { createFakePlayerBrokenHeartByCupidDeath, createFakePlayerEatenByWerewolvesDeath, createFakePlayerShotByHunterDeath, createFakePlayerVoteBySurvivorsDeath } from \"@tests/factories/game/schemas/player/player-death/player-death.schema.factory\";\nimport { createFakeAngelAlivePlayer, createFakeCupidAlivePlayer, createFakePiedPiperAlivePlayer, createFakePrejudicedManipulatorAlivePlayer, createFakeSeerAlivePlayer, createFakeVillagerAlivePlayer, createFakeWerewolfAlivePlayer, createFakeWhiteWerewolfAlivePlayer } from \"@tests/factories/game/schemas/player/player-with-role.schema.factory\";\nimport { createFakePlayerSide } from \"@tests/factories/game/schemas/player/player.schema.factory\";\n\ndescribe(\"Game Victory Service\", () => {\n let services: { gameVictory: GameVictoryService };\n let mocks: {\n unexpectedExceptionFactory: {\n createNoCurrentGamePlayUnexpectedException: jest.SpyInstance;\n };\n };\n\n beforeEach(async() => {\n const module: TestingModule = await Test.createTestingModule({ providers: [GameVictoryService] }).compile();\n mocks = { unexpectedExceptionFactory: { createNoCurrentGamePlayUnexpectedException: jest.spyOn(UnexpectedExceptionFactory, \"createNoCurrentGamePlayUnexpectedException\").mockImplementation() } };\n services = { gameVictory: module.get(GameVictoryService) };\n });\n\n describe(\"isGameOver\", () => {\n it(\"should throw error when game's current play is not set.\", () => {\n const game = createFakeGame();\n const expectedError = new UnexpectedException(\"isGameOver\", UnexpectedExceptionReasons.NO_CURRENT_GAME_PLAY, { gameId: game._id.toString() });\n mocks.unexpectedExceptionFactory.createNoCurrentGamePlayUnexpectedException.mockReturnValueOnce(expectedError);\n\n expect(() => services.gameVictory.isGameOver(game)).toThrow(expectedError);\n expect(mocks.unexpectedExceptionFactory.createNoCurrentGamePlayUnexpectedException).toHaveBeenCalledExactlyOnceWith(\"isGameOver\", { gameId: game._id });\n });\n\n it(\"should return true when all players are dead.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeSeerAlivePlayer({ isAlive: false }),\n ];\n const upcomingPlays = [\n createFakeGamePlayHunterShoots({ source: createFakeGamePlaySource({ name: \"hunter\" }) }),\n createFakeGamePlayWerewolvesEat(),\n ];\n const currentPlay = createFakeGamePlaySurvivorsVote();\n const game = createFakeGame({ players, upcomingPlays, currentPlay });\n\n expect(services.gameVictory.isGameOver(game)).toBe(true);\n });\n\n it(\"should return false when there is a incoming shoot by hunter play.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer({ isAlive: false }),\n ];\n const upcomingPlays = [\n createFakeGamePlayHunterShoots(),\n createFakeGamePlayWerewolvesEat(),\n ];\n const currentPlay = createFakeGamePlaySurvivorsVote();\n const game = createFakeGame({ players, upcomingPlays, currentPlay });\n\n expect(services.gameVictory.isGameOver(game)).toBe(false);\n });\n\n it(\"should return false when current play is shoot by hunter play.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer({ isAlive: false }),\n ];\n const upcomingPlays = [\n createFakeGamePlaySurvivorsVote(),\n createFakeGamePlayWerewolvesEat(),\n ];\n const currentPlay = createFakeGamePlayHunterShoots();\n const game = createFakeGame({ players, upcomingPlays, currentPlay });\n\n expect(services.gameVictory.isGameOver(game)).toBe(false);\n });\n\n it(\"should return true when werewolves win.\", () => {\n const players = [\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeSeerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const upcomingPlays = [\n createFakeGamePlayHunterShoots({ action: \"look\" }),\n createFakeGamePlayWerewolvesEat(),\n ];\n const currentPlay = createFakeGamePlaySurvivorsVote();\n const game = createFakeGame({ players, currentPlay, upcomingPlays });\n\n expect(services.gameVictory.isGameOver(game)).toBe(true);\n });\n\n it(\"should return true when villagers win.\", () => {\n const players = [\n createFakeVillagerAlivePlayer(),\n createFakeSeerAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n ];\n const upcomingPlays = [\n createFakeGamePlayHunterShoots({ source: createFakeGamePlaySource({ name: \"thief\" }) }),\n createFakeGamePlaySurvivorsVote(),\n createFakeGamePlayWerewolvesEat(),\n ];\n const currentPlay = createFakeGamePlaySurvivorsVote();\n const game = createFakeGame({ players, currentPlay, upcomingPlays });\n\n expect(services.gameVictory.isGameOver(game)).toBe(true);\n });\n\n it(\"should return true when lovers win.\", () => {\n const players = [\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeSeerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n ];\n const upcomingPlays = [\n createFakeGamePlaySurvivorsVote(),\n createFakeGamePlayWerewolvesEat(),\n ];\n const currentPlay = createFakeGamePlaySurvivorsVote();\n const game = createFakeGame({ players, upcomingPlays, currentPlay });\n\n expect(services.gameVictory.isGameOver(game)).toBe(true);\n });\n\n it(\"should return true when white werewolf wins.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeSeerAlivePlayer({ isAlive: false }),\n createFakeWhiteWerewolfAlivePlayer({ isAlive: true }),\n ];\n const upcomingPlays = [\n createFakeGamePlaySurvivorsVote(),\n createFakeGamePlayWerewolvesEat(),\n ];\n const currentPlay = createFakeGamePlaySurvivorsVote();\n const game = createFakeGame({ players, upcomingPlays, currentPlay });\n\n expect(services.gameVictory.isGameOver(game)).toBe(true);\n });\n\n it(\"should return true when pied piper wins.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakeSeerAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakeVillagerAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakePiedPiperAlivePlayer({ side: createFakePlayerSide({ current: \"werewolves\" }) }),\n ];\n const upcomingPlays = [\n createFakeGamePlaySurvivorsVote(),\n createFakeGamePlayWerewolvesEat(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ piedPiper: createFakePiedPiperGameOptions({ isPowerlessOnWerewolvesSide: false }) }) });\n const currentPlay = createFakeGamePlaySurvivorsVote();\n const game = createFakeGame({ players, upcomingPlays, currentPlay, options });\n\n expect(services.gameVictory.isGameOver(game)).toBe(true);\n });\n\n it(\"should return true when angel wins.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeAngelAlivePlayer({ isAlive: false, death: createFakePlayerVoteBySurvivorsDeath() }),\n ];\n const upcomingPlays = [\n createFakeGamePlaySurvivorsVote(),\n createFakeGamePlayWerewolvesEat(),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ piedPiper: createFakePiedPiperGameOptions({ isPowerlessOnWerewolvesSide: false }) }) });\n const currentPlay = createFakeGamePlaySurvivorsVote();\n const game = createFakeGame({\n players,\n upcomingPlays,\n currentPlay,\n options,\n turn: 1,\n phase: createFakeGamePhase({ name: \"night\" }),\n });\n\n expect(services.gameVictory.isGameOver(game)).toBe(true);\n });\n });\n\n describe(\"generateGameVictoryData\", () => {\n it(\"should return no winners when all players are dead.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeSeerAlivePlayer({ isAlive: false }),\n ];\n const upcomingPlays = [\n createFakeGamePlayHunterShoots({ source: createFakeGamePlaySource({ name: \"hunter\" }) }),\n createFakeGamePlayWerewolvesEat(),\n ];\n const game = createFakeGame({ players, upcomingPlays });\n const expectedGameVictory = createFakeGameVictory({ type: \"none\" });\n\n expect(services.gameVictory.generateGameVictoryData(game)).toStrictEqual(expectedGameVictory);\n });\n\n it(\"should return angel victory when angel wins.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeAngelAlivePlayer({ isAlive: false, death: createFakePlayerVoteBySurvivorsDeath() }),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ piedPiper: createFakePiedPiperGameOptions({ isPowerlessOnWerewolvesSide: false }) }) });\n const game = createFakeGame({\n players,\n options,\n phase: createFakeGamePhase({ name: \"night\" }),\n turn: 1,\n });\n const expectedGameVictory = createFakeGameVictory({ type: \"angel\", winners: [players[3]] });\n\n expect(services.gameVictory.generateGameVictoryData(game)).toStrictEqual(expectedGameVictory);\n });\n\n it(\"should return lovers victory when lovers win.\", () => {\n const players = [\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeSeerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n ];\n const game = createFakeGame({ players });\n const expectedGameVictory = createFakeGameVictory({ type: \"lovers\", winners: [players[2], players[3]] });\n\n expect(services.gameVictory.generateGameVictoryData(game)).toStrictEqual(expectedGameVictory);\n });\n\n it(\"should return pied piper victory when pied piper wins.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakeSeerAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakeVillagerAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakePiedPiperAlivePlayer({ side: createFakePlayerSide({ current: \"werewolves\" }) }),\n ];\n const options = createFakeGameOptions({ roles: createFakeRolesGameOptions({ piedPiper: createFakePiedPiperGameOptions({ isPowerlessOnWerewolvesSide: false }) }) });\n const game = createFakeGame({ players, options });\n const expectedGameVictory = createFakeGameVictory({ type: \"pied-piper\", winners: [players[3]] });\n\n expect(services.gameVictory.generateGameVictoryData(game)).toStrictEqual(expectedGameVictory);\n });\n\n it(\"should return white werewolf victory when white werewolf wins.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeSeerAlivePlayer({ isAlive: false }),\n createFakeWhiteWerewolfAlivePlayer({ isAlive: true }),\n ];\n const game = createFakeGame({ players });\n const expectedGameVictory = createFakeGameVictory({ type: \"white-werewolf\", winners: [players[2]] });\n\n expect(services.gameVictory.generateGameVictoryData(game)).toStrictEqual(expectedGameVictory);\n });\n\n it(\"should return prejudiced manipulator victory when prejudiced manipulator wins.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ isAlive: false, group: \"girl\" }),\n createFakeSeerAlivePlayer({ isAlive: false, group: \"girl\" }),\n createFakePrejudicedManipulatorAlivePlayer({ group: \"boy\" }),\n createFakeWerewolfAlivePlayer({ group: \"boy\" }),\n ];\n const game = createFakeGame({ players });\n const expectedGameVictory = createFakeGameVictory({ type: \"prejudiced-manipulator\", winners: [players[2]] });\n\n expect(services.gameVictory.generateGameVictoryData(game)).toStrictEqual(expectedGameVictory);\n });\n\n it(\"should return werewolves victory when werewolves win.\", () => {\n const players = [\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeSeerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n ];\n const game = createFakeGame({ players });\n const expectedGameVictory = createFakeGameVictory({ type: \"werewolves\", winners: [players[2], players[3]] });\n\n expect(services.gameVictory.generateGameVictoryData(game)).toStrictEqual(expectedGameVictory);\n });\n\n it(\"should return villagers victory when villagers win.\", () => {\n const players = [\n createFakeVillagerAlivePlayer(),\n createFakeSeerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n ];\n const game = createFakeGame({ players });\n const expectedGameVictory = createFakeGameVictory({ type: \"villagers\", winners: [players[0], players[1]] });\n\n expect(services.gameVictory.generateGameVictoryData(game)).toStrictEqual(expectedGameVictory);\n });\n\n it(\"should return undefined when no victory can't be generated.\", () => {\n const players = [\n createFakeVillagerAlivePlayer(),\n createFakeSeerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n ];\n const game = createFakeGame({ players });\n\n expect(services.gameVictory.generateGameVictoryData(game)).toBeUndefined();\n });\n });\n\n describe(\"doWerewolvesWin\", () => {\n it.each<{\n test: string;\n game: Game;\n expected: boolean;\n }>([\n {\n test: \"should return false when there are no players provided.\",\n game: createFakeGame(),\n expected: false,\n },\n {\n test: \"should return false when there are no werewolves among players.\",\n game: createFakeGame({\n players: [\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeSeerAlivePlayer({ isAlive: false }),\n ],\n }),\n expected: false,\n },\n {\n test: \"should return false when there are at least one alive villager among players.\",\n game: createFakeGame({\n players: [\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeSeerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ],\n }),\n expected: false,\n },\n {\n test: \"should return true when all villagers are dead.\",\n game: createFakeGame({\n players: [\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeSeerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ],\n }),\n expected: true,\n },\n ])(\"$test\", ({ game, expected }) => {\n expect(services.gameVictory[\"doWerewolvesWin\"](game)).toBe(expected);\n });\n\n it(\"should return false when there are no players provided.\", () => {\n const game = createFakeGame();\n\n expect(services.gameVictory[\"doWerewolvesWin\"](game)).toBe(false);\n });\n\n it(\"should return false when there are no werewolves among players.\", () => {\n const players = [\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeSeerAlivePlayer({ isAlive: false }),\n ];\n const game = createFakeGame({ players });\n\n expect(services.gameVictory[\"doWerewolvesWin\"](game)).toBe(false);\n });\n\n it(\"should return false when there are at least one alive villager among players.\", () => {\n const players = [\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeSeerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(services.gameVictory[\"doWerewolvesWin\"](game)).toBe(false);\n });\n\n it(\"should return true when all villagers are dead.\", () => {\n const players = [\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeSeerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n const game = createFakeGame({ players });\n\n expect(services.gameVictory[\"doWerewolvesWin\"](game)).toBe(true);\n });\n });\n\n describe(\"doVillagersWin\", () => {\n it(\"should return false when there are no players provided.\", () => {\n const game = createFakeGame();\n\n expect(services.gameVictory[\"doVillagersWin\"](game)).toBe(false);\n });\n\n it(\"should return false when there are no villagers among players.\", () => {\n const players = [\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeWhiteWerewolfAlivePlayer({ isAlive: false }),\n ];\n const game = createFakeGame({ players });\n\n expect(services.gameVictory[\"doVillagersWin\"](game)).toBe(false);\n });\n\n it(\"should return false when there are at least one alive werewolf among players.\", () => {\n const players = [\n createFakeVillagerAlivePlayer(),\n createFakeSeerAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n ];\n const game = createFakeGame({ players });\n\n expect(services.gameVictory[\"doVillagersWin\"](game)).toBe(false);\n });\n\n it(\"should return true when all werewolves are dead.\", () => {\n const players = [\n createFakeVillagerAlivePlayer(),\n createFakeSeerAlivePlayer(),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n ];\n const game = createFakeGame({ players });\n\n expect(services.gameVictory[\"doVillagersWin\"](game)).toBe(true);\n });\n });\n\n describe(\"doLoversWin\", () => {\n it.each<{\n test: string;\n game: Game;\n expected: boolean;\n }>([\n {\n test: \"should return false when there are no players provided.\",\n game: createFakeGame(),\n expected: false,\n },\n {\n test: \"should return false when there are no lovers among players.\",\n game: createFakeGame({\n players: [\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeSeerAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ],\n options: createFakeGameOptions({ roles: createFakeRolesGameOptions({ cupid: createFakeCupidGameOptions({ mustWinWithLovers: false }) }) }),\n }),\n expected: false,\n },\n {\n test: \"should return false when there are at least one alive non-lover player among players.\",\n game: createFakeGame({\n players: [\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeSeerAlivePlayer(),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n ],\n options: createFakeGameOptions({ roles: createFakeRolesGameOptions({ cupid: createFakeCupidGameOptions({ mustWinWithLovers: true }) }) }),\n }),\n expected: false,\n },\n {\n test: \"should return true when all non-lover players are dead.\",\n game: createFakeGame({\n players: [\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeCupidAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n ],\n options: createFakeGameOptions({ roles: createFakeRolesGameOptions({ cupid: createFakeCupidGameOptions({ mustWinWithLovers: false }) }) }),\n }),\n expected: true,\n },\n {\n test: \"should return true when all non-lover players are dead and cupid can win with lovers.\",\n game: createFakeGame({\n players: [\n createFakeVillagerAlivePlayer({ isAlive: false }),\n createFakeCupidAlivePlayer(),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeInLoveByCupidPlayerAttribute()] }),\n ],\n options: createFakeGameOptions({ roles: createFakeRolesGameOptions({ cupid: createFakeCupidGameOptions({ mustWinWithLovers: true }) }) }),\n }),\n expected: true,\n },\n ])(\"$test\", ({ game, expected }) => {\n expect(services.gameVictory[\"doLoversWin\"](game)).toBe(expected);\n });\n });\n\n describe(\"doesWhiteWerewolfWin\", () => {\n it.each<{\n test: string;\n game: Game;\n expected: boolean;\n }>([\n {\n test: \"should return false when no players are provided.\",\n game: createFakeGame(),\n expected: false,\n },\n {\n test: \"should return false when there is no white werewolf among players.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ],\n }),\n expected: false,\n },\n {\n test: \"should return false when there is at least one alive players among players except white werewolf himself.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer({ isAlive: false }),\n createFakeWhiteWerewolfAlivePlayer(),\n ],\n }),\n expected: false,\n },\n {\n test: \"should return false when all players are dead even white werewolf himself.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeSeerAlivePlayer({ isAlive: false }),\n createFakeWhiteWerewolfAlivePlayer({ isAlive: false }),\n ],\n }),\n expected: false,\n },\n {\n test: \"should return true when all players are dead except white werewolf.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n createFakeSeerAlivePlayer({ isAlive: false }),\n createFakeWhiteWerewolfAlivePlayer({ isAlive: true }),\n ],\n }),\n expected: true,\n },\n ])(\"$test\", ({ game, expected }) => {\n expect(services.gameVictory[\"doesWhiteWerewolfWin\"](game)).toBe(expected);\n });\n });\n\n describe(\"doesPiedPiperWin\", () => {\n it.each<{\n test: string;\n game: Game;\n expected: boolean;\n }>([\n {\n test: \"should return false when no players are provided.\",\n game: createFakeGame(),\n expected: false,\n },\n {\n test: \"should return false when there is no pied piper among players.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n ],\n }),\n expected: false,\n },\n {\n test: \"should return false when pied piper is dead but all are charmed.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakeSeerAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakeVillagerAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakePiedPiperAlivePlayer({ isAlive: false }),\n ],\n }),\n expected: false,\n },\n {\n test: \"should return false when pied piper is powerless but all are charmed.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakeSeerAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakeVillagerAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakePiedPiperAlivePlayer({ attributes: [createFakePowerlessByElderPlayerAttribute()] }),\n ],\n }),\n expected: false,\n },\n {\n test: \"should return false when there are still left to charm players.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakeSeerAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakeVillagerAlivePlayer({ attributes: [] }),\n createFakePiedPiperAlivePlayer({ attributes: [createFakePowerlessByElderPlayerAttribute()] }),\n ],\n }),\n expected: false,\n },\n {\n test: \"should return false when all are charmed but pied piper is powerless because infected.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakeSeerAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakeVillagerAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakePiedPiperAlivePlayer({ side: createFakePlayerSide({ current: \"werewolves\" }) }),\n ],\n options: createFakeGameOptions({ roles: createFakeRolesGameOptions({ piedPiper: createFakePiedPiperGameOptions({ isPowerlessOnWerewolvesSide: true }) }) }),\n }),\n expected: false,\n },\n {\n test: \"should return true when all are charmed but pied piper is not powerless because infected.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakeSeerAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakeVillagerAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakePiedPiperAlivePlayer({ side: createFakePlayerSide({ current: \"werewolves\" }) }),\n ],\n options: createFakeGameOptions({ roles: createFakeRolesGameOptions({ piedPiper: createFakePiedPiperGameOptions({ isPowerlessOnWerewolvesSide: false }) }) }),\n }),\n expected: true,\n },\n {\n test: \"should return true when all are charmed and pied piper is not infected anyway.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakeSeerAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakeVillagerAlivePlayer({ attributes: [createFakeCharmedByPiedPiperPlayerAttribute()] }),\n createFakePiedPiperAlivePlayer(),\n ],\n options: createFakeGameOptions({ roles: createFakeRolesGameOptions({ piedPiper: createFakePiedPiperGameOptions({ isPowerlessOnWerewolvesSide: true }) }) }),\n }),\n expected: true,\n },\n ])(\"$test\", ({ game, expected }) => {\n expect(services.gameVictory[\"doesPiedPiperWin\"](game)).toBe(expected);\n });\n });\n\n describe(\"doesAngelWin\", () => {\n it.each<{\n test: string;\n game: Game;\n expected: boolean;\n }>([\n {\n test: \"should return false when no players are provided.\",\n game: createFakeGame(),\n expected: false,\n },\n {\n test: \"should return false when there is no angel among players.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ],\n }),\n expected: false,\n },\n {\n test: \"should return false when angel is still alive.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeAngelAlivePlayer(),\n ],\n }),\n expected: false,\n },\n {\n test: \"should return false when angel is dead but has no death cause.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeAngelAlivePlayer({ isAlive: false }),\n ],\n }),\n expected: false,\n },\n {\n test: \"should return false when angel is dead but powerless.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeAngelAlivePlayer({ isAlive: false, attributes: [createFakePowerlessByElderPlayerAttribute()] }),\n ],\n }),\n expected: false,\n },\n {\n test: \"should return false when it's not first turn of the game.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeAngelAlivePlayer({ isAlive: false, death: createFakePlayerEatenByWerewolvesDeath() }),\n ],\n turn: 2,\n }),\n expected: false,\n },\n {\n test: \"should return false when angel is not dead from vote or eaten cause.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeAngelAlivePlayer({ isAlive: false, death: createFakePlayerBrokenHeartByCupidDeath() }),\n ],\n turn: 1,\n }),\n expected: false,\n },\n {\n test: \"should return false when angel dead for shot cause on night phase.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeAngelAlivePlayer({ isAlive: false, death: createFakePlayerShotByHunterDeath() }),\n ],\n turn: 1,\n phase: createFakeGamePhase({ name: \"night\" }),\n }),\n expected: false,\n },\n {\n test: \"should return false when angel dead for vote cause but on phase day.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeAngelAlivePlayer({ isAlive: false, death: createFakePlayerVoteBySurvivorsDeath() }),\n ],\n turn: 1,\n phase: createFakeGamePhase({ name: \"day\" }),\n }),\n expected: false,\n },\n {\n test: \"should return true when angel is dead from eaten cause.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeAngelAlivePlayer({ isAlive: false, death: createFakePlayerEatenByWerewolvesDeath() }),\n ],\n turn: 1,\n }),\n expected: true,\n },\n {\n test: \"should return true when angel is dead from vote cause.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer(),\n createFakeSeerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeAngelAlivePlayer({ isAlive: false, death: createFakePlayerVoteBySurvivorsDeath() }),\n ],\n turn: 1,\n phase: createFakeGamePhase({ name: \"night\" }),\n }),\n expected: true,\n },\n ])(\"$test\", ({ game, expected }) => {\n expect(services.gameVictory[\"doesAngelWin\"](game)).toBe(expected);\n });\n });\n\n describe(\"doesPrejudicedManipulatorWin\", () => {\n it.each<{\n test: string;\n game: Game;\n expected: boolean;\n }>([\n {\n test: \"should return false when no players are provided.\",\n game: createFakeGame(),\n expected: false,\n },\n {\n test: \"should return false when there is no prejudiced manipulator among players.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer({ group: \"boy\" }),\n createFakeSeerAlivePlayer({ group: \"boy\" }),\n createFakeVillagerAlivePlayer({ group: \"boy\" }),\n createFakeVillagerAlivePlayer({ group: \"girl\", isAlive: false }),\n ],\n }),\n expected: false,\n },\n {\n test: \"should return false when prejudiced manipulator is dead.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer({ group: \"boy\" }),\n createFakeSeerAlivePlayer({ group: \"boy\" }),\n createFakePrejudicedManipulatorAlivePlayer({ group: \"boy\", isAlive: false }),\n createFakeVillagerAlivePlayer({ group: \"girl\", isAlive: false }),\n ],\n }),\n expected: false,\n },\n {\n test: \"should return false when prejudiced manipulator is powerless.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer({ group: \"boy\" }),\n createFakeSeerAlivePlayer({ group: \"boy\" }),\n createFakePrejudicedManipulatorAlivePlayer({ group: \"boy\", attributes: [createFakePowerlessByElderPlayerAttribute()] }),\n createFakeVillagerAlivePlayer({ group: \"girl\", isAlive: false }),\n ],\n }),\n expected: false,\n },\n {\n test: \"should return false when one of the prejudiced manipulator's other group is still alive.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer({ group: \"boy\" }),\n createFakeSeerAlivePlayer({ group: \"girl\" }),\n createFakePrejudicedManipulatorAlivePlayer({ group: \"boy\" }),\n createFakeVillagerAlivePlayer({ group: \"girl\", isAlive: false }),\n ],\n }),\n expected: false,\n },\n {\n test: \"should return true when every one of the prejudiced manipulator's other group is dead.\",\n game: createFakeGame({\n players: [\n createFakeWerewolfAlivePlayer({ group: \"boy\" }),\n createFakeSeerAlivePlayer({ group: \"girl\", isAlive: false }),\n createFakePrejudicedManipulatorAlivePlayer({ group: \"boy\" }),\n createFakeVillagerAlivePlayer({ group: \"girl\", isAlive: false }),\n ],\n }),\n expected: true,\n },\n ])(\"$test\", ({ game, expected }) => {\n expect(services.gameVictory[\"doesPrejudicedManipulatorWin\"](game)).toBe(expected);\n });\n });\n});" }, "tests/unit/specs/modules/game/providers/services/game.service.spec.ts": { "tests": [ @@ -196158,7 +196160,7 @@ } } ], - "source": "import { GameHistoryRecordRepository } from \"@/modules/game/providers/repositories/game-history-record/game-history-record.repository\";\nimport { GameEventsGeneratorService } from \"@/modules/game/providers/services/game-event/game-events-generator.service\";\nimport { GameFeedbackService } from \"@/modules/game/providers/services/game-feedback/game-feedback.service\";\nimport { GameHistoryRecordToInsertGeneratorService } from \"@/modules/game/providers/services/game-history/game-history-record-to-insert-generator.service\";\nimport type { TestingModule } from \"@nestjs/testing\";\nimport { Test } from \"@nestjs/testing\";\n\nimport * as GamePhaseHelper from \"@/modules/game/helpers/game-phase/game-phase.helpers\";\nimport * as GamePlayHelper from \"@/modules/game/helpers/game-play/game-play.helpers\";\nimport { GameRepository } from \"@/modules/game/providers/repositories/game.repository\";\nimport { GameHistoryRecordService } from \"@/modules/game/providers/services/game-history/game-history-record.service\";\nimport { GamePhaseService } from \"@/modules/game/providers/services/game-phase/game-phase.service\";\nimport { GamePlayMakerService } from \"@/modules/game/providers/services/game-play/game-play-maker/game-play-maker.service\";\nimport { GamePlayValidatorService } from \"@/modules/game/providers/services/game-play/game-play-validator.service\";\nimport { GamePlayVoteService } from \"@/modules/game/providers/services/game-play/game-play-vote/game-play-vote.service\";\nimport { GamePlayService } from \"@/modules/game/providers/services/game-play/game-play.service\";\nimport { GameVictoryService } from \"@/modules/game/providers/services/game-victory/game-victory.service\";\nimport { GameService } from \"@/modules/game/providers/services/game.service\";\nimport { PlayerAttributeService } from \"@/modules/game/providers/services/player/player-attribute.service\";\nimport type { Game } from \"@/modules/game/schemas/game.schema\";\n\nimport { ApiResources } from \"@/shared/api/enums/api.enums\";\nimport { BadResourceMutationReasons } from \"@/shared/exception/enums/bad-resource-mutation-error.enum\";\nimport { UnexpectedExceptionReasons } from \"@/shared/exception/enums/unexpected-exception.enum\";\nimport { BadResourceMutationException } from \"@/shared/exception/types/bad-resource-mutation-exception.types\";\nimport { ResourceNotFoundException } from \"@/shared/exception/types/resource-not-found-exception.types\";\nimport { UnexpectedException } from \"@/shared/exception/types/unexpected-exception.types\";\nimport { createFakeCreateGameFeedbackDto } from \"@tests/factories/game/dto/create-game-feedback/create-game-feedback.dto.factory\";\nimport { createFakeCreateGamePlayerDto } from \"@tests/factories/game/dto/create-game/create-game-player/create-game-player.dto.factory\";\n\nimport { createFakeCreateGameDto } from \"@tests/factories/game/dto/create-game/create-game.dto.factory\";\nimport { createFakeMakeGamePlayWithRelationsDto } from \"@tests/factories/game/dto/make-game-play/make-game-play-with-relations/make-game-play-with-relations.dto.factory\";\nimport { createFakeMakeGamePlayDto } from \"@tests/factories/game/dto/make-game-play/make-game-play.dto.factory\";\nimport { createFakeGameFeedback } from \"@tests/factories/game/schemas/game-feedback/game-feedback.factory\";\nimport { createFakeGameHistoryRecord } from \"@tests/factories/game/schemas/game-history-record/game-history-record.schema.factory\";\nimport { createFakeGamePhase } from \"@tests/factories/game/schemas/game-phase/game-phase.schema.factory\";\nimport { createFakeGamePlaySurvivorsVote } from \"@tests/factories/game/schemas/game-play/game-play.schema.factory\";\nimport { createFakeGameVictory } from \"@tests/factories/game/schemas/game-victory/game-victory.schema.factory\";\nimport { createFakeGame, createFakeGameWithCurrentPlay } from \"@tests/factories/game/schemas/game.schema.factory\";\nimport { createFakeVillagerAlivePlayer, createFakeWerewolfAlivePlayer } from \"@tests/factories/game/schemas/player/player-with-role.schema.factory\";\nimport { createFakeGameHistoryRecordToInsert } from \"@tests/factories/game/types/game-history-record/game-history-record.type.factory\";\nimport { createFakeObjectId } from \"@tests/factories/shared/mongoose/mongoose.factory\";\nimport { getError } from \"@tests/helpers/exception/exception.helpers\";\n\ndescribe(\"Game Service\", () => {\n let mocks: {\n gameService: {\n handleTwilightPhaseCompletion: jest.SpyInstance;\n handleGamePhaseCompletion: jest.SpyInstance;\n updateGame: jest.SpyInstance;\n setGameAsOver: jest.SpyInstance;\n };\n gameRepository: {\n find: jest.SpyInstance;\n findOne: jest.SpyInstance;\n create: jest.SpyInstance;\n updateOne: jest.SpyInstance;\n };\n gameHistoryRecordService: {\n createGameHistoryRecord: jest.SpyInstance;\n };\n gameHistoryRecordToInsertGeneratorService: { generateCurrentGameHistoryRecordToInsert: jest.SpyInstance };\n gamePlayService: {\n getPhaseUpcomingPlays: jest.SpyInstance;\n proceedToNextGamePlay: jest.SpyInstance;\n refreshUpcomingPlays: jest.SpyInstance;\n augmentCurrentGamePlay: jest.SpyInstance;\n };\n gamePlayValidatorService: { validateGamePlayWithRelationsDto: jest.SpyInstance };\n gamePlayMakerService: { makeGamePlay: jest.SpyInstance };\n gamePhaseService: {\n applyEndingGamePhaseOutcomes: jest.SpyInstance;\n switchPhaseAndAppendGamePhaseUpcomingPlays: jest.SpyInstance;\n applyStartingGamePhaseOutcomes: jest.SpyInstance;\n isTwilightPhaseOver: jest.SpyInstance;\n };\n gameVictoryService: {\n isGameOver: jest.SpyInstance;\n generateGameVictoryData: jest.SpyInstance;\n };\n playerAttributeService: {\n decreaseRemainingPhasesAndRemoveObsoletePlayerAttributes: jest.SpyInstance;\n };\n gameEventsGeneratorService: { generateGameEventsFromGameAndLastRecord: jest.SpyInstance };\n gameFeedbackService: { createGameFeedback: jest.SpyInstance };\n gamePhaseHelper: { isGamePhaseOver: jest.SpyInstance };\n gamePlayHelper: { createMakeGamePlayDtoWithRelations: jest.SpyInstance };\n };\n let services: { game: GameService };\n let repositories: { game: GameRepository };\n\n beforeEach(async() => {\n mocks = {\n gameService: {\n handleTwilightPhaseCompletion: jest.fn(),\n handleGamePhaseCompletion: jest.fn(),\n updateGame: jest.fn(),\n setGameAsOver: jest.fn(),\n },\n gameRepository: {\n find: jest.fn(),\n findOne: jest.fn(),\n create: jest.fn(),\n updateOne: jest.fn(),\n },\n gameHistoryRecordService: {\n createGameHistoryRecord: jest.fn(),\n },\n gameHistoryRecordToInsertGeneratorService: { generateCurrentGameHistoryRecordToInsert: jest.fn() },\n gamePlayService: {\n getPhaseUpcomingPlays: jest.fn(),\n proceedToNextGamePlay: jest.fn(),\n refreshUpcomingPlays: jest.fn(),\n augmentCurrentGamePlay: jest.fn(),\n },\n gamePlayValidatorService: { validateGamePlayWithRelationsDto: jest.fn() },\n gamePlayMakerService: { makeGamePlay: jest.fn() },\n gamePhaseService: {\n applyEndingGamePhaseOutcomes: jest.fn(),\n switchPhaseAndAppendGamePhaseUpcomingPlays: jest.fn(),\n applyStartingGamePhaseOutcomes: jest.fn(),\n isTwilightPhaseOver: jest.fn(),\n },\n gameVictoryService: {\n isGameOver: jest.fn(),\n generateGameVictoryData: jest.fn(),\n },\n gameEventsGeneratorService: { generateGameEventsFromGameAndLastRecord: jest.fn() },\n gameFeedbackService: { createGameFeedback: jest.fn() },\n playerAttributeService: { decreaseRemainingPhasesAndRemoveObsoletePlayerAttributes: jest.fn() },\n gamePhaseHelper: { isGamePhaseOver: jest.spyOn(GamePhaseHelper, \"isGamePhaseOver\").mockImplementation() },\n gamePlayHelper: { createMakeGamePlayDtoWithRelations: jest.spyOn(GamePlayHelper, \"createMakeGamePlayDtoWithRelations\").mockImplementation() },\n };\n\n const module: TestingModule = await Test.createTestingModule({\n providers: [\n {\n provide: GameRepository,\n useValue: mocks.gameRepository,\n },\n {\n provide: GameHistoryRecordService,\n useValue: mocks.gameHistoryRecordService,\n },\n {\n provide: GameHistoryRecordToInsertGeneratorService,\n useValue: mocks.gameHistoryRecordToInsertGeneratorService,\n },\n {\n provide: GamePlayService,\n useValue: mocks.gamePlayService,\n },\n {\n provide: GamePlayValidatorService,\n useValue: mocks.gamePlayValidatorService,\n },\n {\n provide: GamePlayMakerService,\n useValue: mocks.gamePlayMakerService,\n },\n {\n provide: GamePhaseService,\n useValue: mocks.gamePhaseService,\n },\n {\n provide: GameVictoryService,\n useValue: mocks.gameVictoryService,\n },\n {\n provide: PlayerAttributeService,\n useValue: mocks.playerAttributeService,\n },\n {\n provide: GameEventsGeneratorService,\n useValue: mocks.gameEventsGeneratorService,\n },\n {\n provide: GameFeedbackService,\n useValue: mocks.gameFeedbackService,\n },\n {\n provide: GameHistoryRecordRepository,\n useValue: {},\n },\n GamePlayVoteService,\n GameService,\n ],\n }).compile();\n\n services = { game: module.get(GameService) };\n repositories = { game: module.get(GameRepository) };\n });\n\n describe(\"getGames\", () => {\n it(\"should get all games when called.\", async() => {\n await services.game.getGames();\n\n expect(repositories.game.find).toHaveBeenCalledExactlyOnceWith();\n });\n });\n\n describe(\"createGame\", () => {\n const createdGame = createFakeGameWithCurrentPlay({ phase: createFakeGamePhase({ name: \"twilight\", tick: 1 }) });\n\n beforeEach(() => {\n mocks.gamePlayService.augmentCurrentGamePlay.mockReturnValue(createdGame);\n mocks.gameRepository.create.mockResolvedValue(createdGame);\n mocks.gameService.updateGame = jest.spyOn(services.game as unknown as { updateGame }, \"updateGame\").mockResolvedValue(createdGame);\n });\n\n it(\"should throw error when can't generate upcoming plays.\", async() => {\n mocks.gamePlayService.getPhaseUpcomingPlays.mockReturnValue([]);\n const toCreateGame = createFakeCreateGameDto();\n const exceptedError = new UnexpectedException(\"createGame\", UnexpectedExceptionReasons.CANT_GENERATE_GAME_PLAYS);\n const error = await getError(async() => services.game.createGame(toCreateGame));\n\n expect(error).toStrictEqual(exceptedError);\n expect(error).toHaveProperty(\"options\", { description: \"Can't generate game plays\" });\n });\n\n it(\"should call createGame repository method when called.\", async() => {\n const toCreateGame = createFakeCreateGameDto();\n mocks.gamePlayService.getPhaseUpcomingPlays.mockReturnValue([createFakeGamePlaySurvivorsVote()]);\n await services.game.createGame(toCreateGame);\n const expectedGame = createFakeCreateGameDto({\n ...toCreateGame,\n currentPlay: createFakeGamePlaySurvivorsVote(),\n upcomingPlays: [],\n });\n\n expect(repositories.game.create).toHaveBeenCalledExactlyOnceWith(expectedGame);\n });\n\n it(\"should call createGame repository method with distinct player groups when player have groups.\", async() => {\n const toCreateGame = createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ group: \"group1\" }),\n createFakeCreateGamePlayerDto({ group: \"group2\" }),\n ],\n });\n mocks.gamePlayService.getPhaseUpcomingPlays.mockReturnValue([createFakeGamePlaySurvivorsVote()]);\n await services.game.createGame(toCreateGame);\n const expectedGame = createFakeCreateGameDto({\n ...toCreateGame,\n currentPlay: createFakeGamePlaySurvivorsVote(),\n upcomingPlays: [],\n playerGroups: [\"group1\", \"group2\"],\n });\n\n expect(repositories.game.create).toHaveBeenCalledExactlyOnceWith(expectedGame);\n });\n\n it(\"should call augmentCurrentGamePlay method when called.\", async() => {\n const toCreateGame = createFakeCreateGameDto();\n mocks.gamePlayService.getPhaseUpcomingPlays.mockReturnValue([createFakeGamePlaySurvivorsVote()]);\n await services.game.createGame(toCreateGame);\n\n expect(mocks.gamePlayService.augmentCurrentGamePlay).toHaveBeenCalledExactlyOnceWith(createdGame);\n });\n\n it(\"should set game phase as night when twilight phase is over.\", async() => {\n const toCreateGame = createFakeCreateGameDto();\n mocks.gamePlayService.getPhaseUpcomingPlays.mockReturnValue([createFakeGamePlaySurvivorsVote()]);\n mocks.gamePhaseService.isTwilightPhaseOver.mockReturnValue(true);\n await services.game.createGame(toCreateGame);\n const expectedGame = createFakeGameWithCurrentPlay({\n ...createdGame,\n phase: createFakeGamePhase({\n ...createdGame.phase,\n name: \"night\",\n }),\n });\n\n expect(mocks.gameService.updateGame).toHaveBeenCalledExactlyOnceWith(createdGame._id, expectedGame);\n });\n\n it(\"should not set game phase as night when twilight phase is not over.\", async() => {\n const toCreateGame = createFakeCreateGameDto();\n mocks.gamePlayService.getPhaseUpcomingPlays.mockReturnValue([createFakeGamePlaySurvivorsVote()]);\n mocks.gamePhaseService.isTwilightPhaseOver.mockReturnValue(false);\n await services.game.createGame(toCreateGame);\n\n expect(mocks.gameService.updateGame).toHaveBeenCalledExactlyOnceWith(createdGame._id, createdGame);\n });\n\n it(\"should call generate game events method when called.\", async() => {\n const toCreateGame = createFakeCreateGameDto();\n mocks.gamePlayService.getPhaseUpcomingPlays.mockReturnValue([createFakeGamePlaySurvivorsVote()]);\n await services.game.createGame(toCreateGame);\n\n expect(mocks.gameEventsGeneratorService.generateGameEventsFromGameAndLastRecord).toHaveBeenCalledExactlyOnceWith(createdGame);\n });\n\n it(\"should call updateGame repository method when called.\", async() => {\n const toCreateGame = createFakeCreateGameDto();\n mocks.gamePlayService.getPhaseUpcomingPlays.mockReturnValue([createFakeGamePlaySurvivorsVote()]);\n await services.game.createGame(toCreateGame);\n\n expect(mocks.gameService.updateGame).toHaveBeenCalledExactlyOnceWith(createdGame._id, createdGame);\n });\n });\n\n describe(\"cancelGame\", () => {\n const existingPlayingGame = createFakeGame({ status: \"playing\" });\n\n beforeEach(() => {\n mocks.gameService.updateGame = jest.spyOn(services.game as unknown as { updateGame }, \"updateGame\").mockResolvedValue(existingPlayingGame);\n });\n\n it(\"should throw error when game is not playing.\", async() => {\n const canceledGame = createFakeGame({ status: \"canceled\" });\n const expectedException = new BadResourceMutationException(ApiResources.GAMES, canceledGame._id.toString(), BadResourceMutationReasons.GAME_NOT_PLAYING);\n const error = await getError(async() => services.game.cancelGame(canceledGame));\n\n expect(error).toStrictEqual(expectedException);\n expect(error).toHaveProperty(\"options\", { description: \"Game doesn't have status with value \\\"playing\\\"\" });\n });\n\n it(\"should call update method when game can be canceled.\", async() => {\n await services.game.cancelGame(existingPlayingGame);\n\n expect(mocks.gameService.updateGame).toHaveBeenCalledExactlyOnceWith(existingPlayingGame._id, { status: \"canceled\" });\n });\n });\n\n describe(\"makeGamePlay\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({ status: \"playing\", players, currentPlay: createFakeGamePlaySurvivorsVote() });\n const play = createFakeMakeGamePlayWithRelationsDto();\n\n beforeEach(() => {\n mocks.gamePlayHelper.createMakeGamePlayDtoWithRelations.mockReturnValue(play);\n mocks.gamePlayMakerService.makeGamePlay.mockResolvedValue(game);\n mocks.gamePlayService.refreshUpcomingPlays.mockReturnValue(game);\n mocks.gamePlayService.proceedToNextGamePlay.mockReturnValue(game);\n mocks.gamePlayService.augmentCurrentGamePlay.mockReturnValue(game);\n mocks.gameVictoryService.isGameOver.mockReturnValue(false);\n mocks.gameService.handleTwilightPhaseCompletion = jest.spyOn(services.game as unknown as { handleTwilightPhaseCompletion }, \"handleTwilightPhaseCompletion\").mockReturnValue(game);\n mocks.gameService.handleGamePhaseCompletion = jest.spyOn(services.game as unknown as { handleGamePhaseCompletion }, \"handleGamePhaseCompletion\").mockResolvedValue(game);\n mocks.gameService.updateGame = jest.spyOn(services.game as unknown as { updateGame }, \"updateGame\").mockReturnValue(game);\n mocks.gameService.setGameAsOver = jest.spyOn(services.game as unknown as { setGameAsOver }, \"setGameAsOver\").mockReturnValue(game);\n });\n\n it(\"should throw an error when game is not playing.\", async() => {\n const makeGamePlayDto = createFakeMakeGamePlayDto();\n const canceledGame = createFakeGame({ status: \"canceled\" });\n const expectedException = new BadResourceMutationException(ApiResources.GAMES, canceledGame._id.toString(), BadResourceMutationReasons.GAME_NOT_PLAYING);\n const error = await getError(async() => services.game.makeGamePlay(canceledGame, makeGamePlayDto));\n\n expect(error).toStrictEqual(expectedException);\n expect(error).toHaveProperty(\"options\", { description: \"Game doesn't have status with value \\\"playing\\\"\" });\n });\n\n it(\"should call play validator method when called.\", async() => {\n const clonedGame = createFakeGame(game);\n const makeGamePlayDto = createFakeMakeGamePlayDto();\n await services.game.makeGamePlay(clonedGame, makeGamePlayDto);\n\n expect(mocks.gamePlayValidatorService.validateGamePlayWithRelationsDto).toHaveBeenCalledExactlyOnceWith(play, clonedGame);\n });\n\n it(\"should call play maker method when called.\", async() => {\n const clonedGame = createFakeGame(game);\n const makeGamePlayDto = createFakeMakeGamePlayDto();\n await services.game.makeGamePlay(clonedGame, makeGamePlayDto);\n\n expect(mocks.gamePlayMakerService.makeGamePlay).toHaveBeenCalledExactlyOnceWith(play, clonedGame);\n });\n\n it(\"should call remove obsolete upcoming plays method when called.\", async() => {\n const clonedGame = createFakeGame(game);\n const makeGamePlayDto = createFakeMakeGamePlayDto();\n await services.game.makeGamePlay(clonedGame, makeGamePlayDto);\n\n expect(mocks.gamePlayService.refreshUpcomingPlays).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call proceed to next game play method when called.\", async() => {\n const clonedGame = createFakeGame(game);\n const makeGamePlayDto = createFakeMakeGamePlayDto();\n await services.game.makeGamePlay(clonedGame, makeGamePlayDto);\n\n expect(mocks.gamePlayService.proceedToNextGamePlay).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should handle twilight phase completion when phase is twilight and phase is over.\", async() => {\n const clonedGame = createFakeGame({\n ...game,\n phase: createFakeGamePhase({ name: \"twilight\", tick: 1 }),\n });\n const makeGamePlayDto = createFakeMakeGamePlayDto();\n mocks.gamePhaseService.isTwilightPhaseOver.mockReturnValue(true);\n await services.game.makeGamePlay(clonedGame, makeGamePlayDto);\n\n expect(mocks.gameService.handleTwilightPhaseCompletion).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should not handle twilight phase completion when phase is not twilight.\", async() => {\n const clonedGame = createFakeGame({\n ...game,\n phase: createFakeGamePhase({ name: \"night\", tick: 1 }),\n });\n mocks.gamePhaseService.isTwilightPhaseOver.mockReturnValue(true);\n const makeGamePlayDto = createFakeMakeGamePlayDto();\n await services.game.makeGamePlay(clonedGame, makeGamePlayDto);\n\n expect(mocks.gameService.handleTwilightPhaseCompletion).not.toHaveBeenCalled();\n });\n\n it(\"should not handle twilight phase completion when phase is not over.\", async() => {\n const clonedGame = createFakeGame({\n ...game,\n phase: createFakeGamePhase({ name: \"twilight\", tick: 1 }),\n });\n mocks.gamePhaseService.isTwilightPhaseOver.mockReturnValue(false);\n const makeGamePlayDto = createFakeMakeGamePlayDto();\n await services.game.makeGamePlay(clonedGame, makeGamePlayDto);\n\n expect(mocks.gameService.handleTwilightPhaseCompletion).not.toHaveBeenCalled();\n });\n\n it(\"should call handle game phase completion method when phase is ending.\", async() => {\n const clonedGame = createFakeGame(game);\n mocks.gamePhaseHelper.isGamePhaseOver.mockReturnValue(true);\n const makeGamePlayDto = createFakeMakeGamePlayDto();\n await services.game.makeGamePlay(clonedGame, makeGamePlayDto);\n\n expect(mocks.gameService.handleGamePhaseCompletion).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call generate current game history record method when called.\", async() => {\n const clonedGame = createFakeGame(game);\n const makeGamePlayDto = createFakeMakeGamePlayDto();\n await services.game.makeGamePlay(clonedGame, makeGamePlayDto);\n\n expect(mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordToInsert).toHaveBeenCalledExactlyOnceWith(clonedGame, game, play);\n });\n\n it(\"should call createGameHistoryRecord method when called.\", async() => {\n const clonedGame = createFakeGame(game);\n const makeGamePlayDto = createFakeMakeGamePlayDto();\n const currentGameHistoryRecordToInsert = createFakeGameHistoryRecordToInsert();\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordToInsert.mockReturnValue(currentGameHistoryRecordToInsert);\n await services.game.makeGamePlay(clonedGame, makeGamePlayDto);\n\n expect(mocks.gameHistoryRecordService.createGameHistoryRecord).toHaveBeenCalledExactlyOnceWith(currentGameHistoryRecordToInsert);\n });\n\n it(\"should call update method when called.\", async() => {\n const makeGamePlayDto = createFakeMakeGamePlayDto();\n await services.game.makeGamePlay(game, makeGamePlayDto);\n\n expect(mocks.gameService.updateGame).toHaveBeenCalledExactlyOnceWith(game._id, game);\n });\n\n it(\"should call set game over method when the game is done.\", async() => {\n const makeGamePlayDto = createFakeMakeGamePlayDto();\n const gameVictoryData = createFakeGameVictory();\n mocks.gameVictoryService.isGameOver.mockReturnValue(true);\n mocks.gameVictoryService.generateGameVictoryData.mockReturnValue(gameVictoryData);\n mocks.gamePlayMakerService.makeGamePlay.mockReturnValue(game);\n mocks.gamePlayService.proceedToNextGamePlay.mockReturnValue(game);\n mocks.gamePlayService.refreshUpcomingPlays.mockReturnValue(game.upcomingPlays);\n await services.game.makeGamePlay(game, makeGamePlayDto);\n\n expect(mocks.gameService.setGameAsOver).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should augment current game play when the game is not over.\", async() => {\n const makeGamePlayDto = createFakeMakeGamePlayDto();\n await services.game.makeGamePlay(game, makeGamePlayDto);\n\n expect(mocks.gamePlayService.augmentCurrentGamePlay).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should not augment current game play when the game is over.\", async() => {\n const makeGamePlayDto = createFakeMakeGamePlayDto();\n mocks.gameVictoryService.isGameOver.mockReturnValue(true);\n await services.game.makeGamePlay(game, makeGamePlayDto);\n\n expect(mocks.gamePlayService.augmentCurrentGamePlay).not.toHaveBeenCalled();\n });\n\n it(\"should generate game events when the game is not over.\", async() => {\n const makeGamePlayDto = createFakeMakeGamePlayDto();\n const gameHistoryRecord = createFakeGameHistoryRecord();\n mocks.gameHistoryRecordService.createGameHistoryRecord.mockResolvedValue(gameHistoryRecord);\n await services.game.makeGamePlay(game, makeGamePlayDto);\n\n expect(mocks.gameEventsGeneratorService.generateGameEventsFromGameAndLastRecord).toHaveBeenCalledExactlyOnceWith(game, gameHistoryRecord);\n });\n });\n\n describe(\"createGameFeedback\", () => {\n it(\"should create game feedback when called.\", async() => {\n const game = createFakeGame();\n const createGameFeedbackDto = createFakeCreateGameFeedbackDto();\n const updatedGame = await services.game.createGameFeedback(game, createGameFeedbackDto);\n\n expect(mocks.gameFeedbackService.createGameFeedback).toHaveBeenCalledExactlyOnceWith(updatedGame, createGameFeedbackDto);\n });\n\n it(\"should return game with feedback when called.\", async() => {\n const game = createFakeGame();\n const createGameFeedbackDto = createFakeCreateGameFeedbackDto();\n const feedback = createFakeGameFeedback();\n mocks.gameFeedbackService.createGameFeedback.mockResolvedValue(feedback);\n const expectedGame = createFakeGame({\n ...game,\n feedback,\n });\n\n await expect(services.game.createGameFeedback(game, createGameFeedbackDto)).resolves.toStrictEqual(expectedGame);\n });\n });\n\n describe(\"validateGameIsPlaying\", () => {\n it(\"should throw error when game is not playing.\", async() => {\n const game = createFakeGame({ status: \"canceled\" });\n const expectedError = new BadResourceMutationException(ApiResources.GAMES, game._id.toString(), BadResourceMutationReasons.GAME_NOT_PLAYING);\n const error = await getError(() => services.game[\"validateGameIsPlaying\"](game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Game doesn't have status with value \\\"playing\\\"\" });\n });\n\n it(\"should not throw error when game is playing.\", () => {\n const game = createFakeGame({ status: \"playing\" });\n\n expect(() => services.game[\"validateGameIsPlaying\"](game)).not.toThrow();\n });\n });\n\n describe(\"handleTwilightPhaseCompletion\", () => {\n const game = createFakeGame({ phase: createFakeGamePhase({ name: \"twilight\", tick: 133 }) });\n\n it(\"should set game phase as night and reset tick when called.\", () => {\n const expectedGame = createFakeGame({\n ...game,\n phase: createFakeGamePhase({ name: \"night\", tick: 1 }),\n });\n\n expect(services.game[\"handleTwilightPhaseCompletion\"](game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"handleGamePhaseCompletion\", () => {\n const game = createFakeGame();\n\n beforeEach(() => {\n mocks.gamePhaseService.applyEndingGamePhaseOutcomes.mockResolvedValue(game);\n mocks.playerAttributeService.decreaseRemainingPhasesAndRemoveObsoletePlayerAttributes.mockReturnValue(game);\n mocks.gamePhaseService.switchPhaseAndAppendGamePhaseUpcomingPlays.mockReturnValue(game);\n mocks.gamePhaseService.applyStartingGamePhaseOutcomes.mockReturnValue(game);\n mocks.gamePlayService.proceedToNextGamePlay.mockReturnValue(game);\n mocks.gamePlayService.refreshUpcomingPlays.mockReturnValue(game);\n });\n\n it(\"should call apply ending phase outcomes method when called.\", async() => {\n await services.game[\"handleGamePhaseCompletion\"](game);\n\n expect(mocks.gamePhaseService.applyEndingGamePhaseOutcomes).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call decrease remaining phases attributes to players method when called.\", async() => {\n await services.game[\"handleGamePhaseCompletion\"](game);\n\n expect(mocks.playerAttributeService.decreaseRemainingPhasesAndRemoveObsoletePlayerAttributes).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call switch phase method when called.\", async() => {\n await services.game[\"handleGamePhaseCompletion\"](game);\n\n expect(mocks.gamePhaseService.switchPhaseAndAppendGamePhaseUpcomingPlays).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call apply starting phase outcomes method when called.\", async() => {\n await services.game[\"handleGamePhaseCompletion\"](game);\n\n expect(mocks.gamePhaseService.applyStartingGamePhaseOutcomes).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call proceed to next game play method when called.\", async() => {\n await services.game[\"handleGamePhaseCompletion\"](game);\n\n expect(mocks.gamePlayService.proceedToNextGamePlay).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should not call handle game phase completion method when phase is not ending.\", async() => {\n mocks.gamePhaseHelper.isGamePhaseOver.mockReturnValue(false);\n const handleGamePhaseCompletionSpy = jest.spyOn(services.game as unknown as { handleGamePhaseCompletion }, \"handleGamePhaseCompletion\");\n await services.game[\"handleGamePhaseCompletion\"](game);\n\n expect(handleGamePhaseCompletionSpy).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call handle game phase completion method when phase is ending.\", async() => {\n mocks.gamePhaseHelper.isGamePhaseOver.mockReturnValue(false);\n mocks.gamePhaseHelper.isGamePhaseOver.mockReturnValueOnce(true);\n const handleGamePhaseCompletionSpy = jest.spyOn(services.game as unknown as { handleGamePhaseCompletion }, \"handleGamePhaseCompletion\");\n await services.game[\"handleGamePhaseCompletion\"](game);\n\n expect(handleGamePhaseCompletionSpy).toHaveBeenCalledTimes(2);\n expect(handleGamePhaseCompletionSpy).toHaveBeenNthCalledWith(1, game);\n expect(handleGamePhaseCompletionSpy).toHaveBeenNthCalledWith(2, game);\n });\n });\n\n describe(\"updateGame\", () => {\n it(\"should throw an error when game not found by update repository method.\", async() => {\n const unknownObjectId = createFakeObjectId();\n mocks.gameRepository.updateOne.mockResolvedValue(null);\n const expectedError = new ResourceNotFoundException(ApiResources.GAMES, unknownObjectId.toString());\n const error = await getError(async() => services.game[\"updateGame\"](unknownObjectId, { status: \"over\" }));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: undefined });\n });\n\n it(\"should return updated game when called.\", async() => {\n const game = createFakeGame();\n const gameDataToUpdate: Partial = { status: \"over\" };\n mocks.gameRepository.updateOne.mockResolvedValue(game);\n\n await expect(services.game[\"updateGame\"](game._id, gameDataToUpdate)).resolves.toStrictEqual(game);\n expect(mocks.gameRepository.updateOne).toHaveBeenCalledExactlyOnceWith({ _id: game._id }, gameDataToUpdate);\n });\n });\n\n describe(\"setGameAsOver\", () => {\n it(\"should set game as over when called.\", () => {\n const game = createFakeGame({ status: \"playing\" });\n const gameVictoryData = createFakeGameVictory();\n mocks.gameVictoryService.generateGameVictoryData.mockReturnValue(gameVictoryData);\n const expectedGame = createFakeGame({\n ...game,\n status: \"over\",\n victory: gameVictoryData,\n });\n\n expect(services.game[\"setGameAsOver\"](game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"updateGameAsOver\", () => {\n beforeEach(() => {\n mocks.gameService.setGameAsOver = jest.spyOn(services.game as unknown as { setGameAsOver }, \"setGameAsOver\").mockImplementation();\n mocks.gameService.updateGame = jest.spyOn(services.game as unknown as { updateGame }, \"updateGame\").mockImplementation();\n });\n\n it(\"should set game as over when called.\", async() => {\n const game = createFakeGame();\n mocks.gameService.setGameAsOver.mockReturnValue(game);\n await services.game[\"updateGameAsOver\"](game);\n\n expect(mocks.gameService.setGameAsOver).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call update game when called.\", async() => {\n const game = createFakeGame();\n mocks.gameService.setGameAsOver.mockReturnValue(game);\n await services.game[\"updateGameAsOver\"](game);\n\n expect(mocks.gameService.updateGame).toHaveBeenCalledExactlyOnceWith(game._id, game);\n });\n });\n});" + "source": "import type { TestingModule } from \"@nestjs/testing\";\nimport { Test } from \"@nestjs/testing\";\n\nimport { GameHistoryRecordRepository } from \"@/modules/game/providers/repositories/game-history-record/game-history-record.repository\";\nimport { GameEventsGeneratorService } from \"@/modules/game/providers/services/game-event/game-events-generator.service\";\nimport { GameFeedbackService } from \"@/modules/game/providers/services/game-feedback/game-feedback.service\";\nimport { GameHistoryRecordToInsertGeneratorService } from \"@/modules/game/providers/services/game-history/game-history-record-to-insert-generator.service\";\nimport * as GamePhaseHelper from \"@/modules/game/helpers/game-phase/game-phase.helpers\";\nimport * as GamePlayHelper from \"@/modules/game/helpers/game-play/game-play.helpers\";\nimport { GameRepository } from \"@/modules/game/providers/repositories/game.repository\";\nimport { GameHistoryRecordService } from \"@/modules/game/providers/services/game-history/game-history-record.service\";\nimport { GamePhaseService } from \"@/modules/game/providers/services/game-phase/game-phase.service\";\nimport { GamePlayMakerService } from \"@/modules/game/providers/services/game-play/game-play-maker/game-play-maker.service\";\nimport { GamePlayValidatorService } from \"@/modules/game/providers/services/game-play/game-play-validator.service\";\nimport { GamePlayVoteService } from \"@/modules/game/providers/services/game-play/game-play-vote/game-play-vote.service\";\nimport { GamePlayService } from \"@/modules/game/providers/services/game-play/game-play.service\";\nimport { GameVictoryService } from \"@/modules/game/providers/services/game-victory/game-victory.service\";\nimport { GameService } from \"@/modules/game/providers/services/game.service\";\nimport { PlayerAttributeService } from \"@/modules/game/providers/services/player/player-attribute.service\";\nimport type { Game } from \"@/modules/game/schemas/game.schema\";\n\nimport { ApiResources } from \"@/shared/api/enums/api.enums\";\nimport { BadResourceMutationReasons } from \"@/shared/exception/enums/bad-resource-mutation-error.enums\";\nimport { UnexpectedExceptionReasons } from \"@/shared/exception/enums/unexpected-exception.enums\";\nimport { BadResourceMutationException } from \"@/shared/exception/types/bad-resource-mutation-exception.types\";\nimport { ResourceNotFoundException } from \"@/shared/exception/types/resource-not-found-exception.types\";\nimport { UnexpectedException } from \"@/shared/exception/types/unexpected-exception.types\";\n\nimport { createFakeCreateGameFeedbackDto } from \"@tests/factories/game/dto/create-game-feedback/create-game-feedback.dto.factory\";\nimport { createFakeCreateGamePlayerDto } from \"@tests/factories/game/dto/create-game/create-game-player/create-game-player.dto.factory\";\nimport { createFakeCreateGameDto } from \"@tests/factories/game/dto/create-game/create-game.dto.factory\";\nimport { createFakeMakeGamePlayWithRelationsDto } from \"@tests/factories/game/dto/make-game-play/make-game-play-with-relations/make-game-play-with-relations.dto.factory\";\nimport { createFakeMakeGamePlayDto } from \"@tests/factories/game/dto/make-game-play/make-game-play.dto.factory\";\nimport { createFakeGameFeedback } from \"@tests/factories/game/schemas/game-feedback/game-feedback.factory\";\nimport { createFakeGameHistoryRecord } from \"@tests/factories/game/schemas/game-history-record/game-history-record.schema.factory\";\nimport { createFakeGamePhase } from \"@tests/factories/game/schemas/game-phase/game-phase.schema.factory\";\nimport { createFakeGamePlaySurvivorsVote } from \"@tests/factories/game/schemas/game-play/game-play.schema.factory\";\nimport { createFakeGameVictory } from \"@tests/factories/game/schemas/game-victory/game-victory.schema.factory\";\nimport { createFakeGame, createFakeGameWithCurrentPlay } from \"@tests/factories/game/schemas/game.schema.factory\";\nimport { createFakeVillagerAlivePlayer, createFakeWerewolfAlivePlayer } from \"@tests/factories/game/schemas/player/player-with-role.schema.factory\";\nimport { createFakeGameHistoryRecordToInsert } from \"@tests/factories/game/types/game-history-record/game-history-record.type.factory\";\nimport { createFakeObjectId } from \"@tests/factories/shared/mongoose/mongoose.factory\";\nimport { getError } from \"@tests/helpers/exception/exception.helpers\";\n\ndescribe(\"Game Service\", () => {\n let mocks: {\n gameService: {\n handleTwilightPhaseCompletion: jest.SpyInstance;\n handleGamePhaseCompletion: jest.SpyInstance;\n updateGame: jest.SpyInstance;\n setGameAsOver: jest.SpyInstance;\n };\n gameRepository: {\n find: jest.SpyInstance;\n findOne: jest.SpyInstance;\n create: jest.SpyInstance;\n updateOne: jest.SpyInstance;\n };\n gameHistoryRecordService: {\n createGameHistoryRecord: jest.SpyInstance;\n };\n gameHistoryRecordToInsertGeneratorService: { generateCurrentGameHistoryRecordToInsert: jest.SpyInstance };\n gamePlayService: {\n getPhaseUpcomingPlays: jest.SpyInstance;\n proceedToNextGamePlay: jest.SpyInstance;\n refreshUpcomingPlays: jest.SpyInstance;\n augmentCurrentGamePlay: jest.SpyInstance;\n };\n gamePlayValidatorService: { validateGamePlayWithRelationsDto: jest.SpyInstance };\n gamePlayMakerService: { makeGamePlay: jest.SpyInstance };\n gamePhaseService: {\n applyEndingGamePhaseOutcomes: jest.SpyInstance;\n switchPhaseAndAppendGamePhaseUpcomingPlays: jest.SpyInstance;\n applyStartingGamePhaseOutcomes: jest.SpyInstance;\n isTwilightPhaseOver: jest.SpyInstance;\n };\n gameVictoryService: {\n isGameOver: jest.SpyInstance;\n generateGameVictoryData: jest.SpyInstance;\n };\n playerAttributeService: {\n decreaseRemainingPhasesAndRemoveObsoletePlayerAttributes: jest.SpyInstance;\n };\n gameEventsGeneratorService: { generateGameEventsFromGameAndLastRecord: jest.SpyInstance };\n gameFeedbackService: { createGameFeedback: jest.SpyInstance };\n gamePhaseHelper: { isGamePhaseOver: jest.SpyInstance };\n gamePlayHelper: { createMakeGamePlayDtoWithRelations: jest.SpyInstance };\n };\n let services: { game: GameService };\n let repositories: { game: GameRepository };\n\n beforeEach(async() => {\n mocks = {\n gameService: {\n handleTwilightPhaseCompletion: jest.fn(),\n handleGamePhaseCompletion: jest.fn(),\n updateGame: jest.fn(),\n setGameAsOver: jest.fn(),\n },\n gameRepository: {\n find: jest.fn(),\n findOne: jest.fn(),\n create: jest.fn(),\n updateOne: jest.fn(),\n },\n gameHistoryRecordService: {\n createGameHistoryRecord: jest.fn(),\n },\n gameHistoryRecordToInsertGeneratorService: { generateCurrentGameHistoryRecordToInsert: jest.fn() },\n gamePlayService: {\n getPhaseUpcomingPlays: jest.fn(),\n proceedToNextGamePlay: jest.fn(),\n refreshUpcomingPlays: jest.fn(),\n augmentCurrentGamePlay: jest.fn(),\n },\n gamePlayValidatorService: { validateGamePlayWithRelationsDto: jest.fn() },\n gamePlayMakerService: { makeGamePlay: jest.fn() },\n gamePhaseService: {\n applyEndingGamePhaseOutcomes: jest.fn(),\n switchPhaseAndAppendGamePhaseUpcomingPlays: jest.fn(),\n applyStartingGamePhaseOutcomes: jest.fn(),\n isTwilightPhaseOver: jest.fn(),\n },\n gameVictoryService: {\n isGameOver: jest.fn(),\n generateGameVictoryData: jest.fn(),\n },\n gameEventsGeneratorService: { generateGameEventsFromGameAndLastRecord: jest.fn() },\n gameFeedbackService: { createGameFeedback: jest.fn() },\n playerAttributeService: { decreaseRemainingPhasesAndRemoveObsoletePlayerAttributes: jest.fn() },\n gamePhaseHelper: { isGamePhaseOver: jest.spyOn(GamePhaseHelper, \"isGamePhaseOver\").mockImplementation() },\n gamePlayHelper: { createMakeGamePlayDtoWithRelations: jest.spyOn(GamePlayHelper, \"createMakeGamePlayDtoWithRelations\").mockImplementation() },\n };\n\n const module: TestingModule = await Test.createTestingModule({\n providers: [\n {\n provide: GameRepository,\n useValue: mocks.gameRepository,\n },\n {\n provide: GameHistoryRecordService,\n useValue: mocks.gameHistoryRecordService,\n },\n {\n provide: GameHistoryRecordToInsertGeneratorService,\n useValue: mocks.gameHistoryRecordToInsertGeneratorService,\n },\n {\n provide: GamePlayService,\n useValue: mocks.gamePlayService,\n },\n {\n provide: GamePlayValidatorService,\n useValue: mocks.gamePlayValidatorService,\n },\n {\n provide: GamePlayMakerService,\n useValue: mocks.gamePlayMakerService,\n },\n {\n provide: GamePhaseService,\n useValue: mocks.gamePhaseService,\n },\n {\n provide: GameVictoryService,\n useValue: mocks.gameVictoryService,\n },\n {\n provide: PlayerAttributeService,\n useValue: mocks.playerAttributeService,\n },\n {\n provide: GameEventsGeneratorService,\n useValue: mocks.gameEventsGeneratorService,\n },\n {\n provide: GameFeedbackService,\n useValue: mocks.gameFeedbackService,\n },\n {\n provide: GameHistoryRecordRepository,\n useValue: {},\n },\n GamePlayVoteService,\n GameService,\n ],\n }).compile();\n\n services = { game: module.get(GameService) };\n repositories = { game: module.get(GameRepository) };\n });\n\n describe(\"getGames\", () => {\n it(\"should get all games when called.\", async() => {\n await services.game.getGames();\n\n expect(repositories.game.find).toHaveBeenCalledExactlyOnceWith();\n });\n });\n\n describe(\"createGame\", () => {\n const createdGame = createFakeGameWithCurrentPlay({ phase: createFakeGamePhase({ name: \"twilight\", tick: 1 }) });\n\n beforeEach(() => {\n mocks.gamePlayService.augmentCurrentGamePlay.mockReturnValue(createdGame);\n mocks.gameRepository.create.mockResolvedValue(createdGame);\n mocks.gameService.updateGame = jest.spyOn(services.game as unknown as { updateGame }, \"updateGame\").mockResolvedValue(createdGame);\n });\n\n it(\"should throw error when can't generate upcoming plays.\", async() => {\n mocks.gamePlayService.getPhaseUpcomingPlays.mockReturnValue([]);\n const toCreateGame = createFakeCreateGameDto();\n const exceptedError = new UnexpectedException(\"createGame\", UnexpectedExceptionReasons.CANT_GENERATE_GAME_PLAYS);\n const error = await getError(async() => services.game.createGame(toCreateGame));\n\n expect(error).toStrictEqual(exceptedError);\n expect(error).toHaveProperty(\"options\", { description: \"Can't generate game plays\" });\n });\n\n it(\"should call createGame repository method when called.\", async() => {\n const toCreateGame = createFakeCreateGameDto();\n mocks.gamePlayService.getPhaseUpcomingPlays.mockReturnValue([createFakeGamePlaySurvivorsVote()]);\n await services.game.createGame(toCreateGame);\n const expectedGame = createFakeCreateGameDto({\n ...toCreateGame,\n currentPlay: createFakeGamePlaySurvivorsVote(),\n upcomingPlays: [],\n });\n\n expect(repositories.game.create).toHaveBeenCalledExactlyOnceWith(expectedGame);\n });\n\n it(\"should call createGame repository method with distinct player groups when player have groups.\", async() => {\n const toCreateGame = createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ group: \"group1\" }),\n createFakeCreateGamePlayerDto({ group: \"group2\" }),\n ],\n });\n mocks.gamePlayService.getPhaseUpcomingPlays.mockReturnValue([createFakeGamePlaySurvivorsVote()]);\n await services.game.createGame(toCreateGame);\n const expectedGame = createFakeCreateGameDto({\n ...toCreateGame,\n currentPlay: createFakeGamePlaySurvivorsVote(),\n upcomingPlays: [],\n playerGroups: [\"group1\", \"group2\"],\n });\n\n expect(repositories.game.create).toHaveBeenCalledExactlyOnceWith(expectedGame);\n });\n\n it(\"should call augmentCurrentGamePlay method when called.\", async() => {\n const toCreateGame = createFakeCreateGameDto();\n mocks.gamePlayService.getPhaseUpcomingPlays.mockReturnValue([createFakeGamePlaySurvivorsVote()]);\n await services.game.createGame(toCreateGame);\n\n expect(mocks.gamePlayService.augmentCurrentGamePlay).toHaveBeenCalledExactlyOnceWith(createdGame);\n });\n\n it(\"should set game phase as night when twilight phase is over.\", async() => {\n const toCreateGame = createFakeCreateGameDto();\n mocks.gamePlayService.getPhaseUpcomingPlays.mockReturnValue([createFakeGamePlaySurvivorsVote()]);\n mocks.gamePhaseService.isTwilightPhaseOver.mockReturnValue(true);\n await services.game.createGame(toCreateGame);\n const expectedGame = createFakeGameWithCurrentPlay({\n ...createdGame,\n phase: createFakeGamePhase({\n ...createdGame.phase,\n name: \"night\",\n }),\n });\n\n expect(mocks.gameService.updateGame).toHaveBeenCalledExactlyOnceWith(createdGame._id, expectedGame);\n });\n\n it(\"should not set game phase as night when twilight phase is not over.\", async() => {\n const toCreateGame = createFakeCreateGameDto();\n mocks.gamePlayService.getPhaseUpcomingPlays.mockReturnValue([createFakeGamePlaySurvivorsVote()]);\n mocks.gamePhaseService.isTwilightPhaseOver.mockReturnValue(false);\n await services.game.createGame(toCreateGame);\n\n expect(mocks.gameService.updateGame).toHaveBeenCalledExactlyOnceWith(createdGame._id, createdGame);\n });\n\n it(\"should call generate game events method when called.\", async() => {\n const toCreateGame = createFakeCreateGameDto();\n mocks.gamePlayService.getPhaseUpcomingPlays.mockReturnValue([createFakeGamePlaySurvivorsVote()]);\n await services.game.createGame(toCreateGame);\n\n expect(mocks.gameEventsGeneratorService.generateGameEventsFromGameAndLastRecord).toHaveBeenCalledExactlyOnceWith(createdGame);\n });\n\n it(\"should call updateGame repository method when called.\", async() => {\n const toCreateGame = createFakeCreateGameDto();\n mocks.gamePlayService.getPhaseUpcomingPlays.mockReturnValue([createFakeGamePlaySurvivorsVote()]);\n await services.game.createGame(toCreateGame);\n\n expect(mocks.gameService.updateGame).toHaveBeenCalledExactlyOnceWith(createdGame._id, createdGame);\n });\n });\n\n describe(\"cancelGame\", () => {\n const existingPlayingGame = createFakeGame({ status: \"playing\" });\n\n beforeEach(() => {\n mocks.gameService.updateGame = jest.spyOn(services.game as unknown as { updateGame }, \"updateGame\").mockResolvedValue(existingPlayingGame);\n });\n\n it(\"should throw error when game is not playing.\", async() => {\n const canceledGame = createFakeGame({ status: \"canceled\" });\n const expectedException = new BadResourceMutationException(ApiResources.GAMES, canceledGame._id.toString(), BadResourceMutationReasons.GAME_NOT_PLAYING);\n const error = await getError(async() => services.game.cancelGame(canceledGame));\n\n expect(error).toStrictEqual(expectedException);\n expect(error).toHaveProperty(\"options\", { description: \"Game doesn't have status with value \\\"playing\\\"\" });\n });\n\n it(\"should call update method when game can be canceled.\", async() => {\n await services.game.cancelGame(existingPlayingGame);\n\n expect(mocks.gameService.updateGame).toHaveBeenCalledExactlyOnceWith(existingPlayingGame._id, { status: \"canceled\" });\n });\n });\n\n describe(\"makeGamePlay\", () => {\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const game = createFakeGame({ status: \"playing\", players, currentPlay: createFakeGamePlaySurvivorsVote() });\n const play = createFakeMakeGamePlayWithRelationsDto();\n\n beforeEach(() => {\n mocks.gamePlayHelper.createMakeGamePlayDtoWithRelations.mockReturnValue(play);\n mocks.gamePlayMakerService.makeGamePlay.mockResolvedValue(game);\n mocks.gamePlayService.refreshUpcomingPlays.mockReturnValue(game);\n mocks.gamePlayService.proceedToNextGamePlay.mockReturnValue(game);\n mocks.gamePlayService.augmentCurrentGamePlay.mockReturnValue(game);\n mocks.gameVictoryService.isGameOver.mockReturnValue(false);\n mocks.gameService.handleTwilightPhaseCompletion = jest.spyOn(services.game as unknown as { handleTwilightPhaseCompletion }, \"handleTwilightPhaseCompletion\").mockReturnValue(game);\n mocks.gameService.handleGamePhaseCompletion = jest.spyOn(services.game as unknown as { handleGamePhaseCompletion }, \"handleGamePhaseCompletion\").mockResolvedValue(game);\n mocks.gameService.updateGame = jest.spyOn(services.game as unknown as { updateGame }, \"updateGame\").mockReturnValue(game);\n mocks.gameService.setGameAsOver = jest.spyOn(services.game as unknown as { setGameAsOver }, \"setGameAsOver\").mockReturnValue(game);\n });\n\n it(\"should throw an error when game is not playing.\", async() => {\n const makeGamePlayDto = createFakeMakeGamePlayDto();\n const canceledGame = createFakeGame({ status: \"canceled\" });\n const expectedException = new BadResourceMutationException(ApiResources.GAMES, canceledGame._id.toString(), BadResourceMutationReasons.GAME_NOT_PLAYING);\n const error = await getError(async() => services.game.makeGamePlay(canceledGame, makeGamePlayDto));\n\n expect(error).toStrictEqual(expectedException);\n expect(error).toHaveProperty(\"options\", { description: \"Game doesn't have status with value \\\"playing\\\"\" });\n });\n\n it(\"should call play validator method when called.\", async() => {\n const clonedGame = createFakeGame(game);\n const makeGamePlayDto = createFakeMakeGamePlayDto();\n await services.game.makeGamePlay(clonedGame, makeGamePlayDto);\n\n expect(mocks.gamePlayValidatorService.validateGamePlayWithRelationsDto).toHaveBeenCalledExactlyOnceWith(play, clonedGame);\n });\n\n it(\"should call play maker method when called.\", async() => {\n const clonedGame = createFakeGame(game);\n const makeGamePlayDto = createFakeMakeGamePlayDto();\n await services.game.makeGamePlay(clonedGame, makeGamePlayDto);\n\n expect(mocks.gamePlayMakerService.makeGamePlay).toHaveBeenCalledExactlyOnceWith(play, clonedGame);\n });\n\n it(\"should call remove obsolete upcoming plays method when called.\", async() => {\n const clonedGame = createFakeGame(game);\n const makeGamePlayDto = createFakeMakeGamePlayDto();\n await services.game.makeGamePlay(clonedGame, makeGamePlayDto);\n\n expect(mocks.gamePlayService.refreshUpcomingPlays).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call proceed to next game play method when called.\", async() => {\n const clonedGame = createFakeGame(game);\n const makeGamePlayDto = createFakeMakeGamePlayDto();\n await services.game.makeGamePlay(clonedGame, makeGamePlayDto);\n\n expect(mocks.gamePlayService.proceedToNextGamePlay).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should handle twilight phase completion when phase is twilight and phase is over.\", async() => {\n const clonedGame = createFakeGame({\n ...game,\n phase: createFakeGamePhase({ name: \"twilight\", tick: 1 }),\n });\n const makeGamePlayDto = createFakeMakeGamePlayDto();\n mocks.gamePhaseService.isTwilightPhaseOver.mockReturnValue(true);\n await services.game.makeGamePlay(clonedGame, makeGamePlayDto);\n\n expect(mocks.gameService.handleTwilightPhaseCompletion).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should not handle twilight phase completion when phase is not twilight.\", async() => {\n const clonedGame = createFakeGame({\n ...game,\n phase: createFakeGamePhase({ name: \"night\", tick: 1 }),\n });\n mocks.gamePhaseService.isTwilightPhaseOver.mockReturnValue(true);\n const makeGamePlayDto = createFakeMakeGamePlayDto();\n await services.game.makeGamePlay(clonedGame, makeGamePlayDto);\n\n expect(mocks.gameService.handleTwilightPhaseCompletion).not.toHaveBeenCalled();\n });\n\n it(\"should not handle twilight phase completion when phase is not over.\", async() => {\n const clonedGame = createFakeGame({\n ...game,\n phase: createFakeGamePhase({ name: \"twilight\", tick: 1 }),\n });\n mocks.gamePhaseService.isTwilightPhaseOver.mockReturnValue(false);\n const makeGamePlayDto = createFakeMakeGamePlayDto();\n await services.game.makeGamePlay(clonedGame, makeGamePlayDto);\n\n expect(mocks.gameService.handleTwilightPhaseCompletion).not.toHaveBeenCalled();\n });\n\n it(\"should call handle game phase completion method when phase is ending.\", async() => {\n const clonedGame = createFakeGame(game);\n mocks.gamePhaseHelper.isGamePhaseOver.mockReturnValue(true);\n const makeGamePlayDto = createFakeMakeGamePlayDto();\n await services.game.makeGamePlay(clonedGame, makeGamePlayDto);\n\n expect(mocks.gameService.handleGamePhaseCompletion).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call generate current game history record method when called.\", async() => {\n const clonedGame = createFakeGame(game);\n const makeGamePlayDto = createFakeMakeGamePlayDto();\n await services.game.makeGamePlay(clonedGame, makeGamePlayDto);\n\n expect(mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordToInsert).toHaveBeenCalledExactlyOnceWith(clonedGame, game, play);\n });\n\n it(\"should call createGameHistoryRecord method when called.\", async() => {\n const clonedGame = createFakeGame(game);\n const makeGamePlayDto = createFakeMakeGamePlayDto();\n const currentGameHistoryRecordToInsert = createFakeGameHistoryRecordToInsert();\n mocks.gameHistoryRecordToInsertGeneratorService.generateCurrentGameHistoryRecordToInsert.mockReturnValue(currentGameHistoryRecordToInsert);\n await services.game.makeGamePlay(clonedGame, makeGamePlayDto);\n\n expect(mocks.gameHistoryRecordService.createGameHistoryRecord).toHaveBeenCalledExactlyOnceWith(currentGameHistoryRecordToInsert);\n });\n\n it(\"should call update method when called.\", async() => {\n const makeGamePlayDto = createFakeMakeGamePlayDto();\n await services.game.makeGamePlay(game, makeGamePlayDto);\n\n expect(mocks.gameService.updateGame).toHaveBeenCalledExactlyOnceWith(game._id, game);\n });\n\n it(\"should call set game over method when the game is done.\", async() => {\n const makeGamePlayDto = createFakeMakeGamePlayDto();\n const gameVictoryData = createFakeGameVictory();\n mocks.gameVictoryService.isGameOver.mockReturnValue(true);\n mocks.gameVictoryService.generateGameVictoryData.mockReturnValue(gameVictoryData);\n mocks.gamePlayMakerService.makeGamePlay.mockReturnValue(game);\n mocks.gamePlayService.proceedToNextGamePlay.mockReturnValue(game);\n mocks.gamePlayService.refreshUpcomingPlays.mockReturnValue(game.upcomingPlays);\n await services.game.makeGamePlay(game, makeGamePlayDto);\n\n expect(mocks.gameService.setGameAsOver).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should augment current game play when the game is not over.\", async() => {\n const makeGamePlayDto = createFakeMakeGamePlayDto();\n await services.game.makeGamePlay(game, makeGamePlayDto);\n\n expect(mocks.gamePlayService.augmentCurrentGamePlay).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should not augment current game play when the game is over.\", async() => {\n const makeGamePlayDto = createFakeMakeGamePlayDto();\n mocks.gameVictoryService.isGameOver.mockReturnValue(true);\n await services.game.makeGamePlay(game, makeGamePlayDto);\n\n expect(mocks.gamePlayService.augmentCurrentGamePlay).not.toHaveBeenCalled();\n });\n\n it(\"should generate game events when the game is not over.\", async() => {\n const makeGamePlayDto = createFakeMakeGamePlayDto();\n const gameHistoryRecord = createFakeGameHistoryRecord();\n mocks.gameHistoryRecordService.createGameHistoryRecord.mockResolvedValue(gameHistoryRecord);\n await services.game.makeGamePlay(game, makeGamePlayDto);\n\n expect(mocks.gameEventsGeneratorService.generateGameEventsFromGameAndLastRecord).toHaveBeenCalledExactlyOnceWith(game, gameHistoryRecord);\n });\n });\n\n describe(\"createGameFeedback\", () => {\n it(\"should create game feedback when called.\", async() => {\n const game = createFakeGame();\n const createGameFeedbackDto = createFakeCreateGameFeedbackDto();\n const updatedGame = await services.game.createGameFeedback(game, createGameFeedbackDto);\n\n expect(mocks.gameFeedbackService.createGameFeedback).toHaveBeenCalledExactlyOnceWith(updatedGame, createGameFeedbackDto);\n });\n\n it(\"should return game with feedback when called.\", async() => {\n const game = createFakeGame();\n const createGameFeedbackDto = createFakeCreateGameFeedbackDto();\n const feedback = createFakeGameFeedback();\n mocks.gameFeedbackService.createGameFeedback.mockResolvedValue(feedback);\n const expectedGame = createFakeGame({\n ...game,\n feedback,\n });\n\n await expect(services.game.createGameFeedback(game, createGameFeedbackDto)).resolves.toStrictEqual(expectedGame);\n });\n });\n\n describe(\"validateGameIsPlaying\", () => {\n it(\"should throw error when game is not playing.\", async() => {\n const game = createFakeGame({ status: \"canceled\" });\n const expectedError = new BadResourceMutationException(ApiResources.GAMES, game._id.toString(), BadResourceMutationReasons.GAME_NOT_PLAYING);\n const error = await getError(() => services.game[\"validateGameIsPlaying\"](game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Game doesn't have status with value \\\"playing\\\"\" });\n });\n\n it(\"should not throw error when game is playing.\", () => {\n const game = createFakeGame({ status: \"playing\" });\n\n expect(() => services.game[\"validateGameIsPlaying\"](game)).not.toThrow();\n });\n });\n\n describe(\"handleTwilightPhaseCompletion\", () => {\n const game = createFakeGame({ phase: createFakeGamePhase({ name: \"twilight\", tick: 133 }) });\n\n it(\"should set game phase as night and reset tick when called.\", () => {\n const expectedGame = createFakeGame({\n ...game,\n phase: createFakeGamePhase({ name: \"night\", tick: 1 }),\n });\n\n expect(services.game[\"handleTwilightPhaseCompletion\"](game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"handleGamePhaseCompletion\", () => {\n const game = createFakeGame();\n\n beforeEach(() => {\n mocks.gamePhaseService.applyEndingGamePhaseOutcomes.mockResolvedValue(game);\n mocks.playerAttributeService.decreaseRemainingPhasesAndRemoveObsoletePlayerAttributes.mockReturnValue(game);\n mocks.gamePhaseService.switchPhaseAndAppendGamePhaseUpcomingPlays.mockReturnValue(game);\n mocks.gamePhaseService.applyStartingGamePhaseOutcomes.mockReturnValue(game);\n mocks.gamePlayService.proceedToNextGamePlay.mockReturnValue(game);\n mocks.gamePlayService.refreshUpcomingPlays.mockReturnValue(game);\n });\n\n it(\"should call apply ending phase outcomes method when called.\", async() => {\n await services.game[\"handleGamePhaseCompletion\"](game);\n\n expect(mocks.gamePhaseService.applyEndingGamePhaseOutcomes).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call decrease remaining phases attributes to players method when called.\", async() => {\n await services.game[\"handleGamePhaseCompletion\"](game);\n\n expect(mocks.playerAttributeService.decreaseRemainingPhasesAndRemoveObsoletePlayerAttributes).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call switch phase method when called.\", async() => {\n await services.game[\"handleGamePhaseCompletion\"](game);\n\n expect(mocks.gamePhaseService.switchPhaseAndAppendGamePhaseUpcomingPlays).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call apply starting phase outcomes method when called.\", async() => {\n await services.game[\"handleGamePhaseCompletion\"](game);\n\n expect(mocks.gamePhaseService.applyStartingGamePhaseOutcomes).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call proceed to next game play method when called.\", async() => {\n await services.game[\"handleGamePhaseCompletion\"](game);\n\n expect(mocks.gamePlayService.proceedToNextGamePlay).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should not call handle game phase completion method when phase is not ending.\", async() => {\n mocks.gamePhaseHelper.isGamePhaseOver.mockReturnValue(false);\n const handleGamePhaseCompletionSpy = jest.spyOn(services.game as unknown as { handleGamePhaseCompletion }, \"handleGamePhaseCompletion\");\n await services.game[\"handleGamePhaseCompletion\"](game);\n\n expect(handleGamePhaseCompletionSpy).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call handle game phase completion method when phase is ending.\", async() => {\n mocks.gamePhaseHelper.isGamePhaseOver.mockReturnValue(false);\n mocks.gamePhaseHelper.isGamePhaseOver.mockReturnValueOnce(true);\n const handleGamePhaseCompletionSpy = jest.spyOn(services.game as unknown as { handleGamePhaseCompletion }, \"handleGamePhaseCompletion\");\n await services.game[\"handleGamePhaseCompletion\"](game);\n\n expect(handleGamePhaseCompletionSpy).toHaveBeenCalledTimes(2);\n expect(handleGamePhaseCompletionSpy).toHaveBeenNthCalledWith(1, game);\n expect(handleGamePhaseCompletionSpy).toHaveBeenNthCalledWith(2, game);\n });\n });\n\n describe(\"updateGame\", () => {\n it(\"should throw an error when game not found by update repository method.\", async() => {\n const unknownObjectId = createFakeObjectId();\n mocks.gameRepository.updateOne.mockResolvedValue(null);\n const expectedError = new ResourceNotFoundException(ApiResources.GAMES, unknownObjectId.toString());\n const error = await getError(async() => services.game[\"updateGame\"](unknownObjectId, { status: \"over\" }));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: undefined });\n });\n\n it(\"should return updated game when called.\", async() => {\n const game = createFakeGame();\n const gameDataToUpdate: Partial = { status: \"over\" };\n mocks.gameRepository.updateOne.mockResolvedValue(game);\n\n await expect(services.game[\"updateGame\"](game._id, gameDataToUpdate)).resolves.toStrictEqual(game);\n expect(mocks.gameRepository.updateOne).toHaveBeenCalledExactlyOnceWith({ _id: game._id }, gameDataToUpdate);\n });\n });\n\n describe(\"setGameAsOver\", () => {\n it(\"should set game as over when called.\", () => {\n const game = createFakeGame({ status: \"playing\" });\n const gameVictoryData = createFakeGameVictory();\n mocks.gameVictoryService.generateGameVictoryData.mockReturnValue(gameVictoryData);\n const expectedGame = createFakeGame({\n ...game,\n status: \"over\",\n victory: gameVictoryData,\n });\n\n expect(services.game[\"setGameAsOver\"](game)).toStrictEqual(expectedGame);\n });\n });\n\n describe(\"updateGameAsOver\", () => {\n beforeEach(() => {\n mocks.gameService.setGameAsOver = jest.spyOn(services.game as unknown as { setGameAsOver }, \"setGameAsOver\").mockImplementation();\n mocks.gameService.updateGame = jest.spyOn(services.game as unknown as { updateGame }, \"updateGame\").mockImplementation();\n });\n\n it(\"should set game as over when called.\", async() => {\n const game = createFakeGame();\n mocks.gameService.setGameAsOver.mockReturnValue(game);\n await services.game[\"updateGameAsOver\"](game);\n\n expect(mocks.gameService.setGameAsOver).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should call update game when called.\", async() => {\n const game = createFakeGame();\n mocks.gameService.setGameAsOver.mockReturnValue(game);\n await services.game[\"updateGameAsOver\"](game);\n\n expect(mocks.gameService.updateGame).toHaveBeenCalledExactlyOnceWith(game._id, game);\n });\n });\n});" }, "tests/unit/specs/modules/game/providers/services/game-phase/game-phase.service.spec.ts": { "tests": [ @@ -196798,7 +196800,7 @@ } } ], - "source": "import type { Types } from \"mongoose\";\n\nimport type { GamePlayCause } from \"@/modules/game/types/game-play/game-play.types\";\nimport type { MakeGamePlayTargetWithRelationsDto } from \"@/modules/game/dto/make-game-play/make-game-play-target/make-game-play-target-with-relations.dto\";\nimport type { MakeGamePlayVoteWithRelationsDto } from \"@/modules/game/dto/make-game-play/make-game-play-vote/make-game-play-vote-with-relations.dto\";\nimport type { MakeGamePlayWithRelationsDto } from \"@/modules/game/dto/make-game-play/make-game-play-with-relations.dto\";\nimport { areGamePlaysEqual, canSurvivorsVote, createMakeGamePlayDtoWithRelations, doesGamePlayHaveAnyCause, doesGamePlayHaveCause, findPlayPriorityIndex, getChosenCardFromMakeGamePlayDto, getTargetsWithRelationsFromMakeGamePlayDto, getVotesWithRelationsFromMakeGamePlayDto, isPlayerInteractableInCurrentGamePlay, isPlayerInteractableWithInteractionTypeInCurrentGamePlay } from \"@/modules/game/helpers/game-play/game-play.helpers\";\nimport type { GameAdditionalCard } from \"@/modules/game/schemas/game-additional-card/game-additional-card.schema\";\nimport type { GamePlay } from \"@/modules/game/schemas/game-play/game-play.schema\";\nimport type { Game } from \"@/modules/game/schemas/game.schema\";\nimport type { GameWithCurrentPlay } from \"@/modules/game/types/game-with-current-play.types\";\nimport type { PlayerInteractionType } from \"@/modules/game/types/player/player-interaction/player-interaction.types\";\n\nimport { ApiResources } from \"@/shared/api/enums/api.enums\";\nimport { ResourceNotFoundReasons } from \"@/shared/exception/enums/resource-not-found-error.enum\";\nimport { ResourceNotFoundException } from \"@/shared/exception/types/resource-not-found-exception.types\";\n\nimport { createFakeMakeGamePlayTargetWithRelationsDto } from \"@tests/factories/game/dto/make-game-play/make-game-play-with-relations/make-game-play-target-with-relations.dto.factory\";\nimport { createFakeMakeGamePlayVoteWithRelationsDto } from \"@tests/factories/game/dto/make-game-play/make-game-play-with-relations/make-game-play-vote-with-relations.dto.factory\";\nimport { createFakeMakeGamePlayWithRelationsDto } from \"@tests/factories/game/dto/make-game-play/make-game-play-with-relations/make-game-play-with-relations.dto.factory\";\nimport { createFakeMakeGamePlayDto } from \"@tests/factories/game/dto/make-game-play/make-game-play.dto.factory\";\nimport { createFakeGameAdditionalCard } from \"@tests/factories/game/schemas/game-additional-card/game-additional-card.schema.factory\";\nimport { createFakeGamePlaySourceInteraction } from \"@tests/factories/game/schemas/game-play/game-play-source/game-play-source-interaction/game-play-source-interaction.schema.factory\";\nimport { createFakeGamePlaySource } from \"@tests/factories/game/schemas/game-play/game-play-source/game-play-source.schema.factory\";\nimport { createFakeGamePlay, createFakeGamePlayHunterShoots, createFakeGamePlaySeerLooks, createFakeGamePlaySurvivorsElectSheriff, createFakeGamePlaySurvivorsVote, createFakeGamePlayWerewolvesEat, createFakeGamePlayWhiteWerewolfEats } from \"@tests/factories/game/schemas/game-play/game-play.schema.factory\";\nimport { createFakeGame, createFakeGameWithCurrentPlay } from \"@tests/factories/game/schemas/game.schema.factory\";\nimport { createFakeCantVoteBySurvivorsPlayerAttribute } from \"@tests/factories/game/schemas/player/player-attribute/player-attribute.schema.factory\";\nimport { createFakeHunterAlivePlayer, createFakeWerewolfAlivePlayer } from \"@tests/factories/game/schemas/player/player-with-role.schema.factory\";\nimport { createFakePlayer } from \"@tests/factories/game/schemas/player/player.schema.factory\";\nimport { createFakeObjectId } from \"@tests/factories/shared/mongoose/mongoose.factory\";\nimport { getError } from \"@tests/helpers/exception/exception.helpers\";\n\ndescribe(\"Game Play Helper\", () => {\n describe(\"getVotesWithRelationsFromMakeGamePlayDto\", () => {\n it(\"should return undefined when votes are undefined.\", () => {\n const game = createFakeGame();\n const makeGamePlayDto = createFakeMakeGamePlayDto();\n\n expect(getVotesWithRelationsFromMakeGamePlayDto(makeGamePlayDto, game)).toBeUndefined();\n });\n\n it(\"should throw error when votes contains one unknown source.\", async() => {\n const players = [\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n ];\n const game = createFakeGame({ players });\n const fakePlayerId = createFakeObjectId();\n const makeGamePlayDto = createFakeMakeGamePlayDto({\n votes: [\n { sourceId: game.players[0]._id, targetId: game.players[1]._id },\n { sourceId: fakePlayerId, targetId: game.players[0]._id },\n ],\n });\n const expectedError = new ResourceNotFoundException(ApiResources.PLAYERS, fakePlayerId.toString(), ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_PLAYER_VOTE_SOURCE);\n const error = await getError(() => getVotesWithRelationsFromMakeGamePlayDto(makeGamePlayDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Game Play - Player in `votes.source` is not in the game players\" });\n });\n\n it(\"should throw error when votes contains one unknown target.\", async() => {\n const players = [\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n ];\n const game = createFakeGame({ players });\n const fakePlayerId = createFakeObjectId();\n const makeGamePlayDto = createFakeMakeGamePlayDto({\n votes: [\n { sourceId: game.players[0]._id, targetId: game.players[1]._id },\n { sourceId: game.players[1]._id, targetId: fakePlayerId },\n ],\n });\n const expectedError = new ResourceNotFoundException(ApiResources.PLAYERS, fakePlayerId.toString(), ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_PLAYER_VOTE_TARGET);\n const error = await getError(() => getVotesWithRelationsFromMakeGamePlayDto(makeGamePlayDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Game Play - Player in `votes.target` is not in the game players\" });\n });\n\n it(\"should fill votes with game players when called.\", () => {\n const players = [\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n ];\n const game = createFakeGame({ players });\n const makeGamePlayDto = createFakeMakeGamePlayDto({\n votes: [\n { sourceId: game.players[0]._id, targetId: game.players[1]._id },\n { sourceId: game.players[1]._id, targetId: game.players[0]._id },\n ],\n });\n const votes = getVotesWithRelationsFromMakeGamePlayDto(makeGamePlayDto, game);\n const expectedVotes = [\n createFakeMakeGamePlayVoteWithRelationsDto({ source: game.players[0], target: game.players[1] }),\n createFakeMakeGamePlayVoteWithRelationsDto({ source: game.players[1], target: game.players[0] }),\n ];\n\n expect(votes).toStrictEqual(expectedVotes);\n });\n });\n\n describe(\"getTargetsWithRelationsFromMakeGamePlayDto\", () => {\n it(\"should return undefined when targets are undefined.\", () => {\n const game = createFakeGame();\n const makeGamePlayDto = createFakeMakeGamePlayDto();\n\n expect(getTargetsWithRelationsFromMakeGamePlayDto(makeGamePlayDto, game)).toBeUndefined();\n });\n\n it(\"should throw error when targets contains one unknown player.\", async() => {\n const players = [\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n ];\n const game = createFakeGame({ players });\n const fakePlayerId = createFakeObjectId();\n const makeGamePlayDto = createFakeMakeGamePlayDto({\n targets: [\n { playerId: game.players[0]._id },\n { playerId: game.players[1]._id },\n { playerId: fakePlayerId },\n ],\n });\n const expectedError = new ResourceNotFoundException(ApiResources.PLAYERS, fakePlayerId.toString(), ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_PLAYER_TARGET);\n const error = await getError(() => getTargetsWithRelationsFromMakeGamePlayDto(makeGamePlayDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Game Play - Player in `targets.player` is not in the game players\" });\n });\n\n it(\"should fill targets with game players when called.\", () => {\n const players = [\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n ];\n const game = createFakeGame({ players });\n const makeGamePlayDto = createFakeMakeGamePlayDto({\n targets: [\n { playerId: game.players[0]._id },\n { playerId: game.players[1]._id },\n { playerId: game.players[2]._id, drankPotion: \"death\" },\n ],\n });\n const expectedTargets = [\n createFakeMakeGamePlayTargetWithRelationsDto({ player: game.players[0] }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: game.players[1] }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: game.players[2], drankPotion: \"death\" }),\n ];\n\n expect(getTargetsWithRelationsFromMakeGamePlayDto(makeGamePlayDto, game)).toStrictEqual(expectedTargets);\n });\n });\n\n describe(\"getChosenCardFromMakeGamePlayDto\", () => {\n it(\"should return undefined when chosenCardId is undefined.\", () => {\n const game = createFakeGame();\n const makeGamePlayDto = createFakeMakeGamePlayDto();\n\n expect(getChosenCardFromMakeGamePlayDto(makeGamePlayDto, game)).toBeUndefined();\n });\n\n it(\"should throw error when chosen card is unknown from game cards.\", async() => {\n const additionalCards = [\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n ];\n const game = createFakeGame({ additionalCards });\n const fakeCardId = createFakeObjectId();\n const makeGamePlayDto = createFakeMakeGamePlayDto({ chosenCardId: fakeCardId });\n const expectedError = new ResourceNotFoundException(ApiResources.GAME_ADDITIONAL_CARDS, fakeCardId.toString(), ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_CHOSEN_CARD);\n const error = await getError(() => getChosenCardFromMakeGamePlayDto(makeGamePlayDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Game Play - Chosen card is not in the game additional cards\" });\n });\n\n it(\"should return chosen card when called.\", () => {\n const additionalCards = [\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n ];\n const game = createFakeGame({ additionalCards });\n const makeGamePlayDto = createFakeMakeGamePlayDto({ chosenCardId: game.additionalCards?.[3]._id });\n\n expect(getChosenCardFromMakeGamePlayDto(makeGamePlayDto, game)).toStrictEqual(additionalCards[3]);\n });\n });\n\n describe(\"createMakeGamePlayDtoWithRelations\", () => {\n it(\"should return same dto with relations when called.\", () => {\n const players = [\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n ];\n const additionalCards = [\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n ];\n const game = createFakeGame({ players, additionalCards });\n const makeGamePlayDto = createFakeMakeGamePlayDto({\n votes: [\n { sourceId: game.players[0]._id, targetId: game.players[1]._id },\n { sourceId: game.players[1]._id, targetId: game.players[0]._id },\n ],\n targets: [\n { playerId: game.players[0]._id },\n { playerId: game.players[1]._id },\n { playerId: game.players[2]._id, drankPotion: \"death\" },\n ],\n chosenCardId: game.additionalCards?.[3]._id,\n doesJudgeRequestAnotherVote: true,\n chosenSide: \"werewolves\",\n });\n const expectedMakeGamePlayDtoWithRelationsDto = createFakeMakeGamePlayWithRelationsDto({\n votes: [\n { source: game.players[0], target: game.players[1] },\n { source: game.players[1], target: game.players[0] },\n ],\n targets: [\n { player: game.players[0] },\n { player: game.players[1] },\n { player: game.players[2], drankPotion: \"death\" },\n ],\n chosenCard: game.additionalCards?.[3],\n doesJudgeRequestAnotherVote: true,\n chosenSide: \"werewolves\",\n });\n\n expect(createMakeGamePlayDtoWithRelations(makeGamePlayDto, game)).toStrictEqual(expectedMakeGamePlayDtoWithRelationsDto);\n });\n });\n\n describe(\"findPlayPriorityIndex\", () => {\n it(\"should return -1 when play is not found in priority list.\", () => {\n const gamePlay = createFakeGamePlaySeerLooks({ action: \"eat\" });\n\n expect(findPlayPriorityIndex(gamePlay)).toBe(-1);\n });\n\n it(\"should return index when play is found in priority list.\", () => {\n const gamePlay = createFakeGamePlayHunterShoots();\n\n expect(findPlayPriorityIndex(gamePlay)).toBe(1);\n });\n });\n\n describe(\"areGamePlaysEqual\", () => {\n it.each<{\n test: string;\n playA: GamePlay;\n playB: GamePlay;\n expected: boolean;\n }>([\n {\n test: \"should return true when both plays are equal.\",\n playA: createFakeGamePlaySeerLooks(),\n playB: createFakeGamePlaySeerLooks(),\n expected: true,\n },\n {\n test: \"should return false when both sources are not equal.\",\n playA: createFakeGamePlayWerewolvesEat(),\n playB: createFakeGamePlayWhiteWerewolfEats(),\n expected: false,\n },\n {\n test: \"should return false when both actions are not equal.\",\n playA: createFakeGamePlaySurvivorsVote(),\n playB: createFakeGamePlaySurvivorsElectSheriff(),\n expected: false,\n },\n {\n test: \"should return false when both causes are not equal.\",\n playA: createFakeGamePlaySurvivorsVote(),\n playB: createFakeGamePlaySurvivorsVote({ causes: [\"previous-votes-were-in-ties\"] }),\n expected: false,\n },\n ])(\"$test\", ({ playA, playB, expected }) => {\n expect(areGamePlaysEqual(playA, playB)).toBe(expected);\n });\n });\n\n describe(\"canSurvivorsVote\", () => {\n it.each<{\n test: string;\n game: Game;\n expected: boolean;\n }>([\n {\n test: \"should return false when all players are dead.\",\n game: createFakeGame({\n players: [\n createFakeHunterAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n ],\n }),\n expected: false,\n },\n {\n test: \"should return false when all survivors has the cant-vote attribute.\",\n game: createFakeGame({\n players: [\n createFakeHunterAlivePlayer({ attributes: [createFakeCantVoteBySurvivorsPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeCantVoteBySurvivorsPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n ],\n }),\n expected: false,\n },\n {\n test: \"should return true when at least one survivor doesn't have the cant-vote attribute.\",\n game: createFakeGame({\n players: [\n createFakeHunterAlivePlayer({ attributes: [createFakeCantVoteBySurvivorsPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer({ attributes: [] }),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n ],\n }),\n expected: true,\n },\n ])(`$test`, ({ game, expected }) => {\n expect(canSurvivorsVote(game)).toBe(expected);\n });\n });\n\n describe(\"isPlayerInteractableInCurrentGamePlay\", () => {\n const players = [\n createFakeHunterAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n\n it.each<{\n playerId: Types.ObjectId;\n game: GameWithCurrentPlay;\n expected: boolean;\n test: string;\n }>([\n {\n playerId: players[0]._id,\n game: createFakeGameWithCurrentPlay({\n players,\n currentPlay: createFakeGamePlay({\n source: createFakeGamePlaySource({\n interactions: [\n createFakeGamePlaySourceInteraction({ eligibleTargets: [players[0]] }),\n createFakeGamePlaySourceInteraction({ eligibleTargets: [players[0], players[1]] }),\n ],\n }),\n }),\n }),\n expected: true,\n test: \"should return true when player is in current play interactions\",\n },\n {\n playerId: players[2]._id,\n game: createFakeGameWithCurrentPlay({\n players,\n currentPlay: createFakeGamePlay({\n source: createFakeGamePlaySource({\n interactions: [\n createFakeGamePlaySourceInteraction({ eligibleTargets: [players[0]] }),\n createFakeGamePlaySourceInteraction({ eligibleTargets: [players[0], players[1]] }),\n ],\n }),\n }),\n }),\n expected: false,\n test: \"should return false when player is not in current play interactions\",\n },\n ])(`$test`, ({ playerId, game, expected }) => {\n expect(isPlayerInteractableInCurrentGamePlay(playerId, game)).toBe(expected);\n });\n });\n\n describe(\"isPlayerInteractableWithInteractionTypeInCurrentGamePlay\", () => {\n const players = [\n createFakeHunterAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n\n it.each<{\n playerId: Types.ObjectId;\n interactionType: PlayerInteractionType;\n game: GameWithCurrentPlay;\n expected: boolean;\n test: string;\n }>([\n {\n playerId: players[0]._id,\n interactionType: \"vote\",\n game: createFakeGameWithCurrentPlay({\n players,\n currentPlay: createFakeGamePlay({\n source: createFakeGamePlaySource({\n interactions: [\n createFakeGamePlaySourceInteraction({\n type: \"shoot\",\n eligibleTargets: [players[0]],\n }),\n createFakeGamePlaySourceInteraction({\n type: \"vote\",\n eligibleTargets: [players[0], players[1]],\n }),\n ],\n }),\n }),\n }),\n expected: true,\n test: \"should return true when player is in current play interactions with the given interaction type\",\n },\n {\n playerId: players[2]._id,\n interactionType: \"vote\",\n game: createFakeGameWithCurrentPlay({\n players,\n currentPlay: createFakeGamePlay({\n source: createFakeGamePlaySource({\n interactions: [\n createFakeGamePlaySourceInteraction({\n type: \"vote\",\n eligibleTargets: [players[0]],\n }),\n createFakeGamePlaySourceInteraction({\n type: \"vote\",\n eligibleTargets: [players[0], players[1]],\n }),\n ],\n }),\n }),\n }),\n expected: false,\n test: \"should return false when player is not in current play interactions with the given interaction type\",\n },\n {\n playerId: players[1]._id,\n interactionType: \"vote\",\n game: createFakeGameWithCurrentPlay({\n players,\n currentPlay: createFakeGamePlay({\n source: createFakeGamePlaySource({\n interactions: [\n createFakeGamePlaySourceInteraction({\n type: \"look\",\n eligibleTargets: [players[0], players[1]],\n }),\n createFakeGamePlaySourceInteraction({\n type: \"vote\",\n eligibleTargets: [players[0]],\n }),\n createFakeGamePlaySourceInteraction({\n type: \"shoot\",\n eligibleTargets: [players[0], players[1]],\n }),\n ],\n }),\n }),\n }),\n expected: false,\n test: \"should return false when player is in current play interactions but not for the given interaction type\",\n },\n ])(`$test`, ({ playerId, interactionType, game, expected }) => {\n expect(isPlayerInteractableWithInteractionTypeInCurrentGamePlay(playerId, interactionType, game)).toBe(expected);\n });\n });\n\n describe(\"doesGamePlayHaveCause\", () => {\n it.each<{\n gamePlay: GamePlay;\n cause: GamePlayCause;\n expected: boolean;\n test: string;\n }>([\n {\n gamePlay: createFakeGamePlaySurvivorsVote(),\n cause: \"previous-votes-were-in-ties\",\n expected: false,\n test: \"should return false when game play doesn't have any cause at all.\",\n },\n {\n gamePlay: createFakeGamePlaySurvivorsVote({ causes: [\"previous-votes-were-in-ties\"] }),\n cause: \"previous-votes-were-in-ties\",\n expected: true,\n test: \"should return true when game play has the cause.\",\n },\n {\n gamePlay: createFakeGamePlaySurvivorsVote({ causes: [\"previous-votes-were-in-ties\"] }),\n cause: \"angel-presence\",\n expected: false,\n test: \"should return false when game play doesn't have the cause.\",\n },\n ])(`$test`, ({ gamePlay, cause, expected }) => {\n expect(doesGamePlayHaveCause(gamePlay, cause)).toBe(expected);\n });\n });\n\n describe(\"doesGamePlayHaveAnyCause\", () => {\n it.each<{\n gamePlay: GamePlay;\n causes: GamePlayCause[];\n expected: boolean;\n test: string;\n }>([\n {\n gamePlay: createFakeGamePlaySurvivorsVote(),\n causes: [\"previous-votes-were-in-ties\"],\n expected: false,\n test: \"should return false when game play doesn't have any of the causes.\",\n },\n {\n gamePlay: createFakeGamePlaySurvivorsVote({ causes: [\"previous-votes-were-in-ties\"] }),\n causes: [\"previous-votes-were-in-ties\"],\n expected: true,\n test: \"should return true when game play has all of the causes.\",\n },\n {\n gamePlay: createFakeGamePlaySurvivorsVote({ causes: [\"previous-votes-were-in-ties\"] }),\n causes: [\"previous-votes-were-in-ties\", \"angel-presence\"],\n expected: true,\n test: \"should return true when game play has any of the causes.\",\n },\n ])(`$test`, ({ gamePlay, causes, expected }) => {\n expect(doesGamePlayHaveAnyCause(gamePlay, causes)).toBe(expected);\n });\n });\n});" + "source": "import type { Types } from \"mongoose\";\n\nimport type { GamePlayCause } from \"@/modules/game/types/game-play/game-play.types\";\nimport type { MakeGamePlayTargetWithRelationsDto } from \"@/modules/game/dto/make-game-play/make-game-play-target/make-game-play-target-with-relations.dto\";\nimport type { MakeGamePlayVoteWithRelationsDto } from \"@/modules/game/dto/make-game-play/make-game-play-vote/make-game-play-vote-with-relations.dto\";\nimport type { MakeGamePlayWithRelationsDto } from \"@/modules/game/dto/make-game-play/make-game-play-with-relations.dto\";\nimport { areGamePlaysEqual, canSurvivorsVote, createMakeGamePlayDtoWithRelations, doesGamePlayHaveAnyCause, doesGamePlayHaveCause, findPlayPriorityIndex, getChosenCardFromMakeGamePlayDto, getTargetsWithRelationsFromMakeGamePlayDto, getVotesWithRelationsFromMakeGamePlayDto, isPlayerInteractableInCurrentGamePlay, isPlayerInteractableWithInteractionTypeInCurrentGamePlay } from \"@/modules/game/helpers/game-play/game-play.helpers\";\nimport type { GameAdditionalCard } from \"@/modules/game/schemas/game-additional-card/game-additional-card.schema\";\nimport type { GamePlay } from \"@/modules/game/schemas/game-play/game-play.schema\";\nimport type { Game } from \"@/modules/game/schemas/game.schema\";\nimport type { GameWithCurrentPlay } from \"@/modules/game/types/game-with-current-play.types\";\nimport type { PlayerInteractionType } from \"@/modules/game/types/player/player-interaction/player-interaction.types\";\n\nimport { ApiResources } from \"@/shared/api/enums/api.enums\";\nimport { ResourceNotFoundReasons } from \"@/shared/exception/enums/resource-not-found-error.enums\";\nimport { ResourceNotFoundException } from \"@/shared/exception/types/resource-not-found-exception.types\";\n\nimport { createFakeMakeGamePlayTargetWithRelationsDto } from \"@tests/factories/game/dto/make-game-play/make-game-play-with-relations/make-game-play-target-with-relations.dto.factory\";\nimport { createFakeMakeGamePlayVoteWithRelationsDto } from \"@tests/factories/game/dto/make-game-play/make-game-play-with-relations/make-game-play-vote-with-relations.dto.factory\";\nimport { createFakeMakeGamePlayWithRelationsDto } from \"@tests/factories/game/dto/make-game-play/make-game-play-with-relations/make-game-play-with-relations.dto.factory\";\nimport { createFakeMakeGamePlayDto } from \"@tests/factories/game/dto/make-game-play/make-game-play.dto.factory\";\nimport { createFakeGameAdditionalCard } from \"@tests/factories/game/schemas/game-additional-card/game-additional-card.schema.factory\";\nimport { createFakeGamePlaySourceInteraction } from \"@tests/factories/game/schemas/game-play/game-play-source/game-play-source-interaction/game-play-source-interaction.schema.factory\";\nimport { createFakeGamePlaySource } from \"@tests/factories/game/schemas/game-play/game-play-source/game-play-source.schema.factory\";\nimport { createFakeGamePlay, createFakeGamePlayHunterShoots, createFakeGamePlaySeerLooks, createFakeGamePlaySurvivorsElectSheriff, createFakeGamePlaySurvivorsVote, createFakeGamePlayWerewolvesEat, createFakeGamePlayWhiteWerewolfEats } from \"@tests/factories/game/schemas/game-play/game-play.schema.factory\";\nimport { createFakeGame, createFakeGameWithCurrentPlay } from \"@tests/factories/game/schemas/game.schema.factory\";\nimport { createFakeCantVoteBySurvivorsPlayerAttribute } from \"@tests/factories/game/schemas/player/player-attribute/player-attribute.schema.factory\";\nimport { createFakeHunterAlivePlayer, createFakeWerewolfAlivePlayer } from \"@tests/factories/game/schemas/player/player-with-role.schema.factory\";\nimport { createFakePlayer } from \"@tests/factories/game/schemas/player/player.schema.factory\";\nimport { createFakeObjectId } from \"@tests/factories/shared/mongoose/mongoose.factory\";\nimport { getError } from \"@tests/helpers/exception/exception.helpers\";\n\ndescribe(\"Game Play Helper\", () => {\n describe(\"getVotesWithRelationsFromMakeGamePlayDto\", () => {\n it(\"should return undefined when votes are undefined.\", () => {\n const game = createFakeGame();\n const makeGamePlayDto = createFakeMakeGamePlayDto();\n\n expect(getVotesWithRelationsFromMakeGamePlayDto(makeGamePlayDto, game)).toBeUndefined();\n });\n\n it(\"should throw error when votes contains one unknown source.\", async() => {\n const players = [\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n ];\n const game = createFakeGame({ players });\n const fakePlayerId = createFakeObjectId();\n const makeGamePlayDto = createFakeMakeGamePlayDto({\n votes: [\n { sourceId: game.players[0]._id, targetId: game.players[1]._id },\n { sourceId: fakePlayerId, targetId: game.players[0]._id },\n ],\n });\n const expectedError = new ResourceNotFoundException(ApiResources.PLAYERS, fakePlayerId.toString(), ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_PLAYER_VOTE_SOURCE);\n const error = await getError(() => getVotesWithRelationsFromMakeGamePlayDto(makeGamePlayDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Game Play - Player in `votes.source` is not in the game players\" });\n });\n\n it(\"should throw error when votes contains one unknown target.\", async() => {\n const players = [\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n ];\n const game = createFakeGame({ players });\n const fakePlayerId = createFakeObjectId();\n const makeGamePlayDto = createFakeMakeGamePlayDto({\n votes: [\n { sourceId: game.players[0]._id, targetId: game.players[1]._id },\n { sourceId: game.players[1]._id, targetId: fakePlayerId },\n ],\n });\n const expectedError = new ResourceNotFoundException(ApiResources.PLAYERS, fakePlayerId.toString(), ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_PLAYER_VOTE_TARGET);\n const error = await getError(() => getVotesWithRelationsFromMakeGamePlayDto(makeGamePlayDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Game Play - Player in `votes.target` is not in the game players\" });\n });\n\n it(\"should fill votes with game players when called.\", () => {\n const players = [\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n ];\n const game = createFakeGame({ players });\n const makeGamePlayDto = createFakeMakeGamePlayDto({\n votes: [\n { sourceId: game.players[0]._id, targetId: game.players[1]._id },\n { sourceId: game.players[1]._id, targetId: game.players[0]._id },\n ],\n });\n const votes = getVotesWithRelationsFromMakeGamePlayDto(makeGamePlayDto, game);\n const expectedVotes = [\n createFakeMakeGamePlayVoteWithRelationsDto({ source: game.players[0], target: game.players[1] }),\n createFakeMakeGamePlayVoteWithRelationsDto({ source: game.players[1], target: game.players[0] }),\n ];\n\n expect(votes).toStrictEqual(expectedVotes);\n });\n });\n\n describe(\"getTargetsWithRelationsFromMakeGamePlayDto\", () => {\n it(\"should return undefined when targets are undefined.\", () => {\n const game = createFakeGame();\n const makeGamePlayDto = createFakeMakeGamePlayDto();\n\n expect(getTargetsWithRelationsFromMakeGamePlayDto(makeGamePlayDto, game)).toBeUndefined();\n });\n\n it(\"should throw error when targets contains one unknown player.\", async() => {\n const players = [\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n ];\n const game = createFakeGame({ players });\n const fakePlayerId = createFakeObjectId();\n const makeGamePlayDto = createFakeMakeGamePlayDto({\n targets: [\n { playerId: game.players[0]._id },\n { playerId: game.players[1]._id },\n { playerId: fakePlayerId },\n ],\n });\n const expectedError = new ResourceNotFoundException(ApiResources.PLAYERS, fakePlayerId.toString(), ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_PLAYER_TARGET);\n const error = await getError(() => getTargetsWithRelationsFromMakeGamePlayDto(makeGamePlayDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Game Play - Player in `targets.player` is not in the game players\" });\n });\n\n it(\"should fill targets with game players when called.\", () => {\n const players = [\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n ];\n const game = createFakeGame({ players });\n const makeGamePlayDto = createFakeMakeGamePlayDto({\n targets: [\n { playerId: game.players[0]._id },\n { playerId: game.players[1]._id },\n { playerId: game.players[2]._id, drankPotion: \"death\" },\n ],\n });\n const expectedTargets = [\n createFakeMakeGamePlayTargetWithRelationsDto({ player: game.players[0] }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: game.players[1] }),\n createFakeMakeGamePlayTargetWithRelationsDto({ player: game.players[2], drankPotion: \"death\" }),\n ];\n\n expect(getTargetsWithRelationsFromMakeGamePlayDto(makeGamePlayDto, game)).toStrictEqual(expectedTargets);\n });\n });\n\n describe(\"getChosenCardFromMakeGamePlayDto\", () => {\n it(\"should return undefined when chosenCardId is undefined.\", () => {\n const game = createFakeGame();\n const makeGamePlayDto = createFakeMakeGamePlayDto();\n\n expect(getChosenCardFromMakeGamePlayDto(makeGamePlayDto, game)).toBeUndefined();\n });\n\n it(\"should throw error when chosen card is unknown from game cards.\", async() => {\n const additionalCards = [\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n ];\n const game = createFakeGame({ additionalCards });\n const fakeCardId = createFakeObjectId();\n const makeGamePlayDto = createFakeMakeGamePlayDto({ chosenCardId: fakeCardId });\n const expectedError = new ResourceNotFoundException(ApiResources.GAME_ADDITIONAL_CARDS, fakeCardId.toString(), ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_CHOSEN_CARD);\n const error = await getError(() => getChosenCardFromMakeGamePlayDto(makeGamePlayDto, game));\n\n expect(error).toStrictEqual(expectedError);\n expect(error).toHaveProperty(\"options\", { description: \"Game Play - Chosen card is not in the game additional cards\" });\n });\n\n it(\"should return chosen card when called.\", () => {\n const additionalCards = [\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n ];\n const game = createFakeGame({ additionalCards });\n const makeGamePlayDto = createFakeMakeGamePlayDto({ chosenCardId: game.additionalCards?.[3]._id });\n\n expect(getChosenCardFromMakeGamePlayDto(makeGamePlayDto, game)).toStrictEqual(additionalCards[3]);\n });\n });\n\n describe(\"createMakeGamePlayDtoWithRelations\", () => {\n it(\"should return same dto with relations when called.\", () => {\n const players = [\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n ];\n const additionalCards = [\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n ];\n const game = createFakeGame({ players, additionalCards });\n const makeGamePlayDto = createFakeMakeGamePlayDto({\n votes: [\n { sourceId: game.players[0]._id, targetId: game.players[1]._id },\n { sourceId: game.players[1]._id, targetId: game.players[0]._id },\n ],\n targets: [\n { playerId: game.players[0]._id },\n { playerId: game.players[1]._id },\n { playerId: game.players[2]._id, drankPotion: \"death\" },\n ],\n chosenCardId: game.additionalCards?.[3]._id,\n doesJudgeRequestAnotherVote: true,\n chosenSide: \"werewolves\",\n });\n const expectedMakeGamePlayDtoWithRelationsDto = createFakeMakeGamePlayWithRelationsDto({\n votes: [\n { source: game.players[0], target: game.players[1] },\n { source: game.players[1], target: game.players[0] },\n ],\n targets: [\n { player: game.players[0] },\n { player: game.players[1] },\n { player: game.players[2], drankPotion: \"death\" },\n ],\n chosenCard: game.additionalCards?.[3],\n doesJudgeRequestAnotherVote: true,\n chosenSide: \"werewolves\",\n });\n\n expect(createMakeGamePlayDtoWithRelations(makeGamePlayDto, game)).toStrictEqual(expectedMakeGamePlayDtoWithRelationsDto);\n });\n });\n\n describe(\"findPlayPriorityIndex\", () => {\n it(\"should return -1 when play is not found in priority list.\", () => {\n const gamePlay = createFakeGamePlaySeerLooks({ action: \"eat\" });\n\n expect(findPlayPriorityIndex(gamePlay)).toBe(-1);\n });\n\n it(\"should return index when play is found in priority list.\", () => {\n const gamePlay = createFakeGamePlayHunterShoots();\n\n expect(findPlayPriorityIndex(gamePlay)).toBe(1);\n });\n });\n\n describe(\"areGamePlaysEqual\", () => {\n it.each<{\n test: string;\n playA: GamePlay;\n playB: GamePlay;\n expected: boolean;\n }>([\n {\n test: \"should return true when both plays are equal.\",\n playA: createFakeGamePlaySeerLooks(),\n playB: createFakeGamePlaySeerLooks(),\n expected: true,\n },\n {\n test: \"should return false when both sources are not equal.\",\n playA: createFakeGamePlayWerewolvesEat(),\n playB: createFakeGamePlayWhiteWerewolfEats(),\n expected: false,\n },\n {\n test: \"should return false when both actions are not equal.\",\n playA: createFakeGamePlaySurvivorsVote(),\n playB: createFakeGamePlaySurvivorsElectSheriff(),\n expected: false,\n },\n {\n test: \"should return false when both causes are not equal.\",\n playA: createFakeGamePlaySurvivorsVote(),\n playB: createFakeGamePlaySurvivorsVote({ causes: [\"previous-votes-were-in-ties\"] }),\n expected: false,\n },\n ])(\"$test\", ({ playA, playB, expected }) => {\n expect(areGamePlaysEqual(playA, playB)).toBe(expected);\n });\n });\n\n describe(\"canSurvivorsVote\", () => {\n it.each<{\n test: string;\n game: Game;\n expected: boolean;\n }>([\n {\n test: \"should return false when all players are dead.\",\n game: createFakeGame({\n players: [\n createFakeHunterAlivePlayer({ isAlive: false }),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n ],\n }),\n expected: false,\n },\n {\n test: \"should return false when all survivors has the cant-vote attribute.\",\n game: createFakeGame({\n players: [\n createFakeHunterAlivePlayer({ attributes: [createFakeCantVoteBySurvivorsPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer({ attributes: [createFakeCantVoteBySurvivorsPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n ],\n }),\n expected: false,\n },\n {\n test: \"should return true when at least one survivor doesn't have the cant-vote attribute.\",\n game: createFakeGame({\n players: [\n createFakeHunterAlivePlayer({ attributes: [createFakeCantVoteBySurvivorsPlayerAttribute()] }),\n createFakeWerewolfAlivePlayer({ attributes: [] }),\n createFakeWerewolfAlivePlayer({ isAlive: false }),\n ],\n }),\n expected: true,\n },\n ])(`$test`, ({ game, expected }) => {\n expect(canSurvivorsVote(game)).toBe(expected);\n });\n });\n\n describe(\"isPlayerInteractableInCurrentGamePlay\", () => {\n const players = [\n createFakeHunterAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n\n it.each<{\n playerId: Types.ObjectId;\n game: GameWithCurrentPlay;\n expected: boolean;\n test: string;\n }>([\n {\n playerId: players[0]._id,\n game: createFakeGameWithCurrentPlay({\n players,\n currentPlay: createFakeGamePlay({\n source: createFakeGamePlaySource({\n interactions: [\n createFakeGamePlaySourceInteraction({ eligibleTargets: [players[0]] }),\n createFakeGamePlaySourceInteraction({ eligibleTargets: [players[0], players[1]] }),\n ],\n }),\n }),\n }),\n expected: true,\n test: \"should return true when player is in current play interactions\",\n },\n {\n playerId: players[2]._id,\n game: createFakeGameWithCurrentPlay({\n players,\n currentPlay: createFakeGamePlay({\n source: createFakeGamePlaySource({\n interactions: [\n createFakeGamePlaySourceInteraction({ eligibleTargets: [players[0]] }),\n createFakeGamePlaySourceInteraction({ eligibleTargets: [players[0], players[1]] }),\n ],\n }),\n }),\n }),\n expected: false,\n test: \"should return false when player is not in current play interactions\",\n },\n ])(`$test`, ({ playerId, game, expected }) => {\n expect(isPlayerInteractableInCurrentGamePlay(playerId, game)).toBe(expected);\n });\n });\n\n describe(\"isPlayerInteractableWithInteractionTypeInCurrentGamePlay\", () => {\n const players = [\n createFakeHunterAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n createFakeWerewolfAlivePlayer(),\n ];\n\n it.each<{\n playerId: Types.ObjectId;\n interactionType: PlayerInteractionType;\n game: GameWithCurrentPlay;\n expected: boolean;\n test: string;\n }>([\n {\n playerId: players[0]._id,\n interactionType: \"vote\",\n game: createFakeGameWithCurrentPlay({\n players,\n currentPlay: createFakeGamePlay({\n source: createFakeGamePlaySource({\n interactions: [\n createFakeGamePlaySourceInteraction({\n type: \"shoot\",\n eligibleTargets: [players[0]],\n }),\n createFakeGamePlaySourceInteraction({\n type: \"vote\",\n eligibleTargets: [players[0], players[1]],\n }),\n ],\n }),\n }),\n }),\n expected: true,\n test: \"should return true when player is in current play interactions with the given interaction type\",\n },\n {\n playerId: players[2]._id,\n interactionType: \"vote\",\n game: createFakeGameWithCurrentPlay({\n players,\n currentPlay: createFakeGamePlay({\n source: createFakeGamePlaySource({\n interactions: [\n createFakeGamePlaySourceInteraction({\n type: \"vote\",\n eligibleTargets: [players[0]],\n }),\n createFakeGamePlaySourceInteraction({\n type: \"vote\",\n eligibleTargets: [players[0], players[1]],\n }),\n ],\n }),\n }),\n }),\n expected: false,\n test: \"should return false when player is not in current play interactions with the given interaction type\",\n },\n {\n playerId: players[1]._id,\n interactionType: \"vote\",\n game: createFakeGameWithCurrentPlay({\n players,\n currentPlay: createFakeGamePlay({\n source: createFakeGamePlaySource({\n interactions: [\n createFakeGamePlaySourceInteraction({\n type: \"look\",\n eligibleTargets: [players[0], players[1]],\n }),\n createFakeGamePlaySourceInteraction({\n type: \"vote\",\n eligibleTargets: [players[0]],\n }),\n createFakeGamePlaySourceInteraction({\n type: \"shoot\",\n eligibleTargets: [players[0], players[1]],\n }),\n ],\n }),\n }),\n }),\n expected: false,\n test: \"should return false when player is in current play interactions but not for the given interaction type\",\n },\n ])(`$test`, ({ playerId, interactionType, game, expected }) => {\n expect(isPlayerInteractableWithInteractionTypeInCurrentGamePlay(playerId, interactionType, game)).toBe(expected);\n });\n });\n\n describe(\"doesGamePlayHaveCause\", () => {\n it.each<{\n gamePlay: GamePlay;\n cause: GamePlayCause;\n expected: boolean;\n test: string;\n }>([\n {\n gamePlay: createFakeGamePlaySurvivorsVote(),\n cause: \"previous-votes-were-in-ties\",\n expected: false,\n test: \"should return false when game play doesn't have any cause at all.\",\n },\n {\n gamePlay: createFakeGamePlaySurvivorsVote({ causes: [\"previous-votes-were-in-ties\"] }),\n cause: \"previous-votes-were-in-ties\",\n expected: true,\n test: \"should return true when game play has the cause.\",\n },\n {\n gamePlay: createFakeGamePlaySurvivorsVote({ causes: [\"previous-votes-were-in-ties\"] }),\n cause: \"angel-presence\",\n expected: false,\n test: \"should return false when game play doesn't have the cause.\",\n },\n ])(`$test`, ({ gamePlay, cause, expected }) => {\n expect(doesGamePlayHaveCause(gamePlay, cause)).toBe(expected);\n });\n });\n\n describe(\"doesGamePlayHaveAnyCause\", () => {\n it.each<{\n gamePlay: GamePlay;\n causes: GamePlayCause[];\n expected: boolean;\n test: string;\n }>([\n {\n gamePlay: createFakeGamePlaySurvivorsVote(),\n causes: [\"previous-votes-were-in-ties\"],\n expected: false,\n test: \"should return false when game play doesn't have any of the causes.\",\n },\n {\n gamePlay: createFakeGamePlaySurvivorsVote({ causes: [\"previous-votes-were-in-ties\"] }),\n causes: [\"previous-votes-were-in-ties\"],\n expected: true,\n test: \"should return true when game play has all of the causes.\",\n },\n {\n gamePlay: createFakeGamePlaySurvivorsVote({ causes: [\"previous-votes-were-in-ties\"] }),\n causes: [\"previous-votes-were-in-ties\", \"angel-presence\"],\n expected: true,\n test: \"should return true when game play has any of the causes.\",\n },\n ])(`$test`, ({ gamePlay, causes, expected }) => {\n expect(doesGamePlayHaveAnyCause(gamePlay, causes)).toBe(expected);\n });\n });\n});" }, "tests/unit/specs/modules/game/providers/services/game-history/game-history-record.service.spec.ts": { "tests": [ @@ -196808,7 +196810,7 @@ "location": { "start": { "column": 6, - "line": 102 + "line": 103 } } }, @@ -196818,7 +196820,7 @@ "location": { "start": { "column": 6, - "line": 115 + "line": 116 } } }, @@ -196828,7 +196830,7 @@ "location": { "start": { "column": 6, - "line": 125 + "line": 126 } } }, @@ -196838,7 +196840,7 @@ "location": { "start": { "column": 6, - "line": 134 + "line": 135 } } }, @@ -196848,7 +196850,7 @@ "location": { "start": { "column": 6, - "line": 143 + "line": 144 } } }, @@ -196858,7 +196860,7 @@ "location": { "start": { "column": 6, - "line": 151 + "line": 152 } } }, @@ -196868,7 +196870,7 @@ "location": { "start": { "column": 6, - "line": 161 + "line": 162 } } }, @@ -196878,7 +196880,7 @@ "location": { "start": { "column": 6, - "line": 171 + "line": 172 } } }, @@ -196888,7 +196890,7 @@ "location": { "start": { "column": 6, - "line": 181 + "line": 182 } } }, @@ -196898,7 +196900,7 @@ "location": { "start": { "column": 6, - "line": 191 + "line": 192 } } }, @@ -196908,7 +196910,7 @@ "location": { "start": { "column": 6, - "line": 201 + "line": 202 } } }, @@ -196918,7 +196920,7 @@ "location": { "start": { "column": 6, - "line": 211 + "line": 212 } } }, @@ -196928,7 +196930,7 @@ "location": { "start": { "column": 6, - "line": 220 + "line": 221 } } }, @@ -196938,7 +196940,7 @@ "location": { "start": { "column": 6, - "line": 229 + "line": 230 } } }, @@ -196948,7 +196950,7 @@ "location": { "start": { "column": 6, - "line": 239 + "line": 240 } } }, @@ -196958,7 +196960,7 @@ "location": { "start": { "column": 6, - "line": 248 + "line": 249 } } }, @@ -196968,7 +196970,7 @@ "location": { "start": { "column": 6, - "line": 256 + "line": 257 } } }, @@ -196978,7 +196980,7 @@ "location": { "start": { "column": 6, - "line": 266 + "line": 267 } } }, @@ -196988,7 +196990,7 @@ "location": { "start": { "column": 6, - "line": 276 + "line": 277 } } }, @@ -196998,7 +197000,7 @@ "location": { "start": { "column": 6, - "line": 285 + "line": 286 } } }, @@ -197008,7 +197010,7 @@ "location": { "start": { "column": 8, - "line": 365 + "line": 366 } } }, @@ -197018,7 +197020,7 @@ "location": { "start": { "column": 8, - "line": 365 + "line": 366 } } }, @@ -197028,7 +197030,7 @@ "location": { "start": { "column": 8, - "line": 365 + "line": 366 } } }, @@ -197038,7 +197040,7 @@ "location": { "start": { "column": 8, - "line": 365 + "line": 366 } } }, @@ -197048,7 +197050,7 @@ "location": { "start": { "column": 8, - "line": 365 + "line": 366 } } }, @@ -197058,7 +197060,7 @@ "location": { "start": { "column": 6, - "line": 371 + "line": 372 } } }, @@ -197068,7 +197070,7 @@ "location": { "start": { "column": 8, - "line": 418 + "line": 419 } } }, @@ -197078,7 +197080,7 @@ "location": { "start": { "column": 8, - "line": 418 + "line": 419 } } }, @@ -197088,7 +197090,7 @@ "location": { "start": { "column": 8, - "line": 418 + "line": 419 } } }, @@ -197098,12 +197100,12 @@ "location": { "start": { "column": 6, - "line": 424 + "line": 425 } } } ], - "source": "import { GameHistoryRecordRepository } from \"@/modules/game/providers/repositories/game-history-record/game-history-record.repository\";\nimport { GameRepository } from \"@/modules/game/providers/repositories/game.repository\";\nimport { GameHistoryRecordService } from \"@/modules/game/providers/services/game-history/game-history-record.service\";\nimport type { GameHistoryRecordPlay } from \"@/modules/game/schemas/game-history-record/game-history-record-play/game-history-record-play.schema\";\nimport type { DeadPlayer } from \"@/modules/game/schemas/player/dead-player.schema\";\nimport type { GameHistoryRecordToInsert } from \"@/modules/game/types/game-history-record/game-history-record.types\";\n\nimport { ApiResources } from \"@/shared/api/enums/api.enums\";\nimport { ResourceNotFoundReasons } from \"@/shared/exception/enums/resource-not-found-error.enum\";\nimport { ResourceNotFoundException } from \"@/shared/exception/types/resource-not-found-exception.types\";\nimport type { TestingModule } from \"@nestjs/testing\";\nimport { Test } from \"@nestjs/testing\";\n\nimport { createFakeGetGameHistoryDto } from \"@tests/factories/game/dto/get-game-history/get-game-history.dto.factory\";\nimport { createFakeGameAdditionalCard } from \"@tests/factories/game/schemas/game-additional-card/game-additional-card.schema.factory\";\nimport { createFakeGameHistoryRecordPlay } from \"@tests/factories/game/schemas/game-history-record/game-history-record.schema.factory\";\nimport { createFakeGamePlay } from \"@tests/factories/game/schemas/game-play/game-play.schema.factory\";\nimport { createFakeGame } from \"@tests/factories/game/schemas/game.schema.factory\";\nimport { createFakeVillagerAlivePlayer, createFakeWerewolfAlivePlayer } from \"@tests/factories/game/schemas/player/player-with-role.schema.factory\";\nimport { createFakeDeadPlayer, createFakePlayer } from \"@tests/factories/game/schemas/player/player.schema.factory\";\nimport { createFakeGameHistoryRecordToInsert } from \"@tests/factories/game/types/game-history-record/game-history-record.type.factory\";\nimport { createFakeObjectId } from \"@tests/factories/shared/mongoose/mongoose.factory\";\nimport { when } from \"jest-when\";\n\ndescribe(\"Game History Record Service\", () => {\n let mocks: {\n gameHistoryRecordService: {\n validateGameHistoryRecordToInsertData: jest.SpyInstance;\n };\n gameHistoryRecordRepository: {\n create: jest.SpyInstance;\n getLastGameHistoryDefenderProtectsRecord: jest.SpyInstance;\n getLastGameHistorySurvivorsVoteRecord: jest.SpyInstance;\n getLastGameHistoryTieInVotesRecord: jest.SpyInstance;\n getGameHistoryWitchUsesSpecificPotionRecords: jest.SpyInstance;\n getLastGameHistoryAccursedWolfFatherInfectsRecord: jest.SpyInstance;\n getGameHistoryStutteringJudgeRequestsAnotherVoteRecords: jest.SpyInstance;\n getGameHistoryJudgeChoosesHisSignRecords: jest.SpyInstance;\n getGameHistoryWerewolvesEatElderRecords: jest.SpyInstance;\n getGameHistoryElderProtectedFromWerewolvesRecords: jest.SpyInstance;\n getPreviousGameHistoryRecord: jest.SpyInstance;\n getGameHistory: jest.SpyInstance;\n getGameHistoryRecordsForTurnAndPhases: jest.SpyInstance;\n getGameHistoryGamePlayRecords: jest.SpyInstance;\n getGameHistoryGamePlayMadeByPlayerRecords: jest.SpyInstance;\n getGameHistoryAccursedWolfFatherInfectsWithTargetRecords: jest.SpyInstance;\n };\n gameRepository: { findOne: jest.SpyInstance };\n };\n let services: { gameHistoryRecord: GameHistoryRecordService };\n let repositories: { gameHistoryRecord: GameHistoryRecordRepository };\n\n beforeEach(async() => {\n mocks = {\n gameHistoryRecordService: {\n validateGameHistoryRecordToInsertData: jest.fn(),\n },\n gameHistoryRecordRepository: {\n create: jest.fn(),\n getLastGameHistoryDefenderProtectsRecord: jest.fn(),\n getLastGameHistorySurvivorsVoteRecord: jest.fn(),\n getLastGameHistoryTieInVotesRecord: jest.fn(),\n getGameHistoryWitchUsesSpecificPotionRecords: jest.fn(),\n getLastGameHistoryAccursedWolfFatherInfectsRecord: jest.fn(),\n getGameHistoryStutteringJudgeRequestsAnotherVoteRecords: jest.fn(),\n getGameHistoryJudgeChoosesHisSignRecords: jest.fn(),\n getGameHistoryWerewolvesEatElderRecords: jest.fn(),\n getGameHistoryElderProtectedFromWerewolvesRecords: jest.fn(),\n getPreviousGameHistoryRecord: jest.fn(),\n getGameHistory: jest.fn(),\n getGameHistoryRecordsForTurnAndPhases: jest.fn(),\n getGameHistoryGamePlayRecords: jest.fn(),\n getGameHistoryGamePlayMadeByPlayerRecords: jest.fn(),\n getGameHistoryAccursedWolfFatherInfectsWithTargetRecords: jest.fn(),\n },\n gameRepository: { findOne: jest.fn() },\n };\n\n const module: TestingModule = await Test.createTestingModule({\n providers: [\n {\n provide: GameHistoryRecordRepository,\n useValue: mocks.gameHistoryRecordRepository,\n },\n {\n provide: GameRepository,\n useValue: mocks.gameRepository,\n },\n GameHistoryRecordService,\n ],\n }).compile();\n\n services = { gameHistoryRecord: module.get(GameHistoryRecordService) };\n repositories = { gameHistoryRecord: module.get(GameHistoryRecordRepository) };\n });\n\n describe(\"createGameHistoryRecord\", () => {\n beforeEach(() => {\n mocks.gameHistoryRecordService.validateGameHistoryRecordToInsertData = jest.spyOn(services.gameHistoryRecord as unknown as { validateGameHistoryRecordToInsertData }, \"validateGameHistoryRecordToInsertData\").mockImplementation();\n });\n\n it(\"should create game history record when called with valid data.\", async() => {\n mocks.gameHistoryRecordService.validateGameHistoryRecordToInsertData.mockImplementation();\n const validPlay = createFakeGameHistoryRecordToInsert({\n gameId: createFakeObjectId(),\n play: createFakeGameHistoryRecordPlay(),\n });\n await services.gameHistoryRecord.createGameHistoryRecord(validPlay);\n\n expect(mocks.gameHistoryRecordRepository.create).toHaveBeenCalledExactlyOnceWith(validPlay);\n });\n });\n\n describe(\"getLastGameHistoryDefenderProtectsRecord\", () => {\n it(\"should get game history when defender protected when called.\", async() => {\n const defenderPlayerId = createFakeObjectId();\n const gameId = createFakeObjectId();\n await services.gameHistoryRecord.getLastGameHistoryDefenderProtectsRecord(gameId, defenderPlayerId);\n\n expect(mocks.gameHistoryRecordRepository.getLastGameHistoryDefenderProtectsRecord).toHaveBeenCalledExactlyOnceWith(gameId, defenderPlayerId);\n });\n });\n\n describe(\"getLastGameHistorySurvivorsVoteRecord\", () => {\n it(\"should get last game history when survivors voted when called.\", async() => {\n const gameId = createFakeObjectId();\n await services.gameHistoryRecord.getLastGameHistorySurvivorsVoteRecord(gameId);\n\n expect(mocks.gameHistoryRecordRepository.getLastGameHistorySurvivorsVoteRecord).toHaveBeenCalledExactlyOnceWith(gameId);\n });\n });\n\n describe(\"getLastGameHistoryTieInVotesRecord\", () => {\n it(\"should get game history when all voted and there was a tie when called.\", async() => {\n const gameId = createFakeObjectId();\n await services.gameHistoryRecord.getLastGameHistoryTieInVotesRecord(gameId, \"vote\");\n\n expect(mocks.gameHistoryRecordRepository.getLastGameHistoryTieInVotesRecord).toHaveBeenCalledExactlyOnceWith(gameId, \"vote\");\n });\n });\n\n describe(\"getGameHistoryWitchUsesSpecificPotionRecords\", () => {\n it(\"should get game history records when witch used life potion when called.\", async() => {\n const witchPlayerId = createFakeObjectId();\n const gameId = createFakeObjectId();\n await services.gameHistoryRecord.getGameHistoryWitchUsesSpecificPotionRecords(gameId, witchPlayerId, \"life\");\n\n expect(mocks.gameHistoryRecordRepository.getGameHistoryWitchUsesSpecificPotionRecords).toHaveBeenCalledExactlyOnceWith(gameId, witchPlayerId, \"life\");\n });\n\n it(\"should get game history records when witch used death potion when called.\", async() => {\n const witchPlayerId = createFakeObjectId();\n const gameId = createFakeObjectId();\n await services.gameHistoryRecord.getGameHistoryWitchUsesSpecificPotionRecords(gameId, witchPlayerId, \"death\");\n\n expect(mocks.gameHistoryRecordRepository.getGameHistoryWitchUsesSpecificPotionRecords).toHaveBeenCalledExactlyOnceWith(gameId, witchPlayerId, \"death\");\n });\n });\n\n describe(\"getGameHistoryAccursedWolfFatherInfectsWithTargetRecords\", () => {\n it(\"should get game history records when accursed wolf-father infected a player when called.\", async() => {\n const accursedWolfFatherPlayerId = createFakeObjectId();\n const gameId = createFakeObjectId();\n await services.gameHistoryRecord.getGameHistoryAccursedWolfFatherInfectsWithTargetRecords(gameId, accursedWolfFatherPlayerId);\n\n expect(mocks.gameHistoryRecordRepository.getGameHistoryAccursedWolfFatherInfectsWithTargetRecords).toHaveBeenCalledExactlyOnceWith(gameId, accursedWolfFatherPlayerId);\n });\n });\n\n describe(\"getLastGameHistoryAccursedWolfFatherInfectsRecord\", () => {\n it(\"should get last game history records when accursed wolf-father infected a player when called.\", async() => {\n const accursedWolfFatherPlayerId = createFakeObjectId();\n const gameId = createFakeObjectId();\n await services.gameHistoryRecord.getLastGameHistoryAccursedWolfFatherInfectsRecord(gameId, accursedWolfFatherPlayerId);\n\n expect(mocks.gameHistoryRecordRepository.getLastGameHistoryAccursedWolfFatherInfectsRecord).toHaveBeenCalledExactlyOnceWith(gameId, accursedWolfFatherPlayerId);\n });\n });\n\n describe(\"getGameHistoryStutteringJudgeRequestsAnotherVoteRecords\", () => {\n it(\"should get game history records when stuttering judge requested another vote when called.\", async() => {\n const stutteringJudgePlayerId = createFakeObjectId();\n const gameId = createFakeObjectId();\n await services.gameHistoryRecord.getGameHistoryStutteringJudgeRequestsAnotherVoteRecords(gameId, stutteringJudgePlayerId);\n\n expect(mocks.gameHistoryRecordRepository.getGameHistoryStutteringJudgeRequestsAnotherVoteRecords).toHaveBeenCalledExactlyOnceWith(gameId, stutteringJudgePlayerId);\n });\n });\n\n describe(\"getGameHistoryWerewolvesEatElderRecords\", () => {\n it(\"should get game history records when any kind of werewolves eat elder when called.\", async() => {\n const elderPlayerId = createFakeObjectId();\n const gameId = createFakeObjectId();\n await services.gameHistoryRecord.getGameHistoryWerewolvesEatElderRecords(gameId, elderPlayerId);\n\n expect(repositories.gameHistoryRecord.getGameHistoryWerewolvesEatElderRecords).toHaveBeenCalledExactlyOnceWith(gameId, elderPlayerId);\n });\n });\n\n describe(\"getGameHistoryElderProtectedFromWerewolvesRecords\", () => {\n it(\"should get game history records when elder is protected from werewolves when called.\", async() => {\n const elderPlayerId = createFakeObjectId();\n const gameId = createFakeObjectId();\n await services.gameHistoryRecord.getGameHistoryElderProtectedFromWerewolvesRecords(gameId, elderPlayerId);\n\n expect(repositories.gameHistoryRecord.getGameHistoryElderProtectedFromWerewolvesRecords).toHaveBeenCalledExactlyOnceWith(gameId, elderPlayerId);\n });\n });\n\n describe(\"getGameHistoryRecordsForTurnAndPhases\", () => {\n it(\"should call getGameHistoryRecordsForTurnAndPhases method when called.\", async() => {\n const game = createFakeGame();\n await services.gameHistoryRecord.getGameHistoryRecordsForTurnAndPhases(game._id, game.turn, [game.phase.name]);\n\n expect(mocks.gameHistoryRecordRepository.getGameHistoryRecordsForTurnAndPhases).toHaveBeenCalledExactlyOnceWith(game._id, game.turn, [game.phase.name]);\n });\n });\n\n describe(\"getPreviousGameHistoryRecord\", () => {\n it(\"should previous game history record when called.\", async() => {\n const gameId = createFakeObjectId();\n await services.gameHistoryRecord.getPreviousGameHistoryRecord(gameId);\n\n expect(repositories.gameHistoryRecord.getPreviousGameHistoryRecord).toHaveBeenCalledExactlyOnceWith(gameId);\n });\n });\n\n describe(\"getGameHistory\", () => {\n it(\"should call getGameHistory repository method when called.\", async() => {\n const game = createFakeGame();\n const getGameHistoryDto = createFakeGetGameHistoryDto();\n await services.gameHistoryRecord.getGameHistory(game._id, getGameHistoryDto);\n\n expect(mocks.gameHistoryRecordRepository.getGameHistory).toHaveBeenCalledExactlyOnceWith(game._id, getGameHistoryDto);\n });\n });\n\n describe(\"hasGamePlayBeenMade\", () => {\n it(\"should call getGameHistoryGamePlayMadeByPlayerRecords repository method when called.\", async() => {\n const game = createFakeGame();\n const gamePlay = createFakeGamePlay();\n mocks.gameHistoryRecordRepository.getGameHistoryGamePlayRecords.mockResolvedValueOnce([]);\n await services.gameHistoryRecord.hasGamePlayBeenMade(game._id, gamePlay);\n\n expect(mocks.gameHistoryRecordRepository.getGameHistoryGamePlayRecords).toHaveBeenCalledExactlyOnceWith(game._id, gamePlay, { limit: 1 });\n });\n\n it(\"should return false when there is no game play record.\", async() => {\n const game = createFakeGame();\n const gamePlay = createFakeGamePlay();\n mocks.gameHistoryRecordRepository.getGameHistoryGamePlayRecords.mockResolvedValueOnce([]);\n\n await expect(services.gameHistoryRecord.hasGamePlayBeenMade(game._id, gamePlay)).resolves.toBe(false);\n });\n\n it(\"should return true when there is a game play record.\", async() => {\n const game = createFakeGame();\n const gamePlay = createFakeGamePlay();\n mocks.gameHistoryRecordRepository.getGameHistoryGamePlayRecords.mockResolvedValueOnce([createFakeGameHistoryRecordPlay()]);\n\n await expect(services.gameHistoryRecord.hasGamePlayBeenMade(game._id, gamePlay)).resolves.toBe(true);\n });\n });\n\n describe(\"hasGamePlayBeenMadeByPlayer\", () => {\n it(\"should call getGameHistoryGamePlayMadeByPlayerRecords repository method when called.\", async() => {\n const game = createFakeGame();\n const gamePlay = createFakeGamePlay();\n const player = createFakePlayer();\n mocks.gameHistoryRecordRepository.getGameHistoryGamePlayMadeByPlayerRecords.mockResolvedValueOnce([]);\n await services.gameHistoryRecord.hasGamePlayBeenMadeByPlayer(game._id, gamePlay, player);\n\n expect(mocks.gameHistoryRecordRepository.getGameHistoryGamePlayMadeByPlayerRecords).toHaveBeenCalledExactlyOnceWith(game._id, gamePlay, player, { limit: 1 });\n });\n\n it(\"should return false when there is no game play record.\", async() => {\n const game = createFakeGame();\n const gamePlay = createFakeGamePlay();\n const player = createFakePlayer();\n mocks.gameHistoryRecordRepository.getGameHistoryGamePlayMadeByPlayerRecords.mockResolvedValueOnce([]);\n\n await expect(services.gameHistoryRecord.hasGamePlayBeenMadeByPlayer(game._id, gamePlay, player)).resolves.toBe(false);\n });\n\n it(\"should return true when there is a game play record.\", async() => {\n const game = createFakeGame();\n const gamePlay = createFakeGamePlay();\n const player = createFakePlayer();\n mocks.gameHistoryRecordRepository.getGameHistoryGamePlayMadeByPlayerRecords.mockResolvedValueOnce([createFakeGameHistoryRecordPlay()]);\n\n await expect(services.gameHistoryRecord.hasGamePlayBeenMadeByPlayer(game._id, gamePlay, player)).resolves.toBe(true);\n });\n });\n\n describe(\"validateGameHistoryRecordToInsertPlayData\", () => {\n const fakeGameAdditionalCards = [\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n ];\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const fakeGame = createFakeGame({ players, additionalCards: fakeGameAdditionalCards });\n const fakePlayer = createFakePlayer();\n const fakeCard = createFakeGameAdditionalCard();\n\n it.each<{\n test: string;\n play: GameHistoryRecordPlay;\n errorParameters: [ApiResources, string, ResourceNotFoundReasons];\n }>([\n {\n test: \"should throw resource not found error when source is not in the game.\",\n play: createFakeGameHistoryRecordPlay({ source: { name: \"sheriff\", players: [fakePlayer] } }),\n errorParameters: [ApiResources.PLAYERS, fakePlayer._id.toString(), ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_PLAYER_SOURCE],\n },\n {\n test: \"should throw resource not found error when a target is not in the game.\",\n play: createFakeGameHistoryRecordPlay({\n source: {\n name: \"sheriff\",\n players: fakeGame.players,\n },\n targets: [{ player: fakePlayer }],\n }),\n errorParameters: [ApiResources.PLAYERS, fakePlayer._id.toString(), ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_PLAYER_TARGET],\n },\n {\n test: \"should throw resource not found error when a vote source is not in the game.\",\n play: createFakeGameHistoryRecordPlay({\n source: {\n name: \"sheriff\",\n players: fakeGame.players,\n },\n votes: [{ source: fakePlayer, target: fakeGame.players[0] }],\n }),\n errorParameters: [ApiResources.PLAYERS, fakePlayer._id.toString(), ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_PLAYER_VOTE_SOURCE],\n },\n {\n test: \"should throw resource not found error when a vote target is not in the game.\",\n play: createFakeGameHistoryRecordPlay({\n source: {\n name: \"sheriff\",\n players: fakeGame.players,\n },\n votes: [{ target: fakePlayer, source: fakeGame.players[0] }],\n }),\n errorParameters: [ApiResources.PLAYERS, fakePlayer._id.toString(), ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_PLAYER_VOTE_TARGET],\n },\n {\n test: \"should throw resource not found error when chosen card is not in the game.\",\n play: createFakeGameHistoryRecordPlay({\n source: {\n name: \"sheriff\",\n players: fakeGame.players,\n },\n chosenCard: fakeCard,\n }),\n errorParameters: [ApiResources.GAME_ADDITIONAL_CARDS, fakeCard._id.toString(), ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_CHOSEN_CARD],\n },\n ])(\"$test\", ({ play, errorParameters }) => {\n const expectedException = new ResourceNotFoundException(...errorParameters);\n\n expect(() => services.gameHistoryRecord[\"validateGameHistoryRecordToInsertPlayData\"](play, fakeGame)).toThrow(expectedException);\n });\n\n it(\"should not throw any errors when called with valid play data.\", () => {\n const validPlay = createFakeGameHistoryRecordPlay({\n source: {\n name: \"sheriff\",\n players: fakeGame.players,\n },\n targets: [{ player: fakeGame.players[0] }],\n votes: [{ target: fakeGame.players[1], source: fakeGame.players[0] }],\n chosenCard: fakeGameAdditionalCards[1],\n });\n\n expect(() => services.gameHistoryRecord[\"validateGameHistoryRecordToInsertPlayData\"](validPlay, fakeGame)).not.toThrow();\n });\n });\n\n describe(\"validateGameHistoryRecordToInsertData\", () => {\n const existingId = createFakeObjectId();\n const existingGame = createFakeGame();\n const fakePlayer = createFakePlayer();\n const fakeDeadPlayer = createFakeDeadPlayer();\n const unknownId = createFakeObjectId();\n\n beforeEach(() => {\n when(mocks.gameRepository.findOne).calledWith({ _id: unknownId.toJSON() }).mockResolvedValue(null);\n when(mocks.gameRepository.findOne).calledWith({ _id: existingId.toJSON() }).mockResolvedValue(existingGame);\n });\n\n it.each<{\n test: string;\n gameHistoryRecord: GameHistoryRecordToInsert;\n errorParameters: [ApiResources, string, ResourceNotFoundReasons];\n }>([\n {\n test: \"should throw resource not found error when game is not found with specified gameId.\",\n gameHistoryRecord: createFakeGameHistoryRecordToInsert({ gameId: unknownId }),\n errorParameters: [ApiResources.GAMES, unknownId.toString(), ResourceNotFoundReasons.UNKNOWN_GAME_PLAY_GAME_ID],\n },\n {\n test: \"should throw resource not found error when a revealed player is not in the game.\",\n gameHistoryRecord: createFakeGameHistoryRecordToInsert({ gameId: existingId, revealedPlayers: [fakePlayer] }),\n errorParameters: [ApiResources.PLAYERS, fakePlayer._id.toString(), ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_REVEALED_PLAYER],\n },\n {\n test: \"should throw resource not found error when a dead player is not in the game.\",\n gameHistoryRecord: createFakeGameHistoryRecordToInsert({ gameId: existingId, deadPlayers: [fakeDeadPlayer] }),\n errorParameters: [ApiResources.PLAYERS, fakeDeadPlayer._id.toString(), ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_DEAD_PLAYER],\n },\n ])(\"$test\", async({ gameHistoryRecord, errorParameters }) => {\n const expectedException = new ResourceNotFoundException(...errorParameters);\n\n await expect(services.gameHistoryRecord[\"validateGameHistoryRecordToInsertData\"](gameHistoryRecord)).rejects.toStrictEqual(expectedException);\n });\n\n it(\"should not throw any errors when called with valid data.\", async() => {\n const validPlay = createFakeGameHistoryRecordToInsert({\n gameId: existingId,\n play: createFakeGameHistoryRecordPlay({ source: { name: \"sheriff\", players: existingGame.players } }),\n revealedPlayers: existingGame.players,\n deadPlayers: existingGame.players.map(player => createFakeDeadPlayer(player as DeadPlayer)),\n });\n\n await expect(services.gameHistoryRecord[\"validateGameHistoryRecordToInsertData\"](validPlay)).resolves.not.toThrow();\n });\n });\n});" + "source": "import type { TestingModule } from \"@nestjs/testing\";\nimport { Test } from \"@nestjs/testing\";\nimport { when } from \"jest-when\";\n\nimport { GameHistoryRecordRepository } from \"@/modules/game/providers/repositories/game-history-record/game-history-record.repository\";\nimport { GameRepository } from \"@/modules/game/providers/repositories/game.repository\";\nimport { GameHistoryRecordService } from \"@/modules/game/providers/services/game-history/game-history-record.service\";\nimport type { GameHistoryRecordPlay } from \"@/modules/game/schemas/game-history-record/game-history-record-play/game-history-record-play.schema\";\nimport type { DeadPlayer } from \"@/modules/game/schemas/player/dead-player.schema\";\nimport type { GameHistoryRecordToInsert } from \"@/modules/game/types/game-history-record/game-history-record.types\";\n\nimport { ApiResources } from \"@/shared/api/enums/api.enums\";\nimport { ResourceNotFoundReasons } from \"@/shared/exception/enums/resource-not-found-error.enums\";\nimport { ResourceNotFoundException } from \"@/shared/exception/types/resource-not-found-exception.types\";\n\nimport { createFakeGetGameHistoryDto } from \"@tests/factories/game/dto/get-game-history/get-game-history.dto.factory\";\nimport { createFakeGameAdditionalCard } from \"@tests/factories/game/schemas/game-additional-card/game-additional-card.schema.factory\";\nimport { createFakeGameHistoryRecordPlay } from \"@tests/factories/game/schemas/game-history-record/game-history-record.schema.factory\";\nimport { createFakeGamePlay } from \"@tests/factories/game/schemas/game-play/game-play.schema.factory\";\nimport { createFakeGame } from \"@tests/factories/game/schemas/game.schema.factory\";\nimport { createFakeVillagerAlivePlayer, createFakeWerewolfAlivePlayer } from \"@tests/factories/game/schemas/player/player-with-role.schema.factory\";\nimport { createFakeDeadPlayer, createFakePlayer } from \"@tests/factories/game/schemas/player/player.schema.factory\";\nimport { createFakeGameHistoryRecordToInsert } from \"@tests/factories/game/types/game-history-record/game-history-record.type.factory\";\nimport { createFakeObjectId } from \"@tests/factories/shared/mongoose/mongoose.factory\";\n\ndescribe(\"Game History Record Service\", () => {\n let mocks: {\n gameHistoryRecordService: {\n validateGameHistoryRecordToInsertData: jest.SpyInstance;\n };\n gameHistoryRecordRepository: {\n create: jest.SpyInstance;\n getLastGameHistoryDefenderProtectsRecord: jest.SpyInstance;\n getLastGameHistorySurvivorsVoteRecord: jest.SpyInstance;\n getLastGameHistoryTieInVotesRecord: jest.SpyInstance;\n getGameHistoryWitchUsesSpecificPotionRecords: jest.SpyInstance;\n getLastGameHistoryAccursedWolfFatherInfectsRecord: jest.SpyInstance;\n getGameHistoryStutteringJudgeRequestsAnotherVoteRecords: jest.SpyInstance;\n getGameHistoryJudgeChoosesHisSignRecords: jest.SpyInstance;\n getGameHistoryWerewolvesEatElderRecords: jest.SpyInstance;\n getGameHistoryElderProtectedFromWerewolvesRecords: jest.SpyInstance;\n getPreviousGameHistoryRecord: jest.SpyInstance;\n getGameHistory: jest.SpyInstance;\n getGameHistoryRecordsForTurnAndPhases: jest.SpyInstance;\n getGameHistoryGamePlayRecords: jest.SpyInstance;\n getGameHistoryGamePlayMadeByPlayerRecords: jest.SpyInstance;\n getGameHistoryAccursedWolfFatherInfectsWithTargetRecords: jest.SpyInstance;\n };\n gameRepository: { findOne: jest.SpyInstance };\n };\n let services: { gameHistoryRecord: GameHistoryRecordService };\n let repositories: { gameHistoryRecord: GameHistoryRecordRepository };\n\n beforeEach(async() => {\n mocks = {\n gameHistoryRecordService: {\n validateGameHistoryRecordToInsertData: jest.fn(),\n },\n gameHistoryRecordRepository: {\n create: jest.fn(),\n getLastGameHistoryDefenderProtectsRecord: jest.fn(),\n getLastGameHistorySurvivorsVoteRecord: jest.fn(),\n getLastGameHistoryTieInVotesRecord: jest.fn(),\n getGameHistoryWitchUsesSpecificPotionRecords: jest.fn(),\n getLastGameHistoryAccursedWolfFatherInfectsRecord: jest.fn(),\n getGameHistoryStutteringJudgeRequestsAnotherVoteRecords: jest.fn(),\n getGameHistoryJudgeChoosesHisSignRecords: jest.fn(),\n getGameHistoryWerewolvesEatElderRecords: jest.fn(),\n getGameHistoryElderProtectedFromWerewolvesRecords: jest.fn(),\n getPreviousGameHistoryRecord: jest.fn(),\n getGameHistory: jest.fn(),\n getGameHistoryRecordsForTurnAndPhases: jest.fn(),\n getGameHistoryGamePlayRecords: jest.fn(),\n getGameHistoryGamePlayMadeByPlayerRecords: jest.fn(),\n getGameHistoryAccursedWolfFatherInfectsWithTargetRecords: jest.fn(),\n },\n gameRepository: { findOne: jest.fn() },\n };\n\n const module: TestingModule = await Test.createTestingModule({\n providers: [\n {\n provide: GameHistoryRecordRepository,\n useValue: mocks.gameHistoryRecordRepository,\n },\n {\n provide: GameRepository,\n useValue: mocks.gameRepository,\n },\n GameHistoryRecordService,\n ],\n }).compile();\n\n services = { gameHistoryRecord: module.get(GameHistoryRecordService) };\n repositories = { gameHistoryRecord: module.get(GameHistoryRecordRepository) };\n });\n\n describe(\"createGameHistoryRecord\", () => {\n beforeEach(() => {\n mocks.gameHistoryRecordService.validateGameHistoryRecordToInsertData = jest.spyOn(services.gameHistoryRecord as unknown as { validateGameHistoryRecordToInsertData }, \"validateGameHistoryRecordToInsertData\").mockImplementation();\n });\n\n it(\"should create game history record when called with valid data.\", async() => {\n mocks.gameHistoryRecordService.validateGameHistoryRecordToInsertData.mockImplementation();\n const validPlay = createFakeGameHistoryRecordToInsert({\n gameId: createFakeObjectId(),\n play: createFakeGameHistoryRecordPlay(),\n });\n await services.gameHistoryRecord.createGameHistoryRecord(validPlay);\n\n expect(mocks.gameHistoryRecordRepository.create).toHaveBeenCalledExactlyOnceWith(validPlay);\n });\n });\n\n describe(\"getLastGameHistoryDefenderProtectsRecord\", () => {\n it(\"should get game history when defender protected when called.\", async() => {\n const defenderPlayerId = createFakeObjectId();\n const gameId = createFakeObjectId();\n await services.gameHistoryRecord.getLastGameHistoryDefenderProtectsRecord(gameId, defenderPlayerId);\n\n expect(mocks.gameHistoryRecordRepository.getLastGameHistoryDefenderProtectsRecord).toHaveBeenCalledExactlyOnceWith(gameId, defenderPlayerId);\n });\n });\n\n describe(\"getLastGameHistorySurvivorsVoteRecord\", () => {\n it(\"should get last game history when survivors voted when called.\", async() => {\n const gameId = createFakeObjectId();\n await services.gameHistoryRecord.getLastGameHistorySurvivorsVoteRecord(gameId);\n\n expect(mocks.gameHistoryRecordRepository.getLastGameHistorySurvivorsVoteRecord).toHaveBeenCalledExactlyOnceWith(gameId);\n });\n });\n\n describe(\"getLastGameHistoryTieInVotesRecord\", () => {\n it(\"should get game history when all voted and there was a tie when called.\", async() => {\n const gameId = createFakeObjectId();\n await services.gameHistoryRecord.getLastGameHistoryTieInVotesRecord(gameId, \"vote\");\n\n expect(mocks.gameHistoryRecordRepository.getLastGameHistoryTieInVotesRecord).toHaveBeenCalledExactlyOnceWith(gameId, \"vote\");\n });\n });\n\n describe(\"getGameHistoryWitchUsesSpecificPotionRecords\", () => {\n it(\"should get game history records when witch used life potion when called.\", async() => {\n const witchPlayerId = createFakeObjectId();\n const gameId = createFakeObjectId();\n await services.gameHistoryRecord.getGameHistoryWitchUsesSpecificPotionRecords(gameId, witchPlayerId, \"life\");\n\n expect(mocks.gameHistoryRecordRepository.getGameHistoryWitchUsesSpecificPotionRecords).toHaveBeenCalledExactlyOnceWith(gameId, witchPlayerId, \"life\");\n });\n\n it(\"should get game history records when witch used death potion when called.\", async() => {\n const witchPlayerId = createFakeObjectId();\n const gameId = createFakeObjectId();\n await services.gameHistoryRecord.getGameHistoryWitchUsesSpecificPotionRecords(gameId, witchPlayerId, \"death\");\n\n expect(mocks.gameHistoryRecordRepository.getGameHistoryWitchUsesSpecificPotionRecords).toHaveBeenCalledExactlyOnceWith(gameId, witchPlayerId, \"death\");\n });\n });\n\n describe(\"getGameHistoryAccursedWolfFatherInfectsWithTargetRecords\", () => {\n it(\"should get game history records when accursed wolf-father infected a player when called.\", async() => {\n const accursedWolfFatherPlayerId = createFakeObjectId();\n const gameId = createFakeObjectId();\n await services.gameHistoryRecord.getGameHistoryAccursedWolfFatherInfectsWithTargetRecords(gameId, accursedWolfFatherPlayerId);\n\n expect(mocks.gameHistoryRecordRepository.getGameHistoryAccursedWolfFatherInfectsWithTargetRecords).toHaveBeenCalledExactlyOnceWith(gameId, accursedWolfFatherPlayerId);\n });\n });\n\n describe(\"getLastGameHistoryAccursedWolfFatherInfectsRecord\", () => {\n it(\"should get last game history records when accursed wolf-father infected a player when called.\", async() => {\n const accursedWolfFatherPlayerId = createFakeObjectId();\n const gameId = createFakeObjectId();\n await services.gameHistoryRecord.getLastGameHistoryAccursedWolfFatherInfectsRecord(gameId, accursedWolfFatherPlayerId);\n\n expect(mocks.gameHistoryRecordRepository.getLastGameHistoryAccursedWolfFatherInfectsRecord).toHaveBeenCalledExactlyOnceWith(gameId, accursedWolfFatherPlayerId);\n });\n });\n\n describe(\"getGameHistoryStutteringJudgeRequestsAnotherVoteRecords\", () => {\n it(\"should get game history records when stuttering judge requested another vote when called.\", async() => {\n const stutteringJudgePlayerId = createFakeObjectId();\n const gameId = createFakeObjectId();\n await services.gameHistoryRecord.getGameHistoryStutteringJudgeRequestsAnotherVoteRecords(gameId, stutteringJudgePlayerId);\n\n expect(mocks.gameHistoryRecordRepository.getGameHistoryStutteringJudgeRequestsAnotherVoteRecords).toHaveBeenCalledExactlyOnceWith(gameId, stutteringJudgePlayerId);\n });\n });\n\n describe(\"getGameHistoryWerewolvesEatElderRecords\", () => {\n it(\"should get game history records when any kind of werewolves eat elder when called.\", async() => {\n const elderPlayerId = createFakeObjectId();\n const gameId = createFakeObjectId();\n await services.gameHistoryRecord.getGameHistoryWerewolvesEatElderRecords(gameId, elderPlayerId);\n\n expect(repositories.gameHistoryRecord.getGameHistoryWerewolvesEatElderRecords).toHaveBeenCalledExactlyOnceWith(gameId, elderPlayerId);\n });\n });\n\n describe(\"getGameHistoryElderProtectedFromWerewolvesRecords\", () => {\n it(\"should get game history records when elder is protected from werewolves when called.\", async() => {\n const elderPlayerId = createFakeObjectId();\n const gameId = createFakeObjectId();\n await services.gameHistoryRecord.getGameHistoryElderProtectedFromWerewolvesRecords(gameId, elderPlayerId);\n\n expect(repositories.gameHistoryRecord.getGameHistoryElderProtectedFromWerewolvesRecords).toHaveBeenCalledExactlyOnceWith(gameId, elderPlayerId);\n });\n });\n\n describe(\"getGameHistoryRecordsForTurnAndPhases\", () => {\n it(\"should call getGameHistoryRecordsForTurnAndPhases method when called.\", async() => {\n const game = createFakeGame();\n await services.gameHistoryRecord.getGameHistoryRecordsForTurnAndPhases(game._id, game.turn, [game.phase.name]);\n\n expect(mocks.gameHistoryRecordRepository.getGameHistoryRecordsForTurnAndPhases).toHaveBeenCalledExactlyOnceWith(game._id, game.turn, [game.phase.name]);\n });\n });\n\n describe(\"getPreviousGameHistoryRecord\", () => {\n it(\"should previous game history record when called.\", async() => {\n const gameId = createFakeObjectId();\n await services.gameHistoryRecord.getPreviousGameHistoryRecord(gameId);\n\n expect(repositories.gameHistoryRecord.getPreviousGameHistoryRecord).toHaveBeenCalledExactlyOnceWith(gameId);\n });\n });\n\n describe(\"getGameHistory\", () => {\n it(\"should call getGameHistory repository method when called.\", async() => {\n const game = createFakeGame();\n const getGameHistoryDto = createFakeGetGameHistoryDto();\n await services.gameHistoryRecord.getGameHistory(game._id, getGameHistoryDto);\n\n expect(mocks.gameHistoryRecordRepository.getGameHistory).toHaveBeenCalledExactlyOnceWith(game._id, getGameHistoryDto);\n });\n });\n\n describe(\"hasGamePlayBeenMade\", () => {\n it(\"should call getGameHistoryGamePlayMadeByPlayerRecords repository method when called.\", async() => {\n const game = createFakeGame();\n const gamePlay = createFakeGamePlay();\n mocks.gameHistoryRecordRepository.getGameHistoryGamePlayRecords.mockResolvedValueOnce([]);\n await services.gameHistoryRecord.hasGamePlayBeenMade(game._id, gamePlay);\n\n expect(mocks.gameHistoryRecordRepository.getGameHistoryGamePlayRecords).toHaveBeenCalledExactlyOnceWith(game._id, gamePlay, { limit: 1 });\n });\n\n it(\"should return false when there is no game play record.\", async() => {\n const game = createFakeGame();\n const gamePlay = createFakeGamePlay();\n mocks.gameHistoryRecordRepository.getGameHistoryGamePlayRecords.mockResolvedValueOnce([]);\n\n await expect(services.gameHistoryRecord.hasGamePlayBeenMade(game._id, gamePlay)).resolves.toBe(false);\n });\n\n it(\"should return true when there is a game play record.\", async() => {\n const game = createFakeGame();\n const gamePlay = createFakeGamePlay();\n mocks.gameHistoryRecordRepository.getGameHistoryGamePlayRecords.mockResolvedValueOnce([createFakeGameHistoryRecordPlay()]);\n\n await expect(services.gameHistoryRecord.hasGamePlayBeenMade(game._id, gamePlay)).resolves.toBe(true);\n });\n });\n\n describe(\"hasGamePlayBeenMadeByPlayer\", () => {\n it(\"should call getGameHistoryGamePlayMadeByPlayerRecords repository method when called.\", async() => {\n const game = createFakeGame();\n const gamePlay = createFakeGamePlay();\n const player = createFakePlayer();\n mocks.gameHistoryRecordRepository.getGameHistoryGamePlayMadeByPlayerRecords.mockResolvedValueOnce([]);\n await services.gameHistoryRecord.hasGamePlayBeenMadeByPlayer(game._id, gamePlay, player);\n\n expect(mocks.gameHistoryRecordRepository.getGameHistoryGamePlayMadeByPlayerRecords).toHaveBeenCalledExactlyOnceWith(game._id, gamePlay, player, { limit: 1 });\n });\n\n it(\"should return false when there is no game play record.\", async() => {\n const game = createFakeGame();\n const gamePlay = createFakeGamePlay();\n const player = createFakePlayer();\n mocks.gameHistoryRecordRepository.getGameHistoryGamePlayMadeByPlayerRecords.mockResolvedValueOnce([]);\n\n await expect(services.gameHistoryRecord.hasGamePlayBeenMadeByPlayer(game._id, gamePlay, player)).resolves.toBe(false);\n });\n\n it(\"should return true when there is a game play record.\", async() => {\n const game = createFakeGame();\n const gamePlay = createFakeGamePlay();\n const player = createFakePlayer();\n mocks.gameHistoryRecordRepository.getGameHistoryGamePlayMadeByPlayerRecords.mockResolvedValueOnce([createFakeGameHistoryRecordPlay()]);\n\n await expect(services.gameHistoryRecord.hasGamePlayBeenMadeByPlayer(game._id, gamePlay, player)).resolves.toBe(true);\n });\n });\n\n describe(\"validateGameHistoryRecordToInsertPlayData\", () => {\n const fakeGameAdditionalCards = [\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n createFakeGameAdditionalCard(),\n ];\n const players = [\n createFakeWerewolfAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n createFakeVillagerAlivePlayer(),\n ];\n const fakeGame = createFakeGame({ players, additionalCards: fakeGameAdditionalCards });\n const fakePlayer = createFakePlayer();\n const fakeCard = createFakeGameAdditionalCard();\n\n it.each<{\n test: string;\n play: GameHistoryRecordPlay;\n errorParameters: [ApiResources, string, ResourceNotFoundReasons];\n }>([\n {\n test: \"should throw resource not found error when source is not in the game.\",\n play: createFakeGameHistoryRecordPlay({ source: { name: \"sheriff\", players: [fakePlayer] } }),\n errorParameters: [ApiResources.PLAYERS, fakePlayer._id.toString(), ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_PLAYER_SOURCE],\n },\n {\n test: \"should throw resource not found error when a target is not in the game.\",\n play: createFakeGameHistoryRecordPlay({\n source: {\n name: \"sheriff\",\n players: fakeGame.players,\n },\n targets: [{ player: fakePlayer }],\n }),\n errorParameters: [ApiResources.PLAYERS, fakePlayer._id.toString(), ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_PLAYER_TARGET],\n },\n {\n test: \"should throw resource not found error when a vote source is not in the game.\",\n play: createFakeGameHistoryRecordPlay({\n source: {\n name: \"sheriff\",\n players: fakeGame.players,\n },\n votes: [{ source: fakePlayer, target: fakeGame.players[0] }],\n }),\n errorParameters: [ApiResources.PLAYERS, fakePlayer._id.toString(), ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_PLAYER_VOTE_SOURCE],\n },\n {\n test: \"should throw resource not found error when a vote target is not in the game.\",\n play: createFakeGameHistoryRecordPlay({\n source: {\n name: \"sheriff\",\n players: fakeGame.players,\n },\n votes: [{ target: fakePlayer, source: fakeGame.players[0] }],\n }),\n errorParameters: [ApiResources.PLAYERS, fakePlayer._id.toString(), ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_PLAYER_VOTE_TARGET],\n },\n {\n test: \"should throw resource not found error when chosen card is not in the game.\",\n play: createFakeGameHistoryRecordPlay({\n source: {\n name: \"sheriff\",\n players: fakeGame.players,\n },\n chosenCard: fakeCard,\n }),\n errorParameters: [ApiResources.GAME_ADDITIONAL_CARDS, fakeCard._id.toString(), ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_CHOSEN_CARD],\n },\n ])(\"$test\", ({ play, errorParameters }) => {\n const expectedException = new ResourceNotFoundException(...errorParameters);\n\n expect(() => services.gameHistoryRecord[\"validateGameHistoryRecordToInsertPlayData\"](play, fakeGame)).toThrow(expectedException);\n });\n\n it(\"should not throw any errors when called with valid play data.\", () => {\n const validPlay = createFakeGameHistoryRecordPlay({\n source: {\n name: \"sheriff\",\n players: fakeGame.players,\n },\n targets: [{ player: fakeGame.players[0] }],\n votes: [{ target: fakeGame.players[1], source: fakeGame.players[0] }],\n chosenCard: fakeGameAdditionalCards[1],\n });\n\n expect(() => services.gameHistoryRecord[\"validateGameHistoryRecordToInsertPlayData\"](validPlay, fakeGame)).not.toThrow();\n });\n });\n\n describe(\"validateGameHistoryRecordToInsertData\", () => {\n const existingId = createFakeObjectId();\n const existingGame = createFakeGame();\n const fakePlayer = createFakePlayer();\n const fakeDeadPlayer = createFakeDeadPlayer();\n const unknownId = createFakeObjectId();\n\n beforeEach(() => {\n when(mocks.gameRepository.findOne).calledWith({ _id: unknownId.toJSON() }).mockResolvedValue(null);\n when(mocks.gameRepository.findOne).calledWith({ _id: existingId.toJSON() }).mockResolvedValue(existingGame);\n });\n\n it.each<{\n test: string;\n gameHistoryRecord: GameHistoryRecordToInsert;\n errorParameters: [ApiResources, string, ResourceNotFoundReasons];\n }>([\n {\n test: \"should throw resource not found error when game is not found with specified gameId.\",\n gameHistoryRecord: createFakeGameHistoryRecordToInsert({ gameId: unknownId }),\n errorParameters: [ApiResources.GAMES, unknownId.toString(), ResourceNotFoundReasons.UNKNOWN_GAME_PLAY_GAME_ID],\n },\n {\n test: \"should throw resource not found error when a revealed player is not in the game.\",\n gameHistoryRecord: createFakeGameHistoryRecordToInsert({ gameId: existingId, revealedPlayers: [fakePlayer] }),\n errorParameters: [ApiResources.PLAYERS, fakePlayer._id.toString(), ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_REVEALED_PLAYER],\n },\n {\n test: \"should throw resource not found error when a dead player is not in the game.\",\n gameHistoryRecord: createFakeGameHistoryRecordToInsert({ gameId: existingId, deadPlayers: [fakeDeadPlayer] }),\n errorParameters: [ApiResources.PLAYERS, fakeDeadPlayer._id.toString(), ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_DEAD_PLAYER],\n },\n ])(\"$test\", async({ gameHistoryRecord, errorParameters }) => {\n const expectedException = new ResourceNotFoundException(...errorParameters);\n\n await expect(services.gameHistoryRecord[\"validateGameHistoryRecordToInsertData\"](gameHistoryRecord)).rejects.toStrictEqual(expectedException);\n });\n\n it(\"should not throw any errors when called with valid data.\", async() => {\n const validPlay = createFakeGameHistoryRecordToInsert({\n gameId: existingId,\n play: createFakeGameHistoryRecordPlay({ source: { name: \"sheriff\", players: existingGame.players } }),\n revealedPlayers: existingGame.players,\n deadPlayers: existingGame.players.map(player => createFakeDeadPlayer(player as DeadPlayer)),\n });\n\n await expect(services.gameHistoryRecord[\"validateGameHistoryRecordToInsertData\"](validPlay)).resolves.not.toThrow();\n });\n });\n});" }, "tests/unit/specs/modules/game/providers/services/game-play/game-play-maker/devoted-servant-game-play-maker.service.spec.ts": { "tests": [ @@ -199058,7 +199060,7 @@ "location": { "start": { "column": 8, - "line": 110 + "line": 111 } } }, @@ -199068,7 +199070,7 @@ "location": { "start": { "column": 8, - "line": 110 + "line": 111 } } }, @@ -199078,7 +199080,7 @@ "location": { "start": { "column": 8, - "line": 110 + "line": 111 } } }, @@ -199088,7 +199090,7 @@ "location": { "start": { "column": 8, - "line": 110 + "line": 111 } } }, @@ -199098,7 +199100,7 @@ "location": { "start": { "column": 8, - "line": 110 + "line": 111 } } }, @@ -199108,7 +199110,7 @@ "location": { "start": { "column": 8, - "line": 190 + "line": 191 } } }, @@ -199118,7 +199120,7 @@ "location": { "start": { "column": 8, - "line": 190 + "line": 191 } } }, @@ -199128,7 +199130,7 @@ "location": { "start": { "column": 8, - "line": 190 + "line": 191 } } }, @@ -199138,12 +199140,12 @@ "location": { "start": { "column": 8, - "line": 190 + "line": 191 } } } ], - "source": "import { doesHavePlayerAttributeAlterationWithNameAndStatus, doesHavePlayerAttributeAlterationWithNameSourceAndStatus } from \"@/modules/game/helpers/game-history-record/game-history-record.helpers\";\nimport type { GameHistoryRecord } from \"@/modules/game/schemas/game-history-record/game-history-record.schema\";\nimport type { GameHistoryRecordPlayerAttributeAlterationStatus } from \"@/modules/game/types/game-history-record/game-history-record.types\";\nimport type { GameSource } from \"@/modules/game/types/game.types\";\nimport type { PlayerAttributeName } from \"@/modules/game/types/player/player-attribute/player-attribute.types\";\nimport { createFakeGameHistoryRecord, createFakeGameHistoryRecordPlayerAttributeAlteration } from \"@tests/factories/game/schemas/game-history-record/game-history-record.schema.factory\";\n\ndescribe(\"Game History Record Helpers\", () => {\n describe(\"doesHavePlayerAttributeAlterationWithNameSourceAndStatus\", () => {\n it.each<{\n test: string;\n gameHistoryRecord: GameHistoryRecord;\n attributeName: PlayerAttributeName;\n source: GameSource;\n status: GameHistoryRecordPlayerAttributeAlterationStatus;\n expectedResult: boolean;\n }>([\n {\n test: \"should return true if the game history record has a player attribute alteration with the given name, source, and status\",\n gameHistoryRecord: createFakeGameHistoryRecord({\n playerAttributeAlterations: [\n createFakeGameHistoryRecordPlayerAttributeAlteration({\n name: \"worshiped\",\n source: \"witch\",\n status: \"attached\",\n }),\n createFakeGameHistoryRecordPlayerAttributeAlteration({\n name: \"sheriff\",\n source: \"survivors\",\n status: \"attached\",\n }),\n ],\n }),\n attributeName: \"sheriff\",\n source: \"survivors\",\n status: \"attached\",\n expectedResult: true,\n },\n {\n test: \"should return false if the game history record does not have a player attribute alteration with the given name\",\n gameHistoryRecord: createFakeGameHistoryRecord({\n playerAttributeAlterations: [\n createFakeGameHistoryRecordPlayerAttributeAlteration({\n name: \"worshiped\",\n source: \"witch\",\n status: \"attached\",\n }),\n createFakeGameHistoryRecordPlayerAttributeAlteration({\n name: \"sheriff\",\n source: \"survivors\",\n status: \"attached\",\n }),\n ],\n }),\n attributeName: \"seen\",\n source: \"survivors\",\n status: \"attached\",\n expectedResult: false,\n },\n {\n test: \"should return false if the game history record does not have a player attribute alteration with the given source\",\n gameHistoryRecord: createFakeGameHistoryRecord({\n playerAttributeAlterations: [\n createFakeGameHistoryRecordPlayerAttributeAlteration({\n name: \"worshiped\",\n source: \"witch\",\n status: \"attached\",\n }),\n createFakeGameHistoryRecordPlayerAttributeAlteration({\n name: \"sheriff\",\n source: \"survivors\",\n status: \"attached\",\n }),\n ],\n }),\n attributeName: \"sheriff\",\n source: \"thief\",\n status: \"attached\",\n expectedResult: false,\n },\n {\n test: \"should return false if the game history record does not have a player attribute alteration with the given status\",\n gameHistoryRecord: createFakeGameHistoryRecord({\n playerAttributeAlterations: [\n createFakeGameHistoryRecordPlayerAttributeAlteration({\n name: \"worshiped\",\n source: \"witch\",\n status: \"attached\",\n }),\n createFakeGameHistoryRecordPlayerAttributeAlteration({\n name: \"sheriff\",\n source: \"survivors\",\n status: \"attached\",\n }),\n ],\n }),\n attributeName: \"sheriff\",\n source: \"survivors\",\n status: \"detached\",\n expectedResult: false,\n },\n {\n test: \"should return false if the game history record does not have any player attribute alterations\",\n gameHistoryRecord: createFakeGameHistoryRecord(),\n attributeName: \"sheriff\",\n source: \"survivors\",\n status: \"attached\",\n expectedResult: false,\n },\n ])(\"$test\", ({ gameHistoryRecord, attributeName, source, status, expectedResult }) => {\n expect(doesHavePlayerAttributeAlterationWithNameSourceAndStatus(gameHistoryRecord, attributeName, source, status)).toBe(expectedResult);\n });\n });\n\n describe(\"doesHavePlayerAttributeAlterationWithNameAndStatus\", () => {\n it.each<{\n test: string;\n gameHistoryRecord: GameHistoryRecord;\n attributeName: PlayerAttributeName;\n status: GameHistoryRecordPlayerAttributeAlterationStatus;\n expectedResult: boolean;\n }>([\n {\n test: \"should return true if the game history record has a player attribute alteration with the given name and status\",\n gameHistoryRecord: createFakeGameHistoryRecord({\n playerAttributeAlterations: [\n createFakeGameHistoryRecordPlayerAttributeAlteration({\n name: \"worshiped\",\n source: \"witch\",\n status: \"attached\",\n }),\n createFakeGameHistoryRecordPlayerAttributeAlteration({\n name: \"sheriff\",\n source: \"survivors\",\n status: \"attached\",\n }),\n ],\n }),\n attributeName: \"sheriff\",\n status: \"attached\",\n expectedResult: true,\n },\n {\n test: \"should return false if the game history record does not have a player attribute alteration with the given name\",\n gameHistoryRecord: createFakeGameHistoryRecord({\n playerAttributeAlterations: [\n createFakeGameHistoryRecordPlayerAttributeAlteration({\n name: \"worshiped\",\n source: \"witch\",\n status: \"attached\",\n }),\n createFakeGameHistoryRecordPlayerAttributeAlteration({\n name: \"sheriff\",\n source: \"survivors\",\n status: \"attached\",\n }),\n ],\n }),\n attributeName: \"seen\",\n status: \"attached\",\n expectedResult: false,\n },\n {\n test: \"should return false if the game history record does not have a player attribute alteration with the given status\",\n gameHistoryRecord: createFakeGameHistoryRecord({\n playerAttributeAlterations: [\n createFakeGameHistoryRecordPlayerAttributeAlteration({\n name: \"worshiped\",\n source: \"witch\",\n status: \"attached\",\n }),\n createFakeGameHistoryRecordPlayerAttributeAlteration({\n name: \"sheriff\",\n source: \"survivors\",\n status: \"attached\",\n }),\n ],\n }),\n attributeName: \"sheriff\",\n status: \"detached\",\n expectedResult: false,\n },\n {\n test: \"should return false if the game history record does not have any player attribute alterations\",\n gameHistoryRecord: createFakeGameHistoryRecord(),\n attributeName: \"sheriff\",\n status: \"attached\",\n expectedResult: false,\n },\n ])(\"$test\", ({ gameHistoryRecord, attributeName, status, expectedResult }) => {\n expect(doesHavePlayerAttributeAlterationWithNameAndStatus(gameHistoryRecord, attributeName, status)).toBe(expectedResult);\n });\n });\n});" + "source": "import { doesHavePlayerAttributeAlterationWithNameAndStatus, doesHavePlayerAttributeAlterationWithNameSourceAndStatus } from \"@/modules/game/helpers/game-history-record/game-history-record.helpers\";\nimport type { GameHistoryRecord } from \"@/modules/game/schemas/game-history-record/game-history-record.schema\";\nimport type { GameHistoryRecordPlayerAttributeAlterationStatus } from \"@/modules/game/types/game-history-record/game-history-record.types\";\nimport type { GameSource } from \"@/modules/game/types/game.types\";\nimport type { PlayerAttributeName } from \"@/modules/game/types/player/player-attribute/player-attribute.types\";\n\nimport { createFakeGameHistoryRecord, createFakeGameHistoryRecordPlayerAttributeAlteration } from \"@tests/factories/game/schemas/game-history-record/game-history-record.schema.factory\";\n\ndescribe(\"Game History Record Helpers\", () => {\n describe(\"doesHavePlayerAttributeAlterationWithNameSourceAndStatus\", () => {\n it.each<{\n test: string;\n gameHistoryRecord: GameHistoryRecord;\n attributeName: PlayerAttributeName;\n source: GameSource;\n status: GameHistoryRecordPlayerAttributeAlterationStatus;\n expectedResult: boolean;\n }>([\n {\n test: \"should return true if the game history record has a player attribute alteration with the given name, source, and status\",\n gameHistoryRecord: createFakeGameHistoryRecord({\n playerAttributeAlterations: [\n createFakeGameHistoryRecordPlayerAttributeAlteration({\n name: \"worshiped\",\n source: \"witch\",\n status: \"attached\",\n }),\n createFakeGameHistoryRecordPlayerAttributeAlteration({\n name: \"sheriff\",\n source: \"survivors\",\n status: \"attached\",\n }),\n ],\n }),\n attributeName: \"sheriff\",\n source: \"survivors\",\n status: \"attached\",\n expectedResult: true,\n },\n {\n test: \"should return false if the game history record does not have a player attribute alteration with the given name\",\n gameHistoryRecord: createFakeGameHistoryRecord({\n playerAttributeAlterations: [\n createFakeGameHistoryRecordPlayerAttributeAlteration({\n name: \"worshiped\",\n source: \"witch\",\n status: \"attached\",\n }),\n createFakeGameHistoryRecordPlayerAttributeAlteration({\n name: \"sheriff\",\n source: \"survivors\",\n status: \"attached\",\n }),\n ],\n }),\n attributeName: \"seen\",\n source: \"survivors\",\n status: \"attached\",\n expectedResult: false,\n },\n {\n test: \"should return false if the game history record does not have a player attribute alteration with the given source\",\n gameHistoryRecord: createFakeGameHistoryRecord({\n playerAttributeAlterations: [\n createFakeGameHistoryRecordPlayerAttributeAlteration({\n name: \"worshiped\",\n source: \"witch\",\n status: \"attached\",\n }),\n createFakeGameHistoryRecordPlayerAttributeAlteration({\n name: \"sheriff\",\n source: \"survivors\",\n status: \"attached\",\n }),\n ],\n }),\n attributeName: \"sheriff\",\n source: \"thief\",\n status: \"attached\",\n expectedResult: false,\n },\n {\n test: \"should return false if the game history record does not have a player attribute alteration with the given status\",\n gameHistoryRecord: createFakeGameHistoryRecord({\n playerAttributeAlterations: [\n createFakeGameHistoryRecordPlayerAttributeAlteration({\n name: \"worshiped\",\n source: \"witch\",\n status: \"attached\",\n }),\n createFakeGameHistoryRecordPlayerAttributeAlteration({\n name: \"sheriff\",\n source: \"survivors\",\n status: \"attached\",\n }),\n ],\n }),\n attributeName: \"sheriff\",\n source: \"survivors\",\n status: \"detached\",\n expectedResult: false,\n },\n {\n test: \"should return false if the game history record does not have any player attribute alterations\",\n gameHistoryRecord: createFakeGameHistoryRecord(),\n attributeName: \"sheriff\",\n source: \"survivors\",\n status: \"attached\",\n expectedResult: false,\n },\n ])(\"$test\", ({ gameHistoryRecord, attributeName, source, status, expectedResult }) => {\n expect(doesHavePlayerAttributeAlterationWithNameSourceAndStatus(gameHistoryRecord, attributeName, source, status)).toBe(expectedResult);\n });\n });\n\n describe(\"doesHavePlayerAttributeAlterationWithNameAndStatus\", () => {\n it.each<{\n test: string;\n gameHistoryRecord: GameHistoryRecord;\n attributeName: PlayerAttributeName;\n status: GameHistoryRecordPlayerAttributeAlterationStatus;\n expectedResult: boolean;\n }>([\n {\n test: \"should return true if the game history record has a player attribute alteration with the given name and status\",\n gameHistoryRecord: createFakeGameHistoryRecord({\n playerAttributeAlterations: [\n createFakeGameHistoryRecordPlayerAttributeAlteration({\n name: \"worshiped\",\n source: \"witch\",\n status: \"attached\",\n }),\n createFakeGameHistoryRecordPlayerAttributeAlteration({\n name: \"sheriff\",\n source: \"survivors\",\n status: \"attached\",\n }),\n ],\n }),\n attributeName: \"sheriff\",\n status: \"attached\",\n expectedResult: true,\n },\n {\n test: \"should return false if the game history record does not have a player attribute alteration with the given name\",\n gameHistoryRecord: createFakeGameHistoryRecord({\n playerAttributeAlterations: [\n createFakeGameHistoryRecordPlayerAttributeAlteration({\n name: \"worshiped\",\n source: \"witch\",\n status: \"attached\",\n }),\n createFakeGameHistoryRecordPlayerAttributeAlteration({\n name: \"sheriff\",\n source: \"survivors\",\n status: \"attached\",\n }),\n ],\n }),\n attributeName: \"seen\",\n status: \"attached\",\n expectedResult: false,\n },\n {\n test: \"should return false if the game history record does not have a player attribute alteration with the given status\",\n gameHistoryRecord: createFakeGameHistoryRecord({\n playerAttributeAlterations: [\n createFakeGameHistoryRecordPlayerAttributeAlteration({\n name: \"worshiped\",\n source: \"witch\",\n status: \"attached\",\n }),\n createFakeGameHistoryRecordPlayerAttributeAlteration({\n name: \"sheriff\",\n source: \"survivors\",\n status: \"attached\",\n }),\n ],\n }),\n attributeName: \"sheriff\",\n status: \"detached\",\n expectedResult: false,\n },\n {\n test: \"should return false if the game history record does not have any player attribute alterations\",\n gameHistoryRecord: createFakeGameHistoryRecord(),\n attributeName: \"sheriff\",\n status: \"attached\",\n expectedResult: false,\n },\n ])(\"$test\", ({ gameHistoryRecord, attributeName, status, expectedResult }) => {\n expect(doesHavePlayerAttributeAlterationWithNameAndStatus(gameHistoryRecord, attributeName, status)).toBe(expectedResult);\n });\n });\n});" }, "tests/unit/specs/modules/game/dto/base/decorators/additional-cards/additional-cards-roles-max-in-game.decorator.spec.ts": { "tests": [ @@ -199323,7 +199325,7 @@ "location": { "start": { "column": 8, - "line": 130 + "line": 131 } } }, @@ -199333,7 +199335,7 @@ "location": { "start": { "column": 8, - "line": 130 + "line": 131 } } }, @@ -199343,7 +199345,7 @@ "location": { "start": { "column": 8, - "line": 130 + "line": 131 } } }, @@ -199353,7 +199355,7 @@ "location": { "start": { "column": 8, - "line": 130 + "line": 131 } } }, @@ -199363,7 +199365,7 @@ "location": { "start": { "column": 8, - "line": 130 + "line": 131 } } }, @@ -199373,7 +199375,7 @@ "location": { "start": { "column": 8, - "line": 130 + "line": 131 } } }, @@ -199383,7 +199385,7 @@ "location": { "start": { "column": 8, - "line": 130 + "line": 131 } } }, @@ -199393,7 +199395,7 @@ "location": { "start": { "column": 8, - "line": 130 + "line": 131 } } }, @@ -199403,12 +199405,12 @@ "location": { "start": { "column": 6, - "line": 148 + "line": 149 } } } ], - "source": "import { getAdditionalCardsForActorSizeDefaultMessage, isAdditionalCardsForActorSizeRespected } from \"@/modules/game/dto/base/decorators/additional-cards/additional-cards-for-actor-size.decorator\";\nimport type { CreateGameAdditionalCardDto } from \"@/modules/game/dto/create-game/create-game-additional-card/create-game-additional-card.dto\";\nimport type { CreateGameDto } from \"@/modules/game/dto/create-game/create-game.dto\";\n\nimport { createFakeCreateGameAdditionalCardDto } from \"@tests/factories/game/dto/create-game/create-game-additional-card/create-game-additional-card.dto.factory\";\nimport { createFakeCreateGamePlayerDto } from \"@tests/factories/game/dto/create-game/create-game-player/create-game-player.dto.factory\";\nimport { createFakeCreateGameDto } from \"@tests/factories/game/dto/create-game/create-game.dto.factory\";\nimport type { ValidationArguments } from \"class-validator\";\n\ndescribe(\"Additional Cards For Actor Size Decorator\", () => {\n describe(\"isAdditionalCardsForActorSizeRespected\", () => {\n it.each<{\n test: string;\n additionalCards: unknown;\n createGameDto: CreateGameDto;\n expected: boolean;\n }>([\n {\n test: \"should return true when cards are not defined.\",\n createGameDto: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"actor\" } }),\n ],\n }),\n additionalCards: undefined,\n expected: true,\n },\n {\n test: \"should return true when cards are defined but there is no actor in players.\",\n createGameDto: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" } }),\n ],\n }),\n additionalCards: undefined,\n expected: true,\n },\n {\n test: \"should return false when cards are not an array.\",\n createGameDto: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"actor\" } }),\n ],\n }),\n additionalCards: null,\n expected: false,\n },\n {\n test: \"should return false when some card is not an object.\",\n createGameDto: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"actor\" } }),\n ],\n }),\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"actor\" }),\n null,\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"actor\" }),\n ],\n expected: false,\n },\n {\n test: \"should return false when some card is not an object with expected structure.\",\n createGameDto: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"actor\" } }),\n ],\n }),\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"actor\" }),\n { bad: \"structure\" },\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"actor\" }),\n ],\n expected: false,\n },\n {\n test: \"should return false when cards length is 0.\",\n createGameDto: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"actor\" } }),\n ],\n }),\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"thief\" }),\n ],\n expected: false,\n },\n {\n test: \"should return false when cards length exceed the max.\",\n createGameDto: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"actor\" } }),\n ],\n }),\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"actor\" }),\n ],\n expected: false,\n },\n {\n test: \"should return true when cards size respects the options.\",\n createGameDto: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"actor\" } }),\n ],\n }),\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"actor\" }),\n ],\n expected: true,\n },\n ])(\"$test\", ({ additionalCards, createGameDto, expected }) => {\n const object = createFakeCreateGameDto({\n ...createGameDto,\n additionalCards: additionalCards as CreateGameAdditionalCardDto[],\n });\n const validationArguments: ValidationArguments = {\n value: additionalCards,\n object,\n constraints: [],\n targetName: \"\",\n property: \"additionalCards\",\n };\n\n expect(isAdditionalCardsForActorSizeRespected(additionalCards, validationArguments)).toBe(expected);\n });\n });\n\n describe(\"getAdditionalCardsForActorSizeDefaultMessage\", () => {\n it(\"should default decorator message when called.\", () => {\n expect(getAdditionalCardsForActorSizeDefaultMessage()).toBe(\"additionalCards length for actor must be between 1 and 5\");\n });\n });\n});" + "source": "import type { ValidationArguments } from \"class-validator\";\n\nimport { getAdditionalCardsForActorSizeDefaultMessage, isAdditionalCardsForActorSizeRespected } from \"@/modules/game/dto/base/decorators/additional-cards/additional-cards-for-actor-size.decorator\";\nimport type { CreateGameAdditionalCardDto } from \"@/modules/game/dto/create-game/create-game-additional-card/create-game-additional-card.dto\";\nimport type { CreateGameDto } from \"@/modules/game/dto/create-game/create-game.dto\";\n\nimport { createFakeCreateGameAdditionalCardDto } from \"@tests/factories/game/dto/create-game/create-game-additional-card/create-game-additional-card.dto.factory\";\nimport { createFakeCreateGamePlayerDto } from \"@tests/factories/game/dto/create-game/create-game-player/create-game-player.dto.factory\";\nimport { createFakeCreateGameDto } from \"@tests/factories/game/dto/create-game/create-game.dto.factory\";\n\ndescribe(\"Additional Cards For Actor Size Decorator\", () => {\n describe(\"isAdditionalCardsForActorSizeRespected\", () => {\n it.each<{\n test: string;\n additionalCards: unknown;\n createGameDto: CreateGameDto;\n expected: boolean;\n }>([\n {\n test: \"should return true when cards are not defined.\",\n createGameDto: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"actor\" } }),\n ],\n }),\n additionalCards: undefined,\n expected: true,\n },\n {\n test: \"should return true when cards are defined but there is no actor in players.\",\n createGameDto: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" } }),\n ],\n }),\n additionalCards: undefined,\n expected: true,\n },\n {\n test: \"should return false when cards are not an array.\",\n createGameDto: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"actor\" } }),\n ],\n }),\n additionalCards: null,\n expected: false,\n },\n {\n test: \"should return false when some card is not an object.\",\n createGameDto: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"actor\" } }),\n ],\n }),\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"actor\" }),\n null,\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"actor\" }),\n ],\n expected: false,\n },\n {\n test: \"should return false when some card is not an object with expected structure.\",\n createGameDto: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"actor\" } }),\n ],\n }),\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"actor\" }),\n { bad: \"structure\" },\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"actor\" }),\n ],\n expected: false,\n },\n {\n test: \"should return false when cards length is 0.\",\n createGameDto: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"actor\" } }),\n ],\n }),\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"thief\" }),\n ],\n expected: false,\n },\n {\n test: \"should return false when cards length exceed the max.\",\n createGameDto: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"actor\" } }),\n ],\n }),\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"actor\" }),\n ],\n expected: false,\n },\n {\n test: \"should return true when cards size respects the options.\",\n createGameDto: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"actor\" } }),\n ],\n }),\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"actor\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"actor\" }),\n ],\n expected: true,\n },\n ])(\"$test\", ({ additionalCards, createGameDto, expected }) => {\n const object = createFakeCreateGameDto({\n ...createGameDto,\n additionalCards: additionalCards as CreateGameAdditionalCardDto[],\n });\n const validationArguments: ValidationArguments = {\n value: additionalCards,\n object,\n constraints: [],\n targetName: \"\",\n property: \"additionalCards\",\n };\n\n expect(isAdditionalCardsForActorSizeRespected(additionalCards, validationArguments)).toBe(expected);\n });\n });\n\n describe(\"getAdditionalCardsForActorSizeDefaultMessage\", () => {\n it(\"should default decorator message when called.\", () => {\n expect(getAdditionalCardsForActorSizeDefaultMessage()).toBe(\"additionalCards length for actor must be between 1 and 5\");\n });\n });\n});" }, "tests/unit/specs/modules/game/dto/base/decorators/additional-cards/additional-cards-for-thief-size.decorator.spec.ts": { "tests": [ @@ -199418,7 +199420,7 @@ "location": { "start": { "column": 8, - "line": 130 + "line": 131 } } }, @@ -199428,7 +199430,7 @@ "location": { "start": { "column": 8, - "line": 130 + "line": 131 } } }, @@ -199438,7 +199440,7 @@ "location": { "start": { "column": 8, - "line": 130 + "line": 131 } } }, @@ -199448,7 +199450,7 @@ "location": { "start": { "column": 8, - "line": 130 + "line": 131 } } }, @@ -199458,7 +199460,7 @@ "location": { "start": { "column": 8, - "line": 130 + "line": 131 } } }, @@ -199468,7 +199470,7 @@ "location": { "start": { "column": 8, - "line": 130 + "line": 131 } } }, @@ -199478,7 +199480,7 @@ "location": { "start": { "column": 8, - "line": 130 + "line": 131 } } }, @@ -199488,7 +199490,7 @@ "location": { "start": { "column": 8, - "line": 130 + "line": 131 } } }, @@ -199498,12 +199500,12 @@ "location": { "start": { "column": 6, - "line": 148 + "line": 149 } } } ], - "source": "import { getAdditionalCardsForThiefSizeDefaultMessage, isAdditionalCardsForThiefSizeRespected } from \"@/modules/game/dto/base/decorators/additional-cards/additional-cards-for-thief-size.decorator\";\nimport type { CreateGameAdditionalCardDto } from \"@/modules/game/dto/create-game/create-game-additional-card/create-game-additional-card.dto\";\nimport type { CreateGameDto } from \"@/modules/game/dto/create-game/create-game.dto\";\n\nimport { createFakeCreateGameAdditionalCardDto } from \"@tests/factories/game/dto/create-game/create-game-additional-card/create-game-additional-card.dto.factory\";\nimport { createFakeCreateGamePlayerDto } from \"@tests/factories/game/dto/create-game/create-game-player/create-game-player.dto.factory\";\nimport { createFakeCreateGameDto } from \"@tests/factories/game/dto/create-game/create-game.dto.factory\";\nimport type { ValidationArguments } from \"class-validator\";\n\ndescribe(\"Additional Cards For Thief Size Decorator\", () => {\n describe(\"isAdditionalCardsForThiefSizeRespected\", () => {\n it.each<{\n test: string;\n createGameDto: CreateGameDto;\n additionalCards: unknown;\n expected: boolean;\n }>([\n {\n test: \"should return true when cards are not defined.\",\n createGameDto: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"thief\" } }),\n ],\n }),\n additionalCards: undefined,\n expected: true,\n },\n {\n test: \"should return true when cards are defined but there is not thief among players.\",\n createGameDto: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"actor\" } }),\n ],\n }),\n additionalCards: [\n null,\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"thief\" }),\n ],\n expected: true,\n },\n {\n test: \"should return false when cards are not an array.\",\n createGameDto: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"thief\" } }),\n ],\n }),\n additionalCards: null,\n expected: false,\n },\n {\n test: \"should return false when every cards is not an object with expected structure.\",\n createGameDto: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"thief\" } }),\n ],\n }),\n additionalCards: [\n { bad: \"structure\" },\n { bad: \"structure\" },\n ],\n expected: false,\n },\n {\n test: \"should return false when some card is not an object with expected structure.\",\n createGameDto: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"thief\" } }),\n ],\n }),\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"thief\" }),\n { bad: \"structure\" },\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"thief\" }),\n ],\n expected: false,\n },\n {\n test: \"should return false when cards size empty.\",\n createGameDto: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"thief\" } }),\n ],\n }),\n additionalCards: [createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"actor\" })],\n expected: false,\n },\n {\n test: \"should return false when cards size is too much.\",\n createGameDto: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"thief\" } }),\n ],\n }),\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"actor\" }),\n ],\n expected: false,\n },\n {\n test: \"should return true when cards size is between 1 and 5.\",\n createGameDto: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"thief\" } }),\n ],\n }),\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"thief\" }),\n ],\n expected: true,\n },\n ])(\"$test\", ({ additionalCards, createGameDto, expected }) => {\n const object = createFakeCreateGameDto({\n ...createGameDto,\n additionalCards: additionalCards as CreateGameAdditionalCardDto[],\n });\n const validationArguments: ValidationArguments = {\n value: additionalCards,\n object,\n constraints: [],\n targetName: \"\",\n property: \"additionalCards\",\n };\n\n expect(isAdditionalCardsForThiefSizeRespected(additionalCards, validationArguments)).toBe(expected);\n });\n });\n\n describe(\"getAdditionalCardsForThiefSizeDefaultMessage\", () => {\n it(\"should default decorator message when called.\", () => {\n expect(getAdditionalCardsForThiefSizeDefaultMessage()).toBe(\"additionalCards length for thief must be between 1 and 5\");\n });\n });\n});" + "source": "import type { ValidationArguments } from \"class-validator\";\n\nimport { getAdditionalCardsForThiefSizeDefaultMessage, isAdditionalCardsForThiefSizeRespected } from \"@/modules/game/dto/base/decorators/additional-cards/additional-cards-for-thief-size.decorator\";\nimport type { CreateGameAdditionalCardDto } from \"@/modules/game/dto/create-game/create-game-additional-card/create-game-additional-card.dto\";\nimport type { CreateGameDto } from \"@/modules/game/dto/create-game/create-game.dto\";\n\nimport { createFakeCreateGameAdditionalCardDto } from \"@tests/factories/game/dto/create-game/create-game-additional-card/create-game-additional-card.dto.factory\";\nimport { createFakeCreateGamePlayerDto } from \"@tests/factories/game/dto/create-game/create-game-player/create-game-player.dto.factory\";\nimport { createFakeCreateGameDto } from \"@tests/factories/game/dto/create-game/create-game.dto.factory\";\n\ndescribe(\"Additional Cards For Thief Size Decorator\", () => {\n describe(\"isAdditionalCardsForThiefSizeRespected\", () => {\n it.each<{\n test: string;\n createGameDto: CreateGameDto;\n additionalCards: unknown;\n expected: boolean;\n }>([\n {\n test: \"should return true when cards are not defined.\",\n createGameDto: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"thief\" } }),\n ],\n }),\n additionalCards: undefined,\n expected: true,\n },\n {\n test: \"should return true when cards are defined but there is not thief among players.\",\n createGameDto: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"actor\" } }),\n ],\n }),\n additionalCards: [\n null,\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"thief\" }),\n ],\n expected: true,\n },\n {\n test: \"should return false when cards are not an array.\",\n createGameDto: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"thief\" } }),\n ],\n }),\n additionalCards: null,\n expected: false,\n },\n {\n test: \"should return false when every cards is not an object with expected structure.\",\n createGameDto: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"thief\" } }),\n ],\n }),\n additionalCards: [\n { bad: \"structure\" },\n { bad: \"structure\" },\n ],\n expected: false,\n },\n {\n test: \"should return false when some card is not an object with expected structure.\",\n createGameDto: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"thief\" } }),\n ],\n }),\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"thief\" }),\n { bad: \"structure\" },\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"thief\" }),\n ],\n expected: false,\n },\n {\n test: \"should return false when cards size empty.\",\n createGameDto: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"thief\" } }),\n ],\n }),\n additionalCards: [createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"actor\" })],\n expected: false,\n },\n {\n test: \"should return false when cards size is too much.\",\n createGameDto: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"thief\" } }),\n ],\n }),\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"actor\" }),\n ],\n expected: false,\n },\n {\n test: \"should return true when cards size is between 1 and 5.\",\n createGameDto: createFakeCreateGameDto({\n players: [\n createFakeCreateGamePlayerDto({ role: { name: \"villager\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"thief\" } }),\n ],\n }),\n additionalCards: [\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"thief\" }),\n createFakeCreateGameAdditionalCardDto({ roleName: \"villager\", recipient: \"thief\" }),\n ],\n expected: true,\n },\n ])(\"$test\", ({ additionalCards, createGameDto, expected }) => {\n const object = createFakeCreateGameDto({\n ...createGameDto,\n additionalCards: additionalCards as CreateGameAdditionalCardDto[],\n });\n const validationArguments: ValidationArguments = {\n value: additionalCards,\n object,\n constraints: [],\n targetName: \"\",\n property: \"additionalCards\",\n };\n\n expect(isAdditionalCardsForThiefSizeRespected(additionalCards, validationArguments)).toBe(expected);\n });\n });\n\n describe(\"getAdditionalCardsForThiefSizeDefaultMessage\", () => {\n it(\"should default decorator message when called.\", () => {\n expect(getAdditionalCardsForThiefSizeDefaultMessage()).toBe(\"additionalCards length for thief must be between 1 and 5\");\n });\n });\n});" }, "tests/unit/specs/shared/exception/helpers/unexpected-exception.factory.spec.ts": { "tests": [ @@ -200538,7 +200540,7 @@ } } ], - "source": "import { doesCompositionHasTwoGroupsWithPrejudicedManipulator, getCompositionHasTwoGroupsWithPrejudicedManipulatorDefaultMessage } from \"@/modules/game/dto/base/decorators/composition/composition-has-two-groups-with-prejudiced-manipulator.decorator\";\n\nimport { createFakeCreateGamePlayerDto } from \"@tests/factories/game/dto/create-game/create-game-player/create-game-player.dto.factory\";\n\ndescribe(\"Composition Has Two Groups With Prejudiced Manipulator Decorator\", () => {\n describe(\"doesCompositionHasTwoGroupsWithPrejudicedManipulator\", () => {\n it(\"should return false when players are undefined.\", () => {\n expect(doesCompositionHasTwoGroupsWithPrejudicedManipulator(undefined)).toBe(false);\n });\n\n it(\"should return false when players are not an array.\", () => {\n expect(doesCompositionHasTwoGroupsWithPrejudicedManipulator(null)).toBe(false);\n });\n\n it(\"should return false when one of the players is not an object.\", () => {\n const players = [\n { role: { name: \"FOX\" } },\n { role: { name: \"VILLAGER\" } },\n { role: { name: \"WEREWOLF\" } },\n { role: { name: \"PREJUDICED_MANIPULATOR\" } },\n ];\n\n expect(doesCompositionHasTwoGroupsWithPrejudicedManipulator([...players, \"toto\"])).toBe(false);\n });\n\n it(\"should return false when one of the players has no role.\", () => {\n const players = [\n { role: { name: \"FOX\" } },\n { role: { name: \"VILLAGER\" } },\n { role: { name: \"WEREWOLF\" } },\n { role: { name: \"PREJUDICED_MANIPULATOR\" } },\n ];\n\n expect(doesCompositionHasTwoGroupsWithPrejudicedManipulator([...players, { role: { toto: \"WITCH\" } }])).toBe(false);\n });\n\n it(\"should return true when nobody is the prejudiced manipulator.\", () => {\n const players = [\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"seer\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n ];\n\n expect(doesCompositionHasTwoGroupsWithPrejudicedManipulator(players)).toBe(true);\n });\n\n it(\"should return false when one player is the prejudiced manipulator and there is only one group.\", () => {\n const players = [\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" }, group: \"toto\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" }, group: \"toto\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"seer\" }, group: \"toto\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"prejudiced-manipulator\" }, group: \"toto\" }),\n ];\n\n expect(doesCompositionHasTwoGroupsWithPrejudicedManipulator(players)).toBe(false);\n });\n\n it(\"should return false when one player is the prejudiced manipulator and there is more than two groups.\", () => {\n const players = [\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" }, group: \"toto\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" }, group: \"toto\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"seer\" }, group: \"titi\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"prejudiced-manipulator\" }, group: \"tata\" }),\n ];\n\n expect(doesCompositionHasTwoGroupsWithPrejudicedManipulator(players)).toBe(false);\n });\n\n it(\"should return true when one player is the prejudiced manipulator and there are two groups.\", () => {\n const players = [\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" }, group: \"toto\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" }, group: \"toto\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"seer\" }, group: \"tata\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"prejudiced-manipulator\" }, group: \"tata\" }),\n ];\n\n expect(doesCompositionHasTwoGroupsWithPrejudicedManipulator(players)).toBe(true);\n });\n });\n\n describe(\"getCompositionHasTwoGroupsWithPrejudicedManipulatorDefaultMessage\", () => {\n it(\"should return the default message when called.\", () => {\n const expectedMessage = \"there must be exactly two groups among players when `prejudiced-manipulator` in the game\";\n expect(getCompositionHasTwoGroupsWithPrejudicedManipulatorDefaultMessage()).toBe(expectedMessage);\n });\n });\n});" + "source": "import { doesCompositionHasTwoGroupsWithPrejudicedManipulator, getCompositionHasTwoGroupsWithPrejudicedManipulatorDefaultMessage } from \"@/modules/game/dto/base/decorators/composition/composition-has-two-groups-with-prejudiced-manipulator.decorator\";\n\nimport { createFakeCreateGamePlayerDto } from \"@tests/factories/game/dto/create-game/create-game-player/create-game-player.dto.factory\";\n\ndescribe(\"Composition Has Two Groups With Prejudiced Manipulator Decorator\", () => {\n describe(\"doesCompositionHasTwoGroupsWithPrejudicedManipulator\", () => {\n it(\"should return false when players are undefined.\", () => {\n expect(doesCompositionHasTwoGroupsWithPrejudicedManipulator(undefined)).toBe(false);\n });\n\n it(\"should return false when players are not an array.\", () => {\n expect(doesCompositionHasTwoGroupsWithPrejudicedManipulator(null)).toBe(false);\n });\n\n it(\"should return false when one of the players is not an object.\", () => {\n const players = [\n { role: { name: \"FOX\" } },\n { role: { name: \"VILLAGER\" } },\n { role: { name: \"WEREWOLF\" } },\n { role: { name: \"PREJUDICED_MANIPULATOR\" } },\n ];\n\n expect(doesCompositionHasTwoGroupsWithPrejudicedManipulator([...players, \"toto\"])).toBe(false);\n });\n\n it(\"should return false when one of the players has no role.\", () => {\n const players = [\n { role: { name: \"FOX\" } },\n { role: { name: \"VILLAGER\" } },\n { role: { name: \"WEREWOLF\" } },\n { role: { name: \"PREJUDICED_MANIPULATOR\" } },\n ];\n\n expect(doesCompositionHasTwoGroupsWithPrejudicedManipulator([...players, { role: { toto: \"WITCH\" } }])).toBe(false);\n });\n\n it(\"should return true when nobody is the prejudiced manipulator.\", () => {\n const players = [\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"seer\" } }),\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" } }),\n ];\n\n expect(doesCompositionHasTwoGroupsWithPrejudicedManipulator(players)).toBe(true);\n });\n\n it(\"should return false when one player is the prejudiced manipulator and there is only one group.\", () => {\n const players = [\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" }, group: \"toto\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" }, group: \"toto\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"seer\" }, group: \"toto\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"prejudiced-manipulator\" }, group: \"toto\" }),\n ];\n\n expect(doesCompositionHasTwoGroupsWithPrejudicedManipulator(players)).toBe(false);\n });\n\n it(\"should return false when one player is the prejudiced manipulator and there is more than two groups.\", () => {\n const players = [\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" }, group: \"toto\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" }, group: \"toto\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"seer\" }, group: \"titi\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"prejudiced-manipulator\" }, group: \"tata\" }),\n ];\n\n expect(doesCompositionHasTwoGroupsWithPrejudicedManipulator(players)).toBe(false);\n });\n\n it(\"should return true when one player is the prejudiced manipulator and there are two groups.\", () => {\n const players = [\n createFakeCreateGamePlayerDto({ role: { name: \"witch\" }, group: \"toto\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"werewolf\" }, group: \"toto\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"seer\" }, group: \"tata\" }),\n createFakeCreateGamePlayerDto({ role: { name: \"prejudiced-manipulator\" }, group: \"tata\" }),\n ];\n\n expect(doesCompositionHasTwoGroupsWithPrejudicedManipulator(players)).toBe(true);\n });\n });\n\n describe(\"getCompositionHasTwoGroupsWithPrejudicedManipulatorDefaultMessage\", () => {\n it(\"should return the default message when called.\", () => {\n const expectedMessage = \"there must be exactly two groups among players when `prejudiced-manipulator` in the game\";\n\n expect(getCompositionHasTwoGroupsWithPrejudicedManipulatorDefaultMessage()).toBe(expectedMessage);\n });\n });\n});" }, "tests/unit/specs/modules/game/providers/services/game-feedback/game-feedback.service.spec.ts": { "tests": [ @@ -200548,7 +200550,7 @@ "location": { "start": { "column": 6, - "line": 51 + "line": 54 } } }, @@ -200558,7 +200560,7 @@ "location": { "start": { "column": 6, - "line": 59 + "line": 62 } } }, @@ -200568,7 +200570,7 @@ "location": { "start": { "column": 6, - "line": 73 + "line": 76 } } }, @@ -200578,12 +200580,12 @@ "location": { "start": { "column": 6, - "line": 81 + "line": 84 } } } ], - "source": "import { GameFeedbackRepository } from \"@/modules/game/providers/repositories/game-feedback/game-feedback.repository\";\nimport { GameFeedbackService } from \"@/modules/game/providers/services/game-feedback/game-feedback.service\";\nimport { ApiResources } from \"@/shared/api/enums/api.enums\";\nimport { BadResourceMutationReasons } from \"@/shared/exception/enums/bad-resource-mutation-error.enum\";\nimport { BadResourceMutationException } from \"@/shared/exception/types/bad-resource-mutation-exception.types\";\nimport type { TestingModule } from \"@nestjs/testing\";\nimport { Test } from \"@nestjs/testing\";\nimport { createFakeCreateGameFeedbackDto } from \"@tests/factories/game/dto/create-game-feedback/create-game-feedback.dto.factory\";\nimport { createFakeGameFeedback, createFakeGameFeedbackToInsert } from \"@tests/factories/game/schemas/game-feedback/game-feedback.factory\";\nimport { createFakeGame } from \"@tests/factories/game/schemas/game.schema.factory\";\nimport { getError } from \"@tests/helpers/exception/exception.helpers\";\n\ndescribe(\"Game Feedback Service\", () => {\n let mocks: {\n gameFeedbackService: {\n validateCreateGameFeedback: jest.SpyInstance;\n };\n gameFeedbackRepository: {\n create: jest.SpyInstance;\n };\n };\n let services: { gameFeedBack: GameFeedbackService };\n\n beforeEach(async() => {\n mocks = {\n gameFeedbackService: {\n validateCreateGameFeedback: jest.fn(),\n },\n gameFeedbackRepository: {\n create: jest.fn(),\n },\n };\n const module: TestingModule = await Test.createTestingModule({\n providers: [\n {\n provide: GameFeedbackRepository,\n useValue: mocks.gameFeedbackRepository,\n },\n GameFeedbackService,\n ],\n }).compile();\n\n services = { gameFeedBack: module.get(GameFeedbackService) };\n });\n\n describe(\"createGameFeedback\", () => {\n beforeEach(() => {\n mocks.gameFeedbackService.validateCreateGameFeedback = jest.spyOn(services.gameFeedBack as unknown as { validateCreateGameFeedback }, \"validateCreateGameFeedback\");\n });\n\n it(\"should validate create game feedback when called.\", async() => {\n const game = createFakeGame();\n const createGameFeedbackDto = createFakeCreateGameFeedbackDto();\n await services.gameFeedBack.createGameFeedback(game, createGameFeedbackDto);\n\n expect(mocks.gameFeedbackService.validateCreateGameFeedback).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should create game feedback when called.\", async() => {\n const game = createFakeGame();\n const createGameFeedbackDto = createFakeCreateGameFeedbackDto();\n await services.gameFeedBack.createGameFeedback(game, createGameFeedbackDto);\n const expectedGameFeedbackToInsert = createFakeGameFeedbackToInsert({\n gameId: game._id,\n ...createGameFeedbackDto,\n });\n\n expect(mocks.gameFeedbackRepository.create).toHaveBeenCalledExactlyOnceWith(expectedGameFeedbackToInsert);\n });\n });\n\n describe(\"validateCreateGameFeedback\", () => {\n it(\"should throw Bad Resource Mutation Exception when feedback already exists.\", async() => {\n const game = createFakeGame({ feedback: createFakeGameFeedback() });\n const expectedError = new BadResourceMutationException(ApiResources.GAMES, game._id.toString(), BadResourceMutationReasons.FEEDBACK_ALREADY_EXISTS);\n const error = await getError(() => services.gameFeedBack[\"validateCreateGameFeedback\"](game));\n\n expect(error).toStrictEqual(expectedError);\n });\n\n it(\"should not throw Bad Resource Mutation Exception when feedback does not exist.\", () => {\n const game = createFakeGame();\n\n expect(() => services.gameFeedBack[\"validateCreateGameFeedback\"](game)).not.toThrow();\n });\n });\n});" + "source": "import type { TestingModule } from \"@nestjs/testing\";\nimport { Test } from \"@nestjs/testing\";\n\nimport { GameFeedbackRepository } from \"@/modules/game/providers/repositories/game-feedback/game-feedback.repository\";\nimport { GameFeedbackService } from \"@/modules/game/providers/services/game-feedback/game-feedback.service\";\n\nimport { ApiResources } from \"@/shared/api/enums/api.enums\";\nimport { BadResourceMutationReasons } from \"@/shared/exception/enums/bad-resource-mutation-error.enums\";\nimport { BadResourceMutationException } from \"@/shared/exception/types/bad-resource-mutation-exception.types\";\n\nimport { createFakeCreateGameFeedbackDto } from \"@tests/factories/game/dto/create-game-feedback/create-game-feedback.dto.factory\";\nimport { createFakeGameFeedback, createFakeGameFeedbackToInsert } from \"@tests/factories/game/schemas/game-feedback/game-feedback.factory\";\nimport { createFakeGame } from \"@tests/factories/game/schemas/game.schema.factory\";\nimport { getError } from \"@tests/helpers/exception/exception.helpers\";\n\ndescribe(\"Game Feedback Service\", () => {\n let mocks: {\n gameFeedbackService: {\n validateCreateGameFeedback: jest.SpyInstance;\n };\n gameFeedbackRepository: {\n create: jest.SpyInstance;\n };\n };\n let services: { gameFeedBack: GameFeedbackService };\n\n beforeEach(async() => {\n mocks = {\n gameFeedbackService: {\n validateCreateGameFeedback: jest.fn(),\n },\n gameFeedbackRepository: {\n create: jest.fn(),\n },\n };\n const module: TestingModule = await Test.createTestingModule({\n providers: [\n {\n provide: GameFeedbackRepository,\n useValue: mocks.gameFeedbackRepository,\n },\n GameFeedbackService,\n ],\n }).compile();\n\n services = { gameFeedBack: module.get(GameFeedbackService) };\n });\n\n describe(\"createGameFeedback\", () => {\n beforeEach(() => {\n mocks.gameFeedbackService.validateCreateGameFeedback = jest.spyOn(services.gameFeedBack as unknown as { validateCreateGameFeedback }, \"validateCreateGameFeedback\");\n });\n\n it(\"should validate create game feedback when called.\", async() => {\n const game = createFakeGame();\n const createGameFeedbackDto = createFakeCreateGameFeedbackDto();\n await services.gameFeedBack.createGameFeedback(game, createGameFeedbackDto);\n\n expect(mocks.gameFeedbackService.validateCreateGameFeedback).toHaveBeenCalledExactlyOnceWith(game);\n });\n\n it(\"should create game feedback when called.\", async() => {\n const game = createFakeGame();\n const createGameFeedbackDto = createFakeCreateGameFeedbackDto();\n await services.gameFeedBack.createGameFeedback(game, createGameFeedbackDto);\n const expectedGameFeedbackToInsert = createFakeGameFeedbackToInsert({\n gameId: game._id,\n ...createGameFeedbackDto,\n });\n\n expect(mocks.gameFeedbackRepository.create).toHaveBeenCalledExactlyOnceWith(expectedGameFeedbackToInsert);\n });\n });\n\n describe(\"validateCreateGameFeedback\", () => {\n it(\"should throw Bad Resource Mutation Exception when feedback already exists.\", async() => {\n const game = createFakeGame({ feedback: createFakeGameFeedback() });\n const expectedError = new BadResourceMutationException(ApiResources.GAMES, game._id.toString(), BadResourceMutationReasons.FEEDBACK_ALREADY_EXISTS);\n const error = await getError(() => services.gameFeedBack[\"validateCreateGameFeedback\"](game));\n\n expect(error).toStrictEqual(expectedError);\n });\n\n it(\"should not throw Bad Resource Mutation Exception when feedback does not exist.\", () => {\n const game = createFakeGame();\n\n expect(() => services.gameFeedBack[\"validateCreateGameFeedback\"](game)).not.toThrow();\n });\n });\n});" }, "tests/unit/specs/modules/game/dto/base/decorators/composition/composition-roles-min-in-game.decorator.spec.ts": { "tests": [ @@ -201763,12 +201765,12 @@ "location": { "start": { "column": 6, - "line": 11 + "line": 12 } } } ], - "source": "import { createGameHistoryRecordToInsert } from \"@/modules/game/helpers/game-history-record/game-history-record.factory\";\nimport type { GameHistoryRecordToInsert } from \"@/modules/game/types/game-history-record/game-history-record.types\";\nimport { createFakeGameHistoryRecordPlay, createFakeGameHistoryRecordPlayerAttributeAlteration } from \"@tests/factories/game/schemas/game-history-record/game-history-record.schema.factory\";\nimport { createFakeGamePhase } from \"@tests/factories/game/schemas/game-phase/game-phase.schema.factory\";\nimport { createFakePlayer } from \"@tests/factories/game/schemas/player/player.schema.factory\";\nimport { createFakeGameHistoryRecordToInsert } from \"@tests/factories/game/types/game-history-record/game-history-record.type.factory\";\nimport { createFakeObjectId } from \"@tests/factories/shared/mongoose/mongoose.factory\";\n\ndescribe(\"Game History Record To Insert Factory\", () => {\n describe(\"create\", () => {\n it(\"should create a game history record to insert when called.\", () => {\n const gameHistoryRecordToInsert: GameHistoryRecordToInsert = {\n gameId: createFakeObjectId(),\n tick: 1,\n turn: 2,\n phase: createFakeGamePhase(),\n play: createFakeGameHistoryRecordPlay(),\n revealedPlayers: [createFakePlayer()],\n playerAttributeAlterations: [\n createFakeGameHistoryRecordPlayerAttributeAlteration(),\n createFakeGameHistoryRecordPlayerAttributeAlteration(),\n ],\n };\n const expectedGameHistoryRecordToInsert = createFakeGameHistoryRecordToInsert(gameHistoryRecordToInsert);\n\n expect(createGameHistoryRecordToInsert(gameHistoryRecordToInsert)).toStrictEqual(expectedGameHistoryRecordToInsert);\n });\n });\n});" + "source": "import { createGameHistoryRecordToInsert } from \"@/modules/game/helpers/game-history-record/game-history-record.factory\";\nimport type { GameHistoryRecordToInsert } from \"@/modules/game/types/game-history-record/game-history-record.types\";\n\nimport { createFakeGameHistoryRecordPlay, createFakeGameHistoryRecordPlayerAttributeAlteration } from \"@tests/factories/game/schemas/game-history-record/game-history-record.schema.factory\";\nimport { createFakeGamePhase } from \"@tests/factories/game/schemas/game-phase/game-phase.schema.factory\";\nimport { createFakePlayer } from \"@tests/factories/game/schemas/player/player.schema.factory\";\nimport { createFakeGameHistoryRecordToInsert } from \"@tests/factories/game/types/game-history-record/game-history-record.type.factory\";\nimport { createFakeObjectId } from \"@tests/factories/shared/mongoose/mongoose.factory\";\n\ndescribe(\"Game History Record To Insert Factory\", () => {\n describe(\"create\", () => {\n it(\"should create a game history record to insert when called.\", () => {\n const gameHistoryRecordToInsert: GameHistoryRecordToInsert = {\n gameId: createFakeObjectId(),\n tick: 1,\n turn: 2,\n phase: createFakeGamePhase(),\n play: createFakeGameHistoryRecordPlay(),\n revealedPlayers: [createFakePlayer()],\n playerAttributeAlterations: [\n createFakeGameHistoryRecordPlayerAttributeAlteration(),\n createFakeGameHistoryRecordPlayerAttributeAlteration(),\n ],\n };\n const expectedGameHistoryRecordToInsert = createFakeGameHistoryRecordToInsert(gameHistoryRecordToInsert);\n\n expect(createGameHistoryRecordToInsert(gameHistoryRecordToInsert)).toStrictEqual(expectedGameHistoryRecordToInsert);\n });\n });\n});" }, "tests/unit/specs/modules/game/helpers/game.factory.spec.ts": { "tests": [ @@ -201783,7 +201785,7 @@ } } ], - "source": "import { createGame } from \"@/modules/game/helpers/game.factory\";\nimport type { Game } from \"@/modules/game/schemas/game.schema\";\nimport { createFakeGameEvent } from \"@tests/factories/game/schemas/game-event/game-event.schema.factory\";\n\nimport { createFakeGameOptions } from \"@tests/factories/game/schemas/game-options/game-options.schema.factory\";\nimport { createFakeGamePhase } from \"@tests/factories/game/schemas/game-phase/game-phase.schema.factory\";\nimport { createFakeGamePlaySurvivorsElectSheriff, createFakeGamePlaySurvivorsVote } from \"@tests/factories/game/schemas/game-play/game-play.schema.factory\";\nimport { createFakeGame } from \"@tests/factories/game/schemas/game.schema.factory\";\nimport { createFakePlayer } from \"@tests/factories/game/schemas/player/player.schema.factory\";\nimport { createFakeObjectId } from \"@tests/factories/shared/mongoose/mongoose.factory\";\n\ndescribe(\"Game Factory\", () => {\n describe(\"createGame\", () => {\n it(\"should create a game when called.\", () => {\n const game: Game = {\n _id: createFakeObjectId(),\n currentPlay: createFakeGamePlaySurvivorsVote(),\n tick: 1,\n turn: 2,\n phase: createFakeGamePhase({ name: \"day\" }),\n players: [createFakePlayer()],\n playerGroups: [\"group1\", \"group2\"],\n options: createFakeGameOptions(),\n upcomingPlays: [createFakeGamePlaySurvivorsElectSheriff()],\n events: [\n createFakeGameEvent(),\n createFakeGameEvent(),\n ],\n status: \"playing\",\n lastGameHistoryRecord: null,\n feedback: null,\n createdAt: new Date(),\n updatedAt: new Date(),\n };\n\n expect(createGame(game)).toStrictEqual(createFakeGame(game));\n });\n });\n});" + "source": "import { createGame } from \"@/modules/game/helpers/game.factory\";\nimport type { Game } from \"@/modules/game/schemas/game.schema\";\n\nimport { createFakeGameEvent } from \"@tests/factories/game/schemas/game-event/game-event.schema.factory\";\nimport { createFakeGameOptions } from \"@tests/factories/game/schemas/game-options/game-options.schema.factory\";\nimport { createFakeGamePhase } from \"@tests/factories/game/schemas/game-phase/game-phase.schema.factory\";\nimport { createFakeGamePlaySurvivorsElectSheriff, createFakeGamePlaySurvivorsVote } from \"@tests/factories/game/schemas/game-play/game-play.schema.factory\";\nimport { createFakeGame } from \"@tests/factories/game/schemas/game.schema.factory\";\nimport { createFakePlayer } from \"@tests/factories/game/schemas/player/player.schema.factory\";\nimport { createFakeObjectId } from \"@tests/factories/shared/mongoose/mongoose.factory\";\n\ndescribe(\"Game Factory\", () => {\n describe(\"createGame\", () => {\n it(\"should create a game when called.\", () => {\n const game: Game = {\n _id: createFakeObjectId(),\n currentPlay: createFakeGamePlaySurvivorsVote(),\n tick: 1,\n turn: 2,\n phase: createFakeGamePhase({ name: \"day\" }),\n players: [createFakePlayer()],\n playerGroups: [\"group1\", \"group2\"],\n options: createFakeGameOptions(),\n upcomingPlays: [createFakeGamePlaySurvivorsElectSheriff()],\n events: [\n createFakeGameEvent(),\n createFakeGameEvent(),\n ],\n status: \"playing\",\n lastGameHistoryRecord: null,\n feedback: null,\n createdAt: new Date(),\n updatedAt: new Date(),\n };\n\n expect(createGame(game)).toStrictEqual(createFakeGame(game));\n });\n });\n});" }, "tests/unit/specs/modules/game/helpers/game-feedback/game-feedback.factory.spec.ts": { "tests": [ @@ -201793,7 +201795,7 @@ "location": { "start": { "column": 6, - "line": 9 + "line": 10 } } }, @@ -201803,12 +201805,12 @@ "location": { "start": { "column": 6, - "line": 23 + "line": 24 } } } ], - "source": "import { createGameFeedback, createGameFeedbackToInsert } from \"@/modules/game/helpers/game-feedback/game-feedback.factory\";\nimport type { GameFeedback } from \"@/modules/game/schemas/game-feedback/game-feedback.schema\";\nimport type { GameFeedbackToInsert } from \"@/modules/game/types/game-feedback/game-feedback.types\";\nimport { createFakeGameFeedback, createFakeGameFeedbackToInsert } from \"@tests/factories/game/schemas/game-feedback/game-feedback.factory\";\nimport { createFakeObjectId } from \"@tests/factories/shared/mongoose/mongoose.factory\";\n\ndescribe(\"Game Feedback Factory\", () => {\n describe(\"createGameFeedbackToInsert\", () => {\n it(\"should create a game feedback to insert when called.\", () => {\n const gameFeedbackToInsert: GameFeedbackToInsert = {\n gameId: createFakeObjectId(),\n score: 5,\n review: \"review\",\n hasEncounteredError: false,\n };\n const result = createGameFeedbackToInsert(gameFeedbackToInsert);\n\n expect(result).toStrictEqual(createFakeGameFeedbackToInsert(gameFeedbackToInsert));\n });\n });\n\n describe(\"createGameFeedback\", () => {\n it(\"should create a game feedback when called.\", () => {\n const gameFeedback: GameFeedback = {\n _id: createFakeObjectId(),\n gameId: createFakeObjectId(),\n score: 5,\n review: \"review\",\n hasEncounteredError: false,\n createdAt: new Date(),\n };\n const result = createGameFeedback(gameFeedback);\n\n expect(result).toStrictEqual(createFakeGameFeedback(gameFeedback));\n });\n });\n});" + "source": "import { createGameFeedback, createGameFeedbackToInsert } from \"@/modules/game/helpers/game-feedback/game-feedback.factory\";\nimport type { GameFeedback } from \"@/modules/game/schemas/game-feedback/game-feedback.schema\";\nimport type { GameFeedbackToInsert } from \"@/modules/game/types/game-feedback/game-feedback.types\";\n\nimport { createFakeGameFeedback, createFakeGameFeedbackToInsert } from \"@tests/factories/game/schemas/game-feedback/game-feedback.factory\";\nimport { createFakeObjectId } from \"@tests/factories/shared/mongoose/mongoose.factory\";\n\ndescribe(\"Game Feedback Factory\", () => {\n describe(\"createGameFeedbackToInsert\", () => {\n it(\"should create a game feedback to insert when called.\", () => {\n const gameFeedbackToInsert: GameFeedbackToInsert = {\n gameId: createFakeObjectId(),\n score: 5,\n review: \"review\",\n hasEncounteredError: false,\n };\n const result = createGameFeedbackToInsert(gameFeedbackToInsert);\n\n expect(result).toStrictEqual(createFakeGameFeedbackToInsert(gameFeedbackToInsert));\n });\n });\n\n describe(\"createGameFeedback\", () => {\n it(\"should create a game feedback when called.\", () => {\n const gameFeedback: GameFeedback = {\n _id: createFakeObjectId(),\n gameId: createFakeObjectId(),\n score: 5,\n review: \"review\",\n hasEncounteredError: false,\n createdAt: new Date(),\n };\n const result = createGameFeedback(gameFeedback);\n\n expect(result).toStrictEqual(createFakeGameFeedback(gameFeedback));\n });\n });\n});" }, "tests/unit/specs/modules/game/helpers/game-phase/game-phase.helpers.spec.ts": { "tests": [ @@ -201863,7 +201865,7 @@ } } ], - "source": "import { isGamePhaseOver, isInNightOrTwilightPhase } from \"@/modules/game/helpers/game-phase/game-phase.helpers\";\nimport { createFakeGamePhase } from \"@tests/factories/game/schemas/game-phase/game-phase.schema.factory\";\n\nimport { createFakeGame, createFakeGameWithCurrentPlay } from \"@tests/factories/game/schemas/game.schema.factory\";\n\ndescribe(\"Game Phase Helper\", () => {\n describe(\"isGamePhaseOver\", () => {\n it(\"should return false when the phase is not over.\", () => {\n const game = createFakeGameWithCurrentPlay();\n\n expect(isGamePhaseOver(game)).toBe(false);\n });\n\n it(\"should return true when the phase is over.\", () => {\n const game = createFakeGame();\n\n expect(isGamePhaseOver(game)).toBe(true);\n });\n });\n\n describe(\"isInNightOrTwilightPhase\", () => {\n it(\"should return true when the game is in the night phase.\", () => {\n const game = createFakeGame({ phase: createFakeGamePhase({ name: \"night\" }) });\n\n expect(isInNightOrTwilightPhase(game)).toBe(true);\n });\n\n it(\"should return true when the game is in the twilight phase.\", () => {\n const game = createFakeGame({ phase: createFakeGamePhase({ name: \"twilight\" }) });\n\n expect(isInNightOrTwilightPhase(game)).toBe(true);\n });\n\n it(\"should return false when the game is in the day phase.\", () => {\n const game = createFakeGame({ phase: createFakeGamePhase({ name: \"day\" }) });\n\n expect(isInNightOrTwilightPhase(game)).toBe(false);\n });\n });\n});" + "source": "import { isGamePhaseOver, isInNightOrTwilightPhase } from \"@/modules/game/helpers/game-phase/game-phase.helpers\";\n\nimport { createFakeGamePhase } from \"@tests/factories/game/schemas/game-phase/game-phase.schema.factory\";\nimport { createFakeGame, createFakeGameWithCurrentPlay } from \"@tests/factories/game/schemas/game.schema.factory\";\n\ndescribe(\"Game Phase Helper\", () => {\n describe(\"isGamePhaseOver\", () => {\n it(\"should return false when the phase is not over.\", () => {\n const game = createFakeGameWithCurrentPlay();\n\n expect(isGamePhaseOver(game)).toBe(false);\n });\n\n it(\"should return true when the phase is over.\", () => {\n const game = createFakeGame();\n\n expect(isGamePhaseOver(game)).toBe(true);\n });\n });\n\n describe(\"isInNightOrTwilightPhase\", () => {\n it(\"should return true when the game is in the night phase.\", () => {\n const game = createFakeGame({ phase: createFakeGamePhase({ name: \"night\" }) });\n\n expect(isInNightOrTwilightPhase(game)).toBe(true);\n });\n\n it(\"should return true when the game is in the twilight phase.\", () => {\n const game = createFakeGame({ phase: createFakeGamePhase({ name: \"twilight\" }) });\n\n expect(isInNightOrTwilightPhase(game)).toBe(true);\n });\n\n it(\"should return false when the game is in the day phase.\", () => {\n const game = createFakeGame({ phase: createFakeGamePhase({ name: \"day\" }) });\n\n expect(isInNightOrTwilightPhase(game)).toBe(false);\n });\n });\n});" }, "tests/unit/specs/modules/game/helpers/game-additional-card/game-additional-card.factory.spec.ts": { "tests": [ @@ -201898,12 +201900,12 @@ "location": { "start": { "column": 6, - "line": 7 + "line": 8 } } } ], - "source": "import { createGameHistoryRecordPlayerAttributeAlteration } from \"@/modules/game/helpers/game-history-record/game-history-record-player-attribute-alteration/game-history-record-player-attribute-alteration.factory\";\nimport type { GameHistoryRecordPlayerAttributeAlteration } from \"@/modules/game/schemas/game-history-record/game-history-record-player-attribute-alteration/game-history-record-player-attribute-alteration.schema\";\nimport { createFakeGameHistoryRecordPlayerAttributeAlteration } from \"@tests/factories/game/schemas/game-history-record/game-history-record.schema.factory\";\n\ndescribe(\"Game History Record Player Attribute Alteration Factory\", () => {\n describe(\"create\", () => {\n it(\"should create a game history record player attribute alteration when called.\", () => {\n const gameHistoryRecordPlayerAttributeAlteration: GameHistoryRecordPlayerAttributeAlteration = {\n playerName: \"playerName\",\n name: \"sheriff\",\n source: \"survivors\",\n status: \"attached\",\n };\n const expectedGameHistoryRecordPlayerAttributeAlteration = createFakeGameHistoryRecordPlayerAttributeAlteration(gameHistoryRecordPlayerAttributeAlteration);\n\n expect(createGameHistoryRecordPlayerAttributeAlteration(gameHistoryRecordPlayerAttributeAlteration)).toStrictEqual(expectedGameHistoryRecordPlayerAttributeAlteration);\n });\n });\n});" + "source": "import { createGameHistoryRecordPlayerAttributeAlteration } from \"@/modules/game/helpers/game-history-record/game-history-record-player-attribute-alteration/game-history-record-player-attribute-alteration.factory\";\nimport type { GameHistoryRecordPlayerAttributeAlteration } from \"@/modules/game/schemas/game-history-record/game-history-record-player-attribute-alteration/game-history-record-player-attribute-alteration.schema\";\n\nimport { createFakeGameHistoryRecordPlayerAttributeAlteration } from \"@tests/factories/game/schemas/game-history-record/game-history-record.schema.factory\";\n\ndescribe(\"Game History Record Player Attribute Alteration Factory\", () => {\n describe(\"create\", () => {\n it(\"should create a game history record player attribute alteration when called.\", () => {\n const gameHistoryRecordPlayerAttributeAlteration: GameHistoryRecordPlayerAttributeAlteration = {\n playerName: \"playerName\",\n name: \"sheriff\",\n source: \"survivors\",\n status: \"attached\",\n };\n const expectedGameHistoryRecordPlayerAttributeAlteration = createFakeGameHistoryRecordPlayerAttributeAlteration(gameHistoryRecordPlayerAttributeAlteration);\n\n expect(createGameHistoryRecordPlayerAttributeAlteration(gameHistoryRecordPlayerAttributeAlteration)).toStrictEqual(expectedGameHistoryRecordPlayerAttributeAlteration);\n });\n });\n});" }, "tests/unit/specs/shared/exception/types/unexpected-exception.types.spec.ts": { "tests": [ @@ -201928,7 +201930,7 @@ } } ], - "source": "import { UnexpectedExceptionReasons } from \"@/shared/exception/enums/unexpected-exception.enum\";\nimport { UnexpectedException } from \"@/shared/exception/types/unexpected-exception.types\";\n\nimport type { ExceptionResponse } from \"@tests/types/exception/exception.types\";\n\ndescribe(\"Unexpected exception type\", () => {\n describe(\"getResponse\", () => {\n it(\"should get response with description without interpolations when interpolations are not necessary.\", () => {\n const exception = new UnexpectedException(\"werewolvesEat\", UnexpectedExceptionReasons.CANT_FIND_PLAYER_WITH_ID_IN_GAME);\n\n expect(exception.getResponse()).toStrictEqual({\n statusCode: 500,\n message: `Unexpected exception in werewolvesEat`,\n error: \"Can't find player with id \\\"undefined\\\" for game with id \\\"undefined\\\"\",\n });\n });\n\n it(\"should get response with description with interpolations when interpolations necessary.\", () => {\n const exception = new UnexpectedException(\"werewolvesEat\", UnexpectedExceptionReasons.CANT_FIND_PLAYER_WITH_ID_IN_GAME, { gameId: \"123\", playerId: \"456\" });\n\n expect(exception.getResponse()).toStrictEqual({\n statusCode: 500,\n message: `Unexpected exception in werewolvesEat`,\n error: `Can't find player with id \"456\" for game with id \"123\"`,\n });\n });\n });\n});" + "source": "import { UnexpectedExceptionReasons } from \"@/shared/exception/enums/unexpected-exception.enums\";\nimport { UnexpectedException } from \"@/shared/exception/types/unexpected-exception.types\";\n\nimport type { ExceptionResponse } from \"@tests/types/exception/exception.types\";\n\ndescribe(\"Unexpected exception type\", () => {\n describe(\"getResponse\", () => {\n it(\"should get response with description without interpolations when interpolations are not necessary.\", () => {\n const exception = new UnexpectedException(\"werewolvesEat\", UnexpectedExceptionReasons.CANT_FIND_PLAYER_WITH_ID_IN_GAME);\n\n expect(exception.getResponse()).toStrictEqual({\n statusCode: 500,\n message: `Unexpected exception in werewolvesEat`,\n error: \"Can't find player with id \\\"undefined\\\" for game with id \\\"undefined\\\"\",\n });\n });\n\n it(\"should get response with description with interpolations when interpolations necessary.\", () => {\n const exception = new UnexpectedException(\"werewolvesEat\", UnexpectedExceptionReasons.CANT_FIND_PLAYER_WITH_ID_IN_GAME, { gameId: \"123\", playerId: \"456\" });\n\n expect(exception.getResponse()).toStrictEqual({\n statusCode: 500,\n message: `Unexpected exception in werewolvesEat`,\n error: `Can't find player with id \"456\" for game with id \"123\"`,\n });\n });\n });\n});" }, "tests/unit/specs/shared/exception/types/resource-not-found-exception.types.spec.ts": { "tests": [ @@ -201953,7 +201955,7 @@ } } ], - "source": "import { ApiResources } from \"@/shared/api/enums/api.enums\";\nimport { ResourceNotFoundReasons } from \"@/shared/exception/enums/resource-not-found-error.enum\";\nimport { ResourceNotFoundException } from \"@/shared/exception/types/resource-not-found-exception.types\";\n\nimport type { ExceptionResponse } from \"@tests/types/exception/exception.types\";\n\ndescribe(\"Resource not found exception type\", () => {\n describe(\"getResponse\", () => {\n it(\"should get response without description when called without reason.\", () => {\n const id = \"123\";\n const exception = new ResourceNotFoundException(ApiResources.PLAYERS, id);\n\n expect(exception.getResponse()).toStrictEqual({\n statusCode: 404,\n message: `Player with id \"${id}\" not found`,\n error: undefined,\n });\n });\n\n it(\"should get response with description when called with reason.\", () => {\n const id = \"123\";\n const exception = new ResourceNotFoundException(ApiResources.PLAYERS, id, ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_PLAYER_VOTE_SOURCE);\n\n expect(exception.getResponse()).toStrictEqual({\n statusCode: 404,\n message: `Player with id \"${id}\" not found`,\n error: \"Game Play - Player in `votes.source` is not in the game players\",\n });\n });\n });\n});" + "source": "import { ApiResources } from \"@/shared/api/enums/api.enums\";\nimport { ResourceNotFoundReasons } from \"@/shared/exception/enums/resource-not-found-error.enums\";\nimport { ResourceNotFoundException } from \"@/shared/exception/types/resource-not-found-exception.types\";\n\nimport type { ExceptionResponse } from \"@tests/types/exception/exception.types\";\n\ndescribe(\"Resource not found exception type\", () => {\n describe(\"getResponse\", () => {\n it(\"should get response without description when called without reason.\", () => {\n const id = \"123\";\n const exception = new ResourceNotFoundException(ApiResources.PLAYERS, id);\n\n expect(exception.getResponse()).toStrictEqual({\n statusCode: 404,\n message: `Player with id \"${id}\" not found`,\n error: undefined,\n });\n });\n\n it(\"should get response with description when called with reason.\", () => {\n const id = \"123\";\n const exception = new ResourceNotFoundException(ApiResources.PLAYERS, id, ResourceNotFoundReasons.UNMATCHED_GAME_PLAY_PLAYER_VOTE_SOURCE);\n\n expect(exception.getResponse()).toStrictEqual({\n statusCode: 404,\n message: `Player with id \"${id}\" not found`,\n error: \"Game Play - Player in `votes.source` is not in the game players\",\n });\n });\n });\n});" }, "tests/unit/specs/shared/exception/types/bad-resource-mutation-exception.types.spec.ts": { "tests": [ @@ -201978,7 +201980,7 @@ } } ], - "source": "import { ApiResources } from \"@/shared/api/enums/api.enums\";\nimport { BadResourceMutationReasons } from \"@/shared/exception/enums/bad-resource-mutation-error.enum\";\nimport { BadResourceMutationException } from \"@/shared/exception/types/bad-resource-mutation-exception.types\";\n\nimport type { ExceptionResponse } from \"@tests/types/exception/exception.types\";\n\ndescribe(\"Resource not found mutation exception type\", () => {\n describe(\"getResponse\", () => {\n it(\"should get response without description when called without reason.\", () => {\n const id = \"123\";\n const exception = new BadResourceMutationException(ApiResources.GAMES, id);\n\n expect(exception.getResponse()).toStrictEqual({\n statusCode: 400,\n message: `Bad mutation for Game with id \"${id}\"`,\n error: undefined,\n });\n });\n\n it(\"should get response with description when called with reason.\", () => {\n const id = \"123\";\n const exception = new BadResourceMutationException(ApiResources.GAMES, id, BadResourceMutationReasons.GAME_NOT_PLAYING);\n\n expect(exception.getResponse()).toStrictEqual({\n statusCode: 400,\n message: `Bad mutation for Game with id \"${id}\"`,\n error: `Game doesn't have status with value \"playing\"`,\n });\n });\n });\n});" + "source": "import { ApiResources } from \"@/shared/api/enums/api.enums\";\nimport { BadResourceMutationReasons } from \"@/shared/exception/enums/bad-resource-mutation-error.enums\";\nimport { BadResourceMutationException } from \"@/shared/exception/types/bad-resource-mutation-exception.types\";\n\nimport type { ExceptionResponse } from \"@tests/types/exception/exception.types\";\n\ndescribe(\"Resource not found mutation exception type\", () => {\n describe(\"getResponse\", () => {\n it(\"should get response without description when called without reason.\", () => {\n const id = \"123\";\n const exception = new BadResourceMutationException(ApiResources.GAMES, id);\n\n expect(exception.getResponse()).toStrictEqual({\n statusCode: 400,\n message: `Bad mutation for Game with id \"${id}\"`,\n error: undefined,\n });\n });\n\n it(\"should get response with description when called with reason.\", () => {\n const id = \"123\";\n const exception = new BadResourceMutationException(ApiResources.GAMES, id, BadResourceMutationReasons.GAME_NOT_PLAYING);\n\n expect(exception.getResponse()).toStrictEqual({\n statusCode: 400,\n message: `Bad mutation for Game with id \"${id}\"`,\n error: `Game doesn't have status with value \"playing\"`,\n });\n });\n });\n});" }, "tests/unit/specs/modules/game/helpers/game-history-record/game-history-record-play/game-history-record-play-voting/game-history-record-play-voting.factory.spec.ts": { "tests": [ @@ -201988,12 +201990,12 @@ "location": { "start": { "column": 6, - "line": 8 + "line": 9 } } } ], - "source": "import { createGameHistoryRecordPlayVoting } from \"@/modules/game/helpers/game-history-record/game-history-record-play/game-history-record-play-voting/game-history-record-play-voting.factory\";\nimport type { GameHistoryRecordPlayVoting } from \"@/modules/game/schemas/game-history-record/game-history-record-play/game-history-record-play-voting/game-history-record-play-voting.schema\";\nimport { createFakeGameHistoryRecordPlayVoting } from \"@tests/factories/game/schemas/game-history-record/game-history-record.schema.factory\";\nimport { createFakePlayer } from \"@tests/factories/game/schemas/player/player.schema.factory\";\n\ndescribe(\"Game History Record Play Voting Factory\", () => {\n describe(\"create\", () => {\n it(\"should create a game history record play voting when called.\", () => {\n const gameHistoryRecordPlayVoting: GameHistoryRecordPlayVoting = {\n result: \"tie\",\n nominatedPlayers: [\n createFakePlayer(),\n createFakePlayer(),\n ],\n };\n const expectedGameHistoryRecordPlayVoting = createFakeGameHistoryRecordPlayVoting(gameHistoryRecordPlayVoting);\n\n expect(createGameHistoryRecordPlayVoting(gameHistoryRecordPlayVoting)).toStrictEqual(expectedGameHistoryRecordPlayVoting);\n });\n });\n});" + "source": "import { createGameHistoryRecordPlayVoting } from \"@/modules/game/helpers/game-history-record/game-history-record-play/game-history-record-play-voting/game-history-record-play-voting.factory\";\nimport type { GameHistoryRecordPlayVoting } from \"@/modules/game/schemas/game-history-record/game-history-record-play/game-history-record-play-voting/game-history-record-play-voting.schema\";\n\nimport { createFakeGameHistoryRecordPlayVoting } from \"@tests/factories/game/schemas/game-history-record/game-history-record.schema.factory\";\nimport { createFakePlayer } from \"@tests/factories/game/schemas/player/player.schema.factory\";\n\ndescribe(\"Game History Record Play Voting Factory\", () => {\n describe(\"create\", () => {\n it(\"should create a game history record play voting when called.\", () => {\n const gameHistoryRecordPlayVoting: GameHistoryRecordPlayVoting = {\n result: \"tie\",\n nominatedPlayers: [\n createFakePlayer(),\n createFakePlayer(),\n ],\n };\n const expectedGameHistoryRecordPlayVoting = createFakeGameHistoryRecordPlayVoting(gameHistoryRecordPlayVoting);\n\n expect(createGameHistoryRecordPlayVoting(gameHistoryRecordPlayVoting)).toStrictEqual(expectedGameHistoryRecordPlayVoting);\n });\n });\n});" }, "tests/unit/specs/modules/game/controllers/decorators/api-game-not-found-response.decorator.spec.ts": { "tests": [ @@ -202028,12 +202030,12 @@ "location": { "start": { "column": 6, - "line": 8 + "line": 9 } } } ], - "source": "import { createGameHistoryRecordPlaySource } from \"@/modules/game/helpers/game-history-record/game-history-record-play/game-history-record-play-source/game-history-record-play-source.factory\";\nimport type { GameHistoryRecordPlaySource } from \"@/modules/game/schemas/game-history-record/game-history-record-play/game-history-record-play-source/game-history-record-play-source.schema\";\nimport { createFakeGameHistoryRecordPlaySource } from \"@tests/factories/game/schemas/game-history-record/game-history-record.schema.factory\";\nimport { createFakePlayer } from \"@tests/factories/game/schemas/player/player.schema.factory\";\n\ndescribe(\"Game History Record Play Source Factory\", () => {\n describe(\"create\", () => {\n it(\"should create a game history record play source when called.\", () => {\n const gameHistoryRecordPlaySource: GameHistoryRecordPlaySource = {\n name: \"sheriff\",\n players: [createFakePlayer()],\n };\n const expectedGameHistoryRecordPlaySource = createFakeGameHistoryRecordPlaySource(gameHistoryRecordPlaySource);\n\n expect(createGameHistoryRecordPlaySource(gameHistoryRecordPlaySource)).toStrictEqual(expectedGameHistoryRecordPlaySource);\n });\n });\n});" + "source": "import { createGameHistoryRecordPlaySource } from \"@/modules/game/helpers/game-history-record/game-history-record-play/game-history-record-play-source/game-history-record-play-source.factory\";\nimport type { GameHistoryRecordPlaySource } from \"@/modules/game/schemas/game-history-record/game-history-record-play/game-history-record-play-source/game-history-record-play-source.schema\";\n\nimport { createFakeGameHistoryRecordPlaySource } from \"@tests/factories/game/schemas/game-history-record/game-history-record.schema.factory\";\nimport { createFakePlayer } from \"@tests/factories/game/schemas/player/player.schema.factory\";\n\ndescribe(\"Game History Record Play Source Factory\", () => {\n describe(\"create\", () => {\n it(\"should create a game history record play source when called.\", () => {\n const gameHistoryRecordPlaySource: GameHistoryRecordPlaySource = {\n name: \"sheriff\",\n players: [createFakePlayer()],\n };\n const expectedGameHistoryRecordPlaySource = createFakeGameHistoryRecordPlaySource(gameHistoryRecordPlaySource);\n\n expect(createGameHistoryRecordPlaySource(gameHistoryRecordPlaySource)).toStrictEqual(expectedGameHistoryRecordPlaySource);\n });\n });\n});" }, "tests/unit/specs/modules/game/helpers/game-history-record/game-history-record-play/game-history-record-play.factory.spec.ts": { "tests": [ @@ -202043,12 +202045,12 @@ "location": { "start": { "column": 6, - "line": 7 + "line": 8 } } } ], - "source": "import { createGameHistoryRecordPlay } from \"@/modules/game/helpers/game-history-record/game-history-record-play/game-history-record-play.factory\";\nimport type { GameHistoryRecordPlay } from \"@/modules/game/schemas/game-history-record/game-history-record-play/game-history-record-play.schema\";\nimport { createFakeGameHistoryRecordPlay, createFakeGameHistoryRecordPlaySource, createFakeGameHistoryRecordPlayTarget } from \"@tests/factories/game/schemas/game-history-record/game-history-record.schema.factory\";\n\ndescribe(\"Game History Record Play Factory\", () => {\n describe(\"create\", () => {\n it(\"should create a game history record play when called.\", () => {\n const gameHistoryRecordPlay: GameHistoryRecordPlay = {\n type: \"target\",\n action: \"eat\",\n source: createFakeGameHistoryRecordPlaySource(),\n targets: [createFakeGameHistoryRecordPlayTarget()],\n };\n const expectedGameHistoryRecordPlay = createFakeGameHistoryRecordPlay(gameHistoryRecordPlay);\n\n expect(createGameHistoryRecordPlay(gameHistoryRecordPlay)).toStrictEqual(expectedGameHistoryRecordPlay);\n });\n });\n});" + "source": "import { createGameHistoryRecordPlay } from \"@/modules/game/helpers/game-history-record/game-history-record-play/game-history-record-play.factory\";\nimport type { GameHistoryRecordPlay } from \"@/modules/game/schemas/game-history-record/game-history-record-play/game-history-record-play.schema\";\n\nimport { createFakeGameHistoryRecordPlay, createFakeGameHistoryRecordPlaySource, createFakeGameHistoryRecordPlayTarget } from \"@tests/factories/game/schemas/game-history-record/game-history-record.schema.factory\";\n\ndescribe(\"Game History Record Play Factory\", () => {\n describe(\"create\", () => {\n it(\"should create a game history record play when called.\", () => {\n const gameHistoryRecordPlay: GameHistoryRecordPlay = {\n type: \"target\",\n action: \"eat\",\n source: createFakeGameHistoryRecordPlaySource(),\n targets: [createFakeGameHistoryRecordPlayTarget()],\n };\n const expectedGameHistoryRecordPlay = createFakeGameHistoryRecordPlay(gameHistoryRecordPlay);\n\n expect(createGameHistoryRecordPlay(gameHistoryRecordPlay)).toStrictEqual(expectedGameHistoryRecordPlay);\n });\n });\n});" }, "tests/unit/specs/shared/validation/helpers/validation.helpers.spec.ts": { "tests": [ @@ -202143,12 +202145,12 @@ "location": { "start": { "column": 6, - "line": 6 + "line": 7 } } } ], - "source": "import { MakeGamePlayTargetWithRelationsDto } from \"@/modules/game/dto/make-game-play/make-game-play-target/make-game-play-target-with-relations.dto\";\nimport { createFakePlayer } from \"@tests/factories/game/schemas/player/player.schema.factory\";\n\ndescribe(\"Make Game Play With Relations Dto\", () => {\n describe(\"create\", () => {\n it(\"should create instance when called.\", () => {\n const expectedMakeGamePlayTargetWithRelationsDto = new MakeGamePlayTargetWithRelationsDto();\n const player = createFakePlayer();\n expectedMakeGamePlayTargetWithRelationsDto.player = player;\n expectedMakeGamePlayTargetWithRelationsDto.drankPotion = \"life\";\n const makeGamePlayTargetWithRelationsDto = MakeGamePlayTargetWithRelationsDto.create({\n player,\n drankPotion: \"life\",\n });\n\n expect(makeGamePlayTargetWithRelationsDto).toStrictEqual(expectedMakeGamePlayTargetWithRelationsDto);\n });\n });\n});" + "source": "import { MakeGamePlayTargetWithRelationsDto } from \"@/modules/game/dto/make-game-play/make-game-play-target/make-game-play-target-with-relations.dto\";\n\nimport { createFakePlayer } from \"@tests/factories/game/schemas/player/player.schema.factory\";\n\ndescribe(\"Make Game Play With Relations Dto\", () => {\n describe(\"create\", () => {\n it(\"should create instance when called.\", () => {\n const expectedMakeGamePlayTargetWithRelationsDto = new MakeGamePlayTargetWithRelationsDto();\n const player = createFakePlayer();\n expectedMakeGamePlayTargetWithRelationsDto.player = player;\n expectedMakeGamePlayTargetWithRelationsDto.drankPotion = \"life\";\n const makeGamePlayTargetWithRelationsDto = MakeGamePlayTargetWithRelationsDto.create({\n player,\n drankPotion: \"life\",\n });\n\n expect(makeGamePlayTargetWithRelationsDto).toStrictEqual(expectedMakeGamePlayTargetWithRelationsDto);\n });\n });\n});" }, "tests/unit/specs/modules/game/dto/base/decorators/composition/composition-unique-names.decorator.spec.ts": { "tests": [ @@ -202195,55 +202197,55 @@ ], "source": "import { getPlayerName } from \"@/modules/game/dto/base/decorators/composition/composition-unique-names.decorator\";\n\ndescribe(\"Composition Unique Names Decorator\", () => {\n describe(\"getPlayerName\", () => {\n it.each<{\n test: string;\n value: unknown;\n expected: unknown;\n }>([\n {\n test: \"should return null when value is null.\",\n value: null,\n expected: null,\n },\n {\n test: \"should return same value when value is not an object.\",\n value: \"toto\",\n expected: \"toto\",\n },\n {\n test: \"should return same value when value doesn't have name field.\",\n value: {},\n expected: {},\n },\n {\n test: \"should return name when called.\",\n value: { name: \"Antoine\" },\n expected: \"Antoine\",\n },\n ])(\"$test\", ({ value, expected }) => {\n expect(getPlayerName(value)).toStrictEqual(expected);\n });\n });\n});" }, - "tests/unit/specs/modules/role/constants/role.constants.spec.ts": { + "tests/unit/specs/modules/game/helpers/game-event/game-event.factory.spec.ts": { "tests": [ { "id": "1695", - "name": "Role Constant werewolvesRoles should contain only roles with side 'werewolves' when called.", + "name": "Game Event Factory createGameEvent should create a game event when called.", "location": { "start": { "column": 6, - "line": 6 + "line": 9 } } - }, + } + ], + "source": "import { createGameEvent } from \"@/modules/game/helpers/game-event/game-event.factory\";\nimport type { GameEvent } from \"@/modules/game/schemas/game-event/game-event.schema\";\n\nimport { createFakeGameEvent } from \"@tests/factories/game/schemas/game-event/game-event.schema.factory\";\nimport { createFakePlayer } from \"@tests/factories/game/schemas/player/player.schema.factory\";\n\ndescribe(\"Game Event Factory\", () => {\n describe(\"createGameEvent\", () => {\n it(\"should create a game event when called.\", () => {\n const gameEvent: GameEvent = {\n type: \"elder-has-taken-revenge\",\n players: [\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n ],\n };\n const gameEventWithExtraProperties = { ...gameEvent, extra: \"extra\" };\n\n expect(createGameEvent(gameEventWithExtraProperties)).toStrictEqual(createFakeGameEvent(gameEvent));\n });\n });\n});" + }, + "tests/unit/specs/modules/role/constants/role.constants.spec.ts": { + "tests": [ { "id": "1696", - "name": "Role Constant villagerRoles should contain only roles with side 'villagers' when called.", + "name": "Role Constant werewolvesRoles should contain only roles with side 'werewolves' when called.", "location": { "start": { "column": 6, - "line": 13 + "line": 6 } } }, { "id": "1697", - "name": "Role Constant roles should contain all roles when called.", + "name": "Role Constant villagerRoles should contain only roles with side 'villagers' when called.", "location": { "start": { "column": 6, - "line": 20 + "line": 13 } } - } - ], - "source": "import { ROLES, VILLAGER_ROLES, WEREWOLF_ROLES } from \"@/modules/role/constants/role-set.constants\";\nimport type { Role } from \"@/modules/role/types/role.class\";\n\ndescribe(\"Role Constant\", () => {\n describe(\"werewolvesRoles\", () => {\n it(\"should contain only roles with side 'werewolves' when called.\", () => {\n expect(WEREWOLF_ROLES.length).toBeGreaterThan(0);\n expect(WEREWOLF_ROLES.every(role => role.side === \"werewolves\")).toBe(true);\n });\n });\n\n describe(\"villagerRoles\", () => {\n it(\"should contain only roles with side 'villagers' when called.\", () => {\n expect(VILLAGER_ROLES.length).toBeGreaterThan(0);\n expect(VILLAGER_ROLES.every(role => role.side === \"villagers\")).toBe(true);\n });\n });\n\n describe(\"roles\", () => {\n it(\"should contain all roles when called.\", () => {\n expect(ROLES).toStrictEqual([...WEREWOLF_ROLES, ...VILLAGER_ROLES] as Role[]);\n });\n });\n});" - }, - "tests/unit/specs/modules/game/helpers/game-event/game-event.factory.spec.ts": { - "tests": [ + }, { "id": "1698", - "name": "Game Event Factory createGameEvent should create a game event when called.", + "name": "Role Constant roles should contain all roles when called.", "location": { "start": { "column": 6, - "line": 8 + "line": 20 } } } ], - "source": "import { createGameEvent } from \"@/modules/game/helpers/game-event/game-event.factory\";\nimport type { GameEvent } from \"@/modules/game/schemas/game-event/game-event.schema\";\nimport { createFakeGameEvent } from \"@tests/factories/game/schemas/game-event/game-event.schema.factory\";\nimport { createFakePlayer } from \"@tests/factories/game/schemas/player/player.schema.factory\";\n\ndescribe(\"Game Event Factory\", () => {\n describe(\"createGameEvent\", () => {\n it(\"should create a game event when called.\", () => {\n const gameEvent: GameEvent = {\n type: \"elder-has-taken-revenge\",\n players: [\n createFakePlayer(),\n createFakePlayer(),\n createFakePlayer(),\n ],\n };\n const gameEventWithExtraProperties = { ...gameEvent, extra: \"extra\" };\n\n expect(createGameEvent(gameEventWithExtraProperties)).toStrictEqual(createFakeGameEvent(gameEvent));\n });\n });\n});" + "source": "import { ROLES, VILLAGER_ROLES, WEREWOLF_ROLES } from \"@/modules/role/constants/role-set.constants\";\nimport type { Role } from \"@/modules/role/types/role.class\";\n\ndescribe(\"Role Constant\", () => {\n describe(\"werewolvesRoles\", () => {\n it(\"should contain only roles with side 'werewolves' when called.\", () => {\n expect(WEREWOLF_ROLES.length).toBeGreaterThan(0);\n expect(WEREWOLF_ROLES.every(role => role.side === \"werewolves\")).toBe(true);\n });\n });\n\n describe(\"villagerRoles\", () => {\n it(\"should contain only roles with side 'villagers' when called.\", () => {\n expect(VILLAGER_ROLES.length).toBeGreaterThan(0);\n expect(VILLAGER_ROLES.every(role => role.side === \"villagers\")).toBe(true);\n });\n });\n\n describe(\"roles\", () => {\n it(\"should contain all roles when called.\", () => {\n expect(ROLES).toStrictEqual([...WEREWOLF_ROLES, ...VILLAGER_ROLES] as Role[]);\n });\n });\n});" }, "tests/e2e/specs/modules/role/controllers/role.controller.e2e-spec.ts": { "tests": [ @@ -202288,7 +202290,7 @@ } } ], - "source": "import { BadGamePlayPayloadReasons } from \"@/shared/exception/enums/bad-game-play-payload-error.enum\";\nimport { BadGamePlayPayloadException } from \"@/shared/exception/types/bad-game-play-payload-exception.types\";\n\nimport type { ExceptionResponse } from \"@tests/types/exception/exception.types\";\n\ndescribe(\"Bad game play payload exception type\", () => {\n describe(\"getResponse\", () => {\n it(\"should get response when called.\", () => {\n const exception = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.TOO_MUCH_TARGETS);\n\n expect(exception.getResponse()).toStrictEqual({\n statusCode: 400,\n message: `Bad game play payload`,\n error: `There are too much targets for this current game's state`,\n });\n });\n });\n});" + "source": "import { BadGamePlayPayloadReasons } from \"@/shared/exception/enums/bad-game-play-payload-error.enums\";\nimport { BadGamePlayPayloadException } from \"@/shared/exception/types/bad-game-play-payload-exception.types\";\n\nimport type { ExceptionResponse } from \"@tests/types/exception/exception.types\";\n\ndescribe(\"Bad game play payload exception type\", () => {\n describe(\"getResponse\", () => {\n it(\"should get response when called.\", () => {\n const exception = new BadGamePlayPayloadException(BadGamePlayPayloadReasons.TOO_MUCH_TARGETS);\n\n expect(exception.getResponse()).toStrictEqual({\n statusCode: 400,\n message: `Bad game play payload`,\n error: `There are too much targets for this current game's state`,\n });\n });\n });\n});" }, "tests/unit/specs/shared/mongoose/mongoose.helpers.spec.ts": { "tests": [ diff --git a/tests/unit/specs/modules/game/dto/base/decorators/additional-cards/additional-cards-for-actor-size.decorator.spec.ts b/tests/unit/specs/modules/game/dto/base/decorators/additional-cards/additional-cards-for-actor-size.decorator.spec.ts index 5baa5c572..d584238a4 100644 --- a/tests/unit/specs/modules/game/dto/base/decorators/additional-cards/additional-cards-for-actor-size.decorator.spec.ts +++ b/tests/unit/specs/modules/game/dto/base/decorators/additional-cards/additional-cards-for-actor-size.decorator.spec.ts @@ -1,3 +1,5 @@ +import type { ValidationArguments } from "class-validator"; + import { getAdditionalCardsForActorSizeDefaultMessage, isAdditionalCardsForActorSizeRespected } from "@/modules/game/dto/base/decorators/additional-cards/additional-cards-for-actor-size.decorator"; import type { CreateGameAdditionalCardDto } from "@/modules/game/dto/create-game/create-game-additional-card/create-game-additional-card.dto"; import type { CreateGameDto } from "@/modules/game/dto/create-game/create-game.dto"; @@ -5,7 +7,6 @@ import type { CreateGameDto } from "@/modules/game/dto/create-game/create-game.d import { createFakeCreateGameAdditionalCardDto } from "@tests/factories/game/dto/create-game/create-game-additional-card/create-game-additional-card.dto.factory"; import { createFakeCreateGamePlayerDto } from "@tests/factories/game/dto/create-game/create-game-player/create-game-player.dto.factory"; import { createFakeCreateGameDto } from "@tests/factories/game/dto/create-game/create-game.dto.factory"; -import type { ValidationArguments } from "class-validator"; describe("Additional Cards For Actor Size Decorator", () => { describe("isAdditionalCardsForActorSizeRespected", () => { diff --git a/tests/unit/specs/modules/game/dto/base/decorators/additional-cards/additional-cards-for-thief-size.decorator.spec.ts b/tests/unit/specs/modules/game/dto/base/decorators/additional-cards/additional-cards-for-thief-size.decorator.spec.ts index c9b382361..c2f540b70 100644 --- a/tests/unit/specs/modules/game/dto/base/decorators/additional-cards/additional-cards-for-thief-size.decorator.spec.ts +++ b/tests/unit/specs/modules/game/dto/base/decorators/additional-cards/additional-cards-for-thief-size.decorator.spec.ts @@ -1,3 +1,5 @@ +import type { ValidationArguments } from "class-validator"; + import { getAdditionalCardsForThiefSizeDefaultMessage, isAdditionalCardsForThiefSizeRespected } from "@/modules/game/dto/base/decorators/additional-cards/additional-cards-for-thief-size.decorator"; import type { CreateGameAdditionalCardDto } from "@/modules/game/dto/create-game/create-game-additional-card/create-game-additional-card.dto"; import type { CreateGameDto } from "@/modules/game/dto/create-game/create-game.dto"; @@ -5,7 +7,6 @@ import type { CreateGameDto } from "@/modules/game/dto/create-game/create-game.d import { createFakeCreateGameAdditionalCardDto } from "@tests/factories/game/dto/create-game/create-game-additional-card/create-game-additional-card.dto.factory"; import { createFakeCreateGamePlayerDto } from "@tests/factories/game/dto/create-game/create-game-player/create-game-player.dto.factory"; import { createFakeCreateGameDto } from "@tests/factories/game/dto/create-game/create-game.dto.factory"; -import type { ValidationArguments } from "class-validator"; describe("Additional Cards For Thief Size Decorator", () => { describe("isAdditionalCardsForThiefSizeRespected", () => { diff --git a/tests/unit/specs/modules/game/dto/base/decorators/composition/composition-has-two-groups-with-prejudiced-manipulator.decorator.spec.ts b/tests/unit/specs/modules/game/dto/base/decorators/composition/composition-has-two-groups-with-prejudiced-manipulator.decorator.spec.ts index 5fae4e7a9..6965f8fe8 100644 --- a/tests/unit/specs/modules/game/dto/base/decorators/composition/composition-has-two-groups-with-prejudiced-manipulator.decorator.spec.ts +++ b/tests/unit/specs/modules/game/dto/base/decorators/composition/composition-has-two-groups-with-prejudiced-manipulator.decorator.spec.ts @@ -82,6 +82,7 @@ describe("Composition Has Two Groups With Prejudiced Manipulator Decorator", () describe("getCompositionHasTwoGroupsWithPrejudicedManipulatorDefaultMessage", () => { it("should return the default message when called.", () => { const expectedMessage = "there must be exactly two groups among players when `prejudiced-manipulator` in the game"; + expect(getCompositionHasTwoGroupsWithPrejudicedManipulatorDefaultMessage()).toBe(expectedMessage); }); }); diff --git a/tests/unit/specs/modules/game/dto/make-game-play/make-game-play-target/make-game-play-with-relations.dto.spec.ts b/tests/unit/specs/modules/game/dto/make-game-play/make-game-play-target/make-game-play-with-relations.dto.spec.ts index 7844d08c8..31a02dca0 100644 --- a/tests/unit/specs/modules/game/dto/make-game-play/make-game-play-target/make-game-play-with-relations.dto.spec.ts +++ b/tests/unit/specs/modules/game/dto/make-game-play/make-game-play-target/make-game-play-with-relations.dto.spec.ts @@ -1,4 +1,5 @@ import { MakeGamePlayTargetWithRelationsDto } from "@/modules/game/dto/make-game-play/make-game-play-target/make-game-play-target-with-relations.dto"; + import { createFakePlayer } from "@tests/factories/game/schemas/player/player.schema.factory"; describe("Make Game Play With Relations Dto", () => { diff --git a/tests/unit/specs/modules/game/helpers/game-event/game-event.factory.spec.ts b/tests/unit/specs/modules/game/helpers/game-event/game-event.factory.spec.ts index 9fcb9fc8e..46653e60e 100644 --- a/tests/unit/specs/modules/game/helpers/game-event/game-event.factory.spec.ts +++ b/tests/unit/specs/modules/game/helpers/game-event/game-event.factory.spec.ts @@ -1,5 +1,6 @@ import { createGameEvent } from "@/modules/game/helpers/game-event/game-event.factory"; import type { GameEvent } from "@/modules/game/schemas/game-event/game-event.schema"; + import { createFakeGameEvent } from "@tests/factories/game/schemas/game-event/game-event.schema.factory"; import { createFakePlayer } from "@tests/factories/game/schemas/player/player.schema.factory"; diff --git a/tests/unit/specs/modules/game/helpers/game-feedback/game-feedback.factory.spec.ts b/tests/unit/specs/modules/game/helpers/game-feedback/game-feedback.factory.spec.ts index 3ebc8de2f..c33b0aba2 100644 --- a/tests/unit/specs/modules/game/helpers/game-feedback/game-feedback.factory.spec.ts +++ b/tests/unit/specs/modules/game/helpers/game-feedback/game-feedback.factory.spec.ts @@ -1,6 +1,7 @@ import { createGameFeedback, createGameFeedbackToInsert } from "@/modules/game/helpers/game-feedback/game-feedback.factory"; import type { GameFeedback } from "@/modules/game/schemas/game-feedback/game-feedback.schema"; import type { GameFeedbackToInsert } from "@/modules/game/types/game-feedback/game-feedback.types"; + import { createFakeGameFeedback, createFakeGameFeedbackToInsert } from "@tests/factories/game/schemas/game-feedback/game-feedback.factory"; import { createFakeObjectId } from "@tests/factories/shared/mongoose/mongoose.factory"; diff --git a/tests/unit/specs/modules/game/helpers/game-history-record/game-history-record-play/game-history-record-play-source/game-history-record-play-source.factory.spec.ts b/tests/unit/specs/modules/game/helpers/game-history-record/game-history-record-play/game-history-record-play-source/game-history-record-play-source.factory.spec.ts index 80a426ec4..2a068c08f 100644 --- a/tests/unit/specs/modules/game/helpers/game-history-record/game-history-record-play/game-history-record-play-source/game-history-record-play-source.factory.spec.ts +++ b/tests/unit/specs/modules/game/helpers/game-history-record/game-history-record-play/game-history-record-play-source/game-history-record-play-source.factory.spec.ts @@ -1,5 +1,6 @@ import { createGameHistoryRecordPlaySource } from "@/modules/game/helpers/game-history-record/game-history-record-play/game-history-record-play-source/game-history-record-play-source.factory"; import type { GameHistoryRecordPlaySource } from "@/modules/game/schemas/game-history-record/game-history-record-play/game-history-record-play-source/game-history-record-play-source.schema"; + import { createFakeGameHistoryRecordPlaySource } from "@tests/factories/game/schemas/game-history-record/game-history-record.schema.factory"; import { createFakePlayer } from "@tests/factories/game/schemas/player/player.schema.factory"; diff --git a/tests/unit/specs/modules/game/helpers/game-history-record/game-history-record-play/game-history-record-play-voting/game-history-record-play-voting.factory.spec.ts b/tests/unit/specs/modules/game/helpers/game-history-record/game-history-record-play/game-history-record-play-voting/game-history-record-play-voting.factory.spec.ts index 80e17d46e..c0de34ec1 100644 --- a/tests/unit/specs/modules/game/helpers/game-history-record/game-history-record-play/game-history-record-play-voting/game-history-record-play-voting.factory.spec.ts +++ b/tests/unit/specs/modules/game/helpers/game-history-record/game-history-record-play/game-history-record-play-voting/game-history-record-play-voting.factory.spec.ts @@ -1,5 +1,6 @@ import { createGameHistoryRecordPlayVoting } from "@/modules/game/helpers/game-history-record/game-history-record-play/game-history-record-play-voting/game-history-record-play-voting.factory"; import type { GameHistoryRecordPlayVoting } from "@/modules/game/schemas/game-history-record/game-history-record-play/game-history-record-play-voting/game-history-record-play-voting.schema"; + import { createFakeGameHistoryRecordPlayVoting } from "@tests/factories/game/schemas/game-history-record/game-history-record.schema.factory"; import { createFakePlayer } from "@tests/factories/game/schemas/player/player.schema.factory"; diff --git a/tests/unit/specs/modules/game/helpers/game-history-record/game-history-record-play/game-history-record-play.factory.spec.ts b/tests/unit/specs/modules/game/helpers/game-history-record/game-history-record-play/game-history-record-play.factory.spec.ts index 99ac4ad15..d47f959ee 100644 --- a/tests/unit/specs/modules/game/helpers/game-history-record/game-history-record-play/game-history-record-play.factory.spec.ts +++ b/tests/unit/specs/modules/game/helpers/game-history-record/game-history-record-play/game-history-record-play.factory.spec.ts @@ -1,5 +1,6 @@ import { createGameHistoryRecordPlay } from "@/modules/game/helpers/game-history-record/game-history-record-play/game-history-record-play.factory"; import type { GameHistoryRecordPlay } from "@/modules/game/schemas/game-history-record/game-history-record-play/game-history-record-play.schema"; + import { createFakeGameHistoryRecordPlay, createFakeGameHistoryRecordPlaySource, createFakeGameHistoryRecordPlayTarget } from "@tests/factories/game/schemas/game-history-record/game-history-record.schema.factory"; describe("Game History Record Play Factory", () => { diff --git a/tests/unit/specs/modules/game/helpers/game-history-record/game-history-record-player-attribute-alteration/game-history-record-player-attribute-alteration.factory.spec.ts b/tests/unit/specs/modules/game/helpers/game-history-record/game-history-record-player-attribute-alteration/game-history-record-player-attribute-alteration.factory.spec.ts index b25c64f9f..e755e8b49 100644 --- a/tests/unit/specs/modules/game/helpers/game-history-record/game-history-record-player-attribute-alteration/game-history-record-player-attribute-alteration.factory.spec.ts +++ b/tests/unit/specs/modules/game/helpers/game-history-record/game-history-record-player-attribute-alteration/game-history-record-player-attribute-alteration.factory.spec.ts @@ -1,5 +1,6 @@ import { createGameHistoryRecordPlayerAttributeAlteration } from "@/modules/game/helpers/game-history-record/game-history-record-player-attribute-alteration/game-history-record-player-attribute-alteration.factory"; import type { GameHistoryRecordPlayerAttributeAlteration } from "@/modules/game/schemas/game-history-record/game-history-record-player-attribute-alteration/game-history-record-player-attribute-alteration.schema"; + import { createFakeGameHistoryRecordPlayerAttributeAlteration } from "@tests/factories/game/schemas/game-history-record/game-history-record.schema.factory"; describe("Game History Record Player Attribute Alteration Factory", () => { diff --git a/tests/unit/specs/modules/game/helpers/game-history-record/game-history-record.factory.spec.ts b/tests/unit/specs/modules/game/helpers/game-history-record/game-history-record.factory.spec.ts index 681c31830..27112bb27 100644 --- a/tests/unit/specs/modules/game/helpers/game-history-record/game-history-record.factory.spec.ts +++ b/tests/unit/specs/modules/game/helpers/game-history-record/game-history-record.factory.spec.ts @@ -1,5 +1,6 @@ import { createGameHistoryRecordToInsert } from "@/modules/game/helpers/game-history-record/game-history-record.factory"; import type { GameHistoryRecordToInsert } from "@/modules/game/types/game-history-record/game-history-record.types"; + import { createFakeGameHistoryRecordPlay, createFakeGameHistoryRecordPlayerAttributeAlteration } from "@tests/factories/game/schemas/game-history-record/game-history-record.schema.factory"; import { createFakeGamePhase } from "@tests/factories/game/schemas/game-phase/game-phase.schema.factory"; import { createFakePlayer } from "@tests/factories/game/schemas/player/player.schema.factory"; diff --git a/tests/unit/specs/modules/game/helpers/game-history-record/game-history-record.helpers.spec.ts b/tests/unit/specs/modules/game/helpers/game-history-record/game-history-record.helpers.spec.ts index c2ab41b5d..13bd3aa42 100644 --- a/tests/unit/specs/modules/game/helpers/game-history-record/game-history-record.helpers.spec.ts +++ b/tests/unit/specs/modules/game/helpers/game-history-record/game-history-record.helpers.spec.ts @@ -3,6 +3,7 @@ import type { GameHistoryRecord } from "@/modules/game/schemas/game-history-reco import type { GameHistoryRecordPlayerAttributeAlterationStatus } from "@/modules/game/types/game-history-record/game-history-record.types"; import type { GameSource } from "@/modules/game/types/game.types"; import type { PlayerAttributeName } from "@/modules/game/types/player/player-attribute/player-attribute.types"; + import { createFakeGameHistoryRecord, createFakeGameHistoryRecordPlayerAttributeAlteration } from "@tests/factories/game/schemas/game-history-record/game-history-record.schema.factory"; describe("Game History Record Helpers", () => { diff --git a/tests/unit/specs/modules/game/helpers/game-phase/game-phase.helpers.spec.ts b/tests/unit/specs/modules/game/helpers/game-phase/game-phase.helpers.spec.ts index 8191c82b4..70f572dc2 100644 --- a/tests/unit/specs/modules/game/helpers/game-phase/game-phase.helpers.spec.ts +++ b/tests/unit/specs/modules/game/helpers/game-phase/game-phase.helpers.spec.ts @@ -1,6 +1,6 @@ import { isGamePhaseOver, isInNightOrTwilightPhase } from "@/modules/game/helpers/game-phase/game-phase.helpers"; -import { createFakeGamePhase } from "@tests/factories/game/schemas/game-phase/game-phase.schema.factory"; +import { createFakeGamePhase } from "@tests/factories/game/schemas/game-phase/game-phase.schema.factory"; import { createFakeGame, createFakeGameWithCurrentPlay } from "@tests/factories/game/schemas/game.schema.factory"; describe("Game Phase Helper", () => { diff --git a/tests/unit/specs/modules/game/helpers/game-play/game-play.helpers.spec.ts b/tests/unit/specs/modules/game/helpers/game-play/game-play.helpers.spec.ts index e3579e17c..0cf6541c5 100644 --- a/tests/unit/specs/modules/game/helpers/game-play/game-play.helpers.spec.ts +++ b/tests/unit/specs/modules/game/helpers/game-play/game-play.helpers.spec.ts @@ -12,7 +12,7 @@ import type { GameWithCurrentPlay } from "@/modules/game/types/game-with-current import type { PlayerInteractionType } from "@/modules/game/types/player/player-interaction/player-interaction.types"; import { ApiResources } from "@/shared/api/enums/api.enums"; -import { ResourceNotFoundReasons } from "@/shared/exception/enums/resource-not-found-error.enum"; +import { ResourceNotFoundReasons } from "@/shared/exception/enums/resource-not-found-error.enums"; import { ResourceNotFoundException } from "@/shared/exception/types/resource-not-found-exception.types"; import { createFakeMakeGamePlayTargetWithRelationsDto } from "@tests/factories/game/dto/make-game-play/make-game-play-with-relations/make-game-play-target-with-relations.dto.factory"; diff --git a/tests/unit/specs/modules/game/helpers/game.factory.spec.ts b/tests/unit/specs/modules/game/helpers/game.factory.spec.ts index 61537e761..9d41e04d5 100644 --- a/tests/unit/specs/modules/game/helpers/game.factory.spec.ts +++ b/tests/unit/specs/modules/game/helpers/game.factory.spec.ts @@ -1,7 +1,7 @@ import { createGame } from "@/modules/game/helpers/game.factory"; import type { Game } from "@/modules/game/schemas/game.schema"; -import { createFakeGameEvent } from "@tests/factories/game/schemas/game-event/game-event.schema.factory"; +import { createFakeGameEvent } from "@tests/factories/game/schemas/game-event/game-event.schema.factory"; import { createFakeGameOptions } from "@tests/factories/game/schemas/game-options/game-options.schema.factory"; import { createFakeGamePhase } from "@tests/factories/game/schemas/game-phase/game-phase.schema.factory"; import { createFakeGamePlaySurvivorsElectSheriff, createFakeGamePlaySurvivorsVote } from "@tests/factories/game/schemas/game-play/game-play.schema.factory"; diff --git a/tests/unit/specs/modules/game/helpers/game.helpers.spec.ts b/tests/unit/specs/modules/game/helpers/game.helpers.spec.ts index 47e4f5cf1..d27ba8873 100644 --- a/tests/unit/specs/modules/game/helpers/game.helpers.spec.ts +++ b/tests/unit/specs/modules/game/helpers/game.helpers.spec.ts @@ -1,6 +1,6 @@ -import { DEFAULT_GAME_OPTIONS } from "@/modules/game/constants/game-options/game-options.constants"; import type { Types } from "mongoose"; +import { DEFAULT_GAME_OPTIONS } from "@/modules/game/constants/game-options/game-options.constants"; import type { CreateGamePlayerDto } from "@/modules/game/dto/create-game/create-game-player/create-game-player.dto"; import { areAllPlayersDead, areAllVillagersAlive, areAllWerewolvesAlive, doesGameHaveCurrentOrUpcomingPlaySourceAndAction, doesGameHaveUpcomingPlaySourceAndAction, getAdditionalCardWithId, getAlivePlayers, getAliveVillagerSidedPlayers, getAliveWerewolfSidedPlayers, getAllowedToVotePlayers, getDistinctPlayerGroups, getEligibleBigBadWolfTargets, getEligibleCupidTargets, getEligiblePiedPiperTargets, getEligibleWerewolvesTargets, getEligibleWhiteWerewolfTargets, getFoxSniffedPlayers, getGroupOfPlayers, getNearestAliveNeighbor, getNonexistentPlayer, getNonexistentPlayerId, getPlayerDtoWithRole, getPlayersWithActiveAttributeName, getPlayersWithCurrentRole, getPlayersWithCurrentSide, getPlayersWithIds, getPlayerWithActiveAttributeName, getPlayerWithCurrentRole, getPlayerWithId, getPlayerWithIdOrThrow, getPlayerWithName, getPlayerWithNameOrThrow, isGameSourceGroup, isGameSourceRole } from "@/modules/game/helpers/game.helpers"; import type { GameAdditionalCard } from "@/modules/game/schemas/game-additional-card/game-additional-card.schema"; @@ -11,7 +11,7 @@ import type { GetNearestPlayerOptions } from "@/modules/game/types/game.types"; import type { PlayerGroup } from "@/modules/game/types/player/player.types"; import type { RoleName } from "@/modules/role/types/role.types"; -import { UnexpectedExceptionReasons } from "@/shared/exception/enums/unexpected-exception.enum"; +import { UnexpectedExceptionReasons } from "@/shared/exception/enums/unexpected-exception.enums"; import type { ExceptionInterpolations } from "@/shared/exception/types/exception.types"; import { UnexpectedException } from "@/shared/exception/types/unexpected-exception.types"; diff --git a/tests/unit/specs/modules/game/providers/services/game-event/game-events-generator.service.spec.ts b/tests/unit/specs/modules/game/providers/services/game-event/game-events-generator.service.spec.ts index df001736a..4275056f5 100644 --- a/tests/unit/specs/modules/game/providers/services/game-event/game-events-generator.service.spec.ts +++ b/tests/unit/specs/modules/game/providers/services/game-event/game-events-generator.service.spec.ts @@ -1,8 +1,10 @@ +import type { TestingModule } from "@nestjs/testing"; +import { Test } from "@nestjs/testing"; + import { DEFAULT_GAME_OPTIONS } from "@/modules/game/constants/game-options/game-options.constants"; import { GameEventsGeneratorService } from "@/modules/game/providers/services/game-event/game-events-generator.service"; import type { GameEvent } from "@/modules/game/schemas/game-event/game-event.schema"; -import type { TestingModule } from "@nestjs/testing"; -import { Test } from "@nestjs/testing"; + import { createFakeGameEvent } from "@tests/factories/game/schemas/game-event/game-event.schema.factory"; import { createFakeGameHistoryRecord, createFakeGameHistoryRecordPlay, createFakeGameHistoryRecordPlayerAttributeAlteration, createFakeGameHistoryRecordPlaySource, createFakeGameHistoryRecordPlayTarget } from "@tests/factories/game/schemas/game-history-record/game-history-record.schema.factory"; import { createFakeGamePhase } from "@tests/factories/game/schemas/game-phase/game-phase.schema.factory"; diff --git a/tests/unit/specs/modules/game/providers/services/game-feedback/game-feedback.service.spec.ts b/tests/unit/specs/modules/game/providers/services/game-feedback/game-feedback.service.spec.ts index 270700fda..80f02bcec 100644 --- a/tests/unit/specs/modules/game/providers/services/game-feedback/game-feedback.service.spec.ts +++ b/tests/unit/specs/modules/game/providers/services/game-feedback/game-feedback.service.spec.ts @@ -1,10 +1,13 @@ +import type { TestingModule } from "@nestjs/testing"; +import { Test } from "@nestjs/testing"; + import { GameFeedbackRepository } from "@/modules/game/providers/repositories/game-feedback/game-feedback.repository"; import { GameFeedbackService } from "@/modules/game/providers/services/game-feedback/game-feedback.service"; + import { ApiResources } from "@/shared/api/enums/api.enums"; -import { BadResourceMutationReasons } from "@/shared/exception/enums/bad-resource-mutation-error.enum"; +import { BadResourceMutationReasons } from "@/shared/exception/enums/bad-resource-mutation-error.enums"; import { BadResourceMutationException } from "@/shared/exception/types/bad-resource-mutation-exception.types"; -import type { TestingModule } from "@nestjs/testing"; -import { Test } from "@nestjs/testing"; + import { createFakeCreateGameFeedbackDto } from "@tests/factories/game/dto/create-game-feedback/create-game-feedback.dto.factory"; import { createFakeGameFeedback, createFakeGameFeedbackToInsert } from "@tests/factories/game/schemas/game-feedback/game-feedback.factory"; import { createFakeGame } from "@tests/factories/game/schemas/game.schema.factory"; diff --git a/tests/unit/specs/modules/game/providers/services/game-history/game-history-record-to-insert-generator.service.spec.ts b/tests/unit/specs/modules/game/providers/services/game-history/game-history-record-to-insert-generator.service.spec.ts index a62bc23e0..bbc360fa3 100644 --- a/tests/unit/specs/modules/game/providers/services/game-history/game-history-record-to-insert-generator.service.spec.ts +++ b/tests/unit/specs/modules/game/providers/services/game-history/game-history-record-to-insert-generator.service.spec.ts @@ -1,3 +1,6 @@ +import type { TestingModule } from "@nestjs/testing"; +import { Test } from "@nestjs/testing"; + import type { MakeGamePlayTargetWithRelationsDto } from "@/modules/game/dto/make-game-play/make-game-play-target/make-game-play-target-with-relations.dto"; import { createGamePlaySurvivorsElectSheriff } from "@/modules/game/helpers/game-play/game-play.factory"; import { GameHistoryRecordToInsertGeneratorService } from "@/modules/game/providers/services/game-history/game-history-record-to-insert-generator.service"; @@ -8,9 +11,9 @@ import type { GameHistoryRecordPlay } from "@/modules/game/schemas/game-history- import type { GameHistoryRecordPlayerAttributeAlteration } from "@/modules/game/schemas/game-history-record/game-history-record-player-attribute-alteration/game-history-record-player-attribute-alteration.schema"; import type { Player } from "@/modules/game/schemas/player/player.schema"; import type { GameHistoryRecordToInsert } from "@/modules/game/types/game-history-record/game-history-record.types"; + import * as UnexpectedExceptionFactory from "@/shared/exception/helpers/unexpected-exception.factory"; -import type { TestingModule } from "@nestjs/testing"; -import { Test } from "@nestjs/testing"; + import { createFakeMakeGamePlayTargetWithRelationsDto } from "@tests/factories/game/dto/make-game-play/make-game-play-with-relations/make-game-play-target-with-relations.dto.factory"; import { createFakeMakeGamePlayWithRelationsDto } from "@tests/factories/game/dto/make-game-play/make-game-play-with-relations/make-game-play-with-relations.dto.factory"; import { createFakeGameAdditionalCard } from "@tests/factories/game/schemas/game-additional-card/game-additional-card.schema.factory"; diff --git a/tests/unit/specs/modules/game/providers/services/game-history/game-history-record.service.spec.ts b/tests/unit/specs/modules/game/providers/services/game-history/game-history-record.service.spec.ts index f2a424c1d..353835a6a 100644 --- a/tests/unit/specs/modules/game/providers/services/game-history/game-history-record.service.spec.ts +++ b/tests/unit/specs/modules/game/providers/services/game-history/game-history-record.service.spec.ts @@ -1,3 +1,7 @@ +import type { TestingModule } from "@nestjs/testing"; +import { Test } from "@nestjs/testing"; +import { when } from "jest-when"; + import { GameHistoryRecordRepository } from "@/modules/game/providers/repositories/game-history-record/game-history-record.repository"; import { GameRepository } from "@/modules/game/providers/repositories/game.repository"; import { GameHistoryRecordService } from "@/modules/game/providers/services/game-history/game-history-record.service"; @@ -6,10 +10,8 @@ import type { DeadPlayer } from "@/modules/game/schemas/player/dead-player.schem import type { GameHistoryRecordToInsert } from "@/modules/game/types/game-history-record/game-history-record.types"; import { ApiResources } from "@/shared/api/enums/api.enums"; -import { ResourceNotFoundReasons } from "@/shared/exception/enums/resource-not-found-error.enum"; +import { ResourceNotFoundReasons } from "@/shared/exception/enums/resource-not-found-error.enums"; import { ResourceNotFoundException } from "@/shared/exception/types/resource-not-found-exception.types"; -import type { TestingModule } from "@nestjs/testing"; -import { Test } from "@nestjs/testing"; import { createFakeGetGameHistoryDto } from "@tests/factories/game/dto/get-game-history/get-game-history.dto.factory"; import { createFakeGameAdditionalCard } from "@tests/factories/game/schemas/game-additional-card/game-additional-card.schema.factory"; @@ -20,7 +22,6 @@ import { createFakeVillagerAlivePlayer, createFakeWerewolfAlivePlayer } from "@t import { createFakeDeadPlayer, createFakePlayer } from "@tests/factories/game/schemas/player/player.schema.factory"; import { createFakeGameHistoryRecordToInsert } from "@tests/factories/game/types/game-history-record/game-history-record.type.factory"; import { createFakeObjectId } from "@tests/factories/shared/mongoose/mongoose.factory"; -import { when } from "jest-when"; describe("Game History Record Service", () => { let mocks: { diff --git a/tests/unit/specs/modules/game/providers/services/game-play/game-play-augmenter.service.spec.ts b/tests/unit/specs/modules/game/providers/services/game-play/game-play-augmenter.service.spec.ts index 3b0d13841..2b501b49d 100644 --- a/tests/unit/specs/modules/game/providers/services/game-play/game-play-augmenter.service.spec.ts +++ b/tests/unit/specs/modules/game/providers/services/game-play/game-play-augmenter.service.spec.ts @@ -1,7 +1,7 @@ -import { DEFAULT_GAME_OPTIONS } from "@/modules/game/constants/game-options/game-options.constants"; import type { TestingModule } from "@nestjs/testing"; import { Test } from "@nestjs/testing"; +import { DEFAULT_GAME_OPTIONS } from "@/modules/game/constants/game-options/game-options.constants"; import * as GameHelper from "@/modules/game/helpers/game.helpers"; import { GameHistoryRecordService } from "@/modules/game/providers/services/game-history/game-history-record.service"; import { GamePlayAugmenterService } from "@/modules/game/providers/services/game-play/game-play-augmenter.service"; @@ -10,7 +10,7 @@ import type { GamePlay } from "@/modules/game/schemas/game-play/game-play.schema import type { Game } from "@/modules/game/schemas/game.schema"; import type { Player } from "@/modules/game/schemas/player/player.schema"; -import { UnexpectedExceptionReasons } from "@/shared/exception/enums/unexpected-exception.enum"; +import { UnexpectedExceptionReasons } from "@/shared/exception/enums/unexpected-exception.enums"; import * as UnexpectedExceptionFactory from "@/shared/exception/helpers/unexpected-exception.factory"; import { UnexpectedException } from "@/shared/exception/types/unexpected-exception.types"; diff --git a/tests/unit/specs/modules/game/providers/services/game-play/game-play-maker/game-play-maker.service.spec.ts b/tests/unit/specs/modules/game/providers/services/game-play/game-play-maker/game-play-maker.service.spec.ts index 6b11c7382..59b1248ff 100644 --- a/tests/unit/specs/modules/game/providers/services/game-play/game-play-maker/game-play-maker.service.spec.ts +++ b/tests/unit/specs/modules/game/providers/services/game-play/game-play-maker/game-play-maker.service.spec.ts @@ -13,7 +13,7 @@ import { PlayerKillerService } from "@/modules/game/providers/services/player/pl import type { Game } from "@/modules/game/schemas/game.schema"; import type { DeadPlayer } from "@/modules/game/schemas/player/dead-player.schema"; -import { UnexpectedExceptionReasons } from "@/shared/exception/enums/unexpected-exception.enum"; +import { UnexpectedExceptionReasons } from "@/shared/exception/enums/unexpected-exception.enums"; import * as UnexpectedExceptionFactory from "@/shared/exception/helpers/unexpected-exception.factory"; import { UnexpectedException } from "@/shared/exception/types/unexpected-exception.types"; diff --git a/tests/unit/specs/modules/game/providers/services/game-play/game-play-validator.service.spec.ts b/tests/unit/specs/modules/game/providers/services/game-play/game-play-validator.service.spec.ts index a3c52a586..d2995e49e 100644 --- a/tests/unit/specs/modules/game/providers/services/game-play/game-play-validator.service.spec.ts +++ b/tests/unit/specs/modules/game/providers/services/game-play/game-play-validator.service.spec.ts @@ -1,15 +1,15 @@ -import { GameHistoryRecordRepository } from "@/modules/game/providers/repositories/game-history-record/game-history-record.repository"; import type { TestingModule } from "@nestjs/testing"; import { Test } from "@nestjs/testing"; import { when } from "jest-when"; +import { GameHistoryRecordRepository } from "@/modules/game/providers/repositories/game-history-record/game-history-record.repository"; import * as GamePlayHelper from "@/modules/game/helpers/game-play/game-play.helpers"; import { GameRepository } from "@/modules/game/providers/repositories/game.repository"; import { GameHistoryRecordService } from "@/modules/game/providers/services/game-history/game-history-record.service"; import { GamePlayValidatorService } from "@/modules/game/providers/services/game-play/game-play-validator.service"; -import { BadGamePlayPayloadReasons } from "@/shared/exception/enums/bad-game-play-payload-error.enum"; -import { UnexpectedExceptionReasons } from "@/shared/exception/enums/unexpected-exception.enum"; +import { BadGamePlayPayloadReasons } from "@/shared/exception/enums/bad-game-play-payload-error.enums"; +import { UnexpectedExceptionReasons } from "@/shared/exception/enums/unexpected-exception.enums"; import * as UnexpectedExceptionFactory from "@/shared/exception/helpers/unexpected-exception.factory"; import { BadGamePlayPayloadException } from "@/shared/exception/types/bad-game-play-payload-exception.types"; import { UnexpectedException } from "@/shared/exception/types/unexpected-exception.types"; diff --git a/tests/unit/specs/modules/game/providers/services/game-victory/game-victory.service.spec.ts b/tests/unit/specs/modules/game/providers/services/game-victory/game-victory.service.spec.ts index 6b693ffce..e507ced20 100644 --- a/tests/unit/specs/modules/game/providers/services/game-victory/game-victory.service.spec.ts +++ b/tests/unit/specs/modules/game/providers/services/game-victory/game-victory.service.spec.ts @@ -5,7 +5,7 @@ import { GameVictoryService } from "@/modules/game/providers/services/game-victo import type { GameVictory } from "@/modules/game/schemas/game-victory/game-victory.schema"; import type { Game } from "@/modules/game/schemas/game.schema"; -import { UnexpectedExceptionReasons } from "@/shared/exception/enums/unexpected-exception.enum"; +import { UnexpectedExceptionReasons } from "@/shared/exception/enums/unexpected-exception.enums"; import * as UnexpectedExceptionFactory from "@/shared/exception/helpers/unexpected-exception.factory"; import { UnexpectedException } from "@/shared/exception/types/unexpected-exception.types"; @@ -421,6 +421,7 @@ describe("Game Victory Service", () => { describe("doVillagersWin", () => { it("should return false when there are no players provided.", () => { const game = createFakeGame(); + expect(services.gameVictory["doVillagersWin"](game)).toBe(false); }); diff --git a/tests/unit/specs/modules/game/providers/services/game.service.spec.ts b/tests/unit/specs/modules/game/providers/services/game.service.spec.ts index 726bbeb02..e2b9f7cb6 100644 --- a/tests/unit/specs/modules/game/providers/services/game.service.spec.ts +++ b/tests/unit/specs/modules/game/providers/services/game.service.spec.ts @@ -1,10 +1,10 @@ +import type { TestingModule } from "@nestjs/testing"; +import { Test } from "@nestjs/testing"; + import { GameHistoryRecordRepository } from "@/modules/game/providers/repositories/game-history-record/game-history-record.repository"; import { GameEventsGeneratorService } from "@/modules/game/providers/services/game-event/game-events-generator.service"; import { GameFeedbackService } from "@/modules/game/providers/services/game-feedback/game-feedback.service"; import { GameHistoryRecordToInsertGeneratorService } from "@/modules/game/providers/services/game-history/game-history-record-to-insert-generator.service"; -import type { TestingModule } from "@nestjs/testing"; -import { Test } from "@nestjs/testing"; - import * as GamePhaseHelper from "@/modules/game/helpers/game-phase/game-phase.helpers"; import * as GamePlayHelper from "@/modules/game/helpers/game-play/game-play.helpers"; import { GameRepository } from "@/modules/game/providers/repositories/game.repository"; @@ -20,14 +20,14 @@ import { PlayerAttributeService } from "@/modules/game/providers/services/player import type { Game } from "@/modules/game/schemas/game.schema"; import { ApiResources } from "@/shared/api/enums/api.enums"; -import { BadResourceMutationReasons } from "@/shared/exception/enums/bad-resource-mutation-error.enum"; -import { UnexpectedExceptionReasons } from "@/shared/exception/enums/unexpected-exception.enum"; +import { BadResourceMutationReasons } from "@/shared/exception/enums/bad-resource-mutation-error.enums"; +import { UnexpectedExceptionReasons } from "@/shared/exception/enums/unexpected-exception.enums"; import { BadResourceMutationException } from "@/shared/exception/types/bad-resource-mutation-exception.types"; import { ResourceNotFoundException } from "@/shared/exception/types/resource-not-found-exception.types"; import { UnexpectedException } from "@/shared/exception/types/unexpected-exception.types"; + import { createFakeCreateGameFeedbackDto } from "@tests/factories/game/dto/create-game-feedback/create-game-feedback.dto.factory"; import { createFakeCreateGamePlayerDto } from "@tests/factories/game/dto/create-game/create-game-player/create-game-player.dto.factory"; - import { createFakeCreateGameDto } from "@tests/factories/game/dto/create-game/create-game.dto.factory"; import { createFakeMakeGamePlayWithRelationsDto } from "@tests/factories/game/dto/make-game-play/make-game-play-with-relations/make-game-play-with-relations.dto.factory"; import { createFakeMakeGamePlayDto } from "@tests/factories/game/dto/make-game-play/make-game-play.dto.factory"; diff --git a/tests/unit/specs/modules/game/providers/services/player/player-killer.service.spec.ts b/tests/unit/specs/modules/game/providers/services/player/player-killer.service.spec.ts index 8329e0569..17dc1346d 100644 --- a/tests/unit/specs/modules/game/providers/services/player/player-killer.service.spec.ts +++ b/tests/unit/specs/modules/game/providers/services/player/player-killer.service.spec.ts @@ -10,7 +10,7 @@ import type { PlayerDeath } from "@/modules/game/schemas/player/player-death/pla import type { Player } from "@/modules/game/schemas/player/player.schema"; import type { PlayerDeathCause } from "@/modules/game/types/player/player-death/player-death.types"; -import { UnexpectedExceptionReasons } from "@/shared/exception/enums/unexpected-exception.enum"; +import { UnexpectedExceptionReasons } from "@/shared/exception/enums/unexpected-exception.enums"; import * as UnexpectedExceptionFactory from "@/shared/exception/helpers/unexpected-exception.factory"; import { UnexpectedException } from "@/shared/exception/types/unexpected-exception.types"; @@ -160,6 +160,7 @@ describe("Player Killer Service", () => { mocks.playerKillerService.doesPlayerRoleMustBeRevealed.mockReturnValue(true); await services.playerKiller.killOrRevealPlayer(players[0]._id, game, death); + expect(mocks.playerKillerService.killPlayer).toHaveBeenCalledExactlyOnceWith(players[0], game, death); }); @@ -178,6 +179,7 @@ describe("Player Killer Service", () => { mocks.playerKillerService.doesPlayerRoleMustBeRevealed.mockReturnValue(true); await services.playerKiller.killOrRevealPlayer(players[0]._id, game, death); + expect(mocks.playerKillerService.killPlayer).not.toHaveBeenCalled(); expect(mocks.playerKillerService.revealPlayerRole).toHaveBeenCalledExactlyOnceWith(players[0], game); }); @@ -1576,6 +1578,7 @@ describe("Player Killer Service", () => { ]; const game = createFakeGame({ players }); services.playerKiller["applyPlayerRoleDeathOutcomes"](players[0] as DeadPlayer, game); + expect(mocks.playerKillerService.applyElderDeathOutcomes).toHaveBeenCalledExactlyOnceWith(players[0], game); expect(mocks.playerKillerService.applyHunterDeathOutcomes).not.toHaveBeenCalled(); expect(mocks.playerKillerService.applyScapegoatDeathOutcomes).not.toHaveBeenCalled(); diff --git a/tests/unit/specs/shared/exception/types/bad-game-play-payload-exception.types.spec.ts b/tests/unit/specs/shared/exception/types/bad-game-play-payload-exception.types.spec.ts index e0776a361..10ae4140e 100644 --- a/tests/unit/specs/shared/exception/types/bad-game-play-payload-exception.types.spec.ts +++ b/tests/unit/specs/shared/exception/types/bad-game-play-payload-exception.types.spec.ts @@ -1,4 +1,4 @@ -import { BadGamePlayPayloadReasons } from "@/shared/exception/enums/bad-game-play-payload-error.enum"; +import { BadGamePlayPayloadReasons } from "@/shared/exception/enums/bad-game-play-payload-error.enums"; import { BadGamePlayPayloadException } from "@/shared/exception/types/bad-game-play-payload-exception.types"; import type { ExceptionResponse } from "@tests/types/exception/exception.types"; diff --git a/tests/unit/specs/shared/exception/types/bad-resource-mutation-exception.types.spec.ts b/tests/unit/specs/shared/exception/types/bad-resource-mutation-exception.types.spec.ts index 4aa84d876..9cd5dd8f2 100644 --- a/tests/unit/specs/shared/exception/types/bad-resource-mutation-exception.types.spec.ts +++ b/tests/unit/specs/shared/exception/types/bad-resource-mutation-exception.types.spec.ts @@ -1,5 +1,5 @@ import { ApiResources } from "@/shared/api/enums/api.enums"; -import { BadResourceMutationReasons } from "@/shared/exception/enums/bad-resource-mutation-error.enum"; +import { BadResourceMutationReasons } from "@/shared/exception/enums/bad-resource-mutation-error.enums"; import { BadResourceMutationException } from "@/shared/exception/types/bad-resource-mutation-exception.types"; import type { ExceptionResponse } from "@tests/types/exception/exception.types"; diff --git a/tests/unit/specs/shared/exception/types/resource-not-found-exception.types.spec.ts b/tests/unit/specs/shared/exception/types/resource-not-found-exception.types.spec.ts index 0c600a48c..2e40c8fcf 100644 --- a/tests/unit/specs/shared/exception/types/resource-not-found-exception.types.spec.ts +++ b/tests/unit/specs/shared/exception/types/resource-not-found-exception.types.spec.ts @@ -1,5 +1,5 @@ import { ApiResources } from "@/shared/api/enums/api.enums"; -import { ResourceNotFoundReasons } from "@/shared/exception/enums/resource-not-found-error.enum"; +import { ResourceNotFoundReasons } from "@/shared/exception/enums/resource-not-found-error.enums"; import { ResourceNotFoundException } from "@/shared/exception/types/resource-not-found-exception.types"; import type { ExceptionResponse } from "@tests/types/exception/exception.types"; diff --git a/tests/unit/specs/shared/exception/types/unexpected-exception.types.spec.ts b/tests/unit/specs/shared/exception/types/unexpected-exception.types.spec.ts index c6d259668..81613353a 100644 --- a/tests/unit/specs/shared/exception/types/unexpected-exception.types.spec.ts +++ b/tests/unit/specs/shared/exception/types/unexpected-exception.types.spec.ts @@ -1,4 +1,4 @@ -import { UnexpectedExceptionReasons } from "@/shared/exception/enums/unexpected-exception.enum"; +import { UnexpectedExceptionReasons } from "@/shared/exception/enums/unexpected-exception.enums"; import { UnexpectedException } from "@/shared/exception/types/unexpected-exception.types"; import type { ExceptionResponse } from "@tests/types/exception/exception.types"; diff --git a/tests/unit/unit-setup.ts b/tests/unit/unit-setup.ts index 48d5e0799..eb6da9599 100644 --- a/tests/unit/unit-setup.ts +++ b/tests/unit/unit-setup.ts @@ -1 +1,2 @@ +// eslint-disable-next-line @typescript-eslint/no-restricted-imports, import/no-unassigned-import import "reflect-metadata"; \ No newline at end of file