From 4dda982ff68937247d01e51cf76d94d745f14cb0 Mon Sep 17 00:00:00 2001 From: Bertie690 Date: Sun, 3 Aug 2025 13:24:53 -0400 Subject: [PATCH] Finished up fixing up tidy up tests; removed matcher to go to its own PR --- src/data/moves/move.ts | 1 + test/@types/vitest.d.ts | 8 -- test/moves/tidy-up.test.ts | 84 +++++++++++-------- test/test-utils/matchers/to-have-arena-tag.ts | 54 ------------ 4 files changed, 48 insertions(+), 99 deletions(-) delete mode 100644 test/test-utils/matchers/to-have-arena-tag.ts diff --git a/src/data/moves/move.ts b/src/data/moves/move.ts index 5ba27c88013..24b263a2a24 100644 --- a/src/data/moves/move.ts +++ b/src/data/moves/move.ts @@ -6096,6 +6096,7 @@ export class AddArenaTrapTagAttr extends AddArenaTagAttr { * @extends AddArenaTagAttr * @see {@linkcode apply} */ +// TODO: This has exactly 1 line of code difference from the base attribute wrt. effect chances... export class AddArenaTrapTagHitAttr extends AddArenaTagAttr { /** * @param user {@linkcode Pokemon} using this move diff --git a/test/@types/vitest.d.ts b/test/@types/vitest.d.ts index ec4d39d7778..a692da5bd65 100644 --- a/test/@types/vitest.d.ts +++ b/test/@types/vitest.d.ts @@ -86,14 +86,6 @@ declare module "vitest" { */ toHaveTerrain(expectedTerrainType: TerrainType): void; - /** - * Matcher to check if the current {@linkcode Arena} contains the given {@linkcode ArenaTag}. - * - * @param expected - The expected {@linkcode ArenaTagType} - * @param options - The options passed to the matcher - */ - toHaveArenaTag(expected: T, options?: toHaveArenaTagOptions): void;v - /** * Check whether a {@linkcode Pokemon} is at full HP. */ diff --git a/test/moves/tidy-up.test.ts b/test/moves/tidy-up.test.ts index 05445ca132b..56c0f338565 100644 --- a/test/moves/tidy-up.test.ts +++ b/test/moves/tidy-up.test.ts @@ -1,12 +1,11 @@ -import { SubstituteTag } from "#data/battler-tags"; import { AbilityId } from "#enums/ability-id"; import { ArenaTagSide } from "#enums/arena-tag-side"; import { ArenaTagType } from "#enums/arena-tag-type"; +import { BattlerIndex } from "#enums/battler-index"; +import { BattlerTagType } from "#enums/battler-tag-type"; import { MoveId } from "#enums/move-id"; import { SpeciesId } from "#enums/species-id"; import { Stat } from "#enums/stat"; -import { MoveEndPhase } from "#phases/move-end-phase"; -import { TurnEndPhase } from "#phases/turn-end-phase"; import { GameManager } from "#test/test-utils/game-manager"; import type { ArenaTrapTagType } from "#types/arena-tags"; import Phaser from "phaser"; @@ -36,51 +35,62 @@ describe("Moves - Tidy Up", () => { .ability(AbilityId.BALL_FETCH); }); - it.each<{ name: string; hazard: ArenaTrapTagType }>([{ name: "Spikes", hazard: ArenaTagType.SPIKES }])( - "should remove $name from both sides of the field", - async ({ hazard }) => { - await game.classicMode.startBattle([SpeciesId.FEEBAS]); + it.each<{ name: string; tagType: ArenaTrapTagType }>([ + { name: "Spikes", tagType: ArenaTagType.SPIKES }, + { name: "Toxic Spikes", tagType: ArenaTagType.TOXIC_SPIKES }, + { name: "Stealth Rock", tagType: ArenaTagType.STEALTH_ROCK }, + { name: "Sticky Web", tagType: ArenaTagType.STICKY_WEB }, + ])("should remove $name from both sides of the field", async ({ tagType }) => { + await game.classicMode.startBattle([SpeciesId.FEEBAS]); - // Add tag to both sides of the field - game.scene.arena.addTag(hazard, 1, undefined, game.field.getPlayerPokemon().id, ArenaTagSide.PLAYER); - game.scene.arena.addTag(hazard, 1, undefined, game.field.getPlayerPokemon().id, ArenaTagSide.ENEMY); + // Add tag to both sides of the field + game.scene.arena.addTag(tagType, 1, undefined, game.field.getPlayerPokemon().id, ArenaTagSide.PLAYER); + game.scene.arena.addTag(tagType, 1, undefined, game.field.getPlayerPokemon().id, ArenaTagSide.ENEMY); - expect(game.scene.arena.getTag()); - game.move.use(MoveId.TIDY_UP); - await game.toEndOfTurn(); - expect(game.scene.arena.getTag(ArenaTagType.SPIKES)).toBeUndefined(); - }, - ); + expect(game.scene.arena.getTag(tagType)).toBeDefined(); - it("substitutes are cleared", async () => { - game.override.moveset([MoveId.SUBSTITUTE, MoveId.TIDY_UP]).enemyMoveset(MoveId.SUBSTITUTE); + game.move.use(MoveId.TIDY_UP); + await game.toEndOfTurn(); - await game.classicMode.startBattle(); + expect(game.scene.arena.getTag(tagType)).toBeUndefined(); + }); - game.move.select(MoveId.SUBSTITUTE); - await game.phaseInterceptor.to(TurnEndPhase); - game.move.select(MoveId.TIDY_UP); - await game.phaseInterceptor.to(MoveEndPhase); + it("should clear substitutes from all pokemon", async () => { + game.override.battleStyle("double"); + await game.classicMode.startBattle([SpeciesId.CINCCINO, SpeciesId.FEEBAS]); - const pokemon = [game.scene.getPlayerPokemon()!, game.scene.getEnemyPokemon()!]; - pokemon.forEach(p => { - expect(p).toBeDefined(); - expect(p!.getTag(SubstituteTag)).toBeUndefined(); + game.move.use(MoveId.SUBSTITUTE, BattlerIndex.PLAYER); + game.move.use(MoveId.SUBSTITUTE, BattlerIndex.PLAYER_2); + await game.move.forceEnemyMove(MoveId.SUBSTITUTE); + await game.move.forceEnemyMove(MoveId.SUBSTITUTE); + await game.toNextTurn(); + + game.scene.getField(true).forEach(p => { + expect(p).toHaveBattlerTag(BattlerTagType.SUBSTITUTE); + }); + + game.move.use(MoveId.TIDY_UP, BattlerIndex.PLAYER); + game.move.use(MoveId.SPLASH, BattlerIndex.PLAYER_2); + await game.move.forceEnemyMove(MoveId.SPLASH); + await game.move.forceEnemyMove(MoveId.SPLASH); + await game.toEndOfTurn(); + + game.scene.getField(true).forEach(p => { + expect(p).not.toHaveBattlerTag(BattlerTagType.SUBSTITUTE); }); }); - it("user's stats are raised with no traps set", async () => { - await game.classicMode.startBattle(); + it("should raise the user's stats even if a tag cannot be removed", async () => { + await game.classicMode.startBattle([SpeciesId.FEEBAS]); - const playerPokemon = game.scene.getPlayerPokemon()!; + const feebas = game.field.getPlayerPokemon(); + expect(feebas).toHaveStatStage(Stat.ATK, 0); + expect(feebas).toHaveStatStage(Stat.SPD, 0); - expect(playerPokemon.getStatStage(Stat.ATK)).toBe(0); - expect(playerPokemon.getStatStage(Stat.SPD)).toBe(0); + game.move.use(MoveId.TIDY_UP); + await game.toEndOfTurn(); - game.move.select(MoveId.TIDY_UP); - await game.phaseInterceptor.to(TurnEndPhase); - - expect(playerPokemon.getStatStage(Stat.ATK)).toBe(1); - expect(playerPokemon.getStatStage(Stat.SPD)).toBe(1); + expect(feebas).toHaveStatStage(Stat.ATK, 1); + expect(feebas).toHaveStatStage(Stat.SPD, 1); }); }); diff --git a/test/test-utils/matchers/to-have-arena-tag.ts b/test/test-utils/matchers/to-have-arena-tag.ts deleted file mode 100644 index cc2155ea3b1..00000000000 --- a/test/test-utils/matchers/to-have-arena-tag.ts +++ /dev/null @@ -1,54 +0,0 @@ -import type { ArenaTagSide } from "#enums/arena-tag-side"; -import { ArenaTagType } from "#enums/arena-tag-type"; -// biome-ignore lint/correctness/noUnusedImports: TSDoc -import type { GameManager } from "#test/test-utils/game-manager"; -import { getEnumStr, stringifyEnumArray } from "#test/test-utils/string-utils"; -import { isGameManagerInstance, receivedStr } from "#test/test-utils/test-utils"; -import type { MatcherState, SyncExpectationResult } from "@vitest/expect"; - -/** - * Matcher to check if the {@linkcode Arena} has a given {@linkcode ArenaTag} active. - * @param received - The object to check. Should be the current {@linkcode GameManager}. - * @param expectedType - The {@linkcode ArenaTagType} of the desired tag - * @param side - The {@linkcode ArenaTagSide | side of the field} the tag should affect, or - * {@linkcode ArenaTagSide.BOTH} to check both sides. - * @param options - The options passed to this matcher - * @returns The result of the matching - */ -export function toHaveArenaTag( - this: MatcherState, - received: unknown, - expectedType: ArenaTagType, - side: ArenaTagSide, -): SyncExpectationResult { - if (!isGameManagerInstance(received)) { - return { - pass: false, - message: () => `Expected to recieve a GameManager, but got ${receivedStr(received)}!`, - }; - } - - if (!received.scene?.arena) { - return { - pass: false, - message: () => `Expected GameManager.${received.scene ? "scene" : "scene.arena"} to be defined!`, - }; - } - - const tag = received.scene.arena.getTagOnSide(expectedType, side); - const pass = !!tag; - const expectedStr = getEnumStr(ArenaTagType, expectedType); - return { - pass, - message: () => - pass - ? `Expected the arena to NOT have a tag matching ${expectedStr}, but it did!` - : // Replace newlines with spaces to preserve one-line ness - `Expected the arena to have a tag matching ${expectedStr}, but it didn't!`, - expected: getEnumStr(ArenaTagType, expectedType), - actual: stringifyEnumArray( - ArenaTagType, - received.scene.arena.tags.map(t => t.tagType), - ), - }; -}