diff --git a/test/abilities/imposter.test.ts b/test/abilities/imposter.test.ts index d58e6a4877a..ec1de8a4a1a 100644 --- a/test/abilities/imposter.test.ts +++ b/test/abilities/imposter.test.ts @@ -2,9 +2,8 @@ import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import Phaser from "phaser"; import GameManager from "#test/testUtils/gameManager"; import { SpeciesId } from "#enums/species-id"; -import { TurnEndPhase } from "#app/phases/turn-end-phase"; import { MoveId } from "#enums/move-id"; -import { Stat, BATTLE_STATS, EFFECTIVE_STATS } from "#enums/stat"; +import { Stat } from "#enums/stat"; import { AbilityId } from "#enums/ability-id"; // TODO: Add more tests once Imposter is fully implemented @@ -38,40 +37,24 @@ describe("Abilities - Imposter", () => { it("should copy species, ability, gender, all stats except HP, all stat stages, moveset, and types of target", async () => { await game.classicMode.startBattle([SpeciesId.DITTO]); - game.move.select(MoveId.SPLASH); - await game.phaseInterceptor.to(TurnEndPhase); - - const player = game.scene.getPlayerPokemon()!; - const enemy = game.scene.getEnemyPokemon()!; + const player = game.field.getPlayerPokemon(); + const enemy = game.field.getEnemyPokemon(); expect(player.getSpeciesForm().speciesId).toBe(enemy.getSpeciesForm().speciesId); expect(player.getAbility()).toBe(enemy.getAbility()); expect(player.getGender()).toBe(enemy.getGender()); - expect(player.getStat(Stat.HP, false)).not.toBe(enemy.getStat(Stat.HP)); - for (const s of EFFECTIVE_STATS) { - expect(player.getStat(s, false)).toBe(enemy.getStat(s, false)); - } + const playerStats = player.getStats(false); + const enemyStats = enemy.getStats(false); + // HP stays the same; all other stats should carry over + expect(playerStats[0]).not.toBe(enemyStats[0]); + expect(playerStats.slice(1)).toEqual(enemyStats.slice(1)); - for (const s of BATTLE_STATS) { - expect(player.getStatStage(s)).toBe(enemy.getStatStage(s)); - } + expect(player.getStatStages()).toEqual(enemy.getStatStages()); - const playerMoveset = player.getMoveset(); - const enemyMoveset = player.getMoveset(); + expect(player.getMoveset().map(m => m.moveId)).toEqual(player.getMoveset().map(m => m.moveId)); - expect(playerMoveset.length).toBe(enemyMoveset.length); - for (let i = 0; i < playerMoveset.length && i < enemyMoveset.length; i++) { - expect(playerMoveset[i]?.moveId).toBe(enemyMoveset[i]?.moveId); - } - - const playerTypes = player.getTypes(); - const enemyTypes = enemy.getTypes(); - - expect(playerTypes.length).toBe(enemyTypes.length); - for (let i = 0; i < playerTypes.length && i < enemyTypes.length; i++) { - expect(playerTypes[i]).toBe(enemyTypes[i]); - } + expect(player.getTypes()).toEqual(enemy.getTypes()); }); it("should copy in-battle overridden stats", async () => { @@ -80,33 +63,37 @@ describe("Abilities - Imposter", () => { const [karp, ditto] = game.scene.getPlayerParty(); const enemy = game.field.getEnemyPokemon(); - game.field.mockAbility(ditto, AbilityId.IMPOSTER); + const abMock = game.field.mockAbility(ditto, AbilityId.IMPOSTER); + + const oldAtk = karp.getStat(Stat.ATK); // Turn 1: Use power split - const avgAtk = Math.floor((karp.getStat(Stat.ATK, false) + enemy.getStat(Stat.ATK, false)) / 2); - const avgSpAtk = Math.floor((karp.getStat(Stat.SPATK, false) + enemy.getStat(Stat.SPATK, false)) / 2); - game.move.use(MoveId.SPLASH); await game.move.forceEnemyMove(MoveId.POWER_SPLIT); await game.toNextTurn(); - expect(enemy.getStat(Stat.ATK, false)).toBe(avgAtk); - expect(enemy.getStat(Stat.SPATK, false)).toBe(avgSpAtk); + const avgAtk = Math.floor((karp.getStat(Stat.ATK, false) + enemy.getStat(Stat.ATK, false)) / 2); - // Turn 2: Switch in ditto, should copy enemy stats + expect(enemy.getStat(Stat.ATK, false)).toBe(avgAtk); + expect(karp.getStat(Stat.ATK, false)).toBe(avgAtk); + expect(avgAtk).not.toBe(oldAtk); + + // Turn 2: Switch in ditto, should copy power split stats game.doSwitchPokemon(1); await game.move.forceEnemyMove(MoveId.SPLASH); - await game.toNextTurn(); + await game.phaseInterceptor.to("PokemonTransformPhase", false); + // reset ability mock after activating so Ditto doesn't keep on transforming into itself + abMock.mockRestore(); + await game.toEndOfTurn(); expect(ditto.getStat(Stat.ATK, false)).toBe(avgAtk); - expect(ditto.getStat(Stat.SPATK, false)).toBe(avgSpAtk); }); it("should set each move's pp to a maximum of 5", async () => { game.override.enemyMoveset([MoveId.SWORDS_DANCE, MoveId.GROWL, MoveId.SKETCH, MoveId.RECOVER]); - await game.classicMode.startBattle([SpeciesId.DITTO]); - const player = game.scene.getPlayerPokemon()!; + + const player = game.field.getPlayerPokemon(); player.getMoveset().forEach(move => { // Should set correct maximum PP without touching `ppUp` @@ -127,43 +114,41 @@ describe("Abilities - Imposter", () => { }); it("should persist transformed attributes across reloads", async () => { - game.override.moveset([MoveId.ABSORB]); - await game.classicMode.startBattle([SpeciesId.DITTO]); - const player = game.scene.getPlayerPokemon()!; - const enemy = game.scene.getEnemyPokemon()!; + const player = game.field.getPlayerPokemon(); + const enemy = game.field.getEnemyPokemon(); game.move.select(MoveId.SPLASH); await game.doKillOpponents(); await game.toNextWave(); - expect(game.scene.phaseManager.getCurrentPhase()?.constructor.name).toBe("CommandPhase"); + expect(game.scene.phaseManager.getCurrentPhase()?.phaseName).toBe("CommandPhase"); expect(game.scene.currentBattle.waveIndex).toBe(2); await game.reload.reloadSession(); - const playerReloaded = game.scene.getPlayerPokemon()!; - const playerMoveset = player.getMoveset(); + const playerReloaded = game.field.getPlayerPokemon(); - expect(playerReloaded.getSpeciesForm().speciesId).toBe(enemy.getSpeciesForm().speciesId); + expect(playerReloaded.getSpeciesForm().speciesId).toBe(SpeciesId.MEW); expect(playerReloaded.getAbility()).toBe(enemy.getAbility()); expect(playerReloaded.getGender()).toBe(enemy.getGender()); - expect(playerReloaded.getStat(Stat.HP, false)).not.toBe(enemy.getStat(Stat.HP)); - for (const s of EFFECTIVE_STATS) { - expect(playerReloaded.getStat(s, false)).toBe(enemy.getStat(s, false)); - } + const playerStats = player.getStats(false); + const playerReloadedStats = player.getStats(false); + // HP stays the same; all other stats should carry over + expect(playerReloadedStats).toEqual(playerStats); - expect(playerMoveset.length).toEqual(1); - expect(playerMoveset[0]?.moveId).toEqual(MoveId.SPLASH); + expect(playerReloaded.getMoveset()).toEqual(player.getMoveset()); }); + // TODO: This doesn't look as though it should work it("should stay transformed with the correct form after reload", async () => { - game.override.moveset([MoveId.ABSORB]).enemySpecies(SpeciesId.UNOWN); + game.override.enemySpecies(SpeciesId.UNOWN); await game.classicMode.startBattle([SpeciesId.DITTO]); - const enemy = game.scene.getEnemyPokemon()!; + const player = game.field.getPlayerPokemon(); + const enemy = game.field.getEnemyPokemon(); // change form enemy.species.forms[5]; @@ -176,11 +161,14 @@ describe("Abilities - Imposter", () => { expect(game.scene.phaseManager.getCurrentPhase()?.constructor.name).toBe("CommandPhase"); expect(game.scene.currentBattle.waveIndex).toBe(2); + expect(player.getSpeciesForm().speciesId).toBe(SpeciesId.UNOWN); + expect(player.getSpeciesForm().formIndex).toBe(5); + await game.reload.reloadSession(); - const playerReloaded = game.scene.getPlayerPokemon()!; + const playerReloaded = game.field.getPlayerPokemon(); - expect(playerReloaded.getSpeciesForm().speciesId).toBe(enemy.getSpeciesForm().speciesId); - expect(playerReloaded.getSpeciesForm().formIndex).toBe(enemy.getSpeciesForm().formIndex); + expect(playerReloaded.getSpeciesForm().speciesId).toBe(SpeciesId.UNOWN); + expect(playerReloaded.getSpeciesForm().formIndex).toBe(5); }); }); diff --git a/test/testUtils/helpers/field-helper.ts b/test/testUtils/helpers/field-helper.ts index 2866c01209f..25cdde08dbe 100644 --- a/test/testUtils/helpers/field-helper.ts +++ b/test/testUtils/helpers/field-helper.ts @@ -70,7 +70,7 @@ export class FieldHelper extends GameManagerHelper { * @see {@linkcode vi.spyOn} * @see https://vitest.dev/api/mock#mockreturnvalue */ - public mockAbility(pokemon: Pokemon, ability: AbilityId): MockInstance<(baseOnly?: boolean) => Ability> { + public mockAbility(pokemon: Pokemon, ability: AbilityId): MockInstance<(ignoreOverride?: boolean) => Ability> { return vi.spyOn(pokemon, "getAbility").mockReturnValue(allAbilities[ability]); }