/* @vitest-environment jsdom */ import { render, screen } from '@testing-library/react'; import { expect, test, vi } from 'vitest'; import type { RuntimeStoryForgeRecipeView } from '../../packages/shared/src/contracts/rpgRuntimeStoryState'; import { type Character, type InventoryItem, WorldType } from '../types'; import { InventoryPanel } from './InventoryPanel'; const inventoryItem: InventoryItem = { id: 'training-token', category: '材料', name: '练习石', quantity: 1, rarity: 'common', tags: [], }; const documentItem: InventoryItem = { id: 'thread-note', category: '文书', name: '潮汐证词', quantity: 1, rarity: 'common', tags: ['document'], description: '记录着潮汐线索。', }; const forgeRecipe: RuntimeStoryForgeRecipeView = { id: 'forge-tide-amulet', name: '潮汐护符', kind: 'forge', description: '用于测试工坊需求状态。', resultLabel: '潮汐护符', currencyCost: 5, currencyText: '5 贝币', requirements: [ { id: 'iron', label: '铁矿', quantity: 2, owned: 2, }, { id: 'wood', label: '木材', quantity: 1, owned: 0, }, ], canCraft: false, disabledReason: '材料不足', action: { functionId: 'craft', actionText: '锻造', enabled: false, reason: '材料不足', }, }; test('背包工坊材料需求状态复用暗色平台胶囊标签', () => { render( false)} onEquipItem={vi.fn(async () => false)} onCraftRecipe={vi.fn(async () => false)} onDismantleItem={vi.fn(async () => false)} onReforgeItem={vi.fn(async () => false)} />, ); const metRequirement = screen.getByText('铁矿 2/2'); const missingRequirement = screen.getByText('木材 0/1'); const forgePanel = screen.getByText('工坊').closest('section'); const recipePanel = screen.getByText('潮汐护符').closest('section'); const forgeButton = screen.getByRole('button', { name: '锻造' }); expect(metRequirement.className).toContain('rounded-full'); expect(metRequirement.className).toContain('font-black'); expect(metRequirement.className).toContain('bg-emerald-500/10'); expect(missingRequirement.className).toContain('rounded-full'); expect(missingRequirement.className).toContain('font-black'); expect(missingRequirement.className).toContain('bg-black/20'); expect(missingRequirement.className).toContain('text-zinc-400'); expect(forgePanel?.className).toContain('border-white/10'); expect(forgePanel?.className).toContain('bg-black/25'); expect(recipePanel?.className).toContain('border-white/10'); expect(recipePanel?.className).toContain('bg-black/25'); expect(forgeButton.className).toContain('platform-action-button--editor-dark'); expect(forgeButton.className).toContain('rounded-lg'); expect(forgeButton.className).toContain('bg-emerald-400'); expect(forgeButton.className).toContain('disabled:bg-black/20'); }); test('背包文书和故事档案区块复用暗色 PlatformSubpanel chrome', () => { render( false)} onEquipItem={vi.fn(async () => false)} onCraftRecipe={vi.fn(async () => false)} onDismantleItem={vi.fn(async () => false)} onReforgeItem={vi.fn(async () => false)} />, ); const documentPanel = screen.getByText('文书与证据').closest('section'); const documentButton = screen.getByRole('button', { name: /潮汐证词/, }); const storyPanel = screen.getByText('故事档案').closest('section'); const qaMessage = screen.getByText('QA:叙事链路稳定。'); const codexPanel = screen.getByText('潮汐档案').closest('section'); expect(documentPanel?.className).toContain('border-white/10'); expect(documentPanel?.className).toContain('bg-black/25'); expect(documentButton.className).toContain('border-white/10'); expect(documentButton.className).toContain('bg-black/25'); expect(storyPanel?.className).toContain('border-white/10'); expect(storyPanel?.className).toContain('bg-black/25'); expect(qaMessage.className).toContain('platform-status-message'); expect(qaMessage.className).toContain('border-amber-300/15'); expect(qaMessage.className).toContain('bg-amber-500/10'); expect(codexPanel?.className).toContain('border-white/10'); expect(codexPanel?.className).toContain('bg-black/25'); });