Files
healer-man/src/avatar/equipmentAppearance.test.ts
T
2026-08-30 14:16:56 -04:00

94 lines
3.1 KiB
TypeScript

import { existsSync } from "node:fs";
import { resolve } from "node:path";
import { describe, expect, it } from "vitest";
import type { InventoryItem } from "../game/lootTypes";
import {
equipmentAssetUrls,
equipmentModelUrls,
resolveEquipmentAppearance,
} from "./equipmentAppearance";
function item(itemId: number): InventoryItem {
return { itemId } as InventoryItem;
}
describe("resolveEquipmentAppearance", () => {
it("maps equipped loot to its exact client-native model attachment", () => {
const resolved = resolveEquipmentAppearance([
item(6472),
item(6447),
item(5404),
], "male");
expect(resolved.models).toEqual(expect.arrayContaining([
expect.objectContaining({ itemId: 6472, attachment: "handRight" }),
expect.objectContaining({ itemId: 6447, attachment: "shield" }),
expect.objectContaining({ itemId: 5404, attachment: "shoulderLeft" }),
expect.objectContaining({ itemId: 5404, attachment: "shoulderRight" }),
]));
});
it("does not stack two equipped models into the same hand", () => {
const resolved = resolveEquipmentAppearance([
item(6472),
item(5243),
], "male");
expect(resolved.models).toEqual([
expect.objectContaining({ itemId: 6472, attachment: "handRight" }),
]);
});
it("routes every shield model through the dedicated shield attachment", () => {
for (const itemId of [6447, 6630, 13245]) {
expect(resolveEquipmentAppearance([item(itemId)], "male").models).toEqual([
expect.objectContaining({ itemId, attachment: "shield" }),
]);
}
});
it("declares a stance-matched procedural fallback for every held model", () => {
for (const itemId of [5243, 6447, 6448, 6469, 6472, 6630, 6631, 13245]) {
const heldModels = resolveEquipmentAppearance([item(itemId)], "male").models
.filter((model) => model.attachment !== "shoulderLeft" && model.attachment !== "shoulderRight");
expect(heldModels).not.toHaveLength(0);
for (const model of heldModels) {
expect(model.fallbackKind).toBeTruthy();
expect(model.weaponStance).toBeTruthy();
}
}
});
it("uses gendered robe textures, equipment geosets, and the actual cape skin", () => {
const resolved = resolveEquipmentAppearance([
item(6465),
item(5970),
item(6632),
], "female");
expect(resolved.bodyLayers.map((layer) => layer.url)).toContain(
"/assets/equipment/wow335a-v1/textures/6465-robe-of-the-moccasin/torso-upper-female.png",
);
expect(resolved.geosets).toMatchObject({
Sleeves: 3,
Chest: 1,
Trousers: 2,
Gloves: 2,
Cloak: 6,
});
expect(resolved.cloakUrl).toContain("6632-feyscale-cloak/cape.png");
});
it("ships every referenced GLB in the public asset tree", () => {
for (const url of equipmentModelUrls()) {
expect(existsSync(resolve("public", url.replace(/^\//, "")))).toBe(true);
}
});
it("ships every referenced client-native model and texture asset", () => {
for (const url of equipmentAssetUrls()) {
expect(existsSync(resolve("public", url.replace(/^\//, "")))).toBe(true);
}
});
});