| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115 |
- #!/usr/bin/env node
- /**
- * 移动端成员管理 + 无组织等待页验证(2026-11-10)
- *
- * ① 移动端成员管理:独立移动布局(卡片行 + 吸顶搜索 + 底部抽屉),不是 PC 表格
- * ② 无组织用户:注入一个 companyId 为空的 me → 应被 orgGuard 拦到 /pending
- */
- import { chromium } from 'playwright';
- import { mkdir } from 'node:fs/promises';
- import { dirname, resolve } from 'node:path';
- import { fileURLToPath } from 'node:url';
- const here = dirname(fileURLToPath(import.meta.url));
- const outDir = resolve(here, '..', 'test-results', 'mobile-org');
- const BASE = process.env.BASE_URL || 'http://127.0.0.1:4300';
- await mkdir(outDir, { recursive: true });
- const browser = await chromium.launch({ channel: 'chrome' });
- const results = [];
- const errors = [];
- // ---------- ① 移动端成员管理 ----------
- {
- const ctx = await browser.newContext({
- viewport: { width: 390, height: 844 },
- userAgent:
- 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1',
- hasTouch: true,
- isMobile: true,
- });
- const page = await ctx.newPage();
- page.on('pageerror', (e) => errors.push(String(e)));
- await page.goto(`${BASE}/mobile/admin/users`, { waitUntil: 'domcontentloaded' });
- await page.waitForTimeout(8000);
- await page.screenshot({ path: `${outDir}/mobile-users.png` });
- const isTable = await page.locator('.table, .thead').count();
- const hasSearch = await page.locator('.m-search-input').count();
- const hasCards = await page.locator('.m-card, app-m-empty').count();
- results.push(['移动端不是 PC 表格', isTable === 0, `table=${isTable}`]);
- results.push(['移动端有吸顶搜索', hasSearch > 0, `search=${hasSearch}`]);
- results.push(['移动端有内容/空态', hasCards > 0, `nodes=${hasCards}`]);
- // 打开「添加成员」抽屉
- const fab = page.getByRole('button', { name: '添加成员' });
- if (await fab.count()) {
- await fab.first().click();
- await page.waitForTimeout(700);
- const sheet = await page.locator('.m-sheet').count();
- await page.screenshot({ path: `${outDir}/mobile-add-sheet.png` });
- results.push(['新增走底部抽屉(不是居中小弹窗)', sheet === 1, `sheet=${sheet}`]);
- } else {
- results.push(['新增走底部抽屉(不是居中小弹窗)', false, '加号按钮不存在']);
- }
- await ctx.close();
- }
- // ---------- ② 无组织用户被拦到等待页 ----------
- {
- const ctx = await browser.newContext({ viewport: { width: 1440, height: 900 } });
- const page = await ctx.newPage();
- page.on('pageerror', (e) => errors.push(String(e)));
- /*
- * 先把正常登录态拿出来,再改写 me 去掉 companyId ——
- * 相当于「账号登录了但还没被组织接纳」。
- */
- await page.goto(`${BASE}/desktop/chat`, { waitUntil: 'domcontentloaded' });
- await page.waitForTimeout(8000);
- const token = await page.evaluate(() => localStorage.getItem('fmode_session_token'));
- await page.evaluate(() => {
- const raw = localStorage.getItem('fmode_me');
- if (!raw) return;
- const me = JSON.parse(raw);
- delete me.companyId;
- delete me.companyName;
- localStorage.setItem('fmode_me', JSON.stringify(me));
- });
- await page.goto(`${BASE}/desktop/chat`, { waitUntil: 'domcontentloaded' });
- await page.waitForTimeout(5000);
- await page.screenshot({ path: `${outDir}/pending-desktop.png` });
- const url = page.url();
- const onPending = url.includes('/pending');
- results.push(['🔴 无组织用户被拦到等待页', onPending, url]);
- const shownId = await page.locator('.id-text').innerText().catch(() => '');
- results.push(['等待页显示用户 ID', shownId.length > 0, shownId || '(空)']);
- // 直接访问业务页也应弹回等待页
- await page.goto(`${BASE}/desktop/tasks`, { waitUntil: 'domcontentloaded' });
- await page.waitForTimeout(3000);
- results.push(['直接访问业务页仍被挡', page.url().includes('/pending'), page.url()]);
- await ctx.close();
- console.log(`(token 存在: ${!!token})`);
- }
- // ---------- 汇总 ----------
- let pass = true;
- console.log('\n=== 结果 ===');
- for (const [name, ok, detail] of results) {
- if (!ok) pass = false;
- console.log(`${ok ? '✓' : '✗'} ${name} (${detail})`);
- }
- if (errors.length) {
- pass = false;
- console.log('页面错误:', errors.slice(0, 3).join(' | '));
- }
- console.log(`\n${pass ? '✓ 全部通过' : '✗ 存在失败项'}`);
- await browser.close();
- process.exit(pass ? 0 : 1);
|