Files
iofficeai--aionui/tests/unit/workspace/WorkspacePreviewSelection.dom.test.tsx
2026-07-13 13:20:22 +08:00

254 lines
7.2 KiB
TypeScript

/**
* @license
* Copyright 2025 AionUi (aionui.com)
* SPDX-License-Identifier: Apache-2.0
*/
import type { IDirOrFile } from '@/common/adapter/ipcBridge';
import ChatWorkspace from '@/renderer/pages/conversation/Workspace';
import type { NodeInstance } from '@arco-design/web-react/es/Tree/interface';
import { act, cleanup, render, screen } from '@testing-library/react';
import React from 'react';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
type TreeProps = {
onSelect?: (_keys: string[], extra: { node: NodeInstance }) => void;
};
const mocks = vi.hoisted(() => ({
ensureNodeSelected: vi.fn(),
handlePreviewFile: vi.fn(),
writeRendererLogInvoke: vi.fn(),
}));
let latestTreeProps: TreeProps | null = null;
const selectedFile: IDirOrFile = {
name: 'financial-wechat-miniapp.html',
relativePath: 'financial-wechat-miniapp.html',
fullPath: '/workspace/financial-wechat-miniapp.html',
isFile: true,
};
vi.mock('react-i18next', () => ({
useTranslation: () => ({
t: (key: string) => key,
}),
}));
vi.mock('@/common', () => ({
ipcBridge: {
conversation: {
getWorkspace: { invoke: vi.fn() },
},
application: {
writeRendererLog: { invoke: mocks.writeRendererLogInvoke },
},
},
}));
vi.mock('@/renderer/components/layout/FlexFullContainer', () => ({
default: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
}));
vi.mock('@arco-design/web-react', () => ({
Empty: () => <div data-testid='empty' />,
Message: {
useMessage: () => [{ error: vi.fn(), success: vi.fn(), info: vi.fn() }, null],
},
Tree: (props: TreeProps) => {
latestTreeProps = props;
return <div data-testid='workspace-tree' />;
},
}));
vi.mock('@icon-park/react', () => ({
Right: () => <span />,
}));
vi.mock('@/renderer/hooks/context/LayoutContext', () => ({
useLayoutContext: () => ({ isMobile: false }),
}));
vi.mock('@/renderer/pages/conversation/Preview', () => ({
usePreviewContext: () => ({
openPreview: vi.fn(),
}),
}));
vi.mock('@/renderer/pages/conversation/Workspace/hooks/useWorkspaceCollapse', () => ({
useWorkspaceCollapse: () => ({
isWorkspaceCollapsed: false,
setIsWorkspaceCollapsed: vi.fn(),
}),
}));
vi.mock('@/renderer/pages/conversation/Workspace/hooks/useWorkspaceTree', () => ({
useWorkspaceTree: () => ({
files: [{ name: 'workspace', relativePath: '', fullPath: '/workspace', isFile: false, children: [selectedFile] }],
loading: false,
treeKey: 1,
expandedKeys: [],
selected: [selectedFile.relativePath],
selectedKeysRef: { current: [selectedFile.relativePath] },
selectedNodeRef: { current: null },
setFiles: vi.fn(),
setLoading: vi.fn(),
setExpandedKeys: vi.fn(),
setSelected: vi.fn(),
setTreeKey: vi.fn(),
refreshWorkspace: vi.fn(),
loadWorkspace: vi.fn(),
ensureNodeSelected: mocks.ensureNodeSelected,
clearSelection: vi.fn(),
}),
}));
vi.mock('@/renderer/pages/conversation/Workspace/hooks/useWorkspaceFileOps', () => ({
useWorkspaceFileOps: () => ({
handlePreviewFile: mocks.handlePreviewFile,
handleAddToChat: vi.fn(),
handleDownloadFile: vi.fn(),
handleOpenNode: vi.fn(),
handleRevealNode: vi.fn(),
handleRenameNode: vi.fn(),
handleDeleteNode: vi.fn(),
}),
}));
vi.mock('@/renderer/pages/conversation/Workspace/hooks/useFileChanges', () => ({
useFileChanges: () => ({
staged: [],
unstaged: [],
loading: false,
snapshotInfo: null,
refreshChanges: vi.fn(),
stageFile: vi.fn(),
stageAll: vi.fn(),
unstageFile: vi.fn(),
unstageAll: vi.fn(),
discardFile: vi.fn(),
resetFile: vi.fn(),
}),
}));
vi.mock('@/renderer/pages/conversation/Workspace/hooks/useWorkspacePaste', () => ({
useWorkspacePaste: () => ({
pasteTargetFolder: null,
pasteConfirm: { visible: false },
onFocusPaste: vi.fn(),
handleFilesToAdd: vi.fn(),
}),
}));
vi.mock('@/renderer/pages/conversation/Workspace/hooks/useWorkspaceDragImport', () => ({
useWorkspaceDragImport: () => ({
isDragging: false,
dragHandlers: {},
}),
}));
vi.mock('@/renderer/pages/conversation/Workspace/hooks/useWorkspaceSearch', () => ({
useWorkspaceSearch: () => ({
showSearch: false,
searchText: '',
setShowSearch: vi.fn(),
setSearchText: vi.fn(),
}),
}));
vi.mock('@/renderer/pages/conversation/Workspace/hooks/useWorkspaceModals', () => ({
useWorkspaceModals: () => ({
contextMenu: { visible: false, x: 0, y: 0, node: null },
renameModal: { visible: false, value: '', target: null },
deleteModal: { visible: false, target: null, loading: false },
pasteConfirm: { visible: false, file_name: '', filesToPaste: [], doNotAsk: false, targetFolder: null },
renameLoading: false,
setContextMenu: vi.fn(),
setRenameModal: vi.fn(),
setDeleteModal: vi.fn(),
setPasteConfirm: vi.fn(),
setRenameLoading: vi.fn(),
closeContextMenu: vi.fn(),
closeRenameModal: vi.fn(),
closeDeleteModal: vi.fn(),
closePasteConfirm: vi.fn(),
}),
}));
vi.mock('@/renderer/pages/conversation/Workspace/hooks/useWorkspaceEvents', () => ({
useWorkspaceEvents: vi.fn(),
}));
vi.mock('@/renderer/hooks/file/useAbortUploadsOnConversationChange', () => ({
useAbortUploadsOnConversationChange: vi.fn(),
}));
vi.mock('@/renderer/pages/conversation/Workspace/components/WorkspaceToolbar', () => ({
default: () => <div data-testid='workspace-toolbar' />,
}));
vi.mock('@/renderer/pages/conversation/Workspace/components/WorkspaceTabBar', () => ({
default: () => <div data-testid='workspace-tabbar' />,
}));
vi.mock('@/renderer/pages/conversation/Workspace/components/WorkspaceContextMenu', () => ({
default: () => null,
}));
vi.mock('@/renderer/pages/conversation/Workspace/components/WorkspaceDialogs', () => ({
default: () => null,
}));
vi.mock('@/renderer/pages/conversation/Workspace/components/PasteConfirmModal', () => ({
default: () => null,
}));
vi.mock('@/renderer/pages/conversation/Workspace/components/FileChangeList', () => ({
default: () => null,
}));
vi.mock('@/renderer/pages/conversation/Workspace/components/FileTypeIcon', () => ({
default: () => <span data-testid='file-type-icon' />,
}));
describe('ChatWorkspace preview selection', () => {
beforeEach(() => {
latestTreeProps = null;
vi.clearAllMocks();
});
afterEach(() => {
cleanup();
});
it('opens preview when the already highlighted file is clicked again', () => {
render(<ChatWorkspace conversation_id='conversation-1' workspace='/workspace' />);
expect(screen.getByTestId('workspace-tree')).toBeInTheDocument();
const node = {
key: selectedFile.relativePath,
props: {
dataRef: selectedFile,
},
} as unknown as NodeInstance;
act(() => {
latestTreeProps?.onSelect?.([], { node });
});
expect(mocks.ensureNodeSelected).toHaveBeenCalledWith(selectedFile);
expect(mocks.writeRendererLogInvoke).toHaveBeenCalledWith({
level: 'debug',
tag: 'Workspace',
message: 'workspace_file_preview_requested',
data: {
fileName: selectedFile.name,
wasSelected: true,
hasKey: true,
},
});
expect(mocks.handlePreviewFile).toHaveBeenCalledWith(selectedFile);
});
});