transcript-view-row.client.spec.tsx 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364
  1. // @vitest-environment jsdom
  2. import { afterEach, describe, expect, it, vi } from 'vitest'
  3. import { cleanup, fireEvent, render, screen } from '@testing-library/react'
  4. import type { SessionListState } from '@deepseek-ai/dsh-api-session-controller/client'
  5. import type { WorkspaceSnapshot } from '@deepseek-ai/dsh-api-workspace-controller/client'
  6. import type { SessionPendingInteractionSnapshot } from '@deepseek-ai/dsh-client-ui-session/client'
  7. import { createSnapshotStore } from '@deepseek-ai/dsh-client-store'
  8. import { bindSnapshotSelector, makeTranslate } from '@deepseek-ai/dsh-client-test-runtime'
  9. import { TranscriptViewRow, type TranscriptViewRowProps } from '../src/client/settings/TranscriptViewRow.tsx'
  10. import { en } from '../src/client/locale.ts'
  11. afterEach(cleanup)
  12. function emptySessions() {
  13. return bindSnapshotSelector(createSnapshotStore<SessionListState>({
  14. ids: [], byId: {}, current: undefined, phase: 'ready', subagentsByParent: {}, jobsBySession: {}, currentAddress: undefined,
  15. }))
  16. }
  17. function emptyWorkspaces() {
  18. return bindSnapshotSelector(createSnapshotStore<WorkspaceSnapshot>({
  19. items: [], archivedSessionIds: [], state: 'idle', phase: 'ready', error: null,
  20. }))
  21. }
  22. function noPendingInteraction() {
  23. return bindSnapshotSelector(createSnapshotStore<SessionPendingInteractionSnapshot>(new Map()))
  24. }
  25. function mount(mode: 'normal' | 'compact' = 'compact') {
  26. const source = createSnapshotStore(mode)
  27. const setTranscriptView = vi.fn((next: 'normal' | 'compact') => { source.set(next) })
  28. const props: TranscriptViewRowProps = {
  29. useSessions: emptySessions(),
  30. useSessionPendingInteraction: noPendingInteraction(),
  31. useWorkspaces: emptyWorkspaces(),
  32. useTranscriptView: bindSnapshotSelector(source),
  33. setTranscriptView,
  34. t: makeTranslate(en),
  35. }
  36. render(<TranscriptViewRow {...props} />)
  37. return { setTranscriptView }
  38. }
  39. describe('TranscriptViewRow', () => {
  40. it('explains the preference and shows Compact by default', () => {
  41. mount()
  42. expect(screen.getByText('Conversation display')).toBeDefined()
  43. expect(screen.getByText('Controls process content in completed turns')).toBeDefined()
  44. expect(screen.getByRole('button', { name: /Compact/ }).getAttribute('aria-expanded')).toBe('false')
  45. })
  46. it('selects Normal and follows the mirrored value', () => {
  47. const b = mount()
  48. fireEvent.click(screen.getByRole('button', { name: /Compact/ }))
  49. fireEvent.click(screen.getByRole('menuitem', { name: 'Normal' }))
  50. expect(b.setTranscriptView).toHaveBeenCalledWith('normal')
  51. const trigger = screen.getByRole('button', { name: /Normal/ })
  52. fireEvent.click(trigger)
  53. expect(screen.getByRole('menuitem', { name: 'Compact' })).toBeDefined()
  54. fireEvent.pointerDown(document.body)
  55. expect(screen.queryByRole('menuitem', { name: 'Compact' })).toBeNull()
  56. })
  57. })