Add test for filtering double ability combinations

This commit is contained in:
Sirz Benjie 2025-04-07 12:29:47 -05:00
parent 7428f2287c
commit 7dc0c4be83
No known key found for this signature in database
GPG Key ID: 4A524B4D196C759E

View File

@ -1,19 +1,33 @@
import { Mode } from "#app/ui/ui"; import { Mode } from "#app/ui/ui";
import GameManager from "#test/testUtils/gameManager"; import GameManager from "#test/testUtils/gameManager";
import Phaser from "phaser"; import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { afterEach, beforeAll, beforeEach, describe, expect, it, type MockInstance, vi } from "vitest";
import PokedexUiHandler from "#app/ui/pokedex-ui-handler"; import PokedexUiHandler from "#app/ui/pokedex-ui-handler";
import { FilterTextRow } from "#app/ui/filter-text"; import { FilterTextRow } from "#app/ui/filter-text";
import { allAbilities } from "#app/data/ability"; import { allAbilities } from "#app/data/ability";
import { Abilities } from "#enums/abilities"; import { Abilities } from "#enums/abilities";
import type { Species } from "#enums/species"; import { Species } from "#enums/species";
import { allSpecies } from "#app/data/pokemon-species"; import { allSpecies, getPokemonSpecies, type PokemonForm } from "#app/data/pokemon-species";
import { Button } from "#enums/buttons"; import { Button } from "#enums/buttons";
import { DropDownColumn } from "#app/ui/filter-bar"; import { DropDownColumn } from "#app/ui/filter-bar";
import type PokemonSpecies from "#app/data/pokemon-species";
/**
* Return all permutations of elements from an array
*/
function permutations<T>(array: T[], length: number): T[][] {
if (length === 0) {
return [[]];
}
return array.flatMap((item, index) =>
permutations([...array.slice(0, index), ...array.slice(index + 1)], length - 1).map(perm => [item, ...perm]),
);
}
describe("UI - Pokedex", () => { describe("UI - Pokedex", () => {
let phaserGame: Phaser.Game; let phaserGame: Phaser.Game;
let game: GameManager; let game: GameManager;
const mocks: MockInstance[] = [];
beforeAll(() => { beforeAll(() => {
phaserGame = new Phaser.Game({ phaserGame = new Phaser.Game({
@ -22,6 +36,9 @@ describe("UI - Pokedex", () => {
}); });
afterEach(() => { afterEach(() => {
while (mocks.length > 0) {
mocks.pop()?.mockRestore();
}
game.phaseInterceptor.restoreOg(); game.phaseInterceptor.restoreOg();
}); });
@ -65,6 +82,53 @@ describe("UI - Pokedex", () => {
return speciesSet; return speciesSet;
} }
/**
* Create mocks for the abilities of a species.
* This is used to set the abilities of a species to a specific value.
* All abilities are optional. Not providing one will set it to NONE.
*
* This will override the ability of the pokemon species only, unless set forms is true
*
* @param species The species to set the abilities for
* @param ability The ability to set for the first ability
* @param ability2 The ability to set for the second ability
* @param hidden The ability to set for the hidden ability
* @param passive The ability to set for the passive ability
* @param setForms Whether to also overwrite the abilities for each of the species' forms (defaults to true)
*/
function createAbilityMocks(
species: Species,
{
ability = Abilities.NONE,
ability2 = Abilities.NONE,
hidden = Abilities.NONE,
passive = Abilities.NONE,
setForms = true,
}: {
ability?: Abilities;
ability2?: Abilities;
hidden?: Abilities;
passive?: Abilities;
setForms?: boolean;
},
) {
const pokemon = getPokemonSpecies(species);
const checks: [PokemonSpecies | PokemonForm] = [pokemon];
if (setForms) {
checks.push(...pokemon.forms);
}
for (const p of checks) {
mocks.push(vi.spyOn(p, "ability1", "get").mockReturnValue(ability));
mocks.push(vi.spyOn(p, "ability2", "get").mockReturnValue(ability2));
mocks.push(vi.spyOn(p, "abilityHidden", "get").mockReturnValue(hidden));
mocks.push(vi.spyOn(p, "getPassiveAbility").mockReturnValue(passive));
}
}
/***************************
* Tests for Filters *
***************************/
it("should filter to show only the pokemon with an ability when filtering by ability", async () => { it("should filter to show only the pokemon with an ability when filtering by ability", async () => {
// await game.importData("test/testUtils/saves/everything.prsv"); // await game.importData("test/testUtils/saves/everything.prsv");
const pokedexHandler = await runToOpenPokedex(); const pokedexHandler = await runToOpenPokedex();
@ -83,33 +147,93 @@ describe("UI - Pokedex", () => {
expect(filteredSpecies).toEqual(overgrowSpecies); expect(filteredSpecies).toEqual(overgrowSpecies);
}); });
it.todo( it("should filter to show only pokemon with ability and passive when filtering by 2 abilities", async () => {
"should wrap the cursor to the top when moving to an empty entry when there are more than 81 pokemon", // Setup mocks for the ability and passive combinations
async () => { const whitelist: Species[] = [];
const pokedexHandler = await runToOpenPokedex(); const blacklist: Species[] = [];
// Filter by gen 2 so we can pan a specific amount. const filter_ab1 = Abilities.OVERGROW;
// @ts-ignore filterText is private const filter_ab2 = Abilities.ADAPTABILITY;
pokedexHandler.filterBar.getFilter(DropDownColumn.GEN).options[2].toggleOptionState(); const ab1_instance = allAbilities[filter_ab1];
pokedexHandler.updateStarters(); const ab2_instance = allAbilities[filter_ab2];
// @ts-ignore filteredPokemonData is private
expect(pokedexHandler.filteredPokemonData.length, "Expecting gen2 to have 100 pokemon").toBe(100);
// Let's try to pan to the right to see what the pokemon it points to is. // Create a species with passive set and each "ability" field
const baseObj = {
ability: Abilities.BALL_FETCH,
ability2: Abilities.NONE,
hidden: Abilities.BLAZE,
passive: Abilities.TORRENT,
};
// pan to the right once and down 11 times // Mock pokemon to have the exhaustive combination of the two selected abilities
pokedexHandler.processInput(Button.RIGHT); const attrs: (keyof typeof baseObj)[] = ["ability", "ability2", "hidden", "passive"];
// Nab the pokemon that is selected for comparison later. for (const [idx, value] of permutations(attrs, 2).entries()) {
createAbilityMocks(Species.BULBASAUR + idx, {
// @ts-ignore filteredPokemonData is private ...baseObj,
const selectedPokemon = pokedexHandler.lastSpecies.speciesId; [value[0]]: filter_ab1,
for (let i = 0; i < 11; i++) { [value[1]]: filter_ab2,
pokedexHandler.processInput(Button.DOWN); });
if (value.includes("passive")) {
whitelist.push(Species.BULBASAUR + idx);
} else {
blacklist.push(Species.BULBASAUR + idx);
} }
}
// @ts-ignore lastSpecies is private const pokedexHandler = await runToOpenPokedex();
const selectedPokemon2 = pokedexHandler.lastSpecies.speciesId;
expect(selectedPokemon).toEqual(selectedPokemon2); // @ts-ignore filterText is private
}, pokedexHandler.filterText.setValue(FilterTextRow.ABILITY_1, ab1_instance.name);
); // @ts-ignore filterText is private
pokedexHandler.filterText.setValue(FilterTextRow.ABILITY_2, ab2_instance.name);
let whiteListCount = 0;
// @ts-ignore filteredPokemonData is private
for (const species of pokedexHandler.filteredPokemonData) {
expect(blacklist, "entry must have one of the abilities as a passive").not.toContain(species.species.speciesId);
const rawAbility = [species.species.ability1, species.species.ability2, species.species.abilityHidden];
const rawPassive = species.species.getPassiveAbility();
const c1 = rawPassive === ab1_instance.id && rawAbility.includes(ab2_instance.id);
const c2 = c1 || (rawPassive === ab2_instance.id && rawAbility.includes(ab1_instance.id));
expect(c2, "each filtered entry should have the ability and passive combination").toBe(true);
if (whitelist.includes(species.species.speciesId)) {
whiteListCount++;
}
}
expect(whiteListCount).toBe(whitelist.length);
});
/****************************
* Tests for UI Input *
****************************/
it("should wrap the cursor to the top when moving to an empty entry when there are more than 81 pokemon", async () => {
const pokedexHandler = await runToOpenPokedex();
// Filter by gen 2 so we can pan a specific amount.
// @ts-ignore filterText is private
pokedexHandler.filterBar.getFilter(DropDownColumn.GEN).options[2].toggleOptionState();
pokedexHandler.updateStarters();
// @ts-ignore filteredPokemonData is private
expect(pokedexHandler.filteredPokemonData.length, "pokemon in gen2").toBe(100);
// Let's try to pan to the right to see what the pokemon it points to is.
// pan to the right once and down 11 times
pokedexHandler.processInput(Button.RIGHT);
// Nab the pokemon that is selected for comparison later.
// @ts-ignore filteredPokemonData is private
const selectedPokemon = pokedexHandler.lastSpecies.speciesId;
for (let i = 0; i < 11; i++) {
pokedexHandler.processInput(Button.DOWN);
}
// @ts-ignore lastSpecies is private
expect(selectedPokemon).toEqual(pokedexHandler.lastSpecies.speciesId);
});
}); });