cleanup(client): extract Tool presentation into ui-tool
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
// @vitest-environment jsdom
|
||||
/** ToolCallTree-owned root/subcall markers and selection projection. */
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import { cleanup, render } from '@testing-library/react'
|
||||
import type { CodeSubCall, ConversationSnapshot, ToolResultNode } from '@deepseek-ai/dsh-client-runtime/client'
|
||||
import { makeTranslate } from '@deepseek-ai/dsh-client-test-runtime'
|
||||
import { zh as commonZh } from '@deepseek-ai/dsh-client-locale/src/locales/zh.ts'
|
||||
import type { ToolTreeProps } from '../src/client/contract/slots.ts'
|
||||
import { ToolCallTree } from '../src/client/tool/ToolCallTree.tsx'
|
||||
import { zh } from '../../ui-conversation/src/client/locales.ts'
|
||||
|
||||
afterEach(cleanup)
|
||||
|
||||
const t: ToolTreeProps['t'] = makeTranslate(zh, commonZh)
|
||||
|
||||
const root = (callId: string, call: ToolResultNode['call']): ToolResultNode => ({
|
||||
kind: 'tool-result', seq: 3, time: 3_000, callId, call, callTime: 2_000,
|
||||
content: [], isError: false, callView: null, resultView: null,
|
||||
})
|
||||
|
||||
function props(
|
||||
block: ToolResultNode,
|
||||
codeDispatches: ReadonlyMap<string, readonly CodeSubCall[]> = new Map(),
|
||||
selectedCallId?: string,
|
||||
): ToolTreeProps {
|
||||
const snapshot = { codeDispatches } as ConversationSnapshot
|
||||
const useSession = ((selector: (value: ConversationSnapshot) => unknown) => selector(snapshot)) as ToolTreeProps['useSession']
|
||||
const renderSlot = ((_key: string, _owner: object, options?: { fallback?: React.ReactNode }) =>
|
||||
options?.fallback ?? null) as unknown as ToolTreeProps['renderSlot']
|
||||
return {
|
||||
useSession,
|
||||
renderSlot,
|
||||
callId: block.callId,
|
||||
toolName: block.call?.name ?? '',
|
||||
block,
|
||||
selectedCallId,
|
||||
openFile: vi.fn(),
|
||||
inspectCall: vi.fn(),
|
||||
t,
|
||||
} as unknown as ToolTreeProps
|
||||
}
|
||||
|
||||
describe('ToolCallTree', () => {
|
||||
it('owns the root marker, generic fallback, and selected state for a window-truncated call', () => {
|
||||
const block = root('w1', null)
|
||||
const view = render(<ToolCallTree {...props(block, new Map(), 'w1')} />)
|
||||
const row = view.container.querySelector('[data-chat-call-id="w1"]')
|
||||
expect(row?.getAttribute('data-chat-anchor-key')).toBe('call:w1')
|
||||
expect(row?.getAttribute('data-selected')).toBe('true')
|
||||
expect(view.container.querySelector('[data-variant="others"]')).not.toBeNull()
|
||||
expect(view.getByText('w1')).toBeTruthy()
|
||||
})
|
||||
|
||||
it('marks a selected subcall without selecting its root', () => {
|
||||
const block = root('parent', { name: 'run_code', argsRaw: '{"code":"return 1"}' })
|
||||
const child: CodeSubCall = root('parent:code:1', { name: 'read', argsRaw: '{"path":"a.ts"}' })
|
||||
const view = render(
|
||||
<ToolCallTree {...props(block, new Map([['parent', [child]]]), child.callId)} />,
|
||||
)
|
||||
expect(view.container.querySelector('[data-chat-call-id="parent"]')?.hasAttribute('data-selected')).toBe(false)
|
||||
expect(view.container.querySelector('[data-chat-call-id="parent:code:1"]')?.getAttribute('data-selected')).toBe('true')
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user