Files
healer-man/src/app/characterCatalog.test.ts
T
2026-08-14 15:56:39 -04:00

106 lines
4.8 KiB
TypeScript

import { describe, expect, it } from "vitest";
import {
CLASS_ICON_BASENAME_BY_ID,
CLASSES,
COA_CLASS_IDS,
PLAYABLE_RACES,
RACES,
classIconUrl,
classesForRace,
clampAppearance,
normalizeCharacterName,
randomAppearance,
supportedGenders,
totalRaceClassCombinations,
validateCharacterName,
} from "./characterCatalog";
describe("wow335a character catalog", () => {
it("limits normal play to the live-verified race roster", () => {
expect(PLAYABLE_RACES.filter((race) => race.categoryId !== "rom").map((race) => race.id)).toEqual([
"human",
"orc",
"dwarf",
"night-elf",
"undead",
"tauren",
"gnome",
"troll",
"blood-elf",
"draenei",
"goblin",
]);
});
it("matches the extracted Ascension playable catalog", () => {
const wowRaces = RACES.filter((race) => race.categoryId !== "rom");
const wowClasses = CLASSES.filter((characterClass) => characterClass.categoryId !== "rom");
expect(wowRaces).toHaveLength(27);
expect(wowClasses).toHaveLength(31);
expect(COA_CLASS_IDS).toHaveLength(21);
expect(wowRaces.reduce((total, race) => total + classesForRace(race.id).length, 0)).toBe(740);
expect(totalRaceClassCombinations()).toBe(758);
expect(wowRaces.map((race) => race.name)).toEqual([
"Human", "Orc", "Dwarf", "Night Elf", "Undead",
"Tauren", "Gnome", "Troll", "Blood Elf", "Draenei",
"Goblin", "Zandalari Troll", "Kul Tiran", "Vulpera", "Pandaren",
"Thin Human", "Fel Orc", "Broken", "Skeleton", "Vrykul", "Tuskarr",
"Forest Troll", "Taunka", "Northrend Skeleton", "Ice Troll", "Earthen",
"Human Cultist",
]);
expect(COA_CLASS_IDS.map((id) => wowClasses.find((entry) => entry.id === id)?.name)).toEqual([
"Barbarian", "Witch Doctor", "Felsworn", "Witch Hunter", "Stormbringer",
"Knight of Xoroth", "Guardian", "Templar", "Bloodmage", "Ranger",
"Chronomancer", "Necromancer", "Pyromancer", "Cultist", "Starcaller",
"Sun Cleric", "Tinker", "Venomancer", "Reaper", "Primalist", "Runemaster",
]);
});
it("applies the race eligibility rows from CharBaseInfo.dbc", () => {
const wowClassCount = CLASSES.filter((characterClass) => characterClass.categoryId !== "rom").length;
expect(classesForRace("human").map((entry) => entry.id)).toContain("barbarian");
expect(classesForRace("human").map((entry) => entry.id)).not.toContain("felsworn");
expect(classesForRace("draenei").map((entry) => entry.id)).toContain("felsworn");
expect(classesForRace("draenei").map((entry) => entry.id)).toContain("knight-of-xoroth");
expect(classesForRace("troll").map((entry) => entry.id)).toContain("venomancer");
expect(classesForRace("troll").map((entry) => entry.id)).not.toContain("knight-of-xoroth");
expect(classesForRace("goblin")).toHaveLength(wowClassCount);
expect(classesForRace("human-cultist")).toHaveLength(wowClassCount);
expect(supportedGenders("vrykul")).toEqual(["male"]);
expect(supportedGenders("earthen")).toEqual(["male", "female"]);
});
it("maps every class to its extracted Ascension class icon", () => {
const wowClasses = CLASSES.filter((characterClass) => characterClass.categoryId !== "rom");
expect(new Set(wowClasses.map((definition) => CLASS_ICON_BASENAME_BY_ID[definition.id])).size)
.toBe(wowClasses.length);
expect(CLASS_ICON_BASENAME_BY_ID.felsworn).toBe("classicon128_demonhunter");
expect(CLASS_ICON_BASENAME_BY_ID["knight-of-xoroth"]).toBe("classicon128_fleshwarden");
expect(CLASS_ICON_BASENAME_BY_ID.venomancer).toBe("classicon128_prophet");
expect(classIconUrl("runemaster")).toBe("/assets/ui/spells/classicon128_spiritmage.png");
});
it("preserves race and gender-specific customization counts", () => {
const tauren = RACES.find((race) => race.id === "tauren")!;
expect(tauren.labels.male.hairStyle).toBe("Horn Style");
expect(tauren.counts.male).toMatchObject({ skinColor: 19, hairColor: 3, feature: 7 });
expect(RACES.find((race) => race.id === "night-elf")!.labels.female.feature).toBe("Markings");
});
it("keeps generated and clamped appearance indexes within the selected model ranges", () => {
expect(randomAppearance("human", "female", () => 0.999)).toEqual({
skinColor: 9, face: 14, hairStyle: 23, hairColor: 9, feature: 6,
});
expect(clampAppearance("gnome", "male", {
skinColor: -2, face: 99, hairStyle: 4.7, hairColor: 20, feature: 2,
})).toEqual({ skinColor: 0, face: 6, hairStyle: 4, hairColor: 8, feature: 2 });
});
it("applies the original 2-12 letter naming boundary", () => {
expect(normalizeCharacterName(" hEAL3R!! ")).toBe("Healr");
expect(validateCharacterName("A")).toMatch(/2 to 12/);
expect(validateCharacterName("Healer-Man")).toMatch(/letters only/);
expect(validateCharacterName("Serenity")).toBeNull();
});
});