216 lines
9.3 KiB
TypeScript
216 lines
9.3 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
|
|
// ─── Test: EquipmentTab barrel export ──────────────────────────────────────────
|
|
|
|
describe('EquipmentTab module structure', () => {
|
|
it('exports EquipmentTab from barrel index', async () => {
|
|
const mod = await import('./EquipmentTab');
|
|
expect(mod.EquipmentTab).toBeDefined();
|
|
expect(typeof mod.EquipmentTab).toBe('function');
|
|
});
|
|
|
|
it('EquipmentTab has correct displayName', async () => {
|
|
const { EquipmentTab } = await import('./EquipmentTab');
|
|
expect(EquipmentTab.displayName).toBe('EquipmentTab');
|
|
});
|
|
});
|
|
|
|
// ─── Test: Barrel export includes EquipmentTab ─────────────────────────────────
|
|
|
|
describe('Tab barrel export', () => {
|
|
it('includes EquipmentTab in the tabs index', async () => {
|
|
const mod = await import('@/components/game/tabs');
|
|
expect(mod.EquipmentTab).toBeDefined();
|
|
expect(typeof mod.EquipmentTab).toBe('function');
|
|
});
|
|
});
|
|
|
|
// ─── Test: Equipment slot definitions ──────────────────────────────────────────
|
|
|
|
describe('Equipment slot definitions', () => {
|
|
it('has exactly 8 equipment slots', async () => {
|
|
const { EQUIPMENT_SLOTS } = await import('@/lib/game/data/equipment');
|
|
expect(EQUIPMENT_SLOTS).toHaveLength(8);
|
|
});
|
|
|
|
it('all slots have display names', async () => {
|
|
const { SLOT_NAMES, EQUIPMENT_SLOTS } = await import('@/lib/game/data/equipment');
|
|
for (const slot of EQUIPMENT_SLOTS) {
|
|
expect(SLOT_NAMES[slot]).toBeDefined();
|
|
expect(SLOT_NAMES[slot].length).toBeGreaterThan(0);
|
|
}
|
|
});
|
|
|
|
it('includes mainHand, offHand, head, body, hands, feet, accessory1, accessory2', async () => {
|
|
const { EQUIPMENT_SLOTS } = await import('@/lib/game/data/equipment');
|
|
expect(EQUIPMENT_SLOTS).toContain('mainHand');
|
|
expect(EQUIPMENT_SLOTS).toContain('offHand');
|
|
expect(EQUIPMENT_SLOTS).toContain('head');
|
|
expect(EQUIPMENT_SLOTS).toContain('body');
|
|
expect(EQUIPMENT_SLOTS).toContain('hands');
|
|
expect(EQUIPMENT_SLOTS).toContain('feet');
|
|
expect(EQUIPMENT_SLOTS).toContain('accessory1');
|
|
expect(EQUIPMENT_SLOTS).toContain('accessory2');
|
|
});
|
|
});
|
|
|
|
// ─── Test: Equipment type definitions ──────────────────────────────────────────
|
|
|
|
describe('Equipment type definitions', () => {
|
|
it('all equipment types have required fields', async () => {
|
|
const { EQUIPMENT_TYPES } = await import('@/lib/game/data/equipment');
|
|
for (const [id, type] of Object.entries(EQUIPMENT_TYPES)) {
|
|
expect(type.id).toBe(id);
|
|
expect(type.name).toBeTruthy();
|
|
expect(type.category).toBeTruthy();
|
|
expect(type.slot).toBeTruthy();
|
|
expect(type.baseCapacity).toBeGreaterThan(0);
|
|
}
|
|
});
|
|
|
|
it('accessory category types can equip in accessory slots', async () => {
|
|
const { EQUIPMENT_TYPES, getValidSlotsForEquipmentType } = await import('@/lib/game/data/equipment');
|
|
const accessories = Object.values(EQUIPMENT_TYPES).filter((t) => t.category === 'accessory');
|
|
expect(accessories.length).toBeGreaterThan(0);
|
|
for (const acc of accessories) {
|
|
const slots = getValidSlotsForEquipmentType(acc);
|
|
expect(slots).toContain('accessory1');
|
|
expect(slots).toContain('accessory2');
|
|
}
|
|
});
|
|
});
|
|
|
|
// ─── Test: Starting equipment ──────────────────────────────────────────────────
|
|
|
|
describe('Starting equipment', () => {
|
|
it('crafting store initial state has valid equippedInstances', async () => {
|
|
const { useCraftingStore } = await import('@/lib/game/stores/craftingStore');
|
|
const state = useCraftingStore.getState();
|
|
|
|
expect(state.equippedInstances.mainHand).toBeTruthy();
|
|
expect(state.equippedInstances.body).toBeTruthy();
|
|
expect(state.equippedInstances.feet).toBeTruthy();
|
|
expect(state.equippedInstances.offHand).toBeNull();
|
|
expect(state.equippedInstances.head).toBeNull();
|
|
expect(state.equippedInstances.hands).toBeNull();
|
|
expect(state.equippedInstances.accessory1).toBeNull();
|
|
expect(state.equippedInstances.accessory2).toBeNull();
|
|
|
|
expect(Object.keys(state.equipmentInstances).length).toBe(3);
|
|
});
|
|
|
|
it('starting equipment instances have valid fields', async () => {
|
|
const { useCraftingStore } = await import('@/lib/game/stores/craftingStore');
|
|
const { equipmentInstances } = useCraftingStore.getState();
|
|
|
|
for (const instance of Object.values(equipmentInstances)) {
|
|
expect(instance.instanceId).toBeTruthy();
|
|
expect(instance.typeId).toBeTruthy();
|
|
expect(instance.name).toBeTruthy();
|
|
expect(instance.rarity).toBe('common');
|
|
expect(instance.quality).toBe(100);
|
|
expect(instance.usedCapacity).toBeGreaterThanOrEqual(0);
|
|
expect(instance.totalCapacity).toBeGreaterThan(0);
|
|
}
|
|
});
|
|
});
|
|
|
|
// ─── Test: Equipment actions ───────────────────────────────────────────────────
|
|
|
|
describe('Equipment actions', () => {
|
|
it('equipItem is a function', async () => {
|
|
const { equipItem } = await import('@/lib/game/crafting-actions/equipment-actions');
|
|
expect(typeof equipItem).toBe('function');
|
|
});
|
|
|
|
it('unequipItem is a function', async () => {
|
|
const { unequipItem } = await import('@/lib/game/crafting-actions/equipment-actions');
|
|
expect(typeof unequipItem).toBe('function');
|
|
});
|
|
|
|
it('deleteEquipmentInstance is a function', async () => {
|
|
const { deleteEquipmentInstance } = await import('@/lib/game/crafting-actions/equipment-actions');
|
|
expect(typeof deleteEquipmentInstance).toBe('function');
|
|
});
|
|
|
|
it('createEquipmentInstance is a function', async () => {
|
|
const { createEquipmentInstance } = await import('@/lib/game/crafting-actions/equipment-actions');
|
|
expect(typeof createEquipmentInstance).toBe('function');
|
|
});
|
|
});
|
|
|
|
// ─── Test: Equipment effects ───────────────────────────────────────────────────
|
|
|
|
describe('Equipment effects computation', () => {
|
|
it('computeEquipmentEffects returns empty for no equipment', async () => {
|
|
const { computeEquipmentEffects } = await import('@/lib/game/effects');
|
|
const result = computeEquipmentEffects({}, { mainHand: null, offHand: null, head: null, body: null, hands: null, feet: null, accessory1: null, accessory2: null });
|
|
expect(Object.keys(result.bonuses)).toHaveLength(0);
|
|
expect(Object.keys(result.multipliers)).toHaveLength(0);
|
|
expect(result.specials.size).toBe(0);
|
|
});
|
|
|
|
it('computeEquipmentEffects detects enchantment bonuses', async () => {
|
|
const { computeEquipmentEffects } = await import('@/lib/game/effects');
|
|
const instances = {
|
|
test1: {
|
|
instanceId: 'test1',
|
|
typeId: 'basicStaff',
|
|
name: 'Test Staff',
|
|
enchantments: [{ effectId: 'spell_manaBolt', stacks: 1, actualCost: 50 }],
|
|
usedCapacity: 50,
|
|
totalCapacity: 50,
|
|
rarity: 'common' as const,
|
|
quality: 100,
|
|
tags: [],
|
|
},
|
|
};
|
|
const equipped = { mainHand: 'test1', offHand: null, head: null, body: null, hands: null, feet: null, accessory1: null, accessory2: null };
|
|
const result = computeEquipmentEffects(instances, equipped);
|
|
// Should at least not crash and return a valid structure
|
|
expect(result).toHaveProperty('bonuses');
|
|
expect(result).toHaveProperty('multipliers');
|
|
expect(result).toHaveProperty('specials');
|
|
});
|
|
});
|
|
|
|
// ─── Test: File size limits ────────────────────────────────────────────────────
|
|
|
|
describe('File size limits (400 lines max)', () => {
|
|
it('EquipmentTab.tsx is under 400 lines', async () => {
|
|
const fs = await import('fs');
|
|
const path = await import('path');
|
|
const filePath = path.join(__dirname, 'EquipmentTab.tsx');
|
|
const content = fs.readFileSync(filePath, 'utf-8');
|
|
const lines = content.split('\n').length;
|
|
expect(lines).toBeLessThan(400);
|
|
});
|
|
|
|
it('EquipmentSlotGrid.tsx is under 400 lines', async () => {
|
|
const fs = await import('fs');
|
|
const path = await import('path');
|
|
const filePath = path.join(__dirname, 'EquipmentTab/EquipmentSlotGrid.tsx');
|
|
const content = fs.readFileSync(filePath, 'utf-8');
|
|
const lines = content.split('\n').length;
|
|
expect(lines).toBeLessThan(400);
|
|
});
|
|
|
|
it('InventoryList.tsx is under 400 lines', async () => {
|
|
const fs = await import('fs');
|
|
const path = await import('path');
|
|
const filePath = path.join(__dirname, 'EquipmentTab/InventoryList.tsx');
|
|
const content = fs.readFileSync(filePath, 'utf-8');
|
|
const lines = content.split('\n').length;
|
|
expect(lines).toBeLessThan(400);
|
|
});
|
|
|
|
it('EquipmentEffectsSummary.tsx is under 400 lines', async () => {
|
|
const fs = await import('fs');
|
|
const path = await import('path');
|
|
const filePath = path.join(__dirname, 'EquipmentTab/EquipmentEffectsSummary.tsx');
|
|
const content = fs.readFileSync(filePath, 'utf-8');
|
|
const lines = content.split('\n').length;
|
|
expect(lines).toBeLessThan(400);
|
|
});
|
|
});
|