import { act, cleanup, fireEvent, render, screen, waitFor, within } from '@testing-library/react'; import { MemoryRouter } from 'react-router-dom'; import { afterEach, beforeEach, expect, it, vi } from 'vitest'; import { ChannelAccounts } from '@/pages/CloudAgents/ChannelAccounts'; import { EMPTY_CLOUD_CONFIGURATION, type CloudAgentDraft, type CloudUserChannelAccount, type CloudWechatBindState } from '../../shared/cloud-agents'; const api = vi.hoisted(() => ({ call: vi.fn(), list: vi.fn(), recovery: vi.fn(), resolvePending: vi.fn() })); vi.mock('@/lib/cloud-agents-api', () => ({ cloudAgentsApi: api })); vi.mock('@/pages/CloudAgents/CloudWechatQr', () => ({ CloudWechatQr: () => 个人微信登录二维码 })); const agentA: CloudAgentDraft = { slug: 'ml-' + 'a'.repeat(32), name: '写作助手', purpose: '', system_prompt: '', published_version: 2, draft_revision: 3, updated_at: '', configuration: EMPTY_CLOUD_CONFIGURATION, enabled: true }; const agentB: CloudAgentDraft = { ...agentA, slug: 'ml-' + 'b'.repeat(32), name: '资料助手', published_version: 4, draft_revision: 5 }; const legacy: CloudUserChannelAccount = { id: 'wechat-legacy', display_name: '原有微信', binding_id: 'binding-legacy', revision: 7, enabled: true, status: 'active', health: 'connected', blockers: [], target_agent_slug: agentA.slug, target_agent_name: agentA.name, target_agent_published_version: 2, provider_generation: 'generation-legacy' }; const spare: CloudUserChannelAccount = { id: 'wechat-spare', display_name: '备用微信', binding_id: 'binding-spare', revision: 2, enabled: false, status: 'paused', health: 'login_required', blockers: ['target_required'], target_agent_slug: null, target_agent_name: null, target_agent_published_version: null, provider_generation: 'generation-spare' }; let accounts: CloudUserChannelAccount[]; let agents: CloudAgentDraft[]; let qrStatus: CloudWechatBindState['status']; let verifyStatus: CloudWechatBindState['status']; const calls = (operation: string) => api.call.mock.calls.filter(([name]) => name === operation); const writes = () => api.call.mock.calls.filter(([name]) => !['channelAccounts', 'channelAccountWechatBindStatus'].includes(name)); function renderPage(entry = '/cloud-agents/channels') { return render(); } async function addWechat(fakeTimers = false) { fireEvent.click(await screen.findByRole('button', { name: '添加微信', exact: true })); const dialog = screen.getByRole('dialog', { name: '添加微信', exact: true }); fireEvent.change(within(dialog).getByLabelText('选择智能体', { exact: true }), { target: { value: agentA.slug } }); fireEvent.change(within(dialog).getByLabelText('微信备注(可选)', { exact: true }), { target: { value: '创作微信' } }); if (fakeTimers) vi.useFakeTimers(); await act(async () => fireEvent.click(within(dialog).getByRole('button', { name: '下一步:扫码连接', exact: true }))); return dialog; } async function manage(name = legacy.display_name) { const card = await screen.findByRole('article', { name: name + '微信', exact: true }); fireEvent.click(within(card).getByRole('button', { name: /管理绑定|继续绑定/ })); return screen.getByRole('dialog', { name: '管理微信绑定', exact: true }); } function installMock() { api.call.mockImplementation(async (operation: string, input: Record) => { if (operation === 'channelAccounts') return { items: accounts.map(item => ({ ...item })) }; if (operation === 'createChannelAccount') { const channel = { ...spare, id: 'wechat-created', display_name: String(input.display_name), revision: 1 }; accounts.push(channel); return { channel }; } const account = accounts.find(item => item.id === input.channel_account_id); if (!account) throw new Error('Unknown fixture account'); if (operation === 'routeChannelAccount') { const target = agents.find(item => item.slug === input.target_agent_slug); Object.assign(account, { revision: account.revision + 1, target_agent_slug: target?.slug ?? null, target_agent_name: target?.name ?? null, target_agent_published_version: target?.published_version ?? null, enabled: input.enabled, blockers: target ? [] : ['target_required'] }); return { channel: { ...account } }; } if (operation === 'enableChannelAccount' || operation === 'pauseChannelAccount') { Object.assign(account, { revision: account.revision + 1, enabled: operation === 'enableChannelAccount' }); return { channel: { ...account } }; } if (operation === 'disconnectChannelAccount') { Object.assign(account, { revision: account.revision + 1, health: 'login_required', enabled: false }); return { channel: { ...account }, disconnected: true }; } if (['channelAccountWechatBindStart', 'channelAccountWechatBindStatus', 'channelAccountWechatBindVerification'].includes(operation)) { const status = operation === 'channelAccountWechatBindVerification' ? verifyStatus : qrStatus; if (status === 'confirmed') account.health = 'connected'; return { session_key: 'qr-' + account.id, status, qrcode_url: 'https://login.example.test/qr' }; } throw new Error('Unexpected fixture operation ' + operation); }); } beforeEach(() => { vi.resetAllMocks(); accounts = [{ ...legacy }, { ...spare }]; agents = [agentA, agentB]; qrStatus = 'verification_required'; verifyStatus = 'pending'; api.list.mockImplementation(async () => ({ agents, next_cursor: null })); api.recovery.mockResolvedValue({ recent: null, pending: [] }); installMock(); }); afterEach(() => { cleanup(); vi.useRealTimers(); }); it('shows binding cards and never fetches or embeds conversation or activity panels', async () => { renderPage(); const card = await screen.findByRole('article', { name: '原有微信微信', exact: true }); expect(within(card).getByText(agentA.name, { exact: true })).toBeVisible(); expect(within(card).getByRole('button', { name: '管理绑定', exact: true })).toBeVisible(); expect(await screen.findByRole('article', { name: '备用微信微信', exact: true })).toBeVisible(); expect(screen.queryByRole('dialog')).not.toBeInTheDocument(); expect(screen.queryByText('微信对话', { exact: true })).not.toBeInTheDocument(); expect(screen.queryByText('活动记录', { exact: true })).not.toBeInTheDocument(); expect(writes()).toEqual([]); expect(api.call.mock.calls.every(([operation]) => operation === 'channelAccounts')).toBe(true); }); it('offers only available published Agents and needs a selection before connecting', async () => { agents.push({ ...agentA, slug: 'ml-' + 'c'.repeat(32), name: '尚未制作好', published_version: null }, { ...agentA, slug: 'ml-' + 'd'.repeat(32), name: '已停用助手', enabled: false }); renderPage(); fireEvent.click(await screen.findByRole('button', { name: '添加微信', exact: true })); const dialog = screen.getByRole('dialog', { name: '添加微信', exact: true }); expect(within(dialog).getByRole('button', { name: '下一步:扫码连接', exact: true })).toBeDisabled(); expect(within(dialog).queryByRole('option', { name: /尚未制作好|已停用助手/ })).not.toBeInTheDocument(); expect(within(dialog).getByRole('option', { name: agentA.name, exact: true })).toBeInTheDocument(); expect(writes()).toEqual([]); }); it('creates, associates then requests a QR without enabling the channel', async () => { renderPage(); const dialog = await addWechat(); expect(await within(dialog).findByRole('img', { name: '个人微信登录二维码' })).toBeVisible(); expect(writes().map(([operation]) => operation)).toEqual(['createChannelAccount', 'routeChannelAccount', 'channelAccountWechatBindStart']); expect(calls('routeChannelAccount')[0][1]).toMatchObject({ channel_account_id: 'wechat-created', target_agent_slug: agentA.slug, expected_revision: 1, enabled: false }); expect(accounts.find(item => item.id === 'wechat-created')).toMatchObject({ enabled: false }); expect(calls('enableChannelAccount')).toHaveLength(0); }); it('keeps a pending verification visible and cannot claim usable or enable before confirmation', async () => { renderPage(); const dialog = await addWechat(); const input = await within(dialog).findByLabelText('微信验证码', { exact: true }); fireEvent.change(input, { target: { value: '123456' } }); fireEvent.click(within(dialog).getByRole('button', { name: '提交验证码', exact: true })); await waitFor(() => expect(calls('channelAccountWechatBindVerification')).toHaveLength(1)); expect(within(dialog).getByRole('img', { name: '个人微信登录二维码' })).toBeVisible(); expect(within(dialog).getByRole('button', { name: '完成绑定并启用', exact: true })).toBeDisabled(); expect(calls('enableChannelAccount')).toHaveLength(0); }); it('closes a confirmed QR, enables only with an explicit click and reports success afterward', async () => { verifyStatus = 'confirmed'; renderPage(); const dialog = await addWechat(); fireEvent.change(await within(dialog).findByLabelText('微信验证码', { exact: true }), { target: { value: '123456' } }); fireEvent.click(within(dialog).getByRole('button', { name: '提交验证码', exact: true })); expect(await within(dialog).findByText('微信已连接', { exact: true })).toBeVisible(); expect(within(dialog).queryByRole('img', { name: '个人微信登录二维码' })).not.toBeInTheDocument(); expect(within(dialog).queryByLabelText('微信验证码')).not.toBeInTheDocument(); expect(calls('enableChannelAccount')).toHaveLength(0); fireEvent.click(within(dialog).getByRole('button', { name: '完成绑定并启用', exact: true })); await waitFor(() => expect(calls('enableChannelAccount')).toHaveLength(1)); expect(await within(dialog).findByRole('button', { name: '完成', exact: true })).toBeEnabled(); fireEvent.click(within(dialog).getByRole('button', { name: '完成', exact: true })); expect(screen.queryByRole('dialog')).not.toBeInTheDocument(); expect(accounts.find(item => item.id === 'wechat-created')).toMatchObject({ enabled: true, health: 'connected', target_agent_slug: agentA.slug }); }); it('does not report binding success when enable fails after the QR is confirmed', async () => { qrStatus = 'confirmed'; const base = api.call.getMockImplementation()!; api.call.mockImplementation(async (operation, input) => { if (operation === 'enableChannelAccount') throw new Error('启用失败'); return base(operation, input); }); renderPage(); const dialog = await addWechat(); fireEvent.click(await within(dialog).findByRole('button', { name: '完成绑定并启用', exact: true })); expect(await within(dialog).findByText(/启用失败/)).toBeVisible(); expect(within(dialog).queryByRole('button', { name: '完成', exact: true })).not.toBeInTheDocument(); expect(accounts.find(item => item.id === 'wechat-created')?.enabled).toBe(false); }); it('ends QR polling once connected and does not automatically enable', async () => { renderPage(); const dialog = await addWechat(true); expect(within(dialog).getByRole('img', { name: '个人微信登录二维码' })).toBeVisible(); qrStatus = 'confirmed'; await act(async () => { await vi.advanceTimersByTimeAsync(2000); }); expect(within(dialog).queryByRole('img', { name: '个人微信登录二维码' })).not.toBeInTheDocument(); expect(within(dialog).getByRole('button', { name: '完成绑定并启用', exact: true })).toBeVisible(); await act(async () => { await vi.advanceTimersByTimeAsync(6000); }); expect(calls('channelAccountWechatBindStatus')).toHaveLength(1); expect(calls('enableChannelAccount')).toHaveLength(0); }); it('changes an existing association only after confirmation and keeps its login and enabled state', async () => { renderPage(); const dialog = await manage(); fireEvent.change(within(dialog).getByLabelText('绑定的智能体', { exact: true }), { target: { value: agentB.slug } }); fireEvent.click(within(dialog).getByRole('button', { name: '保存更换', exact: true })); expect(calls('routeChannelAccount')).toHaveLength(0); const confirmation = screen.getByRole('dialog', { name: '更换绑定的智能体', exact: true }); fireEvent.click(within(confirmation).getByRole('button', { name: /确认更换/ })); await waitFor(() => expect(calls('routeChannelAccount')).toHaveLength(1)); expect(calls('routeChannelAccount')[0][1]).toMatchObject({ channel_account_id: legacy.id, target_agent_slug: agentB.slug, expected_revision: 7, enabled: true }); expect(calls('createChannelAccount')).toHaveLength(0); expect(calls('channelAccountWechatBindStart')).toHaveLength(0); expect(accounts[0].health).toBe('connected'); }); it('lets independent WeChat accounts choose the same Agent without creating another slot', async () => { accounts[1] = { ...spare, health: 'connected', target_agent_slug: agentB.slug, target_agent_name: agentB.name, target_agent_published_version: 4 }; renderPage(); const dialog = await manage(spare.display_name); fireEvent.change(within(dialog).getByLabelText('绑定的智能体', { exact: true }), { target: { value: agentA.slug } }); fireEvent.click(within(dialog).getByRole('button', { name: '保存更换', exact: true })); const confirmation = screen.getByRole('dialog', { name: '更换绑定的智能体', exact: true }); fireEvent.click(within(confirmation).getByRole('button', { name: /确认更换/ })); await waitFor(() => expect(calls('routeChannelAccount')).toHaveLength(1)); expect(accounts.every(item => item.target_agent_slug === agentA.slug)).toBe(true); expect(accounts[1].enabled).toBe(false); expect(calls('createChannelAccount')).toHaveLength(0); expect(calls('channelAccountWechatBindStart')).toHaveLength(0); }); it('pauses and resumes an existing binding without clearing its target or login', async () => { renderPage(); const dialog = await manage(); fireEvent.click(within(dialog).getByRole('button', { name: '暂停使用', exact: true })); expect(await within(dialog).findByRole('button', { name: '恢复使用', exact: true })).toBeEnabled(); expect(accounts[0]).toMatchObject({ enabled: false, health: 'connected', target_agent_slug: agentA.slug }); fireEvent.click(within(dialog).getByRole('button', { name: '恢复使用', exact: true })); await within(dialog).findByRole('button', { name: '暂停使用', exact: true }); expect(calls('pauseChannelAccount')[0][1]).toMatchObject({ channel_account_id: legacy.id, expected_revision: 7 }); expect(calls('enableChannelAccount')[0][1]).toMatchObject({ channel_account_id: legacy.id, expected_revision: 8 }); expect(calls('routeChannelAccount')).toHaveLength(0); expect(calls('channelAccountWechatBindStart')).toHaveLength(0); }); it('clears an association only after confirmation and preserves the WeChat login', async () => { renderPage(); const dialog = await manage(); fireEvent.click(within(dialog).getByRole('button', { name: '解除绑定', exact: true })); expect(calls('routeChannelAccount')).toHaveLength(0); const confirmation = screen.getByRole('dialog', { name: '解除智能体绑定', exact: true }); fireEvent.click(within(confirmation).getByRole('button', { name: '确认解除', exact: true })); await waitFor(() => expect(calls('routeChannelAccount')).toHaveLength(1)); expect(calls('routeChannelAccount')[0][1]).toMatchObject({ channel_account_id: legacy.id, target_agent_slug: null, enabled: false, expected_revision: 7 }); expect(accounts[0]).toMatchObject({ health: 'connected', target_agent_slug: null, enabled: false }); expect(calls('disconnectChannelAccount')).toHaveLength(0); expect(calls('channelAccountWechatUnbind')).toHaveLength(0); }); it('disconnects only after confirmation and retains the selected Agent and account card', async () => { renderPage(); const dialog = await manage(); fireEvent.click(within(dialog).getByRole('button', { name: '断开微信连接', exact: true })); expect(calls('disconnectChannelAccount')).toHaveLength(0); const confirmation = screen.getByRole('dialog', { name: '断开微信连接', exact: true }); fireEvent.click(within(confirmation).getByRole('button', { name: '确认断开', exact: true })); await waitFor(() => expect(calls('disconnectChannelAccount')).toHaveLength(1)); expect(accounts[0]).toMatchObject({ enabled: false, health: 'login_required', target_agent_slug: agentA.slug }); expect(calls('routeChannelAccount')).toHaveLength(0); await within(dialog).findByRole('button', { name: '扫码连接', exact: true }); }); it('retries a failed association without creating another account and reuses the original request', async () => { const base = api.call.getMockImplementation()!; let attempts = 0; api.call.mockImplementation(async (operation, input) => { if (operation === 'routeChannelAccount' && ++attempts === 1) throw new Error('绑定未完成'); return base(operation, input); }); renderPage(); const dialog = await addWechat(); expect(await within(dialog).findByText('绑定未完成', { exact: true })).toBeVisible(); expect(calls('createChannelAccount')).toHaveLength(1); expect(calls('channelAccountWechatBindStart')).toHaveLength(0); fireEvent.click(within(dialog).getByRole('button', { name: '下一步:扫码连接', exact: true })); await within(dialog).findByRole('img', { name: '个人微信登录二维码' }); expect(calls('createChannelAccount')).toHaveLength(1); expect(calls('routeChannelAccount')).toHaveLength(2); expect(calls('routeChannelAccount')[0][1]).toEqual(calls('routeChannelAccount')[1][1]); }); it('continues an unfinished account without creating another account slot', async () => { accounts = [{ ...spare, health: 'connected' }]; renderPage(); const dialog = await manage(spare.display_name); fireEvent.change(within(dialog).getByLabelText('绑定的智能体', { exact: true }), { target: { value: agentA.slug } }); fireEvent.click(within(dialog).getByRole('button', { name: '下一步:扫码连接', exact: true })); expect(await within(dialog).findByRole('button', { name: '完成绑定并启用', exact: true })).toBeEnabled(); expect(calls('createChannelAccount')).toHaveLength(0); expect(calls('channelAccountWechatBindStart')).toHaveLength(0); expect(calls('routeChannelAccount')[0][1]).toMatchObject({ channel_account_id: spare.id, target_agent_slug: agentA.slug }); }); it('does not erase the old association or claim success after a rejected change', async () => { const base = api.call.getMockImplementation()!; api.call.mockImplementation(async (operation, input) => { if (operation === 'routeChannelAccount') throw new Error('渠道状态已变化'); return base(operation, input); }); renderPage(); const dialog = await manage(); fireEvent.change(within(dialog).getByLabelText('绑定的智能体', { exact: true }), { target: { value: agentB.slug } }); fireEvent.click(within(dialog).getByRole('button', { name: '保存更换', exact: true })); fireEvent.click(within(screen.getByRole('dialog', { name: '更换绑定的智能体', exact: true })).getByRole('button', { name: '确认更换', exact: true })); await screen.findByText('渠道状态已变化', { exact: true }); expect(accounts[0].target_agent_slug).toBe(agentA.slug); expect(within(dialog).getByLabelText('绑定的智能体', { exact: true })).toHaveValue(agentB.slug); expect(screen.queryByText('已更换绑定的智能体,微信连接保留。')).not.toBeInTheDocument(); }); it.each(['failed', 'expired'] as const)('cannot enable an unsuccessful %s QR connection and can explicitly refresh it', async (status) => { qrStatus = status; renderPage(); const dialog = await addWechat(); expect(await within(dialog).findByRole('button', { name: '刷新二维码', exact: true })).toBeEnabled(); expect(within(dialog).getByRole('button', { name: '完成绑定并启用', exact: true })).toBeDisabled(); expect(calls('enableChannelAccount')).toHaveLength(0); qrStatus = 'confirmed'; fireEvent.click(within(dialog).getByRole('button', { name: '刷新二维码', exact: true })); expect(await within(dialog).findByText('微信已连接', { exact: true })).toBeVisible(); expect(calls('channelAccountWechatBindStart')[1][1]).toMatchObject({ channel_account_id: 'wechat-created', force: true }); expect(calls('enableChannelAccount')).toHaveLength(0); }); it('does not call a blocked or unconfirmed existing account ready to use', async () => { accounts = [{ ...legacy, health: 'unknown' }, { ...legacy, id: spare.id, display_name: spare.display_name, blockers: ['worker_offline'] }]; renderPage(); const unknown = await screen.findByRole('article', { name: '原有微信微信', exact: true }); const blocked = screen.getByRole('article', { name: '备用微信微信', exact: true }); expect(within(unknown).queryByText('可以使用', { exact: true })).not.toBeInTheDocument(); expect(within(blocked).queryByText('可以使用', { exact: true })).not.toBeInTheDocument(); expect(calls('enableChannelAccount')).toHaveLength(0); }); it('keeps adding unavailable after a failed initial read instead of showing a false empty account list', async () => { api.call.mockRejectedValue(new Error('微信列表暂时不可用')); renderPage(); await screen.findByText('微信列表暂时不可用', { exact: true }); expect(screen.getByRole('button', { name: '添加微信', exact: true })).toBeDisabled(); expect(screen.queryByText('还没有微信绑定', { exact: true })).not.toBeInTheDocument(); installMock(); fireEvent.click(screen.getByRole('button', { name: '刷新微信列表', exact: true })); expect(await screen.findByRole('article', { name: '原有微信微信', exact: true })).toBeVisible(); expect(screen.getByRole('button', { name: '添加微信', exact: true })).toBeEnabled(); }); it('allows the optional WeChat remark to stay empty', async () => { renderPage(); fireEvent.click(await screen.findByRole('button', { name: '添加微信', exact: true })); const dialog = screen.getByRole('dialog', { name: '添加微信', exact: true }); fireEvent.change(within(dialog).getByLabelText('选择智能体', { exact: true }), { target: { value: agentA.slug } }); fireEvent.click(within(dialog).getByRole('button', { name: '下一步:扫码连接', exact: true })); await within(dialog).findByRole('img', { name: '个人微信登录二维码' }); expect(calls('createChannelAccount')).toHaveLength(1); expect(calls('createChannelAccount')[0][1].display_name).toMatch(/\S/); }); it('completes a reconnected already enabled account without sending another enable request', async () => { accounts = [{ ...legacy, health: 'login_required' }]; qrStatus = 'confirmed'; renderPage(); const dialog = await manage(); fireEvent.click(within(dialog).getByRole('button', { name: '扫码连接', exact: true })); expect(await within(dialog).findByText('微信已连接', { exact: true })).toBeVisible(); fireEvent.click(within(dialog).getByRole('button', { name: '完成绑定并启用', exact: true })); expect(await within(dialog).findByRole('button', { name: '完成', exact: true })).toBeVisible(); expect(calls('enableChannelAccount')).toHaveLength(0); expect(calls('createChannelAccount')).toHaveLength(0); expect(calls('routeChannelAccount')).toHaveLength(0); }); it.each(['channelAccountWechatBindStart', 'channelAccountWechatBindVerification'])('blocks new slots and QR actions while %s has an uncertain result', async operation => { accounts = [{ ...legacy, health: 'login_required' }]; api.recovery.mockResolvedValue({ recent: null, pending: [{ id: 'uncertain-wechat', operation, input: { channel_account_id: legacy.id }, created_at: '2026-10-12T00:00:00Z' }] }); renderPage('/cloud-agents/channels?account=' + legacy.id); const dialog = await screen.findByRole('dialog', { name: '管理微信绑定', exact: true }); expect(screen.getByRole('button', { name: '添加微信', exact: true, hidden: true })).toBeDisabled(); expect(within(dialog).getByRole('button', { name: '扫码连接', exact: true })).toBeDisabled(); fireEvent.click(within(dialog).getByRole('button', { name: '扫码连接', exact: true })); expect(calls('channelAccountWechatBindStart')).toHaveLength(0); expect(calls('createChannelAccount')).toHaveLength(0); expect(calls('enableChannelAccount')).toHaveLength(0); }); it('uses the latest account state when enabling after QR confirmation', async () => { qrStatus = 'confirmed'; renderPage(); const dialog = await addWechat(); await within(dialog).findByText('微信已连接', { exact: true }); const created = accounts.find(item => item.id === 'wechat-created')!; created.revision = 77; fireEvent.click(within(dialog).getByRole('button', { name: '完成绑定并启用', exact: true })); await within(dialog).findByRole('button', { name: '完成', exact: true }); expect(calls('enableChannelAccount')[0][1]).toMatchObject({ channel_account_id: 'wechat-created', expected_revision: 77 }); }); it('does not enable when the authoritative account has become blocked after QR confirmation', async () => { qrStatus = 'confirmed'; renderPage(); const dialog = await addWechat(); await within(dialog).findByText('微信已连接', { exact: true }); accounts.find(item => item.id === 'wechat-created')!.blockers = ['worker_offline']; fireEvent.click(within(dialog).getByRole('button', { name: '完成绑定并启用', exact: true })); expect(await within(dialog).findByText('微信还没有准备好,请刷新连接状态后再试。', { exact: true })).toBeVisible(); expect(calls('enableChannelAccount')).toHaveLength(0); expect(within(dialog).queryByRole('button', { name: '完成', exact: true })).not.toBeInTheDocument(); }); it('does not silently enable another Agent if the association changes while scanning', async () => { qrStatus = 'confirmed'; renderPage(); const dialog = await addWechat(); await within(dialog).findByText('微信已连接', { exact: true }); const created = accounts.find(item => item.id === 'wechat-created')!; Object.assign(created, { target_agent_slug: agentB.slug, target_agent_name: agentB.name }); fireEvent.click(within(dialog).getByRole('button', { name: '完成绑定并启用', exact: true })); expect(await within(dialog).findByText('绑定的智能体已发生变化,请返回上一步确认。', { exact: true })).toBeVisible(); expect(calls('enableChannelAccount')).toHaveLength(0); expect(within(dialog).queryByRole('button', { name: '完成', exact: true })).not.toBeInTheDocument(); }); it('does not show successful enable or completed binding when the enable receipt remains disabled', async () => { qrStatus = 'confirmed'; const base = api.call.getMockImplementation()!; api.call.mockImplementation(async (operation, input) => { if (operation === 'enableChannelAccount') return { channel: { ...accounts.find(item => item.id === input.channel_account_id)!, enabled: false } }; return base(operation, input); }); renderPage(); const dialog = await addWechat(); fireEvent.click(await within(dialog).findByRole('button', { name: '完成绑定并启用', exact: true })); await within(dialog).findByText('微信还没有准备好,请刷新连接状态后再试。', { exact: true }); expect(calls('enableChannelAccount')).toHaveLength(1); expect(within(dialog).queryByRole('heading', { name: '绑定完成啦', exact: true })).not.toBeInTheDocument(); expect(within(dialog).queryByRole('button', { name: '完成', exact: true })).not.toBeInTheDocument(); expect(screen.queryByText('微信绑定已启用。', { exact: true })).not.toBeInTheDocument(); expect(accounts.find(item => item.id === 'wechat-created')?.enabled).toBe(false); });