diff --git a/src/renderer/src/components/native-chat/native-chat-composer-drop-scope.test.tsx b/src/renderer/src/components/native-chat/native-chat-composer-drop-scope.test.tsx index 90029987cf4..73953f509a9 100644 --- a/src/renderer/src/components/native-chat/native-chat-composer-drop-scope.test.tsx +++ b/src/renderer/src/components/native-chat/native-chat-composer-drop-scope.test.tsx @@ -32,7 +32,7 @@ const intake = vi.hoisted(() => ({ readFile: vi.fn(), upload: vi.fn() })) -vi.mock('@/store', () => ({ useAppStore: { getState: () => ({}) } })) +vi.mock('@/store', () => ({ useAppStore: { getState: () => ({ tabsByWorktree: {} }) } })) // Keeps the real notice strings so the silent-failure guards assert what users see. vi.mock('./native-chat-attachment-upload', async (importOriginal) => ({ ...(await importOriginal()), diff --git a/src/renderer/src/components/native-chat/native-chat-external-attachments-destination.test.tsx b/src/renderer/src/components/native-chat/native-chat-external-attachments-destination.test.tsx new file mode 100644 index 00000000000..2b0fe635187 --- /dev/null +++ b/src/renderer/src/components/native-chat/native-chat-external-attachments-destination.test.tsx @@ -0,0 +1,214 @@ +// @vitest-environment happy-dom +import { act, useRef, useState } from 'react' +import { createRoot, type Root } from 'react-dom/client' +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' +import type * as AttachmentUploadModule from './native-chat-attachment-upload' +import type { NativeChatAttachmentOwner } from './native-chat-attachment-upload' +import { useNativeChatExternalAttachments } from './use-native-chat-external-attachments' +import { + clearNativeChatAttachmentCacheForTests, + useNativeChatComposerAttachments +} from './use-native-chat-composer-attachments' + +const mocks = vi.hoisted(() => { + const state: { + owner: NativeChatAttachmentOwner + remoteTarget: boolean + stat: ReturnType + upload: ReturnType + tabsByWorktree: Record + } = { + owner: { kind: 'local' }, + remoteTarget: false, + stat: vi.fn(), + upload: vi.fn(), + tabsByWorktree: { 'workspace-1': [{ id: 'tab-1' }] } + } + return state +}) +vi.mock('@/store', () => ({ + useAppStore: { getState: () => ({ tabsByWorktree: mocks.tabsByWorktree }) } +})) +vi.mock('@/i18n/i18n', () => ({ translate: (_key: string, fallback: string) => fallback })) +vi.mock('@/runtime/runtime-terminal-inspection', () => ({ + isRemoteRuntimePtyId: () => mocks.remoteTarget +})) +vi.mock('./native-chat-attachment-upload', async (importOriginal) => ({ + ...(await importOriginal()), + resolveNativeChatAttachmentOwner: () => mocks.owner, + resolveNativeChatAttachmentOwnerForWorktree: () => mocks.owner, + uploadNativeChatAttachmentPaths: mocks.upload +})) + +type Api = ReturnType & + ReturnType +let api: Api | undefined +let root: Root +let container: HTMLDivElement +let composing = true + +function Probe({ worktreeId }: { worktreeId?: string }): React.JSX.Element { + const [draft, setDraft] = useState('') + const [caret, setCaret] = useState(0) + const [notice, setNotice] = useState(null) + const textareaRef = useRef(null) + const attachments = useNativeChatComposerAttachments({ + attachmentScopeKey: 'drop-test', + caret, + disabled: false, + isComposing: () => composing, + resolveTarget: () => ({ ptyId: 'pty-1', settings: { activeRuntimeEnvironmentId: null } }), + textareaRef, + setCaret, + setDraft, + setNotice + }) + const external = useNativeChatExternalAttachments({ + terminalTabId: 'tab-1', + structuredWorktreeId: worktreeId, + disabled: false, + attachResolvedPaths: attachments.attachResolvedPaths, + setNotice + }) + api = { ...attachments, ...external } + return ( + <> +