verify-thread-relation.mjs 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. /**
  2. * 验证:App 真实会话发消息时,容器能否读到 threadRoot
  3. *
  4. * 背景:容器说 HERMES_SESSION_THREAD_ID 是空。
  5. * 根因待查:App 的 sendReal 明明传了 sid 作为 threadRootId。
  6. *
  7. * 本脚本在 App 里真实发一条消息,然后问容器那一回合读到的值。
  8. */
  9. import { chromium } from 'playwright';
  10. import { mkdirSync } from 'node:fs';
  11. import { resolve } from 'node:path';
  12. import { loadDevLogin } from './dev-login.mjs';
  13. const OUT = resolve('test-results/thread-check-20261110');
  14. mkdirSync(OUT, { recursive: true });
  15. const login = loadDevLogin();
  16. if (!login.enabled) throw new Error(`开发态登录不可用:${login.reason}`);
  17. const b = await chromium.launch({ headless: true, channel: 'chromium' });
  18. const ctx = await b.newContext({ viewport: { width: 1440, height: 900 } });
  19. const page = await ctx.newPage();
  20. await page.addInitScript((d) => {
  21. localStorage.setItem('fmode_session_token', d.token);
  22. localStorage.setItem('fmode_me', JSON.stringify(d.me));
  23. }, login.payload);
  24. /* 🔴 抓取 App 真正发出去的 m.room.message content —— 这是判定依据 */
  25. let sentContent = null;
  26. page.on('request', (req) => {
  27. const u = req.url();
  28. if (!u.includes('/send/m.room.message/')) return;
  29. try {
  30. sentContent = JSON.parse(req.postData() ?? '{}');
  31. } catch {
  32. /* 忽略 */
  33. }
  34. });
  35. await page.goto('http://localhost:4200/desktop/chat', { waitUntil: 'domcontentloaded' });
  36. await page.waitForTimeout(6000);
  37. /* 点开列表里第一个真实会话(按文本更稳,类名可能变) */
  38. const byText = page.getByText(/写一份团队周报/).first();
  39. if ((await byText.count()) > 0) {
  40. await byText.click({ timeout: 8000 }).catch(() => undefined);
  41. } else {
  42. const first = page.locator('.session-item').first();
  43. if ((await first.count()) > 0) await first.click().catch(() => undefined);
  44. }
  45. await page.waitForTimeout(6000);
  46. const url = page.url();
  47. const sessionId = decodeURIComponent(url.split('/').pop() ?? '');
  48. console.log(`会话: ${sessionId}`);
  49. const ta = page.locator('textarea').first();
  50. await ta.waitFor({ timeout: 15000 });
  51. await ta.fill('请只回一句话:收到。不要调用任何工具。');
  52. await ta.press('Enter');
  53. await page.waitForTimeout(4000);
  54. if (sentContent) {
  55. const rel = sentContent['m.relates_to'];
  56. console.log('\n=== App 发出的 m.room.message content ===');
  57. console.log(JSON.stringify(sentContent, null, 2).slice(0, 800));
  58. console.log(`\n是否带 m.relates_to: ${rel ? '✅ 有' : '❌ 没有'}`);
  59. if (rel) console.log(` rel_type = ${rel.rel_type}`);
  60. if (rel) console.log(` event_id = ${rel.event_id}`);
  61. console.log(` 与当前会话 id 一致: ${rel?.event_id === sessionId ? '✅' : `❌ (${rel?.event_id} vs ${sessionId})`}`);
  62. } else {
  63. console.log('❌ 没抓到发送请求');
  64. }
  65. await page.screenshot({ path: `${OUT}/01-sent.png` });
  66. await ctx.close();
  67. await b.close();