conversationDeliveryMode.test.ts 4.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152
  1. import { afterEach, expect, it, vi } from 'vitest'
  2. import { flushPromises, mount, type VueWrapper } from '@vue/test-utils'
  3. import { shallowRef } from 'vue'
  4. import { createMemoryHistory, createRouter, matchedRouteKey } from 'vue-router'
  5. import ConversationsView from '@/views/ConversationsView.vue'
  6. import ComposerShell from '@/components/composer/ComposerShell.vue'
  7. import { apiRequest } from '@/api/client'
  8. import type { WorkspaceConversation } from '@shared/workspace'
  9. vi.mock('@/api/client', () => ({ apiRequest: vi.fn(), setApiCsrfToken: vi.fn(), ApiError: class extends Error {} }))
  10. vi.mock('@/stores/auth', () => ({ useAuthStore: () => ({ user: { id: 'owner' }, profiles: [], refreshProfileAvatars: async () => {} }) }))
  11. vi.mock('@/stores/theme', () => ({ useThemeStore: () => ({}) }))
  12. let wrapper: VueWrapper | undefined
  13. afterEach(() => { wrapper?.unmount(); wrapper = undefined; vi.restoreAllMocks(); vi.unstubAllGlobals(); vi.mocked(apiRequest).mockReset() })
  14. it.each([true, false])('sends the selected delivery mode through the real composer (enabled=%s)', async enabled => {
  15. const group: WorkspaceConversation = { id: 'group', kind: 'group', name: '开发团队', avatar: '', memberIds: ['bot'], instructions: '', administratorId: 'bot', mode: 'host', autoReplyIds: [], maxReplyRounds: 3, archived: false, pinned: false, readSeq: 0, lastSeq: 0, preview: '', createdAt: 1, updatedAt: 1 }
  16. const agents = [{ id: 'bot', name: '开发者', avatar: '', instructions: '', nodeId: 'local', profile: 'default', archived: false }]
  17. vi.stubGlobal('localStorage', { getItem: () => null, setItem: () => {}, removeItem: () => {} })
  18. vi.stubGlobal('EventSource', class { addEventListener() {} close() {} })
  19. vi.mocked(apiRequest).mockImplementation(async (path, options) => {
  20. if (path === '/api/app/capabilities') return { features: [], csrfToken: 'fixture' } as never
  21. if (path.split('?')[0] === '/api/app/workspace/snapshot') return { agents, conversations: [group], cursor: 1, details: [] } as never
  22. if (path === '/api/app/agents') return { agents } as never
  23. if (path === '/api/app/agents/sources') return { sources: [] } as never
  24. if (path === '/api/app/conversations') return { conversations: [group], cursor: 1 } as never
  25. if (path.startsWith('/api/app/events')) return { events: [], cursor: 1 } as never
  26. if (path.split('?')[0] === '/api/app/conversations/group') return { conversation: group, messages: [], runs: [], run: null, interactions: [], tasks: [] } as never
  27. if (path.endsWith('/messages') && options?.method === 'POST') throw new Error('fixture: keep submitted draft')
  28. return {} as never
  29. })
  30. const router = createRouter({ history: createMemoryHistory(), routes: [{ path: '/conversations/:id?', component: { template: '<div />' } }] })
  31. await router.push('/conversations/group'); await router.isReady()
  32. wrapper = mount(ConversationsView, { shallow: true, attachTo: document.body, global: {
  33. plugins: [router], provide: { [matchedRouteKey as symbol]: shallowRef(router.currentRoute.value.matched[0]) },
  34. stubs: { WorkspaceShell: { template: '<div><slot /></div>' }, ComposerShell: false, Teleport: true },
  35. } })
  36. await flushPromises()
  37. const composer = wrapper.getComponent(ComposerShell)
  38. expect(composer.props('deliveryAvailable')).toBe(true)
  39. expect(wrapper.find('.delivery-mode').exists()).toBe(false)
  40. await composer.get('[aria-label="添加"]').trigger('click')
  41. await composer.findAll('[role="menuitem"]').find(item => item.text().includes('交付目标'))!.trigger('click')
  42. expect(composer.props('deliveryMode')).toBe(true)
  43. await composer.get('textarea').setValue('完成交付报告')
  44. if (!enabled) await composer.get('.composer-delivery-chip').trigger('click')
  45. await composer.get('[aria-label="发送消息"]').trigger('click')
  46. await flushPromises()
  47. expect(apiRequest).toHaveBeenCalledWith('/api/app/conversations/group/messages', expect.objectContaining({ method: 'POST', body: expect.objectContaining({ mode: enabled ? 'goal' : 'chat', content: '完成交付报告' }) }))
  48. expect(composer.get('textarea').element.value).toBe('完成交付报告')
  49. })