test(web): cover the same-slot equipped-item filter in InventoryPageComponent
The equippedItemInSelectedSlot computed is the riskiest logic this component owns, but every existing test mocked selectedItem() as null, so the slot-matching branch never ran and a regression to "any equipped item" would have gone unnoticed. Adds a test with three items across two slots that asserts the detail panel receives the same-slot equipped item, not just any equipped item.
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
import { signal } from '@angular/core';
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { vi } from 'vitest';
|
||||
import type { CharacterResponse, EquipmentResponse, InventoryResponse } from '../../core/api/game-api.models';
|
||||
import type { CharacterResponse, EquipmentResponse, InventoryItem, InventoryResponse } from '../../core/api/game-api.models';
|
||||
import { WorldStore } from '../world/world.store';
|
||||
import { InventoryDetailPanelComponent } from './inventory-detail-panel.component';
|
||||
import { InventoryPageComponent } from './inventory-page.component';
|
||||
import { InventoryStore } from './inventory.store';
|
||||
|
||||
@@ -70,17 +72,23 @@ const character: CharacterResponse = {
|
||||
currentLocation: { id: 'loc-1', key: 'south-gate', name: 'Südtor' },
|
||||
};
|
||||
|
||||
async function setup() {
|
||||
interface SetupOptions {
|
||||
inventoryData?: InventoryResponse;
|
||||
selectedItemId?: string | null;
|
||||
selectedItem?: InventoryItem | null;
|
||||
}
|
||||
|
||||
async function setup(options: SetupOptions = {}) {
|
||||
const inventoryStore = {
|
||||
inventory: signal(inventory),
|
||||
inventory: signal(options.inventoryData ?? inventory),
|
||||
equipment: signal(equipment),
|
||||
selectedItemId: signal<string | null>(null),
|
||||
selectedItemId: signal<string | null>(options.selectedItemId ?? null),
|
||||
loading: signal(false),
|
||||
equipping: signal(false),
|
||||
error: signal<string | null>(null),
|
||||
load: vi.fn(() => Promise.resolve()),
|
||||
selectItem: vi.fn(),
|
||||
selectedItem: vi.fn(() => null),
|
||||
selectedItem: vi.fn(() => options.selectedItem ?? null),
|
||||
equip: vi.fn(() => Promise.resolve()),
|
||||
};
|
||||
const worldStore = { character: signal(character) };
|
||||
@@ -140,4 +148,44 @@ describe('InventoryPageComponent', () => {
|
||||
expect(text).toContain('6');
|
||||
expect(text).toContain('8');
|
||||
});
|
||||
|
||||
it('passes the equipped item from the SAME slot as the selection — not just any equipped item — to the detail panel', async () => {
|
||||
// item-helm (HEAD, equipped) is placed before item-sword (WEAPON, equipped) so that a
|
||||
// regression which drops the equipmentSlot match (i.e. "find the first equipped item")
|
||||
// would surface item-helm instead of item-sword, and this test would fail.
|
||||
const threeItemInventory: InventoryResponse = {
|
||||
items: [
|
||||
{
|
||||
id: 'item-helm',
|
||||
quantity: 1,
|
||||
equipped: true,
|
||||
item: {
|
||||
key: 'iron-helm',
|
||||
name: 'Eiserner Helm',
|
||||
rarity: 'COMMON',
|
||||
equipmentSlot: 'HEAD',
|
||||
requiredLevel: 1,
|
||||
weaponDamage: 0,
|
||||
bonusAttack: 0,
|
||||
bonusHp: 5,
|
||||
bonusArmor: 2,
|
||||
iconPath: '/images/items/iron-helm.png',
|
||||
},
|
||||
},
|
||||
inventory.items[0], // item-sword, WEAPON, equipped
|
||||
inventory.items[1], // item-blade, WEAPON, not equipped — this is the selection
|
||||
],
|
||||
};
|
||||
|
||||
const { fixture } = await setup({
|
||||
inventoryData: threeItemInventory,
|
||||
selectedItemId: 'item-blade',
|
||||
selectedItem: threeItemInventory.items[2],
|
||||
});
|
||||
|
||||
const panel = fixture.debugElement.query(By.directive(InventoryDetailPanelComponent))
|
||||
.componentInstance as InventoryDetailPanelComponent;
|
||||
|
||||
expect(panel.equippedItemInSlot()?.id).toBe('item-sword');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user