cc-haha/desktop/src/components/chat/AssistantOutputTargetCard.test.tsx
程序员阿江(Relakkes) 95d1ba997a feat(desktop): render message-complete previewable refs as rich cards (drop inline pill)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 17:40:46 +08:00

111 lines
4.4 KiB
TypeScript

import '@testing-library/jest-dom'
import { fireEvent, render, screen } from '@testing-library/react'
import { afterEach, describe, expect, it, vi } from 'vitest'
const { openBrowser } = vi.hoisted(() => ({ openBrowser: vi.fn() }))
vi.mock('../../stores/browserPanelStore', () => ({
useBrowserPanelStore: { getState: () => ({ open: openBrowser }) },
}))
vi.mock('../../lib/desktopRuntime', async (orig) => ({
...(await orig<Record<string, unknown>>()),
getServerBaseUrl: () => 'http://127.0.0.1:4321',
}))
const ensureTargets = vi.hoisted(() => vi.fn().mockResolvedValue(undefined))
const openTargetFn = vi.hoisted(() => vi.fn())
vi.mock('../../stores/openTargetStore', () => ({
useOpenTargetStore: {
getState: () => ({ ensureTargets, targets: [], openTarget: openTargetFn }),
},
}))
const openPreviewFn = vi.hoisted(() => vi.fn().mockResolvedValue(undefined))
vi.mock('../../stores/workspacePanelStore', () => ({
useWorkspacePanelStore: {
getState: () => ({ statusBySession: {}, openPreview: openPreviewFn }),
},
}))
const shellOpen = vi.hoisted(() => vi.fn().mockResolvedValue(undefined))
vi.mock('@tauri-apps/plugin-shell', () => ({ open: shellOpen }))
// Mock i18n — return the key (plus interpolation) so we can assert on keys
vi.mock('../../i18n', () => ({
useTranslation: () => (k: string, v?: Record<string, string>) => (v?.target ? `${k}:${v.target}` : k),
}))
import { AssistantOutputTargetCard } from './AssistantOutputTargetCard'
import type { AssistantOutputTarget } from '../../lib/assistantOutputTargets'
const markdownTarget: AssistantOutputTarget = {
id: 'markdown:docs/readme.md',
kind: 'markdown',
title: 'readme.md',
subtitle: 'docs/readme.md',
href: 'docs/readme.md',
normalizedPath: 'docs/readme.md',
confidence: 'high',
source: 'markdown-link',
}
const localhostTarget: AssistantOutputTarget = {
id: 'localhost-url:http://localhost:5173/',
kind: 'localhost-url',
title: 'http://localhost:5173/',
href: 'http://localhost:5173/',
confidence: 'high',
source: 'plain-url',
}
afterEach(() => {
openBrowser.mockReset()
ensureTargets.mockReset().mockResolvedValue(undefined)
openTargetFn.mockReset()
openPreviewFn.mockReset().mockResolvedValue(undefined)
shellOpen.mockReset().mockResolvedValue(undefined)
})
describe('AssistantOutputTargetCard', () => {
it('renders a markdown target title + Markdown badge', () => {
render(<AssistantOutputTargetCard target={markdownTarget} sessionId="s1" />)
expect(screen.getByText('readme.md')).toBeInTheDocument()
expect(screen.getByText('assistantOutputs.kind.markdown')).toBeInTheDocument()
expect(screen.getByText('docs/readme.md')).toBeInTheDocument()
})
it('renders a localhost target title + Localhost badge', () => {
render(<AssistantOutputTargetCard target={localhostTarget} sessionId="s1" />)
// Title + subtitle both fall back to href, so it appears twice.
expect(screen.getAllByText('http://localhost:5173/').length).toBeGreaterThan(0)
expect(screen.getByText('assistantOutputs.kind.localhost')).toBeInTheDocument()
})
it('routes Open to workspace preview for a markdown target', () => {
render(<AssistantOutputTargetCard target={markdownTarget} sessionId="s1" />)
fireEvent.click(screen.getByLabelText('assistantOutputs.open'))
expect(openPreviewFn).toHaveBeenCalledWith('s1', 'docs/readme.md', 'file')
})
it('routes Open to the in-app browser for a localhost target', () => {
render(<AssistantOutputTargetCard target={localhostTarget} sessionId="s1" />)
fireEvent.click(screen.getByLabelText('assistantOutputs.open'))
expect(openBrowser).toHaveBeenCalledWith('s1', 'http://localhost:5173/')
})
it('copies the normalized path when Copy is clicked', () => {
const writeText = vi.fn().mockResolvedValue(undefined)
Object.assign(navigator, { clipboard: { writeText } })
render(<AssistantOutputTargetCard target={markdownTarget} sessionId="s1" />)
fireEvent.click(screen.getByLabelText('assistantOutputs.copy'))
expect(writeText).toHaveBeenCalledWith('docs/readme.md')
})
it('opens the open-with menu with URL items for a localhost target', async () => {
render(<AssistantOutputTargetCard target={localhostTarget} sessionId="s1" />)
fireEvent.click(screen.getByLabelText('openWith.title'))
expect(await screen.findByText('openWith.inAppBrowser')).toBeInTheDocument()
expect(screen.getByText('openWith.systemBrowser')).toBeInTheDocument()
})
})