feat: v0.8.2 安全纵深补全 · 协议保真 · 断链修复 — 图片SSRF/根MEMORY.md保护根治 · Anthropic thinking回传+pause_turn续传 · 2523 用例全量回归 + E2E 扩充
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* MetonaAI Desktop — E2E 中断链路(v0.8.2 P3-3)
|
||||
*
|
||||
* 独立应用实例(独立 userData + mock),杜绝跨用例运行态竞态:
|
||||
* 发送挂起脚本(mock 首帧后保持连接、心跳保活)→ 流式态出现中断按钮 →
|
||||
* 点击中断 → 恢复 idle → 再次发送正常消息可完成(恢复力闭环)。
|
||||
*/
|
||||
|
||||
import { expect, test } from '@playwright/test';
|
||||
import { launchApp, type AppHarness } from './app-harness';
|
||||
import { HANG_PREFIX, MOCK_REPLY } from './mock-llm';
|
||||
|
||||
let harness: AppHarness;
|
||||
|
||||
test.beforeAll(async () => {
|
||||
harness = await launchApp();
|
||||
});
|
||||
|
||||
test.afterAll(async () => {
|
||||
await harness?.cleanup();
|
||||
});
|
||||
|
||||
test('中断:挂起的流式回复 → 中断 → 恢复 idle → 可继续对话', async () => {
|
||||
const page = harness.page;
|
||||
const input = page.locator('[data-chat-input] textarea').first();
|
||||
await expect(input).toBeVisible({ timeout: 30_000 });
|
||||
|
||||
// 发送挂起脚本:mock 推送首帧后保持连接(心跳保活,不会自然结束)
|
||||
await input.click();
|
||||
await input.fill('请执行 __E2E_HANG__ 脚本');
|
||||
await input.press('Enter');
|
||||
|
||||
// 流式态:挂起脚本的首帧文本可见
|
||||
await expect(page.getByText(HANG_PREFIX).first()).toBeVisible({ timeout: 30_000 });
|
||||
|
||||
// 中断按钮出现(发送按钮在流式态变为「中断」)
|
||||
const stopButton = page.getByRole('button', { name: /中断|Stop/ }).first();
|
||||
await expect(stopButton).toBeVisible({ timeout: 15_000 });
|
||||
await stopButton.click();
|
||||
|
||||
// 中断后恢复 idle:输入框重新可用
|
||||
await expect(input).toBeEnabled({ timeout: 15_000 });
|
||||
|
||||
// 恢复力闭环:中断后可继续正常对话(新 run → mock 正常回复)。
|
||||
// abort 点击后引擎需短暂时间真正终止(waitForAbort),期间的发送会被
|
||||
// 同会话防重入拒绝(busy 提示)—— 以"忙则等待重试"保证确定性。
|
||||
const busyHint = page.getByText(/该会话正在执行任务|already running/).first();
|
||||
let sent = false;
|
||||
for (let attempt = 0; attempt < 10 && !sent; attempt++) {
|
||||
await input.click();
|
||||
await input.fill('中断后请再回复一次');
|
||||
await input.press('Enter');
|
||||
try {
|
||||
await busyHint.waitFor({ state: 'visible', timeout: 1_500 });
|
||||
await page.waitForTimeout(1_000);
|
||||
} catch {
|
||||
sent = true; // 未出现 busy 提示 → 本次发送已被接受
|
||||
}
|
||||
}
|
||||
expect(sent).toBe(true);
|
||||
// 独立实例中首条 MOCK_REPLY 即恢复对话的回答
|
||||
await expect(page.getByText(MOCK_REPLY).first()).toBeVisible({ timeout: 30_000 });
|
||||
});
|
||||
Reference in New Issue
Block a user