mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-08-11 01:49:29 +02:00
Added toHaveArenaTagMatcher
This commit is contained in:
parent
1b9e4e05ee
commit
808e29f55e
@ -847,23 +847,21 @@ export class Arena {
|
|||||||
side: ArenaTagSide,
|
side: ArenaTagSide,
|
||||||
quiet = false,
|
quiet = false,
|
||||||
): void {
|
): void {
|
||||||
const indicesToRemove: number[] = [];
|
const leftoverTags: ArenaTag[] = [];
|
||||||
for (const [i, tag] of this.tags.entries()) {
|
for (const tag of this.tags) {
|
||||||
// Skip tags of different types or on the wrong side of the field
|
// Skip tags of different types or on the wrong side of the field
|
||||||
if (!tagTypes.includes(tag.tagType)) {
|
if (
|
||||||
continue;
|
!tagTypes.includes(tag.tagType) ||
|
||||||
}
|
!(side === ArenaTagSide.BOTH || tag.side === ArenaTagSide.BOTH || tag.side === side)
|
||||||
if (!(side === ArenaTagSide.BOTH || tag.side === ArenaTagSide.BOTH || tag.side === side)) {
|
) {
|
||||||
|
leftoverTags.push(tag);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
indicesToRemove.push(i);
|
tag.onRemove(this, quiet);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const index of indicesToRemove) {
|
this.tags = leftoverTags;
|
||||||
this.tags[index].onRemove(this, quiet);
|
|
||||||
this.tags.splice(index, 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
removeAllTags(): void {
|
removeAllTags(): void {
|
||||||
|
12
test/@types/vitest.d.ts
vendored
12
test/@types/vitest.d.ts
vendored
@ -1,7 +1,11 @@
|
|||||||
import type { Pokemon } from "#field/pokemon";
|
import type { Pokemon } from "#field/pokemon";
|
||||||
import type { PokemonType } from "#enums/pokemon-type";
|
import type { PokemonType } from "#enums/pokemon-type";
|
||||||
import type { expect } from "vitest";
|
import type { expect } from "vitest";
|
||||||
|
import type { Arena } from "#field/arena";
|
||||||
|
import type { ArenaTag } from "#data/arena-tag";
|
||||||
import type { toHaveTypesOptions } from "#test/test-utils/matchers/to-have-types";
|
import type { toHaveTypesOptions } from "#test/test-utils/matchers/to-have-types";
|
||||||
|
import { ArenaTagType } from "#enums/arena-tag-type";
|
||||||
|
import { toHaveArenaTagOptions } from "#test/test-utils/matchers/to-have-arena-tag";
|
||||||
|
|
||||||
declare module "vitest" {
|
declare module "vitest" {
|
||||||
interface Assertion {
|
interface Assertion {
|
||||||
@ -22,5 +26,13 @@ declare module "vitest" {
|
|||||||
* @param options - The options passed to the matcher.
|
* @param options - The options passed to the matcher.
|
||||||
*/
|
*/
|
||||||
toHaveTypes(expected: PokemonType[], options?: toHaveTypesOptions): void;
|
toHaveTypes(expected: PokemonType[], options?: toHaveTypesOptions): 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<T extends ArenaTagType>(expected: T, options?: toHaveArenaTagOptions<T>): void;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,5 +1,6 @@
|
|||||||
import { SubstituteTag } from "#data/battler-tags";
|
import { SubstituteTag } from "#data/battler-tags";
|
||||||
import { AbilityId } from "#enums/ability-id";
|
import { AbilityId } from "#enums/ability-id";
|
||||||
|
import { ArenaTagSide } from "#enums/arena-tag-side";
|
||||||
import { ArenaTagType } from "#enums/arena-tag-type";
|
import { ArenaTagType } from "#enums/arena-tag-type";
|
||||||
import { MoveId } from "#enums/move-id";
|
import { MoveId } from "#enums/move-id";
|
||||||
import { SpeciesId } from "#enums/species-id";
|
import { SpeciesId } from "#enums/species-id";
|
||||||
@ -7,6 +8,7 @@ import { Stat } from "#enums/stat";
|
|||||||
import { MoveEndPhase } from "#phases/move-end-phase";
|
import { MoveEndPhase } from "#phases/move-end-phase";
|
||||||
import { TurnEndPhase } from "#phases/turn-end-phase";
|
import { TurnEndPhase } from "#phases/turn-end-phase";
|
||||||
import { GameManager } from "#test/test-utils/game-manager";
|
import { GameManager } from "#test/test-utils/game-manager";
|
||||||
|
import type { ArenaTrapTagType } from "#types/arena-tags";
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
@ -31,56 +33,24 @@ describe("Moves - Tidy Up", () => {
|
|||||||
.enemySpecies(SpeciesId.MAGIKARP)
|
.enemySpecies(SpeciesId.MAGIKARP)
|
||||||
.enemyAbility(AbilityId.BALL_FETCH)
|
.enemyAbility(AbilityId.BALL_FETCH)
|
||||||
.enemyMoveset(MoveId.SPLASH)
|
.enemyMoveset(MoveId.SPLASH)
|
||||||
.starterSpecies(SpeciesId.FEEBAS)
|
.ability(AbilityId.BALL_FETCH);
|
||||||
.ability(AbilityId.BALL_FETCH)
|
|
||||||
.moveset([MoveId.TIDY_UP])
|
|
||||||
.startingLevel(50);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("spikes are cleared", async () => {
|
it.each<{ name: string; hazard: ArenaTrapTagType }>([{ name: "Spikes", hazard: ArenaTagType.SPIKES }])(
|
||||||
game.override.moveset([MoveId.SPIKES, MoveId.TIDY_UP]).enemyMoveset(MoveId.SPIKES);
|
"should remove $name from both sides of the field",
|
||||||
await game.classicMode.startBattle();
|
async ({ hazard }) => {
|
||||||
|
await game.classicMode.startBattle([SpeciesId.FEEBAS]);
|
||||||
|
|
||||||
game.move.select(MoveId.SPIKES);
|
// Add tag to both sides of the field
|
||||||
await game.phaseInterceptor.to(TurnEndPhase);
|
game.scene.arena.addTag(hazard, 1, undefined, game.field.getPlayerPokemon().id, ArenaTagSide.PLAYER);
|
||||||
game.move.select(MoveId.TIDY_UP);
|
game.scene.arena.addTag(hazard, 1, undefined, game.field.getPlayerPokemon().id, ArenaTagSide.ENEMY);
|
||||||
await game.phaseInterceptor.to(MoveEndPhase);
|
|
||||||
|
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(ArenaTagType.SPIKES)).toBeUndefined();
|
||||||
});
|
},
|
||||||
|
);
|
||||||
it("stealth rocks are cleared", async () => {
|
|
||||||
game.override.moveset([MoveId.STEALTH_ROCK, MoveId.TIDY_UP]).enemyMoveset(MoveId.STEALTH_ROCK);
|
|
||||||
await game.classicMode.startBattle();
|
|
||||||
|
|
||||||
game.move.select(MoveId.STEALTH_ROCK);
|
|
||||||
await game.phaseInterceptor.to(TurnEndPhase);
|
|
||||||
game.move.select(MoveId.TIDY_UP);
|
|
||||||
await game.phaseInterceptor.to(MoveEndPhase);
|
|
||||||
expect(game.scene.arena.getTag(ArenaTagType.STEALTH_ROCK)).toBeUndefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("toxic spikes are cleared", async () => {
|
|
||||||
game.override.moveset([MoveId.TOXIC_SPIKES, MoveId.TIDY_UP]).enemyMoveset(MoveId.TOXIC_SPIKES);
|
|
||||||
await game.classicMode.startBattle();
|
|
||||||
|
|
||||||
game.move.select(MoveId.TOXIC_SPIKES);
|
|
||||||
await game.phaseInterceptor.to(TurnEndPhase);
|
|
||||||
game.move.select(MoveId.TIDY_UP);
|
|
||||||
await game.phaseInterceptor.to(MoveEndPhase);
|
|
||||||
expect(game.scene.arena.getTag(ArenaTagType.TOXIC_SPIKES)).toBeUndefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("sticky webs are cleared", async () => {
|
|
||||||
game.override.moveset([MoveId.STICKY_WEB, MoveId.TIDY_UP]).enemyMoveset(MoveId.STICKY_WEB);
|
|
||||||
|
|
||||||
await game.classicMode.startBattle();
|
|
||||||
|
|
||||||
game.move.select(MoveId.STICKY_WEB);
|
|
||||||
await game.phaseInterceptor.to(TurnEndPhase);
|
|
||||||
game.move.select(MoveId.TIDY_UP);
|
|
||||||
await game.phaseInterceptor.to(MoveEndPhase);
|
|
||||||
expect(game.scene.arena.getTag(ArenaTagType.STICKY_WEB)).toBeUndefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("substitutes are cleared", async () => {
|
it("substitutes are cleared", async () => {
|
||||||
game.override.moveset([MoveId.SUBSTITUTE, MoveId.TIDY_UP]).enemyMoveset(MoveId.SUBSTITUTE);
|
game.override.moveset([MoveId.SUBSTITUTE, MoveId.TIDY_UP]).enemyMoveset(MoveId.SUBSTITUTE);
|
||||||
|
54
test/test-utils/matchers/to-have-arena-tag.ts
Normal file
54
test/test-utils/matchers/to-have-arena-tag.ts
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
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),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user