groupsSelection.test.ts 3.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. import { beforeEach, describe, expect, it, vi } from 'vitest'
  2. import { createPinia, setActivePinia } from 'pinia'
  3. import type { GroupRoomDetail, GroupRoomSummary, GroupTopicSummary } from '@shared/types'
  4. const api = vi.hoisted(() => ({
  5. getGroupCapabilities: vi.fn(),
  6. getGroupMessages: vi.fn(),
  7. getGroupRoom: vi.fn(),
  8. getGroupRooms: vi.fn(),
  9. getGroupTopics: vi.fn(),
  10. getPinnedGroupTopics: vi.fn(),
  11. }))
  12. vi.mock('@/api/groups', async importOriginal => ({
  13. ...await importOriginal<typeof import('@/api/groups')>(),
  14. ...api,
  15. }))
  16. vi.mock('@/api/realtime', async importOriginal => ({
  17. ...await importOriginal<typeof import('@/api/realtime')>(),
  18. GroupEventSocket: class {
  19. async connect(): Promise<void> {}
  20. close(): void {}
  21. },
  22. }))
  23. vi.mock('@/stores/auth', () => ({
  24. useAuthStore: () => ({
  25. user: { id: 'groups-selection-test', role: 'user' },
  26. activeProfile: { name: 'default' },
  27. status: 'authenticated',
  28. isAuthenticated: true,
  29. }),
  30. }))
  31. import { useGroupsStore } from '@/stores/groups'
  32. const room = (id: string, name: string): GroupRoomSummary => ({
  33. id, name, cwd: '', avatar: '', createdAt: 1, updatedAt: 1, archived: false,
  34. agentCount: 0, lastMessage: null, unreadCount: 0, maxReplyRounds: 3,
  35. })
  36. const detail = (summary: GroupRoomSummary): GroupRoomDetail => ({
  37. ...summary, agents: [], runs: [], pendingInteractions: [], latestCursor: 0,
  38. })
  39. const topic = (id: string, roomId: string): GroupTopicSummary => ({
  40. id, roomId, title: id, preview: '', messageCount: 0, createdAt: 1, updatedAt: 1,
  41. })
  42. describe('groups selection state', () => {
  43. beforeEach(() => {
  44. setActivePinia(createPinia())
  45. vi.clearAllMocks()
  46. })
  47. it('publishes the target topic with its room instead of retaining the previous room topic', async () => {
  48. const roomA = room('room-a', '团队 A')
  49. const roomB = room('room-b', '团队 B')
  50. const topicA = topic('topic-a', roomA.id)
  51. const topicB = topic('topic-b', roomB.id)
  52. let resolveRoomB!: (value: GroupRoomDetail) => void
  53. const roomBRequest = new Promise<GroupRoomDetail>(resolve => { resolveRoomB = resolve })
  54. api.getGroupCapabilities.mockResolvedValue({
  55. protocolVersion: 12,
  56. journalEpoch: '11111111-1111-4111-8111-111111111111',
  57. latestCursor: 0,
  58. limits: {},
  59. eventTypes: [],
  60. features: [],
  61. })
  62. api.getGroupRooms.mockResolvedValue({ items: [roomA, roomB], nextCursor: null })
  63. api.getPinnedGroupTopics.mockResolvedValue({ items: [] })
  64. api.getGroupRoom.mockImplementation((roomId: string) => roomId === roomA.id ? Promise.resolve(detail(roomA)) : roomBRequest)
  65. api.getGroupTopics.mockImplementation((roomId: string) => Promise.resolve({ items: roomId === roomA.id ? [topicA] : [topicB], nextCursor: null }))
  66. api.getGroupMessages.mockResolvedValue({ items: [] })
  67. const groups = useGroupsStore()
  68. await groups.start()
  69. expect(groups.selectedRoomId).toBe(roomA.id)
  70. expect(groups.selectedTopicId).toBe(topicA.id)
  71. await groups.loadRoomTopics(roomB.id)
  72. const selection = groups.selectRoom(roomB.id, topicB.id)
  73. expect(groups.selectedRoomId).toBe(roomB.id)
  74. expect(groups.selectedTopicId).toBe(topicB.id)
  75. expect(groups.selectedTopic?.id).toBe(topicB.id)
  76. resolveRoomB(detail(roomB))
  77. await selection
  78. expect(groups.selectedRoomId).toBe(roomB.id)
  79. expect(groups.selectedTopicId).toBe(topicB.id)
  80. groups.stop()
  81. })
  82. })