俊希全流程用例补充:前置数据检查判定+界面模拟点击脚本(cdp-test-junxi.mjs 实测通过)
This commit is contained in:
1 parent
bd69d1c9a4
commit
0d63ffd8e0
3 files changed
+179
-9
No files matched your search
@@ -0,0 +1,115 @@
|
||||
// 模拟点击测试:俊希「AI写脚本」界面链路(#/accounts → AI写脚本弹窗 → AI 选题生成)
|
||||
// 覆盖测试用例 TC-09 的界面交互环节(真实模拟用户点击,非仅文字步骤)
|
||||
//
|
||||
// 前置:
|
||||
// 1. 工作台服务运行中(node server.js,端口 8899)
|
||||
// 2. 浏览器 9223 调试实例已启动(browser-harness 调试实例)
|
||||
// 3. 账号列表(hot_accounts)含「俊希」
|
||||
// 用法:
|
||||
// node cdp-test-junxi.mjs # 只验证到「选题生成」,不触发创作任务(安全模式)
|
||||
// node cdp-test-junxi.mjs --confirm # 选题生成后继续点「确认执行」,真实触发创作任务
|
||||
// 说明:脚本在 9223 实例新开标签页操作,不干扰用户已打开的页面;结束后自动关闭新开标签页。
|
||||
|
||||
const CONFIRM = process.argv.includes('--confirm');
|
||||
const BASE = 'http://localhost:8899';
|
||||
|
||||
// 1) 连接 9223 调试实例
|
||||
const list = await fetch('http://localhost:9223/json').then((r) => r.json());
|
||||
const page = list.find((t) => t.type === 'page');
|
||||
if (!page) { console.log('ERR: 9223 无可用页面,请先启动 browser-harness 调试实例'); process.exit(1); }
|
||||
|
||||
const ws = new WebSocket(page.webSocketDebuggerUrl);
|
||||
let id = 0; const pending = new Map();
|
||||
const send = (method, params = {}) => new Promise((res, rej) => { const i = ++id; pending.set(i, { res, rej }); ws.send(JSON.stringify({ id: i, method, params })); });
|
||||
ws.onmessage = (e) => { const m = JSON.parse(e.data); if (m.id && pending.has(m.id)) { const p = pending.get(m.id); pending.delete(m.id); m.error ? p.rej(new Error(m.error.message)) : p.res(m.result); } };
|
||||
await new Promise((r) => (ws.onopen = r));
|
||||
const ev = async (expr) => { const r = await send('Runtime.evaluate', { expression: expr, returnByValue: true, awaitPromise: true }); if (r.exceptionDetails) return { __err: (r.exceptionDetails.exception?.description || r.exceptionDetails.text).slice(0, 300) }; return r.result.value; };
|
||||
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
||||
await send('Page.enable'); await send('Runtime.enable');
|
||||
|
||||
// 2) 新开标签页打开账号列表(不干扰现有页面)
|
||||
const { targetId } = await send('Target.createTarget', { url: BASE + '/#/accounts' });
|
||||
await sleep(2500);
|
||||
let targetPage = list2 => list2.find((t) => t.type === 'page' && t.url.includes('localhost:8899') && t.id === targetId);
|
||||
let pages = await fetch('http://localhost:9223/json').then((r) => r.json());
|
||||
let tp = targetPage(pages);
|
||||
if (!tp) { console.log('ERR: 新开标签页未找到 8899 页面'); process.exit(1); }
|
||||
// 切换 WS 到新页面
|
||||
const ws2 = new WebSocket(tp.webSocketDebuggerUrl);
|
||||
let id2 = 0; const pending2 = new Map();
|
||||
const send2 = (method, params = {}) => new Promise((res, rej) => { const i = ++id2; pending2.set(i, { res, rej }); ws2.send(JSON.stringify({ id: i, method, params })); });
|
||||
ws2.onmessage = (e) => { const m = JSON.parse(e.data); if (m.id && pending2.has(m.id)) { const p = pending2.get(m.id); pending2.delete(m.id); m.error ? p.rej(new Error(m.error.message)) : p.res(m.result); } };
|
||||
await new Promise((r) => (ws2.onopen = r));
|
||||
const ev2 = async (expr) => { const r = await send2('Runtime.evaluate', { expression: expr, returnByValue: true, awaitPromise: true }); if (r.exceptionDetails) return { __err: (r.exceptionDetails.exception?.description || r.exceptionDetails.text).slice(0, 300) }; return r.result.value; };
|
||||
const sleep2 = (ms) => new Promise((r) => setTimeout(r, ms));
|
||||
await send2('Page.enable'); await send2('Runtime.enable');
|
||||
await send2('Page.reload', { ignoreCache: true }); await sleep2(3500);
|
||||
|
||||
// 3) 账号列表页:定位俊希行「AI写脚本」按钮
|
||||
const findBtn = await ev2(`(() => {
|
||||
const btns = [...document.querySelectorAll('[data-create]')];
|
||||
const b = btns.find((x) => x.dataset.create === '俊希');
|
||||
if (!b) return { found: false, total: btns.length, names: btns.slice(0, 20).map((x) => x.dataset.create) };
|
||||
return { found: true, accId: b.dataset.accId, txt: b.textContent.trim() };
|
||||
})()`);
|
||||
console.log('【Step1 账号列表定位俊希】', JSON.stringify(findBtn));
|
||||
if (!findBtn.found) {
|
||||
console.log('FAIL: 账号列表未找到俊希「AI写脚本」按钮(若账号未关注,请先到周榜/账号列表关注俊希)');
|
||||
await send('Target.closeTarget', { targetId }); ws.close(); ws2.close(); process.exit(1);
|
||||
}
|
||||
|
||||
// 4) 模拟点击「AI写脚本」→ 轮询等待弹窗出现(confirmAiScript 先 await persona 接口再建弹窗,需等待)
|
||||
await ev2(`(() => { const b = [...document.querySelectorAll('[data-create]')].find((x) => x.dataset.create === '俊希'); b.click(); return true; })()`);
|
||||
const modal = await ev2(`(async () => {
|
||||
for (let i = 0; i < 24; i++) {
|
||||
// 只认非 hidden 且含 #aiTopicGen 的弹窗(index.html 有 hidden 的 #settingsModal 干扰)
|
||||
const m = [...document.querySelectorAll('.modal-mask')].find((x) => !x.hidden && x.querySelector('#aiTopicGen'));
|
||||
if (m) {
|
||||
return { open: true, title: m.querySelector('h3')?.textContent.trim() || '', desc: m.querySelector('.dim')?.textContent.trim() || '', hasTopicInput: !!m.querySelector('#aiTopicInput'), hasGenBtn: !!m.querySelector('#aiTopicGen'), hasOk: !!m.querySelector('[data-ok]') };
|
||||
}
|
||||
await new Promise((r) => setTimeout(r, 500));
|
||||
}
|
||||
return { open: false };
|
||||
})()`);
|
||||
console.log('【Step2 AI写脚本弹窗】', JSON.stringify(modal, null, 1));
|
||||
const descOk = modal.open && modal.title.includes('AI写脚本') && modal.hasTopicInput && modal.hasGenBtn;
|
||||
const branch = modal.open && (modal.desc || '').includes('账号设定');
|
||||
console.log(branch ? ' → 文案分支:先进行账号设定分析(首次场景,符合预期)' : ' → 文案分支:基于当前账号设定(有设定场景)');
|
||||
|
||||
// 5) 模拟点击「AI」选题按钮 → 轮询选题输入框(Dify 约 50s)
|
||||
await ev2(`(() => { const g = document.querySelector('#aiTopicGen'); g.click(); return true; })()`);
|
||||
console.log('【Step3 AI 选题生成中…(最长等待 100s)】');
|
||||
let topics = '';
|
||||
const t0 = Date.now();
|
||||
while (Date.now() - t0 < 100000) {
|
||||
await sleep2(3000);
|
||||
topics = (await ev2(`(() => document.querySelector('#aiTopicInput')?.value || '')()`)) || '';
|
||||
if (topics && !topics.includes('(未生成内容)')) break;
|
||||
}
|
||||
console.log('【Step4 选题结果】');
|
||||
console.log(topics || '(超时未返回)');
|
||||
const topicOk = topics.split('\n').filter((l) => l.trim()).length >= 3 || /选题|方向/.test(topics);
|
||||
|
||||
// 6) --confirm 模式:确认执行触发创作任务
|
||||
if (CONFIRM) {
|
||||
console.log('【Step5 --confirm】点击确认执行,触发创作任务…');
|
||||
await ev2(`(() => { document.querySelector('[data-ok]').click(); return true; })()`);
|
||||
await sleep2(1500);
|
||||
const toast = await ev2(`(() => document.querySelector('.toast')?.textContent || '')()`);
|
||||
console.log(' toast:', toast || '(未捕获)');
|
||||
} else {
|
||||
console.log('【Step5 安全模式】未触发创作任务(加 --confirm 参数可真实触发)');
|
||||
await ev2(`(() => { document.querySelector('[data-cancel]')?.click(); return true; })()`);
|
||||
}
|
||||
|
||||
// 7) 汇总
|
||||
console.log('\n===== 测试结果 =====');
|
||||
console.log('Step1 定位俊希按钮:', findBtn.found ? 'PASS' : 'FAIL');
|
||||
console.log('Step2 弹窗结构:', descOk ? 'PASS' : 'FAIL');
|
||||
console.log('Step3-4 AI 选题:', topicOk ? 'PASS' : 'CHECK');
|
||||
console.log(CONFIRM ? 'Step5 任务触发: 已提交(到左侧会话栏查看)' : 'Step5 任务触发: 未触发(安全模式)');
|
||||
|
||||
// 关闭新开标签页
|
||||
await send('Target.closeTarget', { targetId });
|
||||
ws.close(); ws2.close();
|
||||
process.exit(descOk && findBtn.found ? 0 : 1);
|
||||
Reference in new issue
Block a user