01c0028b87
账号安全面板空态统一复用 PlatformEmptyState 登录入口不可用提示改为复用 PlatformEmptyState RPG运行态底部与覆盖层动作统一委托 PlatformActionButton 背包工坊按钮回到共享 success tone 更新 PlatformUiKit 收口文档与团队决策记录
166 lines
5.4 KiB
TypeScript
166 lines
5.4 KiB
TypeScript
/* @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(
|
|
<InventoryPanel
|
|
playerCharacter={{} as Character}
|
|
worldType={WorldType.CUSTOM}
|
|
playerInventory={[inventoryItem]}
|
|
playerCurrency={0}
|
|
playerHp={10}
|
|
playerMaxHp={10}
|
|
playerMana={5}
|
|
playerMaxMana={5}
|
|
inBattle={false}
|
|
forgeRecipes={[forgeRecipe]}
|
|
onUseItem={vi.fn(async () => 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(
|
|
<InventoryPanel
|
|
playerCharacter={{} as Character}
|
|
worldType={WorldType.CUSTOM}
|
|
playerInventory={[documentItem]}
|
|
playerCurrency={0}
|
|
playerHp={10}
|
|
playerMaxHp={10}
|
|
playerMana={5}
|
|
playerMaxMana={5}
|
|
inBattle={false}
|
|
forgeRecipes={[]}
|
|
narrativeQaReport={{
|
|
generatedAt: '2026-06-10T00:00:00.000Z',
|
|
issues: [],
|
|
summary: '叙事链路稳定。',
|
|
}}
|
|
narrativeCodex={[
|
|
{
|
|
id: 'codex-tide',
|
|
title: '潮汐档案',
|
|
entries: [
|
|
{
|
|
id: 'entry-tide',
|
|
title: '旧港线索',
|
|
summary: '证词指向旧港。',
|
|
category: 'document',
|
|
relatedIds: [],
|
|
},
|
|
],
|
|
},
|
|
]}
|
|
onUseItem={vi.fn(async () => 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');
|
|
});
|