import { fireEvent, render, screen, waitFor } from '@testing-library/react'; import { beforeEach, expect, test, vi } from 'vitest'; import BusinessAssistantPage from '@/pages/BusinessAssistant'; import { apiRequest } from '@/services/api'; vi.mock('@/services/api', () => ({ apiRequest: vi.fn(), jsonOptions: vi.fn((method, body) => ({ method, body: JSON.stringify(body) })), })); vi.mock('@/contexts/BotAccess', () => ({ useBotAccess: () => ({ bot: { bot_id: 'primary', label: 'Test Bot', enabled: true, bot_token_configured: true, sudo_users_id: [], log_group_id: '0', gban_log_group_id: '0', message_dump_chat: '0', role_ids: ['business_assistant_manager'], permissions: ['business_assistant.manage'], identity: { id: '999', username: 'business_bot', name: 'Business Bot', can_connect_to_business: true, }, business_assistant: { base_url: 'https://models.example.com/v1', api_key_configured: true, model: 'support-model', timeout_seconds: 30, max_output_tokens: 600, configured: true, }, ready_to_connect: true, runtime: { state: 'running' }, }, }), })); const settings = { connection_id: 'conn-a', assistant_enabled: true, system_prompt: '只依据知识库回答。', language: 'zh-CN', tone: 'professional', account_daily_limit: 200, customer_daily_limit: 20, human_pause_hours: 24, notification_destination: 'both', ops_group_id: '-100123', timezone: 'Asia/Shanghai', digest_enabled: false, digest_time: '09:00', handoff_message: '请稍候,已转人工。', unsupported_message: '该消息需要人工处理。', }; beforeEach(() => { vi.mocked(apiRequest).mockClear(); vi.mocked(apiRequest).mockImplementation(async (path) => { if (path === '/business-assistant/status') { return { polling_state: 'running', business_mode_supported: true, webhook_conflict: false, webhook_url: '', model_configured: true, usage: { ai_calls: 8, customers: 3, conversations: 3, handoffs: 1, human_paused: 1 }, }; } if (path.startsWith('/business-assistant/connections')) { return { items: [ { connection_id: 'conn-a', user: { id: '900', username: 'owner', first_name: '店主' }, user_chat_id: '900', rights: { can_reply: true, can_read_messages: true }, is_enabled: true, last_event_at: '2026-08-14T08:00:00Z', settings, }, ], total: 1, page: 1, page_size: 100, }; } if (path.startsWith('/business-assistant/settings')) return settings; if (path.startsWith('/business-assistant/knowledge')) { return { items: [ { entry_id: 'entry-1', connection_id: 'conn-a', question: '营业时间是什么?', aliases: ['几点营业'], keywords: ['营业时间'], answer: '每天 09:00 至 18:00 营业。', tags: ['营业'], priority: 10, enabled: true, }, ], total: 1, page: 1, page_size: 20, }; } if (path.startsWith('/business-assistant/conversations')) { return { items: [ { conversation_id: 'conversation-1', connection_id: 'conn-a', chat_id: '501', customer: { id: '501', first_name: '客户甲' }, status: 'handoff', summary: '客户询问退款。', handoff_reason: 'sensitive_request', last_message_at: '2026-08-14T08:01:00Z', }, ], total: 1, page: 1, page_size: 20, }; } if (path.startsWith('/business-assistant/usage')) { return { ai_calls: 8, customers: 3, conversations: 3, handoffs: 1, human_paused: 1 }; } throw new Error(`Unexpected request: ${path}`); }); }); test('展示运行状态、连接权限,并用最新搜索词查询知识库', async () => { render(); expect(screen.getByRole('heading', { name: '智能接待' })).toBeInTheDocument(); expect((await screen.findAllByText('店主')).length).toBeGreaterThan(0); expect(screen.getByText('允许回复')).toBeInTheDocument(); expect(screen.getByText('允许标记已读')).toBeInTheDocument(); fireEvent.click(await screen.findByRole('tab', { name: /知识库/ })); expect(await screen.findByText('营业时间是什么?')).toBeInTheDocument(); const search = screen.getByLabelText('搜索知识库'); fireEvent.change(search, { target: { value: '配送' } }); fireEvent.keyDown(search, { key: 'Enter', code: 'Enter' }); await waitFor(() => { expect( vi.mocked(apiRequest).mock.calls.some(([path]) => String(path).includes('query=%E9%85%8D%E9%80%81'), ), ).toBe(true); }); });