mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-08-14 19:39:29 +02:00
Fixed log message to not be overly verbose
This commit is contained in:
parent
3a6a16f3ff
commit
4b447073a7
8
global.d.ts
vendored
8
global.d.ts
vendored
@ -1,3 +1,4 @@
|
||||
import type { AnyFn } from "#types/type-helpers";
|
||||
import type { SetupServerApi } from "msw/node";
|
||||
|
||||
declare global {
|
||||
@ -9,4 +10,11 @@ declare global {
|
||||
* To set up your own server in a test see `game-data.test.ts`
|
||||
*/
|
||||
var server: SetupServerApi;
|
||||
|
||||
// Overloads for `Function.apply` and `Function.call` to add type safety on matching argument types
|
||||
interface Function {
|
||||
apply<T extends AnyFn>(this: T, thisArg: ThisParameterType<T>, argArray: Parameters<T>): ReturnType<T>;
|
||||
|
||||
call<T extends AnyFn>(this: T, thisArg: ThisParameterType<T>, ...argArray: Parameters<T>): ReturnType<T>;
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { getOnelineDiffStr } from "#test/test-utils/string-utils";
|
||||
import type { MatcherState, SyncExpectationResult } from "@vitest/expect";
|
||||
|
||||
/**
|
||||
@ -28,17 +29,20 @@ export function toEqualArrayUnsorted(
|
||||
}
|
||||
|
||||
// Create shallow copies of the arrays in case we have
|
||||
const gotSorted = received.slice().sort();
|
||||
const wantSorted = expected.slice().sort();
|
||||
const pass = this.equals(gotSorted, wantSorted, [...this.customTesters, this.utils.iterableEquality]);
|
||||
const actualSorted = received.slice().sort();
|
||||
const expectedSorted = expected.slice().sort();
|
||||
const pass = this.equals(actualSorted, expectedSorted, [...this.customTesters, this.utils.iterableEquality]);
|
||||
|
||||
const actualStr = getOnelineDiffStr.call(this, actualSorted);
|
||||
const expectedStr = getOnelineDiffStr.call(this, expectedSorted);
|
||||
|
||||
return {
|
||||
pass,
|
||||
message: () =>
|
||||
pass
|
||||
? `Expected ${this.utils.stringify(received)} to NOT exactly equal ${this.utils.stringify(expected)} without order!`
|
||||
: `Expected ${this.utils.stringify(received)} to exactly equal ${this.utils.stringify(expected)} without order!`,
|
||||
expected: wantSorted,
|
||||
actual: gotSorted,
|
||||
? `Expected ${actualStr} to NOT exactly equal ${expectedStr} without order, but it did!`
|
||||
: `Expected ${actualStr} to exactly equal ${expectedStr} without order, but it didn't!`,
|
||||
expected: expectedSorted,
|
||||
actual: actualSorted,
|
||||
};
|
||||
}
|
||||
|
@ -29,14 +29,14 @@ export function toHaveBattlerTag(
|
||||
const pass = !!received.getTag(expectedBattlerTagType);
|
||||
const pkmName = getPokemonNameWithAffix(received);
|
||||
// "BattlerTagType.SEEDED (=1)"
|
||||
const expectedTagStr = getEnumStr(BattlerTagType, expectedBattlerTagType);
|
||||
const expectedTagStr = getEnumStr(BattlerTagType, expectedBattlerTagType, { prefix: "BattlerTagType." });
|
||||
|
||||
return {
|
||||
pass,
|
||||
message: () =>
|
||||
pass
|
||||
? `Expected ${pkmName} to NOT have BattlerTagType.${expectedTagStr}, but it did!`
|
||||
: `Expected ${pkmName} to have BattlerTagType.${expectedTagStr}, but it didn't!`,
|
||||
? `Expected ${pkmName} to NOT have ${expectedTagStr}, but it did!`
|
||||
: `Expected ${pkmName} to have ${expectedTagStr}, but it didn't!`,
|
||||
expected: expectedBattlerTagType,
|
||||
actual: received.summonData.tags.map(t => t.tagType),
|
||||
};
|
||||
|
@ -43,7 +43,7 @@ export function toHaveStatStage(
|
||||
pass
|
||||
? `Expected ${pkmName}'s ${statName} stat stage to NOT be ${expectedStage}, but it was!`
|
||||
: `Expected ${pkmName}'s ${statName} stat stage to be ${expectedStage}, but got ${actualStage} instead!`,
|
||||
actual: actualStage,
|
||||
expected: expectedStage,
|
||||
actual: actualStage,
|
||||
};
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import type { Pokemon } from "#field/pokemon";
|
||||
|
||||
import { getPokemonNameWithAffix } from "#app/messages";
|
||||
import { StatusEffect } from "#enums/status-effect";
|
||||
import { getEnumStr } from "#test/test-utils/string-utils";
|
||||
import { getEnumStr, getOnelineDiffStr } from "#test/test-utils/string-utils";
|
||||
import { isPokemonInstance, receivedStr } from "#test/test-utils/test-utils";
|
||||
import type { MatcherState, SyncExpectationResult } from "@vitest/expect";
|
||||
|
||||
@ -33,14 +33,20 @@ export function toHaveStatusEffect(
|
||||
}
|
||||
|
||||
const pkmName = getPokemonNameWithAffix(received);
|
||||
|
||||
// Check exclusively effect equality
|
||||
if (typeof expectedStatus === "number" || received.status?.effect !== expectedStatus.effect) {
|
||||
const actualEffect = received.status?.effect ?? StatusEffect.NONE;
|
||||
|
||||
// Check exclusively effect equality first, coercing non-matching status effects to numbers.
|
||||
if (actualEffect !== (expectedStatus as Exclude<typeof expectedStatus, StatusEffect>)?.effect) {
|
||||
// This is actually 100% safe as `expectedStatus?.effect` will evaluate to `undefined` if a StatusEffect was passed,
|
||||
// which will never match actualEffect by definition
|
||||
expectedStatus = (expectedStatus as Exclude<typeof expectedStatus, StatusEffect>).effect;
|
||||
}
|
||||
|
||||
if (typeof expectedStatus === "number") {
|
||||
const pass = this.equals(actualEffect, expectedStatus, [...this.customTesters, this.utils.iterableEquality]);
|
||||
|
||||
const actualStr = getEnumStr(StatusEffect, actualEffect, { prefix: "StatusEffect." });
|
||||
const expectedStr = getEnumStr(StatusEffect, actualEffect, { prefix: "StatusEffect." });
|
||||
const expectedStr = getEnumStr(StatusEffect, expectedStatus, { prefix: "StatusEffect." });
|
||||
|
||||
return {
|
||||
pass,
|
||||
@ -53,7 +59,7 @@ export function toHaveStatusEffect(
|
||||
};
|
||||
}
|
||||
|
||||
// Check for equality of all fields (for toxic turn count)
|
||||
// Check for equality of all fields (for toxic turn count/etc)
|
||||
const actualStatus = received.status;
|
||||
const pass = this.equals(received, expectedStatus, [
|
||||
...this.customTesters,
|
||||
@ -61,12 +67,15 @@ export function toHaveStatusEffect(
|
||||
this.utils.iterableEquality,
|
||||
]);
|
||||
|
||||
const expectedStr = getOnelineDiffStr.call(this, expectedStatus);
|
||||
const actualStr = getOnelineDiffStr.call(this, actualStatus);
|
||||
|
||||
return {
|
||||
pass,
|
||||
message: () =>
|
||||
pass
|
||||
? `Expected ${pkmName}'s status to NOT match ${this.utils.stringify(expectedStatus)}, but it did!`
|
||||
: `Expected ${pkmName}'s status to match ${this.utils.stringify(expectedStatus)}, but got ${this.utils.stringify(actualStatus)} instead!`,
|
||||
? `Expected ${pkmName}'s status to NOT match ${expectedStr}, but it did!`
|
||||
: `Expected ${pkmName}'s status to match ${expectedStr}, but got ${actualStr} instead!`,
|
||||
expected: expectedStatus,
|
||||
actual: actualStatus,
|
||||
};
|
||||
|
@ -39,8 +39,8 @@ export function toHaveTerrain(
|
||||
pass
|
||||
? `Expected Arena to NOT have ${expectedStr} active, but it did!`
|
||||
: `Expected Arena to have ${expectedStr} active, but got ${actualStr} instead!`,
|
||||
actual,
|
||||
expected: expectedTerrainType,
|
||||
actual,
|
||||
};
|
||||
}
|
||||
|
||||
@ -53,5 +53,6 @@ function toTerrainStr(terrainType: TerrainType) {
|
||||
if (terrainType === TerrainType.NONE) {
|
||||
return "no terrain";
|
||||
}
|
||||
// "Electric Terrain (=2)"
|
||||
return getEnumStr(TerrainType, terrainType, { casing: "Title", suffix: " Terrain" });
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ export function toHaveTypes(
|
||||
pass
|
||||
? `Expected ${pkmName} to NOT have types ${expectedStr}, but it did!`
|
||||
: `Expected ${pkmName} to have types ${expectedStr}, but got ${actualStr} instead!`,
|
||||
actual: actualTypes,
|
||||
expected: expectedTypes,
|
||||
actual: actualTypes,
|
||||
};
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ import { getPokemonNameWithAffix } from "#app/messages";
|
||||
import type { MoveId } from "#enums/move-id";
|
||||
// biome-ignore lint/correctness/noUnusedImports: TSDocs
|
||||
import type { Pokemon } from "#field/pokemon";
|
||||
import { getOrdinal } from "#test/test-utils/string-utils";
|
||||
import { getOnelineDiffStr, getOrdinal } from "#test/test-utils/string-utils";
|
||||
import { isPokemonInstance, receivedStr } from "#test/test-utils/test-utils";
|
||||
import type { TurnMove } from "#types/turn-move";
|
||||
import type { AtLeastOne } from "#types/type-helpers";
|
||||
@ -54,12 +54,14 @@ export function toHaveUsedMove(
|
||||
this.utils.iterableEquality,
|
||||
]);
|
||||
|
||||
const expectedStr = getOnelineDiffStr.call(this, expectedResult);
|
||||
return {
|
||||
pass,
|
||||
message: () =>
|
||||
pass
|
||||
? `Expected ${pkmName}'s ${moveIndexStr} to NOT match ${this.utils.stringify(expectedResult)}, but it did!`
|
||||
: `Expected ${pkmName}'s ${moveIndexStr} to match ${this.utils.stringify(expectedResult)}, but got ${this.utils.stringify(move)} instead!`,
|
||||
? `Expected ${pkmName}'s ${moveIndexStr} to NOT match ${expectedStr}, but it did!`
|
||||
: // Replace newlines with spaces to preserve one-line ness
|
||||
`Expected ${pkmName}'s ${moveIndexStr} to match ${expectedStr}, but it didn't!`,
|
||||
expected: expectedResult,
|
||||
actual: move,
|
||||
};
|
||||
|
@ -39,8 +39,8 @@ export function toHaveWeather(
|
||||
pass
|
||||
? `Expected Arena to NOT have ${expectedStr} weather active, but it did!`
|
||||
: `Expected Arena to have ${expectedStr} weather active, but got ${actualStr} instead!`,
|
||||
actual,
|
||||
expected: expectedWeatherType,
|
||||
actual,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ import { getStatKey, type Stat } from "#enums/stat";
|
||||
import type { EnumOrObject, EnumValues, NormalEnum, TSNumericEnum } from "#types/enum-types";
|
||||
import { enumValueToKey } from "#utils/enums";
|
||||
import { toTitleCase } from "#utils/strings";
|
||||
import type { MatcherState } from "@vitest/expect";
|
||||
import i18next from "i18next";
|
||||
|
||||
type Casing = "Preserve" | "Title";
|
||||
@ -23,12 +24,12 @@ interface getEnumStrOptions {
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to return the name of an enum member or const object value, alongside its corresponding value.
|
||||
* 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 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
|
||||
* @returns The stringified representation of `val` as dictated by the options.
|
||||
* @example
|
||||
* ```ts
|
||||
@ -37,8 +38,8 @@ interface getEnumStrOptions {
|
||||
* TWO: 2,
|
||||
* THREE: 3,
|
||||
* }
|
||||
* console.log(getEnumStr(fakeEnum, fakeEnum.ONE)); // Output: "ONE (=1)"
|
||||
* console.log(getEnumStr(fakeEnum, fakeEnum.TWO, {case: "Title", prefix: "fakeEnum."})); // Output: "fakeEnum.Two (=2)"
|
||||
* getEnumStr(fakeEnum, fakeEnum.ONE); // Output: "ONE (=1)"
|
||||
* getEnumStr(fakeEnum, fakeEnum.TWO, {casing: "Title", prefix: "fakeEnum.", suffix: "!!!"}); // Output: "fakeEnum.TWO!!! (=2)"
|
||||
* ```
|
||||
*/
|
||||
export function getEnumStr<E extends EnumOrObject>(
|
||||
@ -73,7 +74,7 @@ export function getEnumStr<E extends EnumOrObject>(
|
||||
* Convert an array of enums or `const object`s into a readable string version.
|
||||
* @param obj - The {@linkcode EnumOrObject} to source reverse mappings from
|
||||
* @param enums - An array of {@linkcode obj}'s values
|
||||
* @returns The stringified representation of `enums`
|
||||
* @returns The stringified representation of `enums`.
|
||||
* @example
|
||||
* ```ts
|
||||
* enum fakeEnum {
|
||||
@ -90,17 +91,47 @@ export function stringifyEnumArray<E extends EnumOrObject>(obj: E, enums: E[keyo
|
||||
}
|
||||
|
||||
const vals = enums.slice();
|
||||
/** An array of string names */
|
||||
let names: string[];
|
||||
|
||||
if (obj[enums[0]] !== undefined) {
|
||||
// Reverse mapping exists - `obj` is a `TSNumericEnum` and its reverse mapped counterparts
|
||||
// Reverse mapping exists - `obj` is a `TSNumericEnum` and its reverse mapped counterparts are strings
|
||||
names = enums.map(e => (obj as TSNumericEnum<E>)[e] as string);
|
||||
} else {
|
||||
// No reverse mapping exists means `obj` is a `NormalEnum`
|
||||
names = enums.map(e => enumValueToKey(obj as NormalEnum<E>, e) as string);
|
||||
// No reverse mapping exists means `obj` is a `NormalEnum`.
|
||||
// NB: This (while ugly) should be more ergonomic than doing a repeated lookup for large `const object`s
|
||||
// as the `enums` array should be significantly shorter than the corresponding enum type.
|
||||
names = [];
|
||||
for (const [k, v] of Object.entries(obj as NormalEnum<E>)) {
|
||||
if (names.length === enums.length) {
|
||||
// No more names to get
|
||||
break;
|
||||
}
|
||||
// Find all matches for the given enum, assigning their keys to the names array
|
||||
findIndices(enums, v).forEach(matchIndex => {
|
||||
names[matchIndex] = k;
|
||||
});
|
||||
}
|
||||
}
|
||||
return `[${names.join(", ")}] (=[${vals.join(", ")}])`;
|
||||
}
|
||||
|
||||
return `[${names.join(", ")}] (=[${vals.join(", ")}])`;
|
||||
/**
|
||||
* Return the indices of all occurrences of a value in an array.
|
||||
* @param arr - The array to search
|
||||
* @param searchElement - The value to locate in the array
|
||||
* @param fromIndex - The array index at which to begin the search. If fromIndex is omitted, the
|
||||
* search starts at index 0
|
||||
*/
|
||||
function findIndices<T>(arr: T[], searchElement: T, fromIndex = 0): number[] {
|
||||
const indices: number[] = [];
|
||||
const arrSliced = arr.slice(fromIndex);
|
||||
for (const [index, value] of arrSliced.entries()) {
|
||||
if (value === searchElement) {
|
||||
indices.push(index);
|
||||
}
|
||||
}
|
||||
return indices;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -137,3 +168,15 @@ export function getOrdinal(num: number): string {
|
||||
export function getStatName(s: Stat): string {
|
||||
return i18next.t(getStatKey(s));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an object into a oneline diff to be shown in an error message.
|
||||
* @param obj - The object to return the oneline diff of
|
||||
* @returns The updated diff
|
||||
*/
|
||||
export function getOnelineDiffStr(this: MatcherState, obj: unknown): string {
|
||||
return this.utils
|
||||
.stringify(obj, undefined, { maxLength: 35, indent: 0, printBasicPrototype: false })
|
||||
.replace(/\n/g, " ") // Replace newlines with spaces
|
||||
.replace(/,(\s*)}$/g, "$1}");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user