Files
deepseek-harness/packages/ui/desktop/tests/renderer-regressions.spec.ts
NI0317 37a03df733 fix(ui): pin dock rows, verb labels on live tools, dedupe reject
Auto placement floated the new docks to the top of the main pane; every
dock now owns an explicit grid row (and the layout regression guards
them). Live tool rows use the streamed kind verb like persisted rows,
and the approval card's fallback reject is omitted when the request
already carries a reject option.
2026-07-20 10:58:21 +08:00

75 lines
3.6 KiB
TypeScript

import { readFile } from 'node:fs/promises'
import { describe, expect, it } from 'vitest'
import { assistantText, contentBlocks, contentText, reasoningText } from '../src/renderer-content.ts'
describe('desktop live content', () => {
it('renders single ACP update blocks before the persisted message exists', () => {
expect(contentText({ type: 'text', text: '你' })).toBe('你')
expect(contentText({ type: 'reasoning', text: '想' })).toBe('想')
})
it('accepts plain strings, arrays, and empty values', () => {
const blocks = [{ type: 'text', text: 'a' }]
expect(contentBlocks(blocks)).toBe(blocks)
expect(contentBlocks(null)).toEqual([])
expect(contentText('plain')).toBe('plain')
expect(assistantText('plain')).toBe('plain')
})
it('keeps persisted content arrays split by visible role', () => {
const content = [
{ type: 'reasoning', text: '先想' },
{ type: 'text', text: '再答' },
]
expect(reasoningText(content)).toBe('先想')
expect(assistantText(content)).toBe('再答')
})
it('renders tool, resource, and unknown blocks without object coercion', () => {
expect(contentText({ type: 'tool-call', name: 'bash', arguments: { command: 'pwd' } }))
.toBe('[tool-call bash] {"command":"pwd"}')
expect(contentText({ type: 'resource_link', name: 'notes', uri: 'file:///notes' }))
.toBe('[resource notes] file:///notes')
expect(contentText({ type: 'custom', value: 1 })).toBe('{"type":"custom","value":1}')
expect(contentText({ type: 'text', text: 1 })).toBe('')
expect(contentText({ type: 'tool-call', name: 1, arguments: 'pwd' })).toBe('[tool-call ] pwd')
expect(contentText({ type: 'tool-call', name: 'bash' })).toBe('[tool-call bash] ')
expect(contentText({ type: 'resource_link' })).toBe('[resource ] ')
expect(reasoningText([{ type: 'reasoning', text: 1 }])).toBe('')
expect(contentText(undefined)).toBe('')
})
})
describe('desktop shell layout', () => {
it('pins the docks and composer to their explicit bottom rows', async () => {
const css = await readFile(new URL('../src/styles.css', import.meta.url), 'utf8')
expect(css).toMatch(/\.session-canvas,\s*\.module-canvas\s*{\s*grid-row: 3;/)
// Every dock needs an explicit row: auto placement once floated the queue
// to the top of the main pane.
expect(css).toMatch(/#interactionDock\s*{\s*grid-row: 4;/)
expect(css).toMatch(/#queueDock\s*{\s*grid-row: 5;/)
expect(css).toMatch(/#planDock\s*{\s*grid-row: 6;/)
expect(css).toMatch(/\.composer\s*{\s*grid-row: 7;/)
})
it('does not launch Electron after a strict-port Vite failure', async () => {
const script = await readFile(new URL('../scripts/dev.mjs', import.meta.url), 'utf8')
expect(script).toContain("'--strictPort'")
expect(script).not.toContain('setTimeout(startElectron')
})
it('suppresses persisted ACP replay updates before forwarding a new prompt', async () => {
const main = await readFile(new URL('../src/main.mjs', import.meta.url), 'utf8')
expect(main).toContain('replayingSessions.has(String(params.sessionId))')
expect(main).toContain('replayingSessions.add(sessionId)')
expect(main).toContain('replayingSessions.delete(sessionId)')
})
it('switches from Develop to Sessions and patches artifact detail in place', async () => {
const app = await readFile(new URL('../src/app.ts', import.meta.url), 'utf8')
expect(app).toMatch(/if \(sessionButton !== null\) \{\s*showModule\('sessions'\)\s*await loadTrace/)
expect(app).toContain("selectDevArtifact(devArtifact.dataset.devArtifact ?? '')")
expect(app).toContain('detail.innerHTML = renderDevArtifactDetail(selected)')
})
})