Fixed type error + removed broken util

This commit is contained in:
Bertie690 2025-09-10 13:48:50 -04:00
parent 3780841e0d
commit 38cafe7b27
2 changed files with 59 additions and 83 deletions

View File

@ -6,7 +6,8 @@ import { BattleType } from "#enums/battle-type";
import { MoveId } from "#enums/move-id";
import { SpeciesId } from "#enums/species-id";
import { GameManager } from "#test/test-utils/game-manager";
import { getEnumTestCases } from "#test/test-utils/string-utils";
import { getEnumStr } from "#test/test-utils/string-utils";
import { getEnumValues } from "#utils/enums";
import { toTitleCase } from "#utils/strings";
import i18next from "i18next";
import Phaser from "phaser";
@ -53,49 +54,53 @@ describe("Arena Tags", () => {
// These tags are either ineligible or just jaaaaaaaaaaank
const FORBIDDEN_TAGS = [ArenaTagType.NONE, ArenaTagType.NEUTRALIZING_GAS] as const;
const sides = getEnumValues(ArenaTagSide);
const arenaTags = Object.values(ArenaTagType)
.filter(t => !(FORBIDDEN_TAGS as readonly ArenaTagType[]).includes(t))
.map(t => ({
tagType: t,
name: toTitleCase(t),
}));
describe.each(arenaTags)("$name", ({ tagType }) => {
it.each(getEnumTestCases(ArenaTagSide))(
"should display a message on addition, and a separate one on removal - ArenaTagSide.$name",
({ value: side }) => {
game.scene.arena.addTag(tagType, 0, undefined, playerId, side);
expect(game).toHaveArenaTag(tagType, side);
const tag = game.scene.arena.getTagOnSide(tagType, side)!;
if (tag["onAddMessageKey"]) {
expect(game.textInterceptor.logs).toContain(
i18next.t(tag["onAddMessageKey"], {
pokemonNameWithAffix: getPokemonNameWithAffix(tag["getSourcePokemon"]()),
moveName: tag["getMoveName"](),
}),
);
} else {
expect(game.textInterceptor.logs).toHaveLength(0);
}
game.textInterceptor.clearLogs();
game.scene.arena.removeTagOnSide(tagType, side, false);
if (tag["onRemoveMessageKey"]) {
// TODO: Convert to `game.toHaveShownMessage`
expect(game.textInterceptor.logs).toContain(
i18next.t(tag["onRemoveMessageKey"], {
pokemonNameWithAffix: getPokemonNameWithAffix(tag["getSourcePokemon"]()),
moveName: tag["getMoveName"](),
}),
);
} else {
expect(game.textInterceptor.logs).toHaveLength(0);
}
expect(game).not.toHaveArenaTag(tagType, side);
},
.flatMap(t =>
sides.map(side => ({
tagType: t,
name: toTitleCase(t),
side,
sideName: getEnumStr(ArenaTagSide, side),
})),
);
});
it.each(arenaTags)(
"$name should display a message on addition, and a separate one on removal - $sideName",
({ tagType, side }) => {
game.scene.arena.addTag(tagType, 0, undefined, playerId, side);
expect(game).toHaveArenaTag(tagType, side);
const tag = game.scene.arena.getTagOnSide(tagType, side)!;
if (tag["onAddMessageKey"]) {
expect(game.textInterceptor.logs).toContain(
i18next.t(tag["onAddMessageKey"], {
pokemonNameWithAffix: getPokemonNameWithAffix(tag["getSourcePokemon"]()),
moveName: tag["getMoveName"](),
}),
);
} else {
expect(game.textInterceptor.logs).toHaveLength(0);
}
game.textInterceptor.clearLogs();
game.scene.arena.removeTagOnSide(tagType, side, false);
if (tag["onRemoveMessageKey"]) {
// TODO: Convert to `game.toHaveShownMessage`
expect(game.textInterceptor.logs).toContain(
i18next.t(tag["onRemoveMessageKey"], {
pokemonNameWithAffix: getPokemonNameWithAffix(tag["getSourcePokemon"]()),
moveName: tag["getMoveName"](),
}),
);
} else {
expect(game.textInterceptor.logs).toHaveLength(0);
}
expect(game).not.toHaveArenaTag(tagType, side);
},
);
});

View File

@ -1,7 +1,7 @@
import { getStatKey, type Stat } from "#enums/stat";
import type { EnumOrObject, NormalEnum, TSNumericEnum } from "#types/enum-types";
import type { ObjectValues } from "#types/type-helpers";
import { enumValueToKey, getEnumValues } from "#utils/enums";
import { enumValueToKey } from "#utils/enums";
import { toTitleCase } from "#utils/strings";
import type { MatcherState } from "@vitest/expect";
import i18next from "i18next";
@ -24,15 +24,18 @@ interface getEnumStrOptions {
* If present, will be added to the end of the enum string.
*/
suffix?: string;
/**
* Whether to omit the value from the text.
* @defaultValue Whether `E` is a non-string enum
*/
omitValue?: boolean;
}
/**
* Return the name of an enum member or const object value, alongside its corresponding value.
* @param obj - The {@linkcode EnumOrObject} to source reverse mappings from
* @param enums - One of {@linkcode obj}'s values
* @param casing - A string denoting the casing method to use; default `Preserve`
* @param prefix - An optional string to be prepended to the enum's string representation
* @param suffix - An optional string to be appended to the enum's string representation
* @param val - One of {@linkcode obj}'s values
* @param options - Options modifying the stringification process.
* @returns The stringified representation of `val` as dictated by the options.
* @example
* ```ts
@ -48,8 +51,9 @@ interface getEnumStrOptions {
export function getEnumStr<E extends EnumOrObject>(
obj: E,
val: ObjectValues<E>,
{ casing = "Preserve", prefix = "", suffix = "" }: getEnumStrOptions = {},
options: getEnumStrOptions = {},
): string {
const { casing = "Preserve", prefix = "", suffix = "", omitValue = typeof val === "number" } = options;
let casingFunc: ((s: string) => string) | undefined;
switch (casing) {
case "Preserve":
@ -70,7 +74,7 @@ export function getEnumStr<E extends EnumOrObject>(
stringPart = casingFunc(stringPart);
}
return `${prefix}${stringPart}${suffix} (=${val})`;
return `${prefix}${stringPart}${suffix}${omitValue ? ` (=${val})` : ""}`;
}
/**
@ -187,36 +191,3 @@ export function getOnelineDiffStr(this: MatcherState, obj: unknown): string {
.replace(/\n/g, " ") // Replace newlines with spaces
.replace(/,(\s*)\}$/g, "$1}"); // Trim trailing commas
}
/**
* Convert an enum or `const object` into an array of object literals
* suitable for use inside {@linkcode describe.each} or {@linkcode it.each}.
* @param obj - The {@linkcode EnumOrObject} to source reverse mappings from
* @param values - An array containing one or more of `obj`'s values to convert.
* Defaults to all the enum's values.
* @param options - Options to pass to {@linkcode getEnumStr}
* @returns An array of objects containing the enum's name and value.
* @example
* ```ts
* enum fakeEnum {
* ONE: 1,
* TWO: 2,
* THREE: 3,
* }
* describe.each(getEnumTestCases(fakeEnum))("should do XYZ - $name", ({value}) => {});
* ```
*/
export function getEnumTestCases<E extends EnumOrObject>(
obj: E,
values: E[keyof E][] = isTSNumericEnum(obj) ? getEnumValues(obj) : (Object.values(obj) as E[keyof E][]),
options: getEnumStrOptions = {},
): { value: E[keyof E]; name: string }[] {
return values.map(e => ({
value: e,
name: getEnumStr(obj, e, options),
}));
}
function isTSNumericEnum<E extends EnumOrObject>(obj: E): obj is TSNumericEnum<E> {
return Object.keys(obj).some(k => typeof k === "number");
}