Files
deepseek-harness/packages/client/ui-conversation/tests/image-labels.client.spec.tsx
imccyu 7ad54e7791 refactor(client): name the compile face in every client test filename
A test file under packages/client now says which face it covers:
`*.client.spec.{ts,tsx}` and its `*.client.{ts,tsx}` helpers belong to the
Client aggregate, `*.host.spec.ts` to the host aggregate. The carrier's four
node-half specs take the Host suffix.

The two suffixes are mutually exclusive, so each aggregate excludes the
other's and both keep one broad test glob: `exclude` wins over `include`, and
`packages/client/**` no longer has to be excluded wholesale from the host
program with per-file `files` entries carved back out of it. A Host-face spec
that reaches only Host source therefore needs no cross-face project
reference, which the split-project rule rejects.

vitest still discovers every file through `**/*.spec.{ts,tsx}`.
2026-08-12 01:41:40 +08:00

83 lines
3.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// @vitest-environment jsdom
// The conversation-side bridge to the ui-attachment atoms: dictionary strings
// flow through image-labels into the gallery, and assistant images keep their
// block position between text blocks.
import { afterEach, describe, expect, it } from 'vitest'
import { cleanup, fireEvent, render } from '@testing-library/react'
import { AttachmentId } from '@deepseek-ai/dsh-attachment'
import { makeTranslate } from '@deepseek-ai/dsh-client-test-runtime'
import { zh as commonZh } from '@deepseek-ai/dsh-client-locale/src/locales/zh.ts'
import { AssistantMarkdown } from '../src/client/chat/AssistantMarkdown.tsx'
import { en, zh } from '../src/client/locales.ts'
afterEach(cleanup)
const t = makeTranslate(zh, commonZh)
const enT = makeTranslate(en, commonZh)
const attachment = {
attachmentId: AttachmentId(`sha256:${'a'.repeat(64)}`),
mediaType: 'image/png' as const,
bytes: 68,
width: 640,
height: 320,
name: 'history.png',
}
describe('assistant images through the label bridge', () => {
it('resolves zh dictionary strings and opens the lightbox on a single click', async () => {
const view = render(
<AssistantMarkdown
t={t}
blocks={[{ kind: 'image', attachment }]}
streaming={false}
loadImage={() => Promise.resolve('blob:history')}
/>,
)
const frame = await view.findByRole('button', { name: 'history.png,点击查看原图' })
expect(frame.getAttribute('title')).toBe('查看原图')
await view.findByAltText('history.png')
fireEvent.click(frame)
expect(view.getByRole('dialog', { name: '原图预览' })).toBeTruthy()
fireEvent.click(view.getByRole('button', { name: '关闭原图预览' }))
expect(view.queryByRole('dialog', { name: '原图预览' })).toBeNull()
})
it('resolves the active English dictionary', async () => {
const view = render(
<AssistantMarkdown
t={enT}
blocks={[{ kind: 'image', attachment }]}
streaming={false}
loadImage={() => Promise.resolve('blob:history')}
/>,
)
const frame = await view.findByRole('button', { name: 'history.png, click to view original' })
await view.findByAltText('history.png')
fireEvent.click(frame)
expect(view.getByRole('dialog', { name: 'Original image preview' })).toBeTruthy()
expect(view.getByRole('button', { name: 'Close original image preview' })).toBeTruthy()
})
it('keeps assistant images at their original position between text blocks', async () => {
const view = render(
<AssistantMarkdown
t={t}
blocks={[
{ kind: 'text', text: 'before' },
{ kind: 'image', attachment },
{ kind: 'text', text: 'after' },
]}
streaming={false}
loadImage={() => Promise.resolve('blob:middle')}
/>,
)
const image = await view.findByAltText('history.png')
const before = view.getByText('before')
const after = view.getByText('after')
expect(before.compareDocumentPosition(image) & Node.DOCUMENT_POSITION_FOLLOWING).not.toBe(0)
expect(image.compareDocumentPosition(after) & Node.DOCUMENT_POSITION_FOLLOWING).not.toBe(0)
})
})