aether-shards/test/ui/character-sheet/inventory-integration.test.js

326 lines
9.5 KiB
JavaScript
Raw Normal View History

import { expect } from "@esm-bundle/chai";
import { CharacterSheet } from "../../../src/ui/components/character-sheet.js";
import { Explorer } from "../../../src/units/Explorer.js";
import { InventoryManager } from "../../../src/managers/InventoryManager.js";
import { InventoryContainer } from "../../../src/models/InventoryContainer.js";
import { Item } from "../../../src/items/Item.js";
import vanguardDef from "../../../src/assets/data/classes/vanguard.json" with {
type: "json",
};
// Import SkillTreeUI to register the custom element
import "../../../src/ui/components/SkillTreeUI.js";
describe("UI: CharacterSheet - Inventory Integration", () => {
let element;
let container;
let testUnit;
let inventoryManager;
let mockItemRegistry;
beforeEach(() => {
container = document.createElement("div");
document.body.appendChild(container);
element = document.createElement("character-sheet");
container.appendChild(element);
// Create mock item registry
mockItemRegistry = {
get: (defId) => {
const items = {
"ITEM_RUSTY_BLADE": new Item({
id: "ITEM_RUSTY_BLADE",
name: "Rusty Blade",
type: "WEAPON",
stats: { attack: 3 },
}),
"ITEM_SCRAP_PLATE": new Item({
id: "ITEM_SCRAP_PLATE",
name: "Scrap Plate",
type: "ARMOR",
stats: { defense: 3 },
}),
"ITEM_HEALTH_POTION": new Item({
id: "ITEM_HEALTH_POTION",
name: "Health Potion",
type: "CONSUMABLE",
stats: {},
}),
};
return items[defId] || null;
},
};
// Create inventory manager
const runStash = new InventoryContainer("RUN_LOOT");
const hubStash = new InventoryContainer("HUB_VAULT");
inventoryManager = new InventoryManager(mockItemRegistry, runStash, hubStash);
// Create test Explorer unit
testUnit = new Explorer("test-unit-1", "Test Vanguard", "CLASS_VANGUARD", vanguardDef);
testUnit.classMastery["CLASS_VANGUARD"] = {
level: 5,
xp: 250,
skillPoints: 2,
unlockedNodes: [],
};
testUnit.recalculateBaseStats(vanguardDef);
testUnit.currentHealth = 100;
testUnit.maxHealth = 120;
// Ensure loadout is initialized (should be done in constructor, but ensure it exists)
if (!testUnit.loadout) {
testUnit.loadout = {
mainHand: null,
offHand: null,
body: null,
accessory: null,
belt: [null, null],
};
}
});
afterEach(() => {
if (container.parentNode) {
container.parentNode.removeChild(container);
}
});
// Helper to wait for LitElement update
async function waitForUpdate() {
await element.updateComplete;
await new Promise((resolve) => setTimeout(resolve, 10));
}
// Helper to query shadow DOM
function queryShadow(selector) {
return element.shadowRoot?.querySelector(selector);
}
function queryShadowAll(selector) {
return element.shadowRoot?.querySelectorAll(selector) || [];
}
describe("CoA 1: inventoryManager property", () => {
it("should accept inventoryManager as property", async () => {
element.unit = testUnit;
element.inventoryManager = inventoryManager;
await waitForUpdate();
expect(element.inventoryManager).to.equal(inventoryManager);
});
it("should work without inventoryManager (legacy mode)", async () => {
element.unit = testUnit;
element.inventory = [];
await waitForUpdate();
expect(element.inventoryManager).to.be.null;
// Should still render
const inventoryGrid = queryShadow(".inventory-grid");
expect(inventoryGrid).to.exist;
});
});
describe("CoA 2: rendering stash items", () => {
it("should render items from runStash in DUNGEON mode", async () => {
// Add items to run stash
inventoryManager.runStash.addItem({
uid: "ITEM_001",
defId: "ITEM_RUSTY_BLADE",
isNew: true,
quantity: 1,
});
inventoryManager.runStash.addItem({
uid: "ITEM_002",
defId: "ITEM_SCRAP_PLATE",
isNew: false,
quantity: 1,
});
element.unit = testUnit;
element.inventoryManager = inventoryManager;
element.gameMode = "DUNGEON";
element.activeTab = "INVENTORY";
await waitForUpdate();
const itemCards = queryShadowAll(".item-card");
expect(itemCards.length).to.equal(2);
});
it("should render items from hubStash in HUB mode", async () => {
// Add items to hub stash
inventoryManager.hubStash.addItem({
uid: "ITEM_001",
defId: "ITEM_RUSTY_BLADE",
isNew: true,
quantity: 1,
});
element.unit = testUnit;
element.inventoryManager = inventoryManager;
element.gameMode = "HUB";
element.activeTab = "INVENTORY";
await waitForUpdate();
const itemCards = queryShadowAll(".item-card");
expect(itemCards.length).to.equal(1);
});
it("should convert ItemInstance to UI format with name and type", async () => {
inventoryManager.runStash.addItem({
uid: "ITEM_001",
defId: "ITEM_RUSTY_BLADE",
isNew: true,
quantity: 1,
});
element.unit = testUnit;
element.inventoryManager = inventoryManager;
element.gameMode = "DUNGEON";
element.activeTab = "INVENTORY";
await waitForUpdate();
const itemCard = queryShadow(".item-card");
expect(itemCard).to.exist;
expect(itemCard.getAttribute("title")).to.equal("Rusty Blade");
});
});
describe("CoA 3: equipping items via inventoryManager", () => {
it("should equip item using inventoryManager.equipItem", async () => {
// Add item to stash
const itemInstance = {
uid: "ITEM_001",
defId: "ITEM_RUSTY_BLADE",
isNew: true,
quantity: 1,
};
inventoryManager.runStash.addItem(itemInstance);
element.unit = testUnit;
element.inventoryManager = inventoryManager;
element.gameMode = "DUNGEON";
element.activeTab = "INVENTORY";
element.selectedSlot = "WEAPON";
await waitForUpdate();
let equipEventFired = false;
element.addEventListener("equip-item", () => {
equipEventFired = true;
});
const itemCard = queryShadow(".item-card");
itemCard.click();
await waitForUpdate();
expect(equipEventFired).to.be.true;
// Item should be equipped to loadout
expect(testUnit.loadout.mainHand).to.exist;
expect(testUnit.loadout.mainHand.defId).to.equal("ITEM_RUSTY_BLADE");
// Item should be removed from stash
expect(inventoryManager.runStash.findItem("ITEM_001")).to.be.null;
});
it("should map legacy slot types to new slot types", async () => {
const itemInstance = {
uid: "ITEM_001",
defId: "ITEM_RUSTY_BLADE",
isNew: true,
quantity: 1,
};
inventoryManager.runStash.addItem(itemInstance);
element.unit = testUnit;
element.inventoryManager = inventoryManager;
element.gameMode = "DUNGEON";
element.activeTab = "INVENTORY";
element.selectedSlot = "WEAPON"; // Legacy slot type
await waitForUpdate();
const itemCard = queryShadow(".item-card");
itemCard.click();
await waitForUpdate();
// Should equip to MAIN_HAND (mapped from WEAPON)
expect(testUnit.loadout.mainHand).to.exist;
});
it("should filter inventory by slot type", async () => {
inventoryManager.runStash.addItem({
uid: "ITEM_001",
defId: "ITEM_RUSTY_BLADE",
isNew: true,
quantity: 1,
});
inventoryManager.runStash.addItem({
uid: "ITEM_002",
defId: "ITEM_SCRAP_PLATE",
isNew: false,
quantity: 1,
});
element.unit = testUnit;
element.inventoryManager = inventoryManager;
element.gameMode = "DUNGEON";
element.activeTab = "INVENTORY";
element.selectedSlot = "WEAPON";
await waitForUpdate();
// Should only show weapons
const itemCards = queryShadowAll(".item-card");
expect(itemCards.length).to.equal(1);
});
});
describe("CoA 4: fallback to legacy system", () => {
it("should use legacy inventory array when inventoryManager is not provided", async () => {
const legacyItem = new Item({
id: "ITEM_LEGACY",
name: "Legacy Item",
type: "WEAPON",
stats: { attack: 5 },
});
element.unit = testUnit;
element.inventory = [legacyItem];
element.selectedSlot = "WEAPON";
element.activeTab = "INVENTORY";
await waitForUpdate();
const itemCards = queryShadowAll(".item-card");
expect(itemCards.length).to.equal(1);
});
it("should use legacy equip logic when item has no uid", async () => {
const legacyItem = new Item({
id: "ITEM_LEGACY",
name: "Legacy Item",
type: "WEAPON",
stats: { attack: 5 },
canEquip: () => true,
});
element.unit = testUnit;
element.inventory = [legacyItem];
element.selectedSlot = "WEAPON";
element.activeTab = "INVENTORY";
await waitForUpdate();
let equipEventFired = false;
element.addEventListener("equip-item", () => {
equipEventFired = true;
});
const itemCard = queryShadow(".item-card");
itemCard.click();
await waitForUpdate();
expect(equipEventFired).to.be.true;
// Should use legacy equipment system
expect(testUnit.equipment.weapon).to.equal(legacyItem);
});
});
});