| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118 |
- #!/usr/bin/env node
- /**
- * 工作组端到端冒烟 —— 11 项断言
- *
- * 用法:npm start(另开终端)→ npm run smoke:groups
- *
- * 覆盖:群列表 / 进群 / 消息渲染 / 发送者名 / 角色标记 /
- * @ 自动补全 / @ 筛选 / @ 回填 / 上下文开关 / 新建入口 / 角色编辑器
- *
- * 🔴 需要真实登录态与真实数据(从平台取 sessionToken)。
- * 这是**联调冒烟**,不是单元测试(单测见 src/app/core/*.spec.ts)。
- */
- // 端到端完整回归:把所有群聊功能串一遍
- import { chromium } from 'playwright';
- const H = { 'X-Parse-Application-Id': 'ncloudmaster', 'X-Parse-Master-Key': 'SnkK12*&sunq2#@20!' };
- const q = await fetch('https://server.fmode.cn/parse/classes/_Session/SGF24QCsOo', { headers: H }).then(r => r.json());
- const results = [];
- function check(name, ok, detail = '') {
- results.push({ name, ok, detail });
- console.log(`${ok ? '✅' : '❌'} ${name}${detail ? ' — ' + detail : ''}`);
- }
- const b = await chromium.launch({ executablePath: 'C:/Program Files/Google/Chrome/Application/chrome.exe' });
- const ctx = await b.newContext({ viewport: { width: 1500, height: 900 } });
- await ctx.addInitScript(([t, m]) => {
- localStorage.setItem('fmode_session_token', t);
- localStorage.setItem('fmode_me', m);
- }, [q.sessionToken, '{"id":"xhVRjTMwQH","name":"用户9836","mobile":"19170119836","companyId":"E4KpGvTEto"}']);
- const page = await ctx.newPage();
- const errs = [];
- page.on('pageerror', e => errs.push(e.message.slice(0, 100)));
- await page.goto('http://localhost:4200/desktop/groups', { waitUntil: 'domcontentloaded' });
- await page.waitForTimeout(15000);
- // 1. 群列表加载
- const groupCount = await page.locator('.group-row').count();
- check('群列表加载', groupCount > 0, `${groupCount} 个群`);
- // 2. 进入群
- await page.locator('.group-row').first().click();
- await page.waitForTimeout(4000);
- const inGroup = await page.evaluate(() => !!document.querySelector('.composer-row'));
- check('进入群会话', inGroup);
- // 3. 消息渲染 + 发送者名
- const msgStats = await page.evaluate(() => ({
- bubbles: document.querySelectorAll('app-message-bubble').length,
- senders: [...document.querySelectorAll('.sender-name')].map(e => e.textContent.trim()).slice(0, 3),
- }));
- check('消息渲染', msgStats.bubbles > 0, `${msgStats.bubbles} 条`);
- check('发送者名显示', msgStats.senders.length > 0, msgStats.senders.join('/'));
- // 4. 成员栏 + 角色
- const members = await page.evaluate(() =>
- [...document.querySelectorAll('.member-row')].map(e => ({
- name: e.querySelector('strong')?.textContent.trim(),
- role: e.querySelector('.role-tag')?.textContent.trim() || '',
- })),
- );
- check('成员栏 + 角色标记', members.length > 0, JSON.stringify(members));
- // 5. @ 边打边筛
- const ta = page.locator('textarea.input');
- await ta.fill('测试 @');
- await page.waitForTimeout(800);
- const acCount = await page.locator('.suggest-item').count();
- check('@ 自动补全', acCount > 0, `${acCount} 个候选`);
- await ta.fill('测试 @lj-t');
- await page.waitForTimeout(800);
- const filtered = await page.locator('.suggest-item').count();
- check('@ 筛选', filtered === 1, `${filtered} 个`);
- await page.locator('.suggest-item').first().click();
- await page.waitForTimeout(800);
- const filled = await page.evaluate(() => document.querySelector('textarea.input')?.value || '');
- check('@ 回填', filled.includes('@lj-test'), JSON.stringify(filled));
- // 6. 上下文开关
- // 🔴 开关在「我的」页,不在群聊页 —— 2026-10-28 起上下文策略改为「只给组长」,
- // 群聊页不再保留开关;设置入口统一收在 我的 → 工作组协作。
- await page.goto('http://localhost:4200/desktop/mine', { waitUntil: 'domcontentloaded' });
- await page.waitForTimeout(6000);
- const ctxToggle = await page.evaluate(() => {
- const el = document.querySelector('.ctx-switch input');
- return el ? { exists: true, checked: el.checked } : { exists: false };
- });
- check('上下文开关(我的页 · 默认开启)', ctxToggle.exists && ctxToggle.checked === true, JSON.stringify(ctxToggle));
- // 回到群页继续后续断言
- await page.goto('http://localhost:4200/desktop/groups', { waitUntil: 'domcontentloaded' });
- await page.waitForTimeout(8000);
- await page.locator('.group-row').first().click().catch(() => {});
- await page.waitForTimeout(4000);
- // 7. 新建工作组入口
- await ta.fill('');
- const createBtn = await page.locator('button[aria-label="新建工作组"]').count();
- check('新建工作组入口', createBtn > 0);
- // 8. 角色编辑
- await page.locator('.member-row').first().click();
- await page.waitForTimeout(1200);
- const roleEditor = await page.evaluate(() => !!document.querySelector('.role-editor'));
- check('角色编辑器', roleEditor);
- await page.keyboard.press('Escape');
- await page.screenshot({ path: 'E:/tmp/e2e-regression.png' });
- // 汇总
- const passed = results.filter(r => r.ok).length;
- console.log(`\n=== 回归结果: ${passed}/${results.length} 通过 ===`);
- if (errs.length) console.log('页面错误:', errs.slice(0, 3).join(' | '));
- await b.close();
|