Integrate delivered Code navigation and Yuxi channel recovery into Canvas trial source
This commit is contained in:
1 parent
2ca6e3199d
commit
3fe3fdb1c0
38 files changed
+1602
-198
No files matched your search
@@ -156,6 +156,13 @@ test('WeChat binding cards connect an account and switch its Agent through the c
|
||||
Object.assign(globalThis, { cloudChannelFixtureCalls: calls });
|
||||
let verified = false;
|
||||
let rejectUnbind = true;
|
||||
const controls = {
|
||||
serverPending: false,
|
||||
pendingOnNextRead: false,
|
||||
disabledTarget: false,
|
||||
legacyPending: false,
|
||||
};
|
||||
Object.assign(globalThis, { cloudChannelFixtureControls: controls });
|
||||
const slug = 'ml-' + 'a'.repeat(32);
|
||||
const configuration = {
|
||||
model: 'test-model',
|
||||
@@ -289,12 +296,47 @@ test('WeChat binding cards connect an account and switch its Agent through the c
|
||||
if (!path.startsWith('/api/cloud-agents/')) return result({ success: true });
|
||||
const body =
|
||||
typeof request.body === 'string' ? JSON.parse(request.body) : (request.body ?? {});
|
||||
if (path.endsWith('/recovery')) return result({ recent: null, pending: [] });
|
||||
if (path.endsWith('/recovery'))
|
||||
return result({
|
||||
recent: null,
|
||||
pending: controls.legacyPending
|
||||
? [
|
||||
{
|
||||
id: 'fixture-legacy-unbind',
|
||||
operation: 'unbindChannelAccount',
|
||||
input: {
|
||||
channel_account_id: 'wechat-b',
|
||||
operation_id: 'legacy-original-id',
|
||||
expected_revision: 1,
|
||||
},
|
||||
created_at: '2026-10-13T00:00:00Z',
|
||||
},
|
||||
]
|
||||
: [],
|
||||
});
|
||||
if (path.endsWith('/recovery/pending')) {
|
||||
calls.push({ operation: 'resolvePending', input: body });
|
||||
if (body.discard) {
|
||||
controls.legacyPending = false;
|
||||
return result({ discarded: true });
|
||||
}
|
||||
return result({
|
||||
operation: 'unbindChannelAccount',
|
||||
pending: true,
|
||||
result: { error_code: 'channel_operation_legacy' },
|
||||
});
|
||||
}
|
||||
if (path.endsWith('/recovery/recent')) return result({ saved: true });
|
||||
if (!path.endsWith('/actions'))
|
||||
return result(
|
||||
path.endsWith('/agents') || path.endsWith('/bootstrap')
|
||||
? { agents: [draft, secondDraft], next_cursor: null }
|
||||
? {
|
||||
agents: [
|
||||
controls.disabledTarget ? { ...draft, enabled: false } : draft,
|
||||
secondDraft,
|
||||
],
|
||||
next_cursor: null,
|
||||
}
|
||||
: path.endsWith(secondSlug)
|
||||
? secondDraft
|
||||
: draft
|
||||
@@ -333,7 +375,31 @@ test('WeChat binding cards connect an account and switch its Agent through the c
|
||||
next_offset: null,
|
||||
summary: { count: 0, settled_points: '0', pending_points: '0' },
|
||||
});
|
||||
if (operation === 'channelAccounts') return result({ items: channelAccounts });
|
||||
if (operation === 'channelAccounts') {
|
||||
if (controls.pendingOnNextRead) {
|
||||
controls.serverPending = true;
|
||||
controls.pendingOnNextRead = false;
|
||||
}
|
||||
return result({
|
||||
items: channelAccounts.map((item) => {
|
||||
if (controls.serverPending && item.id === 'wechat-b')
|
||||
return {
|
||||
...item,
|
||||
health: 'unknown',
|
||||
sync_state: 'degraded',
|
||||
blockers: ['wechat_disconnect_pending'],
|
||||
};
|
||||
if (controls.disabledTarget && item.id === 'wechat-created')
|
||||
return {
|
||||
...item,
|
||||
enabled: false,
|
||||
desired_state: 'paused',
|
||||
blockers: ['binding_paused'],
|
||||
};
|
||||
return item;
|
||||
}),
|
||||
});
|
||||
}
|
||||
if (operation === 'createChannelAccount') {
|
||||
const created = {
|
||||
...spare,
|
||||
@@ -671,7 +737,10 @@ test('WeChat binding cards connect an account and switch its Agent through the c
|
||||
},
|
||||
]);
|
||||
await legacyCard.getByRole('button', { name: '更多操作', exact: true }).click();
|
||||
await page.screenshot({ path: testInfo.outputPath('wechat-binding-more-compact.png'), fullPage: true });
|
||||
await page.screenshot({
|
||||
path: testInfo.outputPath('wechat-binding-more-compact.png'),
|
||||
fullPage: true,
|
||||
});
|
||||
await expect(legacyCard.getByRole('button', { name: '暂停自动回复', exact: true })).toBeVisible();
|
||||
await legacyCard.getByRole('button', { name: '解除微信绑定', exact: true }).click();
|
||||
const unbinding = page.getByRole('dialog', { name: '解除微信绑定', exact: true });
|
||||
@@ -700,6 +769,148 @@ test('WeChat binding cards connect an account and switch its Agent through the c
|
||||
);
|
||||
expect(unbindCalls).toHaveLength(2);
|
||||
expect(unbindCalls[0].input).toEqual(unbindCalls[1].input);
|
||||
|
||||
await app.evaluate(() => {
|
||||
(
|
||||
globalThis as typeof globalThis & { cloudChannelFixtureControls: { serverPending: boolean } }
|
||||
).cloudChannelFixtureControls.serverPending = true;
|
||||
});
|
||||
await page.getByRole('button', { name: '刷新微信列表', exact: true }).click();
|
||||
await expect(spareCard.getByText('正在确认', { exact: true })).toBeVisible();
|
||||
await expect(page.getByText(/请回到发起操作的设备确认原来的操作/)).toBeVisible();
|
||||
await expect(page.getByRole('button', { name: '添加微信', exact: true })).toBeDisabled();
|
||||
await expect(legacyCard.getByRole('button', { name: '绑定智能体', exact: true })).toBeDisabled();
|
||||
const createdCard = page.getByRole('article', { name: '微信 3微信', exact: true });
|
||||
await expect(createdCard.getByRole('button', { name: '更多操作', exact: true })).toBeDisabled();
|
||||
await page.screenshot({
|
||||
path: testInfo.outputPath('wechat-server-pending-owner-lock.png'),
|
||||
fullPage: true,
|
||||
});
|
||||
|
||||
await app.evaluate(() => {
|
||||
(
|
||||
globalThis as typeof globalThis & { cloudChannelFixtureControls: { serverPending: boolean } }
|
||||
).cloudChannelFixtureControls.serverPending = false;
|
||||
});
|
||||
await page.getByRole('button', { name: '刷新微信列表', exact: true }).click();
|
||||
await expect(legacyCard.getByRole('button', { name: '绑定智能体', exact: true })).toBeEnabled();
|
||||
await legacyCard.getByRole('button', { name: '绑定智能体', exact: true }).click();
|
||||
const latePending = page.getByRole('dialog', { name: '更换智能体', exact: true });
|
||||
await latePending
|
||||
.getByRole('radiogroup', { name: '选择智能体' })
|
||||
.getByText('资料整理助手', { exact: true })
|
||||
.click();
|
||||
const managementCallsBefore = await app.evaluate(
|
||||
() =>
|
||||
(
|
||||
globalThis as typeof globalThis & { cloudChannelFixtureCalls: { operation: string }[] }
|
||||
).cloudChannelFixtureCalls.filter((call) => call.operation !== 'channelAccounts').length
|
||||
);
|
||||
await app.evaluate(() => {
|
||||
(
|
||||
globalThis as typeof globalThis & { cloudChannelFixtureControls: { pendingOnNextRead: boolean } }
|
||||
).cloudChannelFixtureControls.pendingOnNextRead = true;
|
||||
});
|
||||
await latePending.getByRole('button', { name: '下一步:扫码连接', exact: true }).click();
|
||||
await expect(latePending.getByRole('alert')).toHaveText(/微信退出还在确认中/);
|
||||
await expect(
|
||||
latePending.getByRole('button', { name: '下一步:扫码连接', exact: true })
|
||||
).toBeDisabled();
|
||||
expect(
|
||||
await app.evaluate(
|
||||
() =>
|
||||
(
|
||||
globalThis as typeof globalThis & { cloudChannelFixtureCalls: { operation: string }[] }
|
||||
).cloudChannelFixtureCalls.filter((call) => call.operation !== 'channelAccounts').length
|
||||
)
|
||||
).toBe(managementCallsBefore);
|
||||
await page.screenshot({
|
||||
path: testInfo.outputPath('wechat-late-pending-dialog.png'),
|
||||
fullPage: true,
|
||||
});
|
||||
await latePending.getByRole('button', { name: '关闭', exact: true }).click();
|
||||
|
||||
await app.evaluate(() => {
|
||||
const control = (
|
||||
globalThis as typeof globalThis & {
|
||||
cloudChannelFixtureControls: { serverPending: boolean; disabledTarget: boolean };
|
||||
}
|
||||
).cloudChannelFixtureControls;
|
||||
control.serverPending = false;
|
||||
control.disabledTarget = true;
|
||||
});
|
||||
await page.getByRole('button', { name: '刷新微信列表', exact: true }).click();
|
||||
await expect(createdCard.getByText('智能体已停用', { exact: true })).toBeVisible();
|
||||
await expect(createdCard.getByText('使用中', { exact: true })).toHaveCount(0);
|
||||
await createdCard.getByRole('button', { name: '更多操作', exact: true }).click();
|
||||
await expect(createdCard.getByRole('button', { name: '恢复自动回复', exact: true })).toBeDisabled();
|
||||
await expect(createdCard.getByRole('button', { name: '解除微信绑定', exact: true })).toBeEnabled();
|
||||
await createdCard
|
||||
.getByRole('button', { name: '解除微信绑定', exact: true })
|
||||
.scrollIntoViewIfNeeded();
|
||||
await page.screenshot({
|
||||
path: testInfo.outputPath('wechat-disabled-target-safe-actions.png'),
|
||||
fullPage: true,
|
||||
});
|
||||
|
||||
await app.evaluate(() => {
|
||||
const control = (
|
||||
globalThis as typeof globalThis & {
|
||||
cloudChannelFixtureControls: {
|
||||
serverPending: boolean;
|
||||
disabledTarget: boolean;
|
||||
legacyPending: boolean;
|
||||
};
|
||||
}
|
||||
).cloudChannelFixtureControls;
|
||||
control.serverPending = true;
|
||||
control.disabledTarget = false;
|
||||
control.legacyPending = true;
|
||||
});
|
||||
await page.getByRole('button', { name: '刷新微信列表', exact: true }).click();
|
||||
await page.getByRole('button', { name: '待处理记录(1)', exact: true }).click();
|
||||
const recovering = page.getByRole('dialog', { name: '待处理记录', exact: true });
|
||||
await recovering.getByRole('button', { name: '再试一次', exact: true }).click();
|
||||
const recoveryRecord = recovering.getByRole('article', { name: '解除微信绑定', exact: true });
|
||||
await expect(recoveryRecord.getByRole('status')).toHaveText(
|
||||
'这次旧微信操作无法安全恢复,请联系管理员核对后再操作。'
|
||||
);
|
||||
await expect(recoveryRecord.getByRole('button', { name: '再试一次', exact: true })).toBeDisabled();
|
||||
await expect(recoveryRecord.getByRole('button', { name: '刷新状态', exact: true })).toHaveCount(0);
|
||||
await expect(recovering.getByText('解除微信绑定的结果已确认。', { exact: true })).toHaveCount(0);
|
||||
await expect(recovering.getByText(/不会取消微信服务端仍在处理的操作/)).toBeVisible();
|
||||
await page.screenshot({
|
||||
path: testInfo.outputPath('wechat-legacy-recovery-attention.png'),
|
||||
fullPage: true,
|
||||
});
|
||||
await recoveryRecord.getByRole('button', { name: '不再提醒', exact: true }).click();
|
||||
await expect(recoveryRecord).toHaveCount(0);
|
||||
await recovering.getByRole('button', { name: '返回列表', exact: true }).click();
|
||||
await expect(page.getByRole('button', { name: '添加微信', exact: true })).toBeDisabled();
|
||||
await expect(spareCard.getByText('正在确认', { exact: true })).toBeVisible();
|
||||
await expect(page.getByText(/请回到发起操作的设备确认原来的操作/)).toBeVisible();
|
||||
expect(
|
||||
await app.evaluate(() =>
|
||||
(
|
||||
globalThis as typeof globalThis & {
|
||||
cloudChannelFixtureCalls: { operation: string; input: Record<string, unknown> }[];
|
||||
}
|
||||
).cloudChannelFixtureCalls
|
||||
.filter((call) => call.operation === 'resolvePending')
|
||||
.map((call) => call.input)
|
||||
)
|
||||
).toEqual([
|
||||
{ id: 'fixture-legacy-unbind', discard: false },
|
||||
{ id: 'fixture-legacy-unbind', discard: true },
|
||||
]);
|
||||
expect(
|
||||
await app.evaluate(
|
||||
() =>
|
||||
(
|
||||
globalThis as typeof globalThis & { cloudChannelFixtureCalls: { operation: string }[] }
|
||||
).cloudChannelFixtureCalls.filter((call) => call.operation === 'unbindChannelAccount').length
|
||||
)
|
||||
).toBe(2);
|
||||
} finally {
|
||||
await app
|
||||
.evaluate(({ BrowserWindow }) => {
|
||||
|
||||
Reference in new issue
Block a user