114 lines
3.5 KiB
TypeScript
114 lines
3.5 KiB
TypeScript
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
import { render, screen, waitFor } from '@testing-library/react';
|
|
import { MapCharacterPanel } from '../../src/components/characters/MapCharacterPanel';
|
|
|
|
const {
|
|
mockGetShopItems,
|
|
mockGetGoldBalance,
|
|
mockSendNpcMessage,
|
|
mockGetNpcChatSession,
|
|
mockStartNpcChat,
|
|
} = vi.hoisted(() => ({
|
|
mockGetShopItems: vi.fn().mockResolvedValue([]),
|
|
mockGetGoldBalance: vi.fn().mockResolvedValue(300),
|
|
mockSendNpcMessage: vi.fn().mockResolvedValue({
|
|
messages: [],
|
|
balance: { gold: 300 },
|
|
negotiation: { status: 'active' },
|
|
shop_items: [],
|
|
}),
|
|
mockGetNpcChatSession: vi.fn().mockResolvedValue({ messages: [] }),
|
|
mockStartNpcChat: vi.fn().mockResolvedValue({ messages: [] }),
|
|
}));
|
|
|
|
const mockUseCharacter = vi.fn();
|
|
|
|
vi.mock('../../src/store/characterStore', () => ({
|
|
useCharacter: () => mockUseCharacter(),
|
|
}));
|
|
|
|
vi.mock('../../src/services/api', () => ({
|
|
apiService: {
|
|
getShopItems: mockGetShopItems,
|
|
getGoldBalance: mockGetGoldBalance,
|
|
sendNpcMessage: mockSendNpcMessage,
|
|
getNpcChatSession: mockGetNpcChatSession,
|
|
startNpcChat: mockStartNpcChat,
|
|
},
|
|
}));
|
|
|
|
describe('MapCharacterPanel rich chat formatting', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
mockGetShopItems.mockResolvedValue([]);
|
|
mockGetGoldBalance.mockResolvedValue(300);
|
|
mockSendNpcMessage.mockResolvedValue({
|
|
messages: [],
|
|
balance: { gold: 300 },
|
|
negotiation: { status: 'active' },
|
|
shop_items: [],
|
|
});
|
|
mockGetNpcChatSession.mockResolvedValue({ messages: [] });
|
|
mockStartNpcChat.mockResolvedValue({ messages: [] });
|
|
mockUseCharacter.mockReturnValue({
|
|
activeCharacter: 'frodo',
|
|
setActiveCharacter: vi.fn(),
|
|
isChatLoading: false,
|
|
chatMessages: [
|
|
{
|
|
role: 'assistant',
|
|
content: "- **Elven Cloak** — ask **88 Gold**\n- **Ranger's Rope** — ask **40 Gold**",
|
|
format: 'markdown',
|
|
type: 'assistant',
|
|
},
|
|
],
|
|
setChatMessages: vi.fn(),
|
|
setChatLoading: vi.fn(),
|
|
});
|
|
});
|
|
|
|
it('renders bold prices and list-like bargaining messages', () => {
|
|
render(<MapCharacterPanel />);
|
|
|
|
expect(screen.getByText('Elven Cloak', { selector: 'strong' })).toBeTruthy();
|
|
expect(screen.getByText('88 Gold', { selector: 'strong' })).toBeTruthy();
|
|
expect(screen.getByText("Ranger's Rope", { selector: 'strong' })).toBeTruthy();
|
|
});
|
|
|
|
it('loads the wares catalog directly instead of opening with generic chat opener', async () => {
|
|
const setChatMessages = vi.fn();
|
|
const catalogMessages = [
|
|
{
|
|
role: 'assistant',
|
|
content: 'Available wares to bargain for:\n- **Shire Herb Satchel** — ask **120 Gold** (id: #2)',
|
|
format: 'markdown',
|
|
type: 'assistant',
|
|
metadata: { kind: 'shop-catalog' },
|
|
},
|
|
];
|
|
|
|
mockUseCharacter.mockReturnValue({
|
|
activeCharacter: 'sam',
|
|
setActiveCharacter: vi.fn(),
|
|
isChatLoading: false,
|
|
chatMessages: [],
|
|
setChatMessages,
|
|
setChatLoading: vi.fn(),
|
|
});
|
|
mockGetNpcChatSession.mockResolvedValue({ messages: [] });
|
|
mockSendNpcMessage.mockResolvedValue({
|
|
messages: catalogMessages,
|
|
balance: { gold: 300 },
|
|
negotiation: { status: 'catalog' },
|
|
shop_items: [],
|
|
});
|
|
|
|
render(<MapCharacterPanel />);
|
|
|
|
await waitFor(() => {
|
|
expect(mockSendNpcMessage).toHaveBeenCalledWith('sam', 'shop');
|
|
});
|
|
expect(mockStartNpcChat).not.toHaveBeenCalled();
|
|
expect(setChatMessages).toHaveBeenCalledWith(catalogMessages);
|
|
});
|
|
}); |