chat-node-source.client.spec.ts 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
  1. import { describe, expect, it, vi } from 'vitest'
  2. import type {
  3. ChatConversationViewNode, ChatNodeSource,
  4. } from '@deepseek-ai/dsh-client-ui-chat/client'
  5. import type { ConversationTimelineSnapshot } from '@deepseek-ai/dsh-client-ui-conversation/client'
  6. import { ChatSnapshotBuilder } from '../src/client/conversation-nodes/chat-snapshot-builder.ts'
  7. const timeline: ConversationTimelineSnapshot = { turnOrder: [], turns: new Map() }
  8. function userNode(index: number, text = `message ${String(index)}`): ChatConversationViewNode {
  9. return {
  10. key: `user:${String(index)}`,
  11. id: String(index),
  12. target: 'chat',
  13. kind: 'user',
  14. anchorSeq: index,
  15. location: { kind: 'session' },
  16. visibility: 'visible',
  17. data: {
  18. kind: 'user',
  19. messageId: `message-${String(index)}`,
  20. seq: index,
  21. time: index,
  22. content: [{ type: 'text', text }],
  23. source: null,
  24. },
  25. }
  26. }
  27. describe('Chat Node keyed sources', () => {
  28. it('notifies only the updated key among 4,000 mounted sources', () => {
  29. const builder = new ChatSnapshotBuilder()
  30. const nodes = Array.from({ length: 4_000 }, (_, index) => userNode(index + 1))
  31. const initial = builder.replace({ nodes, timeline })
  32. const listeners = nodes.map(() => vi.fn())
  33. const sources: ChatNodeSource[] = nodes.map((node, index) => {
  34. const source = initial.nodes.source(node.key)
  35. source.subscribe(listeners[index]!)
  36. return source
  37. })
  38. const target = 2_347
  39. const changed = userNode(target + 1, 'streamed update')
  40. const next = builder.apply({ upserts: [changed], timeline })
  41. expect(listeners[target]).toHaveBeenCalledOnce()
  42. expect(listeners.reduce((count, listener) => count + listener.mock.calls.length, 0)).toBe(1)
  43. expect(next.nodes.source(changed.key)).toBe(sources[target])
  44. expect(next.nodes.get(changed.key)).toBe(changed)
  45. })
  46. })