Files
metona-ai-desktop/e2e/interrupt.spec.ts
T
thzxx 4cd6e997b5
CI / 类型检查 + Lint + 单元测试 (push) Failing after 9m45s
CI / 全量测试 (Electron ABI) (push) Failing after 6m28s
CI / 产物编译验证 (push) Successful in 11m18s
feat: v0.8.2 安全纵深补全 · 协议保真 · 断链修复 — 图片SSRF/根MEMORY.md保护根治 · Anthropic thinking回传+pause_turn续传 · 2523 用例全量回归 + E2E 扩充
2026-09-08 14:30:27 +08:00

64 lines
2.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 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 });
});