| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230 |
- /**
- * ================================================================
- * 场景:后台管理端逐菜单可达性测试
- * ================================================================
- * 目标:管理员通过 cfc-web 管理后台(远程部署 http://cfc.iwintrue.com/admin/)
- * 逐一访问 router/index.js 中的全部菜单路由,验证:
- * - 未因权限不足被重定向到 /login 或 /403
- * - 页面主体渲染成功(非白屏)
- *
- * 部署信息(已验证):
- * - SPA 静态资源: http://cfc.iwintrue.com/admin/* (200)
- * - 后端 API: http://cfc.iwintrue.com/api/* (openresty 代理)
- * - 管理员登录: POST /api/admin-auth/login-by-password {phone, password}
- * - 测试账号: 13800138000 / admin123(role=admin, adminId=1001)
- * - 滑块验证码: 纯前端模拟(拖动 >=88% 即成功),UI 登录可自动化;
- * 本测试采用 API 登录 + localStorage 注入,更稳定
- *
- * 运行:npx playwright test tests/e2e/admin-menu-survey.spec.js --project=desktop
- * ================================================================
- */
- const { test, expect } = require('@playwright/test');
- var BASE_URL = process.env.PW_BASE_URL || 'http://cfc.iwintrue.com';
- var APP_PREFIX = '/admin';
- // ================================================================
- // 全部菜单路由(来自 cfc-web/src/router/index.js,admin 角色可见)
- // 参数化路由(:orderNo / :id / :systemId)单独处理
- // ================================================================
- var ADMIN_MENUS = [
- // 首页/看板
- { path: '/dashboard', title: '首页' },
- { path: '/admin/dashboard', title: '数据大屏' },
- // 家庭管理
- { path: '/families', title: '家庭列表' },
- { path: '/children', title: '孩子管理' },
- { path: '/points', title: '积分管理' },
- { path: '/points-log', title: '积分记录' },
- { path: '/membership-center', title: '会员中心' },
- // 任务管理
- { path: '/tasks', title: '任务列表' },
- { path: '/task-templates', title: '任务模板' },
- { path: '/growth-task', title: '成长任务管理' },
- // 奖励管理
- { path: '/rewards', title: '奖励列表' },
- { path: '/wishes', title: '心愿管理' },
- // 系统管理
- { path: '/users', title: '用户管理' },
- { path: '/review-center', title: '审核中心' },
- { path: '/operation-logs', title: '操作日志' },
- // 服务管理(管理员)
- { path: '/service-role-applications', title: '服务角色申请审核' },
- // 测评管理
- { path: '/assessment-admin', title: '测评管理' },
- { path: '/assessment-assign', title: '待分配规划师' },
- { path: '/assessment-orders', title: '测评订单' },
- { path: '/dan-execution', title: 'DAN服务执行' },
- { path: '/dan-settlement', title: 'DAN结算管理' },
- // 商品/订单管理
- { path: '/product-manage', title: '商品管理' },
- { path: '/product-edit', title: '商品编辑' },
- { path: '/assessment-products', title: '测评商品管理' },
- { path: '/assessment-plan-rules', title: '方案生成规则' },
- { path: '/plan-management', title: '方案管理' },
- { path: '/category-manage', title: '商品分类' },
- { path: '/order-manage', title: '订单管理' },
- { path: '/pending-refund', title: '待退款管理' },
- // 系统配置
- { path: '/sys-config', title: '系统配置' },
- { path: '/energy-sandbox', title: '五维能量' },
- { path: '/energy-rule', title: '能量规则管理' },
- { path: '/energy-behavior-config', title: '能量行为配置' },
- { path: '/periodic-service-config', title: '周期性服务配置' },
- { path: '/virtual-goods-config', title: '虚拟支付道具' },
- { path: '/knowledge-tags', title: '知识标签' },
- // 文章管理
- { path: '/article-categories', title: '文章分类' },
- { path: '/article-manage', title: '文章管理' },
- { path: '/article-edit', title: '文章编辑' },
- { path: '/comment-review', title: '评论审核' },
- // 佣金推荐系统
- { path: '/product-profit-rate', title: '产品利润率' },
- { path: '/product-ppoint', title: 'P点配置' },
- { path: '/supply-system', title: '供应商体系' },
- { path: '/supplier-products', title: '供应商商品管理' },
- { path: '/supply-hierarchy/change-requests', title: '更换上级审核' },
- // 供应商管理
- { path: '/supply-manage', title: '供应商管理' },
- { path: '/supply-manage/create', title: '新增供应商' },
- // 星座/八字/血型配置
- { path: '/zodiac-configs', title: '星座配置' },
- { path: '/bazi-configs', title: '八字配置' },
- { path: '/blood-type-configs', title: '血型配置' },
- // 饮食管理
- { path: '/foods', title: '食材管理' },
- { path: '/recipes', title: '食谱管理' },
- { path: '/seasonal-foods', title: '应季食材' },
- // 健康/报告
- { path: '/health-reports', title: '健康报告' },
- { path: '/report-management', title: '报告管理' },
- { path: '/report-audit', title: '报告草稿审核' },
- { path: '/health-indicators', title: '健康指标' },
- { path: '/health-checkins', title: '健康打卡' },
- { path: '/emotion-alert', title: '情绪告警管理' },
- { path: '/nutrition-mappings', title: '营养素映射管理' },
- // 活动管理
- { path: '/activities', title: '活动列表' },
- { path: '/activity-edit', title: '活动编辑' },
- { path: '/activity-review', title: '活动审核' },
- { path: '/activity-registration-review', title: '活动报名审核' },
- // 营销管理
- { path: '/coupon', title: '优惠券管理' },
- { path: '/promotion', title: '推广管理' },
- { path: '/family-earnings', title: '家庭收益管理' },
- { path: '/family-earnings-withdraw', title: '家庭收益提现审核' },
- // 维度配置 + 知识库
- { path: '/dimension-config', title: '维度配置' },
- { path: '/knowledge-base', title: '知识库管理' },
- { path: '/health-knowledge', title: '健康知识库管理' },
- { path: '/health-norm-config', title: '健康常模配置' },
- { path: '/health-data-source', title: '健康数据源配置' },
- { path: '/health-energy-config', title: '五维能量配置' },
- { path: '/energy-config', title: '五行能量配置' },
- { path: '/indicators', title: '指标管理' },
- // 虚拟团队
- { path: '/virtual-teams', title: '虚拟团队管理' },
- // 电商供应商
- { path: '/ecom-supplier', title: '电商供应商管理' },
- { path: '/badge-manage', title: '勋章管理' }
- ];
- // 参数化路由(需要具体 ID,用占位 ID 验证可达性)
- var PARAM_MENUS = [
- { path: '/order-detail/1', title: '订单详情' },
- { path: '/supply-system/1', title: '供应商体系详情' },
- { path: '/supply-system/1/edit', title: '编辑体系' },
- { path: '/supply-manage/1', title: '供应商详情' },
- { path: '/supply-manage/1/edit', title: '编辑供应商' },
- { path: '/virtual-team-detail/1', title: '团队成员管理' }
- ];
- // ================================================================
- // 登录 helper:API 登录 → 注入 localStorage(含 roles 数组)
- // ================================================================
- var ADMIN_PHONE = '13800138000';
- var ADMIN_PASSWORD = 'admin123';
- async function loginAsAdmin(page) {
- var res = await page.request.post(BASE_URL + '/api/admin-auth/login-by-password', {
- data: { phone: ADMIN_PHONE, password: ADMIN_PASSWORD },
- headers: { 'Content-Type': 'application/json' }
- });
- expect(res.ok()).toBeTruthy();
- var body = await res.json();
- expect(body.code).toBe(200);
- expect(body.data && body.data.token).toBeTruthy();
- var token = body.data.token;
- var role = body.data.role || 'admin';
- var roles = body.data.roles && body.data.roles.length ? body.data.roles : [role];
- // 注意:addInitScript 只接受一个 arg,必须打包成单个对象传参
- await page.addInitScript(function (auth) {
- localStorage.setItem('token', auth.token);
- localStorage.setItem('access_token', auth.token);
- localStorage.setItem('role', auth.role);
- localStorage.setItem('roles', JSON.stringify(auth.roles));
- localStorage.setItem('adminId', String(auth.adminId));
- }, { token: token, role: role, roles: roles, adminId: body.data.adminId });
- }
- // ================================================================
- // 菜单可达性检查:goto → 非 /login、非 /403、主体渲染
- // ================================================================
- async function assertMenuAccessible(page, route) {
- var url = BASE_URL + APP_PREFIX + route.path;
- await page.goto(url, { waitUntil: 'networkidle', timeout: 60000 });
- // 1. 不应被踢回登录页(token 失效/权限不足)
- var currentUrl = page.url();
- expect(currentUrl).not.toContain('/login');
- expect(currentUrl).not.toContain('/403');
- // 2. 页面主体应渲染:侧边栏 + 内容区
- var sidebar = page.locator('.sidebar-container, .el-aside, .el-menu');
- await expect(sidebar.first()).toBeVisible({ timeout: 15000 });
- // 3. 内容区非空(.app-container / .el-main / 页面根)
- var content = page.locator('.app-container, .el-main, #app > div');
- var contentCount = await content.count();
- expect(contentCount).toBeGreaterThan(0);
- }
- test.describe('【后台管理】逐菜单可达性测试', () => {
- test('管理员登录并访问全部菜单 - 期望全部可达', async ({ page }) => {
- await loginAsAdmin(page);
- var failures = [];
- for (var i = 0; i < ADMIN_MENUS.length; i++) {
- var menu = ADMIN_MENUS[i];
- try {
- await assertMenuAccessible(page, menu);
- console.log('[PASS] ' + menu.path + ' (' + menu.title + ')');
- } catch (e) {
- failures.push(menu.path + ' (' + menu.title + '): ' + (e.message || e).split('\n')[0]);
- console.log('[FAIL] ' + menu.path + ' (' + menu.title + ')');
- await page.screenshot({ path: 'test-artifacts/menu-fail-' + menu.path.replace(/\//g, '_') + '.png' })
- .catch(function () {});
- }
- }
- expect(failures, '以下菜单访问失败:\n' + failures.join('\n')).toEqual([]);
- });
- test('参数化路由可达性 - 期望不跳登录/403', async ({ page }) => {
- await loginAsAdmin(page);
- for (var j = 0; j < PARAM_MENUS.length; j++) {
- var pmenu = PARAM_MENUS[j];
- await assertMenuAccessible(page, pmenu);
- console.log('[PASS] ' + pmenu.path + ' (' + pmenu.title + ')');
- }
- });
- });
|