Files
mcn-short-video/project/短视频脚本创作/V1.0/mcn-work-shop/cdp-verify-title-link.mjs
T

91 lines
4.4 KiB
JavaScript
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.
/* cdp-verify-title-link.mjs — 验证:视频列表去掉视频ID列 + 标题点击进入详情页(09-01) */
const CDP = 'http://127.0.0.1:9223';
async function getWs(targetId) {
const tabs = await (await fetch(CDP + '/json')).json();
const t = tabs.find((x) => x.id === targetId);
if (!t) throw new Error('target not found: ' + targetId);
return t.webSocketDebuggerUrl;
}
function cdp(ws, method, params = {}) {
return new Promise((resolve, reject) => {
const id = ++cdp._id;
const w = new WebSocket(ws);
const timer = setTimeout(() => { try { w.close(); } catch (e) {} reject(new Error('timeout: ' + method)); }, 30000);
w.onopen = () => w.send(JSON.stringify({ id, method, params }));
w.onmessage = (ev) => {
const m = JSON.parse(ev.data);
if (m.id !== id) return;
clearTimeout(timer);
try { w.close(); } catch (e) {}
m.error ? reject(new Error(method + ': ' + JSON.stringify(m.error))) : resolve(m.result);
};
w.onerror = () => { clearTimeout(timer); reject(new Error('ws error: ' + method)); };
});
}
cdp._id = 0;
async function evalJs(ws, expr) {
const r = await cdp(ws, 'Runtime.evaluate', { expression: expr, awaitPromise: true, returnByValue: true });
if (r.exceptionDetails) throw new Error('eval err: ' + JSON.stringify(r.exceptionDetails).slice(0, 300));
return r.result && r.result.value;
}
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
const waitFor = async (ws, expr, timeout = 15000, label = '') => {
const t0 = Date.now();
while (Date.now() - t0 < timeout) {
if (await evalJs(ws, expr)) return true;
await sleep(300);
}
throw new Error('waitFor timeout: ' + label);
};
async function main() {
const tabs = await (await fetch(CDP + '/json')).json();
const tab = tabs.find((x) => x.url.includes('localhost:8900')) || tabs.find((x) => x.type === 'page');
if (!tab) throw new Error('no 8900 tab found');
const ws = await getWs(tab.id);
await cdp(ws, 'Page.enable');
await cdp(ws, 'Runtime.enable');
let pass = 0, fail = 0;
const check = (name, cond) => { cond ? pass++ : fail++; console.log((cond ? 'PASS' : 'FAIL') + ' | ' + name); };
// ① 账号详情视频列表:无视频ID列、标题为链接
await cdp(ws, 'Page.navigate', { url: 'http://localhost:8900/?v=tlink#/account/3' });
await waitFor(ws, `!!document.querySelector('.table tbody tr')`, 20000, '视频列表渲染');
const r1 = await evalJs(ws, `(() => {
const ths = [...document.querySelectorAll('.table thead th')].map((t) => t.textContent.trim());
const first = document.querySelector('.table tbody tr');
const tds = first ? [...first.children] : [];
const titleA = first ? first.querySelector('td.td-title a') : null;
return {
ths, tdCount: tds.length,
hasVideoIdCol: ths.includes('视频ID'),
titleHref: titleA ? titleA.getAttribute('href') : null,
titleText: titleA ? titleA.textContent.trim().slice(0, 20) : null
};
})()`);
check('表头无「视频ID」列', !r1.hasVideoIdCol);
check('表头列为 ' + r1.ths.join('/'), r1.ths.includes('发布时间') && r1.ths.includes('视频标题'));
check('行单元格数=7(发布时间/标题/点赞/评论/分享/时长/操作)', r1.tdCount === 7);
check('标题为链接 → ' + r1.titleHref, r1.titleHref && r1.titleHref.startsWith('#/video/'));
check('标题有文字', !!r1.titleText && r1.titleText !== '-');
// ② 点击标题 → 进入视频详情页
const href = r1.titleHref;
const vid = href ? href.replace('#/video/', '') : '';
await evalJs(ws, `document.querySelector('td.td-title a').click()`);
await waitFor(ws, `location.hash.startsWith('#/video/')`, 8000, 'hash 跳转');
await waitFor(ws, `!!document.querySelector('.page-detail, .page .page-title, .page-title')`, 10000, '视频详情渲染');
const r2 = await evalJs(ws, `(() => {
const title = document.querySelector('.page-title') ? document.querySelector('.page-title').textContent.trim() : '';
const err = document.querySelector('.page') && document.querySelector('.page').textContent.includes('渲染失败') ? '渲染失败' : '';
return { hash: location.hash, title, err };
})()`);
check('hash 已跳转 #/video/' + vid + '(实际 ' + r2.hash + ')', r2.hash === '#/video/' + vid);
check('视频详情页无渲染失败', !r2.err);
console.log(`\n结果: ${pass} PASS / ${fail} FAIL`);
process.exit(fail ? 1 : 0);
}
main().catch((e) => { console.error('ERROR:', e.message); process.exit(1); });