import { cleanup, render, screen, waitFor } from '@testing-library/react' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import BasicAppPreview from './basic-app-preview' vi.mock('react-i18next', () => ({ useTranslation: () => ({ t: (key: string) => key, }), })) const mockUseGetTryAppInfo = vi.fn() const mockUseAllToolProviders = vi.fn() const mockUseGetTryAppDataSets = vi.fn() const mockUseTextGenerationCurrentProviderAndModelAndModelList = vi.fn() vi.mock('@/service/use-try-app', () => ({ useGetTryAppInfo: (...args: unknown[]) => mockUseGetTryAppInfo(...args), useGetTryAppDataSets: (...args: unknown[]) => mockUseGetTryAppDataSets(...args), })) vi.mock('@/service/use-tools', () => ({ useAllToolProviders: () => mockUseAllToolProviders(), })) vi.mock('../../../header/account-setting/model-provider-page/hooks', () => ({ useTextGenerationCurrentProviderAndModelAndModelList: (...args: unknown[]) => mockUseTextGenerationCurrentProviderAndModelAndModelList(...args), })) vi.mock('@/hooks/use-breakpoints', () => ({ default: () => 'pc', MediaType: { mobile: 'mobile', pc: 'pc', }, })) vi.mock('@/app/components/app/configuration/config', () => ({ default: () =>
Config
, })) vi.mock('@/app/components/app/configuration/debug', () => ({ default: () =>
Debug
, })) vi.mock('@/app/components/base/features', () => ({ FeaturesProvider: ({ children }: { children: React.ReactNode }) => (
{children}
), })) const createMockAppDetail = (mode: string = 'chat'): Record => ({ id: 'test-app-id', name: 'Test App', description: 'Test Description', mode, site: { title: 'Test Site Title', icon: '🚀', icon_type: 'emoji', icon_background: '#FFFFFF', icon_url: '', }, model_config: { model: { provider: 'langgenius/openai/openai', name: 'gpt-4', mode: 'chat', }, pre_prompt: 'You are a helpful assistant', user_input_form: [] as unknown[], external_data_tools: [] as unknown[], dataset_configs: { datasets: { datasets: [] as unknown[], }, }, agent_mode: { tools: [] as unknown[], enabled: false, }, more_like_this: { enabled: false }, opening_statement: 'Hello!', suggested_questions: ['Question 1'], sensitive_word_avoidance: null, speech_to_text: null, text_to_speech: null, file_upload: null as unknown, suggested_questions_after_answer: null, retriever_resource: null, annotation_reply: null, }, deleted_tools: [] as unknown[], }) describe('BasicAppPreview', () => { beforeEach(() => { mockUseGetTryAppInfo.mockReturnValue({ data: createMockAppDetail(), isLoading: false, }) mockUseAllToolProviders.mockReturnValue({ data: [], isLoading: false, }) mockUseGetTryAppDataSets.mockReturnValue({ data: { data: [] }, isLoading: false, }) mockUseTextGenerationCurrentProviderAndModelAndModelList.mockReturnValue({ currentModel: { features: [], }, }) }) afterEach(() => { cleanup() vi.clearAllMocks() }) describe('loading state', () => { it('renders loading when app detail is loading', () => { mockUseGetTryAppInfo.mockReturnValue({ data: null, isLoading: true, }) render() expect(screen.getByRole('status')).toBeInTheDocument() }) it('renders loading when tool providers are loading', () => { mockUseAllToolProviders.mockReturnValue({ data: null, isLoading: true, }) render() expect(screen.getByRole('status')).toBeInTheDocument() }) it('renders loading when datasets are loading', () => { mockUseGetTryAppDataSets.mockReturnValue({ data: null, isLoading: true, }) render() expect(screen.getByRole('status')).toBeInTheDocument() }) }) describe('content rendering', () => { it('renders Config component when data is loaded', async () => { render() await waitFor(() => { expect(screen.getByTestId('config-component')).toBeInTheDocument() }) }) it('renders Debug component when data is loaded on PC', async () => { render() await waitFor(() => { expect(screen.getByTestId('debug-component')).toBeInTheDocument() }) }) it('renders FeaturesProvider', async () => { render() await waitFor(() => { expect(screen.getByTestId('features-provider')).toBeInTheDocument() }) }) }) describe('different app modes', () => { it('handles chat mode', async () => { mockUseGetTryAppInfo.mockReturnValue({ data: createMockAppDetail('chat'), isLoading: false, }) render() await waitFor(() => { expect(screen.getByTestId('config-component')).toBeInTheDocument() }) }) it('handles completion mode', async () => { mockUseGetTryAppInfo.mockReturnValue({ data: createMockAppDetail('completion'), isLoading: false, }) render() await waitFor(() => { expect(screen.getByTestId('config-component')).toBeInTheDocument() }) }) it('handles agent-chat mode', async () => { const agentAppDetail = createMockAppDetail('agent-chat') const modelConfig = agentAppDetail.model_config as Record modelConfig.agent_mode = { tools: [ { provider_id: 'test-provider', provider_name: 'test-provider', provider_type: 'builtin', tool_name: 'test-tool', enabled: true, }, ], enabled: true, max_iteration: 5, } mockUseGetTryAppInfo.mockReturnValue({ data: agentAppDetail, isLoading: false, }) mockUseAllToolProviders.mockReturnValue({ data: [ { id: 'test-provider', is_team_authorization: true, icon: '/icon.png', }, ], isLoading: false, }) render() await waitFor(() => { expect(screen.getByTestId('config-component')).toBeInTheDocument() }) }) }) describe('hook calls', () => { it('calls useGetTryAppInfo with correct appId', () => { render() expect(mockUseGetTryAppInfo).toHaveBeenCalledWith('my-app-id') }) it('calls useTextGenerationCurrentProviderAndModelAndModelList with model config', async () => { render() await waitFor(() => { expect(mockUseTextGenerationCurrentProviderAndModelAndModelList).toHaveBeenCalled() }) }) }) describe('model features', () => { it('handles vision feature', async () => { mockUseTextGenerationCurrentProviderAndModelAndModelList.mockReturnValue({ currentModel: { features: ['vision'], }, }) render() await waitFor(() => { expect(screen.getByTestId('config-component')).toBeInTheDocument() }) }) it('handles document feature', async () => { mockUseTextGenerationCurrentProviderAndModelAndModelList.mockReturnValue({ currentModel: { features: ['document'], }, }) render() await waitFor(() => { expect(screen.getByTestId('config-component')).toBeInTheDocument() }) }) it('handles audio feature', async () => { mockUseTextGenerationCurrentProviderAndModelAndModelList.mockReturnValue({ currentModel: { features: ['audio'], }, }) render() await waitFor(() => { expect(screen.getByTestId('config-component')).toBeInTheDocument() }) }) it('handles video feature', async () => { mockUseTextGenerationCurrentProviderAndModelAndModelList.mockReturnValue({ currentModel: { features: ['video'], }, }) render() await waitFor(() => { expect(screen.getByTestId('config-component')).toBeInTheDocument() }) }) }) describe('dataset handling', () => { it('handles app with datasets in agent mode', async () => { const appWithDatasets = createMockAppDetail('agent-chat') const modelConfig = appWithDatasets.model_config as Record modelConfig.agent_mode = { tools: [ { dataset: { enabled: true, id: 'dataset-1', }, }, ], enabled: true, } mockUseGetTryAppInfo.mockReturnValue({ data: appWithDatasets, isLoading: false, }) render() await waitFor(() => { expect(mockUseGetTryAppDataSets).toHaveBeenCalled() }) }) it('handles app with datasets in dataset_configs', async () => { const appWithDatasets = createMockAppDetail('chat') const modelConfig = appWithDatasets.model_config as Record modelConfig.dataset_configs = { datasets: { datasets: [ { dataset: { id: 'dataset-1' } }, { dataset: { id: 'dataset-2' } }, ], }, } mockUseGetTryAppInfo.mockReturnValue({ data: appWithDatasets, isLoading: false, }) render() await waitFor(() => { expect(mockUseGetTryAppDataSets).toHaveBeenCalled() }) }) }) describe('advanced prompt mode', () => { it('handles advanced prompt mode', async () => { const appWithAdvancedPrompt = createMockAppDetail('chat') const modelConfig = appWithAdvancedPrompt.model_config as Record modelConfig.prompt_type = 'advanced' modelConfig.chat_prompt_config = { prompt: [{ role: 'system', text: 'You are helpful' }], } mockUseGetTryAppInfo.mockReturnValue({ data: appWithAdvancedPrompt, isLoading: false, }) render() await waitFor(() => { expect(screen.getByTestId('config-component')).toBeInTheDocument() }) }) }) describe('file upload config', () => { it('handles file upload config', async () => { const appWithFileUpload = createMockAppDetail('chat') const modelConfig = appWithFileUpload.model_config as Record modelConfig.file_upload = { enabled: true, image: { enabled: true, detail: 'high', number_limits: 5, transfer_methods: ['local_file', 'remote_url'], }, allowed_file_types: ['image'], allowed_file_extensions: ['.jpg', '.png'], allowed_file_upload_methods: ['local_file'], number_limits: 3, } mockUseGetTryAppInfo.mockReturnValue({ data: appWithFileUpload, isLoading: false, }) render() await waitFor(() => { expect(screen.getByTestId('config-component')).toBeInTheDocument() }) }) }) describe('external data tools', () => { it('handles app with external_data_tools', async () => { const appWithExternalTools = createMockAppDetail('chat') const modelConfig = appWithExternalTools.model_config as Record modelConfig.external_data_tools = [ { variable: 'test_var', label: 'Test Label', enabled: true, type: 'text', config: {}, icon: '/icon.png', icon_background: '#FFFFFF', }, ] mockUseGetTryAppInfo.mockReturnValue({ data: appWithExternalTools, isLoading: false, }) render() await waitFor(() => { expect(screen.getByTestId('config-component')).toBeInTheDocument() }) }) }) describe('deleted tools handling', () => { it('handles app with deleted tools', async () => { const agentAppDetail = createMockAppDetail('agent-chat') const modelConfig = agentAppDetail.model_config as Record modelConfig.agent_mode = { tools: [ { id: 'tool-1', provider_id: 'test-provider', provider_name: 'test-provider', provider_type: 'builtin', tool_name: 'test-tool', enabled: true, }, ], enabled: true, max_iteration: 5, } agentAppDetail.deleted_tools = [ { id: 'tool-1', tool_name: 'test-tool', }, ] mockUseGetTryAppInfo.mockReturnValue({ data: agentAppDetail, isLoading: false, }) mockUseAllToolProviders.mockReturnValue({ data: [ { id: 'test-provider', is_team_authorization: false, icon: '/icon.png', }, ], isLoading: false, }) render() await waitFor(() => { expect(screen.getByTestId('config-component')).toBeInTheDocument() }) }) }) describe('edge cases', () => { it('handles app without model_config', async () => { const appWithoutModelConfig = createMockAppDetail('chat') appWithoutModelConfig.model_config = undefined mockUseGetTryAppInfo.mockReturnValue({ data: appWithoutModelConfig, isLoading: false, }) render() // Should still render (with default model config) await waitFor(() => { expect(mockUseGetTryAppDataSets).toHaveBeenCalled() }) }) }) })