import { TestBed } from '@angular/core/testing'; import { vi } from 'vitest'; import type { InventoryItem } from '../../core/api/game-api.models'; import { InventoryDetailPanelComponent } from './inventory-detail-panel.component'; const wornSword: InventoryItem = { id: 'item-sword', quantity: 1, equipped: true, item: { key: 'worn-short-sword', name: 'Worn Shortsword', description: 'Item description.', rarity: 'COMMON', equipmentSlot: 'WEAPON', weaponDamage: 8, bonusAttack: 0, bonusHp: 0, bonusArmor: 0, iconPath: '/images/items/worn-short-sword.png', }, }; const banditBlade: InventoryItem = { id: 'item-blade', quantity: 1, equipped: false, item: { key: 'bandit-blade', name: 'Bandit Blade', description: 'Item description.', rarity: 'COMMON', equipmentSlot: 'WEAPON', weaponDamage: 11, bonusAttack: 1, bonusHp: 0, bonusArmor: 0, iconPath: '/images/items/bandit-blade.png', }, }; const ashPelt: InventoryItem = { id: 'item-pelt', quantity: 3, equipped: false, item: { key: 'ash-pelt', name: 'Ash Pelt', description: 'Item description.', rarity: 'COMMON', equipmentSlot: null, weaponDamage: 0, bonusAttack: 0, bonusHp: 0, bonusArmor: 0, iconPath: '/images/items/ash-pelt.png', }, }; async function setup(overrides: { item?: InventoryItem | null; equippedItemInSlot?: InventoryItem | null; busy?: boolean; }) { TestBed.resetTestingModule(); await TestBed.configureTestingModule({ imports: [InventoryDetailPanelComponent] }).compileComponents(); const fixture = TestBed.createComponent(InventoryDetailPanelComponent); fixture.componentRef.setInput('item', overrides.item ?? null); fixture.componentRef.setInput('equippedItemInSlot', overrides.equippedItemInSlot ?? null); fixture.componentRef.setInput('busy', overrides.busy ?? false); fixture.detectChanges(); return fixture; } describe('InventoryDetailPanelComponent', () => { it('shows a placeholder when nothing is selected', async () => { const fixture = await setup({ item: null }); expect((fixture.nativeElement as HTMLElement).querySelector('[data-detail-empty]')).not.toBeNull(); }); it('shows Equipped for the currently equipped item, with no equip button', async () => { const fixture = await setup({ item: wornSword }); const element = fixture.nativeElement as HTMLElement; expect(element.querySelector('[data-detail-equipped]')?.textContent).toContain('Equipped'); expect(element.querySelector('[data-detail-equip]')).toBeNull(); }); it('refuses to offer an equip button for a non-equippable item', async () => { const fixture = await setup({ item: ashPelt }); const element = fixture.nativeElement as HTMLElement; expect(element.textContent).toContain('Not equippable'); expect(element.querySelector('[data-detail-equip]')).toBeNull(); expect(element.querySelector('[data-detail-equipped]')).toBeNull(); }); it('shows the item flavour text from the server', async () => { const fixture = await setup({ item: { ...banditBlade, item: { ...banditBlade.item, description: 'A roughly serrated blade, forged for quick raids.' }, }, }); expect((fixture.nativeElement as HTMLElement).textContent).toContain( 'A roughly serrated blade, forged for quick raids.', ); }); it('shows the stat comparison against the equipped item in the same slot', async () => { const fixture = await setup({ item: banditBlade, equippedItemInSlot: wornSword }); const text = (fixture.nativeElement as HTMLElement).querySelector('[data-detail-stats]')?.textContent ?? ''; expect(text).toContain('11'); expect(text).toContain('+3'); expect(text).toContain('+1'); }); it('always shows the plain equip button for an owned equippable item', async () => { const fixture = await setup({ item: banditBlade }); const element = fixture.nativeElement as HTMLElement; const button = element.querySelector('[data-detail-equip]'); expect(button?.disabled).toBe(false); expect(button?.textContent?.trim()).toBe('Equip'); }); it('emits equip with the characterItemId when Equip is clicked', async () => { const fixture = await setup({ item: banditBlade }); const emitted: string[] = []; fixture.componentInstance.equip.subscribe((id: string) => emitted.push(id)); (fixture.nativeElement as HTMLElement).querySelector('[data-detail-equip]')?.click(); expect(emitted).toEqual(['item-blade']); }); it('disables the equip button while busy', async () => { const fixture = await setup({ item: banditBlade, busy: true }); const button = (fixture.nativeElement as HTMLElement).querySelector('[data-detail-equip]'); expect(button?.disabled).toBe(true); }); });