order-detail-sync.spec.ts 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. import { TIMEOUTS } from '../../utils/timeouts';
  2. import { test, expect } from '../../utils/test-setup';
  3. import { EnterpriseMiniPage } from '../../pages/mini/enterprise-mini.page';
  4. /**
  5. * 跨端数据同步 E2E 测试 - 订单详情页完整性验证 (Story 13.11)
  6. *
  7. * 测试目标:验证企业小程序订单详情页显示完整、准确的订单信息
  8. *
  9. * 测试流程:
  10. * 1. 小程序登录 → 导航到订单列表 → 点击订单卡片 → 验证详情页各区域信息
  11. *
  12. * 测试要点:
  13. * - 验证头部信息、基本信息、打卡数据统计、关联人才列表的显示
  14. * - 使用 data-testid 选择器
  15. * - 遵循项目测试规范
  16. */
  17. // 测试常量
  18. // 移除硬编码的订单名称,改为动态获取订单列表中的第一个订单
  19. const MINI_LOGIN_PHONE = '13800001111'; // 小程序登录手机号
  20. const MINI_LOGIN_PASSWORD = process.env.TEST_ENTERPRISE_PASSWORD || 'password123'; // 小程序登录密码
  21. /**
  22. * 获取订单列表中的第一个可用订单名称
  23. * @param miniPage 企业小程序页面实例
  24. * @returns 第一个订单的名称,如果没有订单则返回空字符串
  25. */
  26. async function getFirstOrderName(miniPage: EnterpriseMiniPage): Promise<string> {
  27. // 从订单列表页面获取所有订单卡片
  28. const pageContent = await miniPage.page.textContent('body') || '';
  29. // 使用更精确的正则表达式匹配订单名称
  30. // 订单名称格式: "跨端同步测试_1768469754054" 或 "Epic13验证测试_1768403960000_Story13.2已编辑"
  31. // 使用负面预查避免匹配到日期
  32. const orderNameMatches = Array.from(
  33. pageContent.matchAll(/(跨端同步测试_\d{10,13}|Epic13验证测试_[\d_]+(?:_已编辑)?)/g)
  34. ).map(match => match[1]);
  35. if (orderNameMatches.length > 0) {
  36. const firstOrderName = orderNameMatches[0];
  37. console.debug(`[订单列表] 使用第一个测试订单: ${firstOrderName}`);
  38. return firstOrderName;
  39. }
  40. // 如果没有找到测试订单,尝试通过查找所有日期前的文本来获取订单名称
  41. // 订单名称后面跟着 "YYYY-MM-DD 创建" 格式的日期
  42. const allOrderMatches = Array.from(
  43. pageContent.matchAll(/([^\n]+?)\s+\d{4}-\d{2}-\d{2}\s+创建/g)
  44. ).map(match => match[1].trim());
  45. if (allOrderMatches.length > 0) {
  46. const firstOrderName = allOrderMatches[0];
  47. console.debug(`[订单列表] 使用第一个可用订单: ${firstOrderName}`);
  48. return firstOrderName;
  49. }
  50. throw new Error('订单列表中没有找到任何可用订单');
  51. }
  52. // 企业小程序登录辅助函数(暂未使用,保留供后续测试使用)
  53. async function _loginMini(page: any) {
  54. const miniPage = new EnterpriseMiniPage(page);
  55. await miniPage.goto();
  56. await miniPage.login(MINI_LOGIN_PHONE, MINI_LOGIN_PASSWORD);
  57. await miniPage.expectLoginSuccess();
  58. console.debug('[小程序] 登录成功');
  59. }
  60. test.describe.serial('跨端数据同步测试 - 订单详情页完整性验证 (Story 13.11)', () => {
  61. // 每个测试使用独立的浏览器上下文
  62. test.use({ storageState: undefined });
  63. /**
  64. * AC1: 测试场景 - 订单详情页头部信息验证
  65. * Given: 后台已创建订单
  66. * When: 在企业小程序点击订单卡片进入订单详情页
  67. * Then: 订单详情页头部应显示订单名称、订单编号、订单状态、创建时间、更新时间、企业名称、平台标识
  68. */
  69. test('应该在小程序订单详情页显示头部信息', async ({ enterpriseMiniPage: miniPage }) => {
  70. // 1. 登录
  71. await miniPage.goto();
  72. await miniPage.login(MINI_LOGIN_PHONE, MINI_LOGIN_PASSWORD);
  73. await miniPage.expectLoginSuccess();
  74. await miniPage.page.waitForTimeout(TIMEOUTS.MEDIUM);
  75. // 2. 导航到订单列表页面
  76. await miniPage.navigateToOrderList();
  77. console.debug('[小程序] 导航到订单列表页面');
  78. // 3. 等待订单列表加载
  79. await miniPage.page.waitForTimeout(TIMEOUTS.LONG);
  80. // 4. 动态获取第一个可用订单名称
  81. const testOrderName = await getFirstOrderName(miniPage);
  82. console.debug(`[小程序] 使用测试订单: ${testOrderName}`);
  83. // 5. 点击测试订单卡片进入详情页
  84. await miniPage.clickOrderCardFromList(testOrderName);
  85. await miniPage.expectUrl('/pages/yongren/order/detail/index');
  86. console.debug('[小程序] 打开订单详情页');
  87. // 6. 验证订单详情页头部信息
  88. await miniPage.expectOrderDetailHeader({
  89. orderName: testOrderName,
  90. // orderNo, orderStatus, createdAt 等字段根据实际数据验证
  91. });
  92. console.debug(`[小程序] 订单名称 "${testOrderName}" 显示正确 ✓`);
  93. // 7. 验证详情页包含订单名称
  94. const pageContent = await miniPage.page.textContent('body') || '';
  95. expect(pageContent).toContain(testOrderName);
  96. console.debug('[小程序] 订单详情页头部信息验证完成 ✓');
  97. });
  98. /**
  99. * AC2: 测试场景 - 订单详情页基本信息验证
  100. * Given: 后台已编辑订单信息
  101. * When: 在企业小程序查看订单详情页
  102. * Then: 基本信息区域应显示预计人数、实际人数、预计开始日期、实际开始日期、预计结束日期、实际结束日期、渠道
  103. */
  104. test('应该在小程序订单详情页显示基本信息', async ({ enterpriseMiniPage: miniPage }) => {
  105. // 1. 登录
  106. await miniPage.goto();
  107. await miniPage.login(MINI_LOGIN_PHONE, MINI_LOGIN_PASSWORD);
  108. await miniPage.expectLoginSuccess();
  109. await miniPage.page.waitForTimeout(TIMEOUTS.MEDIUM);
  110. // 2. 导航到订单列表页面
  111. await miniPage.navigateToOrderList();
  112. console.debug('[小程序] 导航到订单列表页面');
  113. // 3. 等待订单列表加载
  114. await miniPage.page.waitForTimeout(TIMEOUTS.LONG);
  115. // 4. 动态获取第一个可用订单名称
  116. const testOrderName = await getFirstOrderName(miniPage);
  117. console.debug(`[小程序] 使用测试订单: ${testOrderName}`);
  118. // 5. 点击测试订单卡片进入详情页
  119. await miniPage.clickOrderCardFromList(testOrderName);
  120. await miniPage.expectUrl('/pages/yongren/order/detail/index');
  121. console.debug('[小程序] 打开订单详情页');
  122. // 6. 等待订单详情页数据加载完成
  123. // 等待"加载中..."消失,或者等待订单名称元素出现
  124. await miniPage.page.waitForTimeout(TIMEOUTS.MEDIUM);
  125. // 等待页面不再显示"加载中..."
  126. await miniPage.page.waitForFunction(
  127. () => !document.body?.textContent?.includes('加载中'),
  128. { timeout: TIMEOUTS.PAGE_LOAD }
  129. ).catch(() => {
  130. console.debug('[小程序] 加载状态检查超时,继续执行测试');
  131. });
  132. // 7. 验证订单详情页基本信息区域显示
  133. const pageContent = await miniPage.page.textContent('body') || '';
  134. // 验证基本信息系统性地存在(这些字段应该总是显示)
  135. expect(pageContent).toContain('预计人数');
  136. expect(pageContent).toContain('实际人数');
  137. expect(pageContent).toContain('开始日期');
  138. // 页面显示的是"预计结束"和"实际结束",而不是"结束日期"
  139. expect(pageContent).toContain('预计结束');
  140. expect(pageContent).toContain('实际结束');
  141. expect(pageContent).toContain('渠道');
  142. console.debug('[小程序] 订单详情页基本信息显示 ✓');
  143. // 8. 尝试验证预计人数字段(如果有实际数据)
  144. await miniPage.expectOrderDetailBasicInfo({
  145. // 根据实际数据填写
  146. });
  147. console.debug('[小程序] 订单详情页基本信息验证完成 ✓');
  148. });
  149. /**
  150. * AC3: 测试场景 - 订单详情页打卡数据统计验证
  151. * Given: 订单存在打卡记录
  152. * When: 在企业小程序查看订单详情页
  153. * Then: 打卡数据统计区域应显示本月打卡人数、工资视频数量、个税视频数量
  154. */
  155. test('应该在小程序订单详情页显示打卡数据统计', async ({ enterpriseMiniPage: miniPage }) => {
  156. // 1. 登录
  157. await miniPage.goto();
  158. await miniPage.login(MINI_LOGIN_PHONE, MINI_LOGIN_PASSWORD);
  159. await miniPage.expectLoginSuccess();
  160. await miniPage.page.waitForTimeout(TIMEOUTS.MEDIUM);
  161. // 2. 导航到订单列表页面
  162. await miniPage.navigateToOrderList();
  163. console.debug('[小程序] 导航到订单列表页面');
  164. // 3. 等待订单列表加载
  165. await miniPage.page.waitForTimeout(TIMEOUTS.LONG);
  166. // 4. 动态获取第一个可用订单名称
  167. const testOrderName = await getFirstOrderName(miniPage);
  168. console.debug(`[小程序] 使用测试订单: ${testOrderName}`);
  169. // 5. 点击测试订单卡片进入详情页
  170. await miniPage.clickOrderCardFromList(testOrderName);
  171. await miniPage.expectUrl('/pages/yongren/order/detail/index');
  172. console.debug('[小程序] 打开订单详情页');
  173. // 6. 等待订单详情页数据加载完成
  174. await miniPage.page.waitForTimeout(TIMEOUTS.MEDIUM);
  175. await miniPage.page.waitForFunction(
  176. () => !document.body?.textContent?.includes('加载中'),
  177. { timeout: TIMEOUTS.PAGE_LOAD }
  178. ).catch(() => {
  179. console.debug('[小程序] 加载状态检查超时,继续执行测试');
  180. });
  181. // 7. 验证打卡数据统计区域显示
  182. const pageContent = await miniPage.page.textContent('body') || '';
  183. // 验证打卡数据统计字段系统性地存在
  184. expect(pageContent).toContain('打卡数据统计');
  185. expect(pageContent).toContain('本月打卡');
  186. expect(pageContent).toContain('工资视频');
  187. expect(pageContent).toContain('个税视频');
  188. // 8. 获取打卡数据统计
  189. const stats = await miniPage.getOrderCheckInStats();
  190. console.debug(`[小程序] 本月打卡人数: ${stats.monthlyCheckInCount}`);
  191. console.debug(`[小程序] 工资视频数量: ${stats.salaryVideoCount}`);
  192. console.debug(`[小程序] 个税视频数量: ${stats.taxVideoCount}`);
  193. console.debug('[小程序] 订单详情页打卡数据统计显示 ✓');
  194. });
  195. /**
  196. * AC4: 测试场景 - 订单详情页关联人才列表验证
  197. * Given: 后台已添加人员到订单
  198. * When: 在企业小程序查看订单详情页
  199. * Then: 关联人才列表应显示该订单的所有人员,每个人才卡片显示姓名、残疾类型、性别、入职日期、工作状态
  200. */
  201. test('应该在小程序订单详情页显示关联人才列表', async ({ enterpriseMiniPage: miniPage }) => {
  202. // 1. 登录
  203. await miniPage.goto();
  204. await miniPage.login(MINI_LOGIN_PHONE, MINI_LOGIN_PASSWORD);
  205. await miniPage.expectLoginSuccess();
  206. await miniPage.page.waitForTimeout(TIMEOUTS.MEDIUM);
  207. // 2. 导航到订单列表页面
  208. await miniPage.navigateToOrderList();
  209. console.debug('[小程序] 导航到订单列表页面');
  210. // 3. 等待订单列表加载
  211. await miniPage.page.waitForTimeout(TIMEOUTS.LONG);
  212. // 4. 动态获取第一个可用订单名称
  213. const testOrderName = await getFirstOrderName(miniPage);
  214. console.debug(`[小程序] 使用测试订单: ${testOrderName}`);
  215. // 5. 点击测试订单卡片进入详情页
  216. await miniPage.clickOrderCardFromList(testOrderName);
  217. await miniPage.expectUrl('/pages/yongren/order/detail/index');
  218. console.debug('[小程序] 打开订单详情页');
  219. // 6. 等待订单详情页数据加载完成
  220. await miniPage.page.waitForTimeout(TIMEOUTS.MEDIUM);
  221. await miniPage.page.waitForFunction(
  222. () => !document.body?.textContent?.includes('加载中'),
  223. { timeout: TIMEOUTS.PAGE_LOAD }
  224. ).catch(() => {
  225. console.debug('[小程序] 加载状态检查超时,继续执行测试');
  226. });
  227. // 7. 验证关联人才区域显示
  228. const pageContent = await miniPage.page.textContent('body') || '';
  229. expect(pageContent).toContain('关联人才');
  230. // 8. 获取关联人才列表
  231. const persons = await miniPage.getOrderRelatedPersons();
  232. console.debug(`[小程序] 关联人才数量: ${persons.length}`);
  233. // 9. 验证关联人才列表显示(即使为空,也应该显示该区域)
  234. console.debug('[小程序] 订单详情页关联人才列表区域显示 ✓');
  235. // 如果有人才,显示第一个人才的信息
  236. if (persons.length > 0) {
  237. const firstPerson = persons[0];
  238. console.debug(`[小程序] 第一个人才: ${firstPerson.name}, 性别: ${firstPerson.gender}, 状态: ${firstPerson.workStatus}`);
  239. // 验证人才卡片包含必要字段
  240. expect(firstPerson.name).toBeTruthy();
  241. // 页面显示的状态可能是"在职"、"已就业"或其他工作状态
  242. const hasWorkStatus = pageContent.includes('在职') ||
  243. pageContent.includes('已就业') ||
  244. pageContent.includes('待入职');
  245. expect(hasWorkStatus).toBeTruthy();
  246. } else {
  247. console.debug('[小程序] 当前订单没有关联人才(符合预期)');
  248. }
  249. });
  250. /**
  251. * AC5: 测试场景 - 后台编辑后订单详情页同步验证
  252. * Given: 后台编辑订单信息(名称、状态、人数、日期等)
  253. * When: 在企业小程序打开订单详情页
  254. * Then: 订单详情页应显示更新后的所有相关字段
  255. */
  256. test('应该在小程序订单详情页显示后台编辑后的更新信息', async ({ enterpriseMiniPage: miniPage }) => {
  257. // 1. 登录
  258. await miniPage.goto();
  259. await miniPage.login(MINI_LOGIN_PHONE, MINI_LOGIN_PASSWORD);
  260. await miniPage.expectLoginSuccess();
  261. await miniPage.page.waitForTimeout(TIMEOUTS.MEDIUM);
  262. // 2. 导航到订单列表页面
  263. await miniPage.navigateToOrderList();
  264. console.debug('[小程序] 导航到订单列表页面');
  265. // 3. 等待订单列表加载
  266. await miniPage.page.waitForTimeout(TIMEOUTS.LONG);
  267. // 4. 动态获取第一个可用订单名称
  268. const testOrderName = await getFirstOrderName(miniPage);
  269. console.debug(`[小程序] 使用测试订单: ${testOrderName}`);
  270. // 5. 点击测试订单卡片进入详情页
  271. await miniPage.clickOrderCardFromList(testOrderName);
  272. await miniPage.expectUrl('/pages/yongren/order/detail/index');
  273. console.debug('[小程序] 打开订单详情页');
  274. // 6. 等待订单详情页数据加载完成
  275. await miniPage.page.waitForTimeout(TIMEOUTS.MEDIUM);
  276. await miniPage.page.waitForFunction(
  277. () => !document.body?.textContent?.includes('加载中'),
  278. { timeout: TIMEOUTS.PAGE_LOAD }
  279. ).catch(() => {
  280. console.debug('[小程序] 加载状态检查超时,继续执行测试');
  281. });
  282. // 7. 验证订单详情页包含订单名称
  283. const pageContent = await miniPage.page.textContent('body') || '';
  284. expect(pageContent).toContain(testOrderName);
  285. console.debug('[小程序] 订单详情页显示后台创建的订单信息 ✓');
  286. // 8. 验证订单状态字段(草稿、进行中、已完成、未开始等状态应该显示)
  287. const hasOrderStatus = pageContent.includes('草稿') ||
  288. pageContent.includes('进行中') ||
  289. pageContent.includes('已完成') ||
  290. pageContent.includes('未开始');
  291. expect(hasOrderStatus).toBeTruthy();
  292. console.debug('[小程序] 订单状态字段显示 ✓');
  293. console.debug('[小程序] 后台编辑后订单详情页同步验证完成 ✓');
  294. });
  295. });