diff --git a/web/app/components/app/configuration/dataset-config/card-item/index.spec.tsx b/web/app/components/app/configuration/dataset-config/card-item/index.spec.tsx index f5a73d9298..3546c642a6 100644 --- a/web/app/components/app/configuration/dataset-config/card-item/index.spec.tsx +++ b/web/app/components/app/configuration/dataset-config/card-item/index.spec.tsx @@ -183,7 +183,7 @@ describe('dataset-config/card-item', () => { expect(onSave).toHaveBeenCalledWith(expect.objectContaining({ name: 'Updated dataset' })) }) await waitFor(() => { - expect(screen.getByText('Mock settings modal')).not.toBeVisible() + expect(screen.queryByText('Mock settings modal')).not.toBeInTheDocument() }) }) diff --git a/web/app/components/apps/index.spec.tsx b/web/app/components/apps/index.spec.tsx index c3dc39955d..c77c1bdb01 100644 --- a/web/app/components/apps/index.spec.tsx +++ b/web/app/components/apps/index.spec.tsx @@ -1,3 +1,5 @@ +import type { ReactNode } from 'react' +import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { render, screen } from '@testing-library/react' import * as React from 'react' @@ -22,6 +24,15 @@ vi.mock('@/app/education-apply/hooks', () => ({ }, })) +vi.mock('@/hooks/use-import-dsl', () => ({ + useImportDSL: () => ({ + handleImportDSL: vi.fn(), + handleImportDSLConfirm: vi.fn(), + versions: [], + isFetching: false, + }), +})) + // Mock List component vi.mock('./list', () => ({ default: () => { @@ -30,6 +41,25 @@ vi.mock('./list', () => ({ })) describe('Apps', () => { + const createQueryClient = () => new QueryClient({ + defaultOptions: { + queries: { + retry: false, + }, + }, + }) + + const renderWithClient = (ui: React.ReactElement) => { + const queryClient = createQueryClient() + const wrapper = ({ children }: { children: ReactNode }) => ( + {children} + ) + return { + queryClient, + ...render(ui, { wrapper }), + } + } + beforeEach(() => { vi.clearAllMocks() documentTitleCalls = [] @@ -38,17 +68,17 @@ describe('Apps', () => { describe('Rendering', () => { it('should render without crashing', () => { - render() + renderWithClient() expect(screen.getByTestId('apps-list')).toBeInTheDocument() }) it('should render List component', () => { - render() + renderWithClient() expect(screen.getByText('Apps List')).toBeInTheDocument() }) it('should have correct container structure', () => { - const { container } = render() + const { container } = renderWithClient() const wrapper = container.firstChild as HTMLElement expect(wrapper).toHaveClass('relative', 'flex', 'h-0', 'shrink-0', 'grow', 'flex-col') }) @@ -56,19 +86,19 @@ describe('Apps', () => { describe('Hooks', () => { it('should call useDocumentTitle with correct title', () => { - render() + renderWithClient() expect(documentTitleCalls).toContain('common.menus.apps') }) it('should call useEducationInit', () => { - render() + renderWithClient() expect(educationInitCalls).toBeGreaterThan(0) }) }) describe('Integration', () => { it('should render full component tree', () => { - render() + renderWithClient() // Verify container exists expect(screen.getByTestId('apps-list')).toBeInTheDocument() @@ -79,23 +109,32 @@ describe('Apps', () => { }) it('should handle multiple renders', () => { - const { rerender } = render() + const queryClient = createQueryClient() + const { rerender } = render( + + + , + ) expect(screen.getByTestId('apps-list')).toBeInTheDocument() - rerender() + rerender( + + + , + ) expect(screen.getByTestId('apps-list')).toBeInTheDocument() }) }) describe('Styling', () => { it('should have overflow-y-auto class', () => { - const { container } = render() + const { container } = renderWithClient() const wrapper = container.firstChild as HTMLElement expect(wrapper).toHaveClass('overflow-y-auto') }) it('should have background styling', () => { - const { container } = render() + const { container } = renderWithClient() const wrapper = container.firstChild as HTMLElement expect(wrapper).toHaveClass('bg-background-body') }) diff --git a/web/app/components/base/action-button/index.tsx b/web/app/components/base/action-button/index.tsx index 735e72b18d..c91d472087 100644 --- a/web/app/components/base/action-button/index.tsx +++ b/web/app/components/base/action-button/index.tsx @@ -60,6 +60,7 @@ const ActionButton = ({ className, size, state = ActionButtonState.Default, styl getActionButtonState(state), disabled && 'cursor-not-allowed text-text-disabled hover:bg-transparent hover:text-text-disabled', )} + disabled={disabled} ref={ref} style={styleCss} {...props} diff --git a/web/app/components/base/chat/chat-with-history/hooks.spec.tsx b/web/app/components/base/chat/chat-with-history/hooks.spec.tsx index f6a8f25cbb..399f16716d 100644 --- a/web/app/components/base/chat/chat-with-history/hooks.spec.tsx +++ b/web/app/components/base/chat/chat-with-history/hooks.spec.tsx @@ -5,6 +5,7 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { act, renderHook, waitFor } from '@testing-library/react' import { ToastProvider } from '@/app/components/base/toast' import { + AppSourceType, fetchChatList, fetchConversations, generationConversationName, @@ -49,20 +50,24 @@ vi.mock('../utils', async () => { } }) -vi.mock('@/service/share', () => ({ - fetchChatList: vi.fn(), - fetchConversations: vi.fn(), - generationConversationName: vi.fn(), - fetchAppInfo: vi.fn(), - fetchAppMeta: vi.fn(), - fetchAppParams: vi.fn(), - getAppAccessModeByAppCode: vi.fn(), - delConversation: vi.fn(), - pinConversation: vi.fn(), - renameConversation: vi.fn(), - unpinConversation: vi.fn(), - updateFeedback: vi.fn(), -})) +vi.mock('@/service/share', async (importOriginal) => { + const actual = await importOriginal() + return { + ...actual, + fetchChatList: vi.fn(), + fetchConversations: vi.fn(), + generationConversationName: vi.fn(), + fetchAppInfo: vi.fn(), + fetchAppMeta: vi.fn(), + fetchAppParams: vi.fn(), + getAppAccessModeByAppCode: vi.fn(), + delConversation: vi.fn(), + pinConversation: vi.fn(), + renameConversation: vi.fn(), + unpinConversation: vi.fn(), + updateFeedback: vi.fn(), + } +}) const mockFetchConversations = vi.mocked(fetchConversations) const mockFetchChatList = vi.mocked(fetchChatList) @@ -162,13 +167,13 @@ describe('useChatWithHistory', () => { // Assert await waitFor(() => { - expect(mockFetchConversations).toHaveBeenCalledWith(false, 'app-1', undefined, true, 100) + expect(mockFetchConversations).toHaveBeenCalledWith(AppSourceType.webApp, 'app-1', undefined, true, 100) }) await waitFor(() => { - expect(mockFetchConversations).toHaveBeenCalledWith(false, 'app-1', undefined, false, 100) + expect(mockFetchConversations).toHaveBeenCalledWith(AppSourceType.webApp, 'app-1', undefined, false, 100) }) await waitFor(() => { - expect(mockFetchChatList).toHaveBeenCalledWith('conversation-1', false, 'app-1') + expect(mockFetchChatList).toHaveBeenCalledWith('conversation-1', AppSourceType.webApp, 'app-1') }) await waitFor(() => { expect(result.current.pinnedConversationList).toEqual(pinnedData.data) @@ -204,7 +209,7 @@ describe('useChatWithHistory', () => { // Assert await waitFor(() => { - expect(mockGenerationConversationName).toHaveBeenCalledWith(false, 'app-1', 'conversation-new') + expect(mockGenerationConversationName).toHaveBeenCalledWith(AppSourceType.webApp, 'app-1', 'conversation-new') }) await waitFor(() => { expect(result.current.conversationList[0]).toEqual(generatedConversation) diff --git a/web/app/components/base/chat/embedded-chatbot/hooks.spec.tsx b/web/app/components/base/chat/embedded-chatbot/hooks.spec.tsx index b0c09e2fbf..4088e709d1 100644 --- a/web/app/components/base/chat/embedded-chatbot/hooks.spec.tsx +++ b/web/app/components/base/chat/embedded-chatbot/hooks.spec.tsx @@ -50,16 +50,20 @@ vi.mock('../utils', async () => { } }) -vi.mock('@/service/share', () => ({ - fetchChatList: vi.fn(), - fetchConversations: vi.fn(), - generationConversationName: vi.fn(), - fetchAppInfo: vi.fn(), - fetchAppMeta: vi.fn(), - fetchAppParams: vi.fn(), - getAppAccessModeByAppCode: vi.fn(), - updateFeedback: vi.fn(), -})) +vi.mock('@/service/share', async (importOriginal) => { + const actual = await importOriginal() + return { + ...actual, + fetchChatList: vi.fn(), + fetchConversations: vi.fn(), + generationConversationName: vi.fn(), + fetchAppInfo: vi.fn(), + fetchAppMeta: vi.fn(), + fetchAppParams: vi.fn(), + getAppAccessModeByAppCode: vi.fn(), + updateFeedback: vi.fn(), + } +}) const mockFetchConversations = vi.mocked(fetchConversations) const mockFetchChatList = vi.mocked(fetchChatList) @@ -150,13 +154,13 @@ describe('useEmbeddedChatbot', () => { // Assert await waitFor(() => { - expect(mockFetchConversations).toHaveBeenCalledWith(false, 'app-1', undefined, true, 100) + expect(mockFetchConversations).toHaveBeenCalledWith(AppSourceType.webApp, 'app-1', undefined, true, 100) }) await waitFor(() => { - expect(mockFetchConversations).toHaveBeenCalledWith(false, 'app-1', undefined, false, 100) + expect(mockFetchConversations).toHaveBeenCalledWith(AppSourceType.webApp, 'app-1', undefined, false, 100) }) await waitFor(() => { - expect(mockFetchChatList).toHaveBeenCalledWith('conversation-1', false, 'app-1') + expect(mockFetchChatList).toHaveBeenCalledWith('conversation-1', AppSourceType.webApp, 'app-1') }) expect(result.current.pinnedConversationList).toEqual(pinnedData.data) expect(result.current.conversationList).toEqual(listData.data) @@ -188,7 +192,7 @@ describe('useEmbeddedChatbot', () => { // Assert await waitFor(() => { - expect(mockGenerationConversationName).toHaveBeenCalledWith(false, 'app-1', 'conversation-new') + expect(mockGenerationConversationName).toHaveBeenCalledWith(AppSourceType.webApp, 'app-1', 'conversation-new') }) await waitFor(() => { expect(result.current.conversationList[0]).toEqual(generatedConversation) diff --git a/web/app/components/explore/app-list/index.spec.tsx b/web/app/components/explore/app-list/index.spec.tsx index e15f37245f..a87d5a2363 100644 --- a/web/app/components/explore/app-list/index.spec.tsx +++ b/web/app/components/explore/app-list/index.spec.tsx @@ -16,9 +16,13 @@ let mockIsError = false const mockHandleImportDSL = vi.fn() const mockHandleImportDSLConfirm = vi.fn() -vi.mock('nuqs', () => ({ - useQueryState: () => [mockTabValue, mockSetTab], -})) +vi.mock('nuqs', async (importOriginal) => { + const actual = await importOriginal() + return { + ...actual, + useQueryState: () => [mockTabValue, mockSetTab], + } +}) vi.mock('ahooks', async () => { const actual = await vi.importActual('ahooks') diff --git a/web/app/components/explore/sidebar/index.spec.tsx b/web/app/components/explore/sidebar/index.spec.tsx index 7f23ce41c4..e06cefd40b 100644 --- a/web/app/components/explore/sidebar/index.spec.tsx +++ b/web/app/components/explore/sidebar/index.spec.tsx @@ -98,8 +98,8 @@ describe('SideBar', () => { renderWithContext(mockInstalledApps) // Assert - expect(screen.getByText('explore.sidebar.discovery')).toBeInTheDocument() - expect(screen.getByText('explore.sidebar.workspace')).toBeInTheDocument() + expect(screen.getByText('explore.sidebar.title')).toBeInTheDocument() + expect(screen.getByText('explore.sidebar.webApps')).toBeInTheDocument() expect(screen.getByText('My App')).toBeInTheDocument() }) }) diff --git a/web/service/use-share.spec.tsx b/web/service/use-share.spec.tsx index 5b1501bead..a56913c534 100644 --- a/web/service/use-share.spec.tsx +++ b/web/service/use-share.spec.tsx @@ -16,15 +16,19 @@ import { useShareConversations, } from './use-share' -vi.mock('./share', () => ({ - fetchChatList: vi.fn(), - fetchConversations: vi.fn(), - generationConversationName: vi.fn(), - fetchAppInfo: vi.fn(), - fetchAppMeta: vi.fn(), - fetchAppParams: vi.fn(), - getAppAccessModeByAppCode: vi.fn(), -})) +vi.mock('./share', async (importOriginal) => { + const actual = await importOriginal() + return { + ...actual, + fetchChatList: vi.fn(), + fetchConversations: vi.fn(), + generationConversationName: vi.fn(), + fetchAppInfo: vi.fn(), + fetchAppMeta: vi.fn(), + fetchAppParams: vi.fn(), + getAppAccessModeByAppCode: vi.fn(), + } +}) const mockFetchConversations = vi.mocked(fetchConversations) const mockFetchChatList = vi.mocked(fetchChatList) @@ -91,7 +95,7 @@ describe('useShareConversations', () => { // Assert await waitFor(() => { - expect(mockFetchConversations).toHaveBeenCalledWith(false, undefined, undefined, true, 50) + expect(mockFetchConversations).toHaveBeenCalledWith(AppSourceType.webApp, undefined, undefined, true, 50) }) await waitFor(() => { expect(result.current.data).toEqual(response) @@ -140,7 +144,7 @@ describe('useShareChatList', () => { // Assert await waitFor(() => { - expect(mockFetchChatList).toHaveBeenCalledWith('conversation-1', true, 'app-1') + expect(mockFetchChatList).toHaveBeenCalledWith('conversation-1', AppSourceType.installedApp, 'app-1') }) await waitFor(() => { expect(result.current.data).toEqual(response) @@ -235,7 +239,7 @@ describe('useShareConversationName', () => { // Assert await waitFor(() => { - expect(mockGenerationConversationName).toHaveBeenCalledWith(false, undefined, 'conversation-2') + expect(mockGenerationConversationName).toHaveBeenCalledWith(AppSourceType.webApp, undefined, 'conversation-2') }) await waitFor(() => { expect(result.current.data).toEqual(response)