/** * ================================================================ * 场景:测评管理全流程 E2E 测试(cfc-web 管理端版) * ================================================================ * 适配远程环境:cfc-web 管理端 (/admin),非 uni-app H5 * 前置条件:无(远程 API 和 SPA 已部署,独立测试账号可用) * 运行:npx playwright test tests/e2e/assessment-order-flow.spec.js --config=playwright.remote.config.js * * 5 个场景对应已部署的 admin 测评页面: * 1. /assessment-admin - 测评管理(积分配置 + 资料管理) * 2. /assessment-orders - 测评订单(预约管理 + 筛选搜索) * 3. /assessment-assign - 待分配规划师 * 4. /dan-execution - DAN服务执行管理 * 5. /assessment-products - 测评商品管理 * ================================================================ */ const { test, expect } = require('@playwright/test'); var BASE_URL = 'http://cfc.iwintrue.com'; var APP_PREFIX = '/admin'; // ================================================================ // 登录 helper:API 登录 → 注入 localStorage(与 menu-survey 一致) // ================================================================ 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 }); } test.describe('【场景流程】测评管理全流程 (cfc-web)', () => { /** * 场景1:测评管理页加载 * 页面:/assessment-admin → Assessment.vue * 验证:积分配置表单 + 测评资料表格均渲染 */ test('[场景1] 测评管理页 - 期望积分配置与资料表格可见', async ({ page }) => { await loginAsAdmin(page); await page.goto(BASE_URL + APP_PREFIX + '/assessment-admin', { waitUntil: 'networkidle', timeout: 60000 }); // 1. 页面根容器 await expect(page.locator('.admin-page')).toBeVisible({ timeout: 15000 }); // 2. 积分配置卡片:el-form + el-input-number var configCard = page.locator('.config-card'); await expect(configCard).toBeVisible(); // 3. 测评资料卡片:表格 el-table 渲染 var materialsCard = page.locator('.materials-card'); await expect(materialsCard).toBeVisible(); // 4. 表格存在(可能有数据或空态) var table = page.locator('.el-table'); await expect(table.first()).toBeVisible(); // 5. 搜索框存在 var searchInput = page.locator('.el-input__inner').first(); await expect(searchInput).toBeVisible(); // 6. 添加资料按钮存在 var addBtn = page.locator('button:has-text("添加资料")'); await expect(addBtn).toBeVisible(); }); /** * 场景2:测评订单管理 - 搜索与状态筛选 * 页面:/assessment-orders → AssessmentOrders.vue * 验证:标题 + 预约表格 + 筛选组件 + 搜索功能 */ test('[场景2] 测评订单管理 - 期望预约表格与筛选功能可用', async ({ page }) => { await loginAsAdmin(page); await page.goto(BASE_URL + APP_PREFIX + '/assessment-orders', { waitUntil: 'networkidle', timeout: 60000 }); // 1. 页面标题 var title = page.locator('.admin-page-title'); await expect(title).toContainText('测评预约管理'); // 2. 表格存在 var table = page.locator('.el-table'); await expect(table.first()).toBeVisible({ timeout: 15000 }); // 3. 表格列标签(用户/孩子/测评方案/状态等) var headerCells = page.locator('.el-table__header th'); var headerCount = await headerCells.count(); expect(headerCount).toBeGreaterThanOrEqual(5); // 4. 状态筛选下拉框 var statusSelect = page.locator('.el-select').first(); await expect(statusSelect).toBeVisible(); // 5. 搜索输入框(用 placeholder 定位,避免与 el-select 的 input 混淆) var searchInput = page.locator('input[placeholder*="搜索"]'); await expect(searchInput).toBeVisible(); // 6. 搜索按钮(使用 force 避免 el-select 下拉箭头遮罩) var searchBtn = page.locator('button:has-text("搜索")'); await expect(searchBtn).toBeVisible(); // 7. 执行搜索(输入关键词测试筛选功能) await searchInput.fill('13701366188'); await searchBtn.click({ force: true }); await page.waitForTimeout(2000); // 搜索后表格仍在(可能无结果,但组件正常工作) await expect(table.first()).toBeVisible(); // 8. 分页组件存在(数据较多时展示) var pagination = page.locator('.el-pagination'); var hasPagination = await pagination.isVisible().catch(function () { return false; }); // 分页可能不显示(数据量小),有则断言,无则跳过 if (hasPagination) { await expect(pagination).toBeVisible(); } }); /** * 场景3:待分配规划师 * 页面:/assessment-assign → AssessmentAssign.vue * 验证:待分配列表 + 分配规划师按钮存在 */ test('[场景3] 待分配规划师 - 期望列表与分配功能可用', async ({ page }) => { await loginAsAdmin(page); await page.goto(BASE_URL + APP_PREFIX + '/assessment-assign', { waitUntil: 'networkidle', timeout: 60000 }); // 1. 页面标题 var title = page.locator('.admin-page-title'); await expect(title).toContainText('待分配规划师'); // 2. 表格存在(可能有记录或空态) var table = page.locator('.el-table'); await expect(table.first()).toBeVisible({ timeout: 15000 }); // 3. 表格列标签(ID/用户/孩子/预约日期等) var headerCells = page.locator('.el-table__header th'); var headerCount = await headerCells.count(); expect(headerCount).toBeGreaterThanOrEqual(4); // 4. 操作列有"分配规划师"按钮(每行一个) var assignBtn = page.locator('button:has-text("分配规划师")').first(); var hasAssignBtn = await assignBtn.isVisible().catch(function () { return false; }); if (hasAssignBtn) { // 有数据行时验证按钮可点击 await expect(assignBtn).toBeEnabled(); } // 5. 刷新按钮存在 var refreshBtn = page.locator('button:has-text("刷新")'); await expect(refreshBtn).toBeVisible(); }); /** * 场景4:DAN服务执行管理 * 页面:/dan-execution → DanExecution.vue * 验证:执行列表 + 状态筛选 + 搜索功能 */ test('[场景4] DAN服务执行管理 - 期望执行列表与筛选可用', async ({ page }) => { await loginAsAdmin(page); await page.goto(BASE_URL + APP_PREFIX + '/dan-execution', { waitUntil: 'networkidle', timeout: 60000 }); // 1. 页面标题 var title = page.locator('.admin-page-title'); await expect(title).toContainText('DAN测评服务执行管理'); // 2. 表格存在 var table = page.locator('.el-table'); await expect(table.first()).toBeVisible({ timeout: 15000 }); // 3. 表格列标签(ID/订单ID/评估师状态/规划师状态等) var headerCells = page.locator('.el-table__header th'); var headerCount = await headerCells.count(); expect(headerCount).toBeGreaterThanOrEqual(5); // 4. 执行状态筛选下拉框 var statusSelect = page.locator('.el-select').first(); await expect(statusSelect).toBeVisible(); // 5. 搜索按钮 var searchBtn = page.locator('button:has-text("搜索")'); await expect(searchBtn).toBeVisible(); // 6. 表格行中的数据若存在则验证状态标签 var statusTag = page.locator('.el-tag').first(); var hasTag = await statusTag.isVisible().catch(function () { return false; }); if (hasTag) { var tagText = await statusTag.textContent(); expect(tagText).toBeTruthy(); } }); /** * 场景5:测评商品管理 * 页面:/assessment-products → AssessmentProducts.vue * 验证:商品列表 + 搜索 + 状态筛选 + 新增商品按钮 */ test('[场景5] 测评商品管理 - 期望商品列表与筛选功能可用', async ({ page }) => { await loginAsAdmin(page); await page.goto(BASE_URL + APP_PREFIX + '/assessment-products', { waitUntil: 'networkidle', timeout: 60000 }); // 1. 页面标题 var title = page.locator('.admin-page-title'); await expect(title).toContainText('测评商品管理'); // 2. 表格存在 var table = page.locator('.el-table'); await expect(table.first()).toBeVisible({ timeout: 15000 }); // 3. 表格列标签(ID/商品名称/状态/售价等) var headerCells = page.locator('.el-table__header th'); var headerCount = await headerCells.count(); expect(headerCount).toBeGreaterThanOrEqual(5); // 4. 搜索框(用 placeholder 定位) var searchInput = page.locator('input[placeholder*="搜索"]'); await expect(searchInput).toBeVisible(); // 5. 商品状态筛选下拉框 var statusSelect = page.locator('.el-select').first(); await expect(statusSelect).toBeVisible(); // 6. 新增测评商品按钮 var addBtn = page.locator('button:has-text("新增测评商品")'); await expect(addBtn).toBeVisible(); // 7. 查询按钮 var queryBtn = page.locator('button:has-text("查询")'); await expect(queryBtn).toBeVisible(); // 8. 执行搜索测试 await searchInput.fill('测评'); // 触发搜索(按回车或点击查询按钮) await queryBtn.click({ force: true }); await page.waitForTimeout(2000); // 搜索后表格仍在 await expect(table.first()).toBeVisible(); }); });