Files
Agent-System-Frontend/test/send-removed-member.test.ts
T
agent-exec-transport 9f7f4a164b
governance / governance (pull_request) Successful in 29s
ci / test-and-build (pull_request) Successful in 1m11s
agent-exec transport 257898d9fdadf655ee20accee6813725/4e997a3ec7a5
2026-10-20 11:54:59 +00:00

57 lines
2.8 KiB
TypeScript

// 被移出项目/项目关闭后的发送拒绝:403 `conversation: not-project-member` 走专用文案,
// 其他失败保持通用文案(见 src/store.ts sendMessage 的 catch 分支)。
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { api } from '../src/api'
import { store } from '../src/store'
import type { Conversation, Message } from '../src/contracts'
const REMOVED_TOAST = '无法继续发送:你已不在该项目中或项目已关闭;历史对话仍可查看'
const REMOVED_DELIVERY_ERROR = '无法发送:你已不在该项目中或项目已关闭,内容已保留'
const GENERIC_DELIVERY_ERROR = '发送未成功,内容已保留;可修改后重试或移除'
function detail(id: string) {
return {
conversation: { id, projectId: 'p', title: id, createdAt: '', updatedAt: '' } as Conversation,
messages: [] as Message[], runs: [], activeHitl: [], lastSeq: 0, resumeSeq: 0,
}
}
class FakeEventSource {
onopen = null
onerror = null
onmessage = null
addEventListener() {}
close() {}
}
beforeEach(async () => {
vi.stubGlobal('EventSource', FakeEventSource)
vi.spyOn(api, 'conversationDetail').mockImplementation(async id => detail(id))
vi.spyOn(api, 'getPlan').mockResolvedValue(null)
vi.spyOn(api, 'getTodos').mockResolvedValue(null)
vi.spyOn(api, 'listCards').mockResolvedValue([])
vi.spyOn(api, 'listTasks').mockResolvedValue([])
vi.spyOn(api, 'listArtifacts').mockResolvedValue([])
vi.spyOn(api, 'surfaceList').mockResolvedValue([])
vi.spyOn(api, 'projectSurfaces').mockResolvedValue([])
vi.spyOn(api, 'listProjectCards').mockResolvedValue([])
await store.openProject('p')
await store.openConversation('a')
})
afterEach(() => { vi.useRealTimers(); vi.restoreAllMocks(); vi.unstubAllGlobals() })
describe('sendMessage rejection copy', () => {
it('keeps the message in the outbox with the removed-member copy on 403 not-project-member', async () => {
vi.spyOn(api, 'sendMessage').mockRejectedValue(new Error('403: conversation: not-project-member'))
expect(await store.sendMessage('这条还要继续吗', [], 'kept-id')).toBe('rejected')
expect(store.getState().outbox[0]).toMatchObject({ id: 'kept-id', text: '这条还要继续吗', attachmentIds: [] })
expect(store.getState().outbox[0].deliveryError).toBe(REMOVED_DELIVERY_ERROR)
expect(store.getState().toast).toBe(REMOVED_TOAST)
})
it('keeps the generic copy for any other send failure', async () => {
vi.spyOn(api, 'sendMessage').mockRejectedValue(new Error('500: upstream down'))
expect(await store.sendMessage('这条还要继续吗', [], 'kept-id')).toBe('rejected')
expect(store.getState().outbox[0].deliveryError).toBe(GENERIC_DELIVERY_ERROR)
expect(store.getState().toast).toContain('发送失败:')
})
})