import { TIMEOUTS } from '../../utils/timeouts'; import { test, expect } from '../../utils/test-setup'; import { EnterpriseMiniPage } from '../../pages/mini/enterprise-mini.page'; /** * 跨端数据同步 E2E 测试 - 订单详情页完整性验证 (Story 13.11) * * 测试目标:验证企业小程序订单详情页显示完整、准确的订单信息 * * 测试流程: * 1. 小程序登录 → 导航到订单列表 → 点击订单卡片 → 验证详情页各区域信息 * * 测试要点: * - 验证头部信息、基本信息、打卡数据统计、关联人才列表的显示 * - 使用 data-testid 选择器 * - 遵循项目测试规范 */ // 测试常量 // 移除硬编码的订单名称,改为动态获取订单列表中的第一个订单 const MINI_LOGIN_PHONE = '13800001111'; // 小程序登录手机号 const MINI_LOGIN_PASSWORD = process.env.TEST_ENTERPRISE_PASSWORD || 'password123'; // 小程序登录密码 /** * 获取订单列表中的第一个可用订单名称 * @param miniPage 企业小程序页面实例 * @returns 第一个订单的名称,如果没有订单则返回空字符串 */ async function getFirstOrderName(miniPage: EnterpriseMiniPage): Promise { // 从订单列表页面获取所有订单卡片 const pageContent = await miniPage.page.textContent('body') || ''; // 使用更精确的正则表达式匹配订单名称 // 订单名称格式: "跨端同步测试_1768469754054" 或 "Epic13验证测试_1768403960000_Story13.2已编辑" // 使用负面预查避免匹配到日期 const orderNameMatches = Array.from( pageContent.matchAll(/(跨端同步测试_\d{10,13}|Epic13验证测试_[\d_]+(?:_已编辑)?)/g) ).map(match => match[1]); if (orderNameMatches.length > 0) { const firstOrderName = orderNameMatches[0]; console.debug(`[订单列表] 使用第一个测试订单: ${firstOrderName}`); return firstOrderName; } // 如果没有找到测试订单,尝试通过查找所有日期前的文本来获取订单名称 // 订单名称后面跟着 "YYYY-MM-DD 创建" 格式的日期 const allOrderMatches = Array.from( pageContent.matchAll(/([^\n]+?)\s+\d{4}-\d{2}-\d{2}\s+创建/g) ).map(match => match[1].trim()); if (allOrderMatches.length > 0) { const firstOrderName = allOrderMatches[0]; console.debug(`[订单列表] 使用第一个可用订单: ${firstOrderName}`); return firstOrderName; } throw new Error('订单列表中没有找到任何可用订单'); } // 企业小程序登录辅助函数(暂未使用,保留供后续测试使用) async function _loginMini(page: any) { const miniPage = new EnterpriseMiniPage(page); await miniPage.goto(); await miniPage.login(MINI_LOGIN_PHONE, MINI_LOGIN_PASSWORD); await miniPage.expectLoginSuccess(); console.debug('[小程序] 登录成功'); } test.describe.serial('跨端数据同步测试 - 订单详情页完整性验证 (Story 13.11)', () => { // 每个测试使用独立的浏览器上下文 test.use({ storageState: undefined }); /** * AC1: 测试场景 - 订单详情页头部信息验证 * Given: 后台已创建订单 * When: 在企业小程序点击订单卡片进入订单详情页 * Then: 订单详情页头部应显示订单名称、订单编号、订单状态、创建时间、更新时间、企业名称、平台标识 */ test('应该在小程序订单详情页显示头部信息', async ({ enterpriseMiniPage: miniPage }) => { // 1. 登录 await miniPage.goto(); await miniPage.login(MINI_LOGIN_PHONE, MINI_LOGIN_PASSWORD); await miniPage.expectLoginSuccess(); await miniPage.page.waitForTimeout(TIMEOUTS.MEDIUM); // 2. 导航到订单列表页面 await miniPage.navigateToOrderList(); console.debug('[小程序] 导航到订单列表页面'); // 3. 等待订单列表加载 await miniPage.page.waitForTimeout(TIMEOUTS.LONG); // 4. 动态获取第一个可用订单名称 const testOrderName = await getFirstOrderName(miniPage); console.debug(`[小程序] 使用测试订单: ${testOrderName}`); // 5. 点击测试订单卡片进入详情页 await miniPage.clickOrderCardFromList(testOrderName); await miniPage.expectUrl('/pages/yongren/order/detail/index'); console.debug('[小程序] 打开订单详情页'); // 6. 验证订单详情页头部信息 await miniPage.expectOrderDetailHeader({ orderName: testOrderName, // orderNo, orderStatus, createdAt 等字段根据实际数据验证 }); console.debug(`[小程序] 订单名称 "${testOrderName}" 显示正确 ✓`); // 7. 验证详情页包含订单名称 const pageContent = await miniPage.page.textContent('body') || ''; expect(pageContent).toContain(testOrderName); console.debug('[小程序] 订单详情页头部信息验证完成 ✓'); }); /** * AC2: 测试场景 - 订单详情页基本信息验证 * Given: 后台已编辑订单信息 * When: 在企业小程序查看订单详情页 * Then: 基本信息区域应显示预计人数、实际人数、预计开始日期、实际开始日期、预计结束日期、实际结束日期、渠道 */ test('应该在小程序订单详情页显示基本信息', async ({ enterpriseMiniPage: miniPage }) => { // 1. 登录 await miniPage.goto(); await miniPage.login(MINI_LOGIN_PHONE, MINI_LOGIN_PASSWORD); await miniPage.expectLoginSuccess(); await miniPage.page.waitForTimeout(TIMEOUTS.MEDIUM); // 2. 导航到订单列表页面 await miniPage.navigateToOrderList(); console.debug('[小程序] 导航到订单列表页面'); // 3. 等待订单列表加载 await miniPage.page.waitForTimeout(TIMEOUTS.LONG); // 4. 动态获取第一个可用订单名称 const testOrderName = await getFirstOrderName(miniPage); console.debug(`[小程序] 使用测试订单: ${testOrderName}`); // 5. 点击测试订单卡片进入详情页 await miniPage.clickOrderCardFromList(testOrderName); await miniPage.expectUrl('/pages/yongren/order/detail/index'); console.debug('[小程序] 打开订单详情页'); // 6. 等待订单详情页数据加载完成 // 等待"加载中..."消失,或者等待订单名称元素出现 await miniPage.page.waitForTimeout(TIMEOUTS.MEDIUM); // 等待页面不再显示"加载中..." await miniPage.page.waitForFunction( () => !document.body?.textContent?.includes('加载中'), { timeout: TIMEOUTS.PAGE_LOAD } ).catch(() => { console.debug('[小程序] 加载状态检查超时,继续执行测试'); }); // 7. 验证订单详情页基本信息区域显示 const pageContent = await miniPage.page.textContent('body') || ''; // 验证基本信息系统性地存在(这些字段应该总是显示) expect(pageContent).toContain('预计人数'); expect(pageContent).toContain('实际人数'); expect(pageContent).toContain('开始日期'); // 页面显示的是"预计结束"和"实际结束",而不是"结束日期" expect(pageContent).toContain('预计结束'); expect(pageContent).toContain('实际结束'); expect(pageContent).toContain('渠道'); console.debug('[小程序] 订单详情页基本信息显示 ✓'); // 8. 尝试验证预计人数字段(如果有实际数据) await miniPage.expectOrderDetailBasicInfo({ // 根据实际数据填写 }); console.debug('[小程序] 订单详情页基本信息验证完成 ✓'); }); /** * AC3: 测试场景 - 订单详情页打卡数据统计验证 * Given: 订单存在打卡记录 * When: 在企业小程序查看订单详情页 * Then: 打卡数据统计区域应显示本月打卡人数、工资视频数量、个税视频数量 */ test('应该在小程序订单详情页显示打卡数据统计', async ({ enterpriseMiniPage: miniPage }) => { // 1. 登录 await miniPage.goto(); await miniPage.login(MINI_LOGIN_PHONE, MINI_LOGIN_PASSWORD); await miniPage.expectLoginSuccess(); await miniPage.page.waitForTimeout(TIMEOUTS.MEDIUM); // 2. 导航到订单列表页面 await miniPage.navigateToOrderList(); console.debug('[小程序] 导航到订单列表页面'); // 3. 等待订单列表加载 await miniPage.page.waitForTimeout(TIMEOUTS.LONG); // 4. 动态获取第一个可用订单名称 const testOrderName = await getFirstOrderName(miniPage); console.debug(`[小程序] 使用测试订单: ${testOrderName}`); // 5. 点击测试订单卡片进入详情页 await miniPage.clickOrderCardFromList(testOrderName); await miniPage.expectUrl('/pages/yongren/order/detail/index'); console.debug('[小程序] 打开订单详情页'); // 6. 等待订单详情页数据加载完成 await miniPage.page.waitForTimeout(TIMEOUTS.MEDIUM); await miniPage.page.waitForFunction( () => !document.body?.textContent?.includes('加载中'), { timeout: TIMEOUTS.PAGE_LOAD } ).catch(() => { console.debug('[小程序] 加载状态检查超时,继续执行测试'); }); // 7. 验证打卡数据统计区域显示 const pageContent = await miniPage.page.textContent('body') || ''; // 验证打卡数据统计字段系统性地存在 expect(pageContent).toContain('打卡数据统计'); expect(pageContent).toContain('本月打卡'); expect(pageContent).toContain('工资视频'); expect(pageContent).toContain('个税视频'); // 8. 获取打卡数据统计 const stats = await miniPage.getOrderCheckInStats(); console.debug(`[小程序] 本月打卡人数: ${stats.monthlyCheckInCount}`); console.debug(`[小程序] 工资视频数量: ${stats.salaryVideoCount}`); console.debug(`[小程序] 个税视频数量: ${stats.taxVideoCount}`); console.debug('[小程序] 订单详情页打卡数据统计显示 ✓'); }); /** * AC4: 测试场景 - 订单详情页关联人才列表验证 * Given: 后台已添加人员到订单 * When: 在企业小程序查看订单详情页 * Then: 关联人才列表应显示该订单的所有人员,每个人才卡片显示姓名、残疾类型、性别、入职日期、工作状态 */ test('应该在小程序订单详情页显示关联人才列表', async ({ enterpriseMiniPage: miniPage }) => { // 1. 登录 await miniPage.goto(); await miniPage.login(MINI_LOGIN_PHONE, MINI_LOGIN_PASSWORD); await miniPage.expectLoginSuccess(); await miniPage.page.waitForTimeout(TIMEOUTS.MEDIUM); // 2. 导航到订单列表页面 await miniPage.navigateToOrderList(); console.debug('[小程序] 导航到订单列表页面'); // 3. 等待订单列表加载 await miniPage.page.waitForTimeout(TIMEOUTS.LONG); // 4. 动态获取第一个可用订单名称 const testOrderName = await getFirstOrderName(miniPage); console.debug(`[小程序] 使用测试订单: ${testOrderName}`); // 5. 点击测试订单卡片进入详情页 await miniPage.clickOrderCardFromList(testOrderName); await miniPage.expectUrl('/pages/yongren/order/detail/index'); console.debug('[小程序] 打开订单详情页'); // 6. 等待订单详情页数据加载完成 await miniPage.page.waitForTimeout(TIMEOUTS.MEDIUM); await miniPage.page.waitForFunction( () => !document.body?.textContent?.includes('加载中'), { timeout: TIMEOUTS.PAGE_LOAD } ).catch(() => { console.debug('[小程序] 加载状态检查超时,继续执行测试'); }); // 7. 验证关联人才区域显示 const pageContent = await miniPage.page.textContent('body') || ''; expect(pageContent).toContain('关联人才'); // 8. 获取关联人才列表 const persons = await miniPage.getOrderRelatedPersons(); console.debug(`[小程序] 关联人才数量: ${persons.length}`); // 9. 验证关联人才列表显示(即使为空,也应该显示该区域) console.debug('[小程序] 订单详情页关联人才列表区域显示 ✓'); // 如果有人才,显示第一个人才的信息 if (persons.length > 0) { const firstPerson = persons[0]; console.debug(`[小程序] 第一个人才: ${firstPerson.name}, 性别: ${firstPerson.gender}, 状态: ${firstPerson.workStatus}`); // 验证人才卡片包含必要字段 expect(firstPerson.name).toBeTruthy(); // 页面显示的状态可能是"在职"、"已就业"或其他工作状态 const hasWorkStatus = pageContent.includes('在职') || pageContent.includes('已就业') || pageContent.includes('待入职'); expect(hasWorkStatus).toBeTruthy(); } else { console.debug('[小程序] 当前订单没有关联人才(符合预期)'); } }); /** * AC5: 测试场景 - 后台编辑后订单详情页同步验证 * Given: 后台编辑订单信息(名称、状态、人数、日期等) * When: 在企业小程序打开订单详情页 * Then: 订单详情页应显示更新后的所有相关字段 */ test('应该在小程序订单详情页显示后台编辑后的更新信息', async ({ enterpriseMiniPage: miniPage }) => { // 1. 登录 await miniPage.goto(); await miniPage.login(MINI_LOGIN_PHONE, MINI_LOGIN_PASSWORD); await miniPage.expectLoginSuccess(); await miniPage.page.waitForTimeout(TIMEOUTS.MEDIUM); // 2. 导航到订单列表页面 await miniPage.navigateToOrderList(); console.debug('[小程序] 导航到订单列表页面'); // 3. 等待订单列表加载 await miniPage.page.waitForTimeout(TIMEOUTS.LONG); // 4. 动态获取第一个可用订单名称 const testOrderName = await getFirstOrderName(miniPage); console.debug(`[小程序] 使用测试订单: ${testOrderName}`); // 5. 点击测试订单卡片进入详情页 await miniPage.clickOrderCardFromList(testOrderName); await miniPage.expectUrl('/pages/yongren/order/detail/index'); console.debug('[小程序] 打开订单详情页'); // 6. 等待订单详情页数据加载完成 await miniPage.page.waitForTimeout(TIMEOUTS.MEDIUM); await miniPage.page.waitForFunction( () => !document.body?.textContent?.includes('加载中'), { timeout: TIMEOUTS.PAGE_LOAD } ).catch(() => { console.debug('[小程序] 加载状态检查超时,继续执行测试'); }); // 7. 验证订单详情页包含订单名称 const pageContent = await miniPage.page.textContent('body') || ''; expect(pageContent).toContain(testOrderName); console.debug('[小程序] 订单详情页显示后台创建的订单信息 ✓'); // 8. 验证订单状态字段(草稿、进行中、已完成、未开始等状态应该显示) const hasOrderStatus = pageContent.includes('草稿') || pageContent.includes('进行中') || pageContent.includes('已完成') || pageContent.includes('未开始'); expect(hasOrderStatus).toBeTruthy(); console.debug('[小程序] 订单状态字段显示 ✓'); console.debug('[小程序] 后台编辑后订单详情页同步验证完成 ✓'); }); });