order-create-sync.spec.ts 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. import { TIMEOUTS } from '../../utils/timeouts';
  2. import { test, expect } from '../../utils/test-setup';
  3. import { AdminLoginPage } from '../../pages/admin/login.page';
  4. import { EnterpriseMiniPage } from '../../pages/mini/enterprise-mini.page';
  5. /**
  6. * 跨端数据同步 E2E 测试
  7. *
  8. * 测试目标:验证后台创建订单后,企业小程序能否正确显示该订单
  9. *
  10. * 测试流程:
  11. * 1. 后台操作:登录 → 导航到订单管理 → 创建测试订单 → 验证创建成功
  12. * 2. 小程序验证:登录 → 导航到订单列表 → 验证订单存在 → 查看详情
  13. *
  14. * 测试要点:
  15. * - 使用两个独立的 browser context(后台和小程序)
  16. * - 记录数据同步时间
  17. * - 使用 data-testid 选择器
  18. * - 遵循项目测试规范
  19. */
  20. // 测试常量
  21. const TEST_SYNC_TIMEOUT = 3000; // 数据同步等待时间(ms)
  22. const TEST_COMPANY_NAME = '测试公司_1768346782396'; // 测试公司名称
  23. const MINI_LOGIN_PHONE = '13800001111'; // 小程序登录手机号
  24. const MINI_LOGIN_PASSWORD = 'password123'; // 小程序登录密码
  25. /**
  26. * 后台登录辅助函数
  27. */
  28. async function loginAdmin(page: any, testUsers: any) {
  29. const adminLoginPage = new AdminLoginPage(page);
  30. await adminLoginPage.goto();
  31. await adminLoginPage.page.getByPlaceholder('请输入用户名').fill(testUsers.admin.username);
  32. await adminLoginPage.page.getByPlaceholder('请输入密码').fill(testUsers.admin.password);
  33. await adminLoginPage.page.getByRole('button', { name: '登录' }).click();
  34. await adminLoginPage.page.waitForURL('**/admin/dashboard', { timeout: TIMEOUTS.PAGE_LOAD });
  35. console.debug('[后台] 登录成功');
  36. }
  37. /**
  38. * 企业小程序登录辅助函数
  39. */
  40. async function loginMini(page: any) {
  41. const miniPage = new EnterpriseMiniPage(page);
  42. await miniPage.goto();
  43. await miniPage.login(MINI_LOGIN_PHONE, MINI_LOGIN_PASSWORD);
  44. await miniPage.expectLoginSuccess();
  45. console.debug('[小程序] 登录成功');
  46. }
  47. // 测试状态管理(使用闭包替代 process.env)
  48. let testOrderName: string | null = null;
  49. test.describe('跨端数据同步测试 - 后台创建订单到企业小程序', () => {
  50. // 在所有测试后清理测试数据
  51. test.afterAll(async () => {
  52. // 清理测试状态
  53. testOrderName = null;
  54. console.debug('[清理] 测试数据已清理');
  55. });
  56. test.describe.serial('后台创建订单', () => {
  57. test('应该成功登录后台并创建订单', async ({ page: adminPage, testUsers }) => {
  58. // 记录开始时间
  59. const startTime = Date.now();
  60. // 1. 后台登录(使用辅助函数)
  61. await loginAdmin(adminPage, testUsers);
  62. // 2. 导航到订单管理页面
  63. await adminPage.goto('/admin/orders');
  64. await adminPage.waitForSelector('table tbody tr', { state: 'visible', timeout: TIMEOUTS.PAGE_LOAD });
  65. console.debug('[后台] 导航到订单管理页面');
  66. // 3. 点击创建订单按钮
  67. await adminPage.getByTestId('create-order-button').click();
  68. await adminPage.waitForSelector('[role="dialog"]', { state: 'visible', timeout: TIMEOUTS.DIALOG });
  69. console.debug('[后台] 打开创建订单对话框');
  70. // 4. 填写订单表单
  71. const timestamp = Date.now();
  72. testOrderName = `跨端同步测试_${timestamp}`;
  73. // 填写订单名称
  74. await adminPage.getByLabel('订单名称').fill(testOrderName);
  75. console.debug(`[后台] 订单名称: ${testOrderName}`);
  76. // 选择平台(选择第一个可用平台)
  77. await adminPage.getByTestId('platform-selector-create').click();
  78. await adminPage.waitForTimeout(TIMEOUTS.SHORT);
  79. const firstPlatformOption = adminPage.locator('[role="option"]').first();
  80. const platformName = await firstPlatformOption.textContent();
  81. await firstPlatformOption.click();
  82. console.debug(`[后台] 选择平台: ${platformName}`);
  83. // 选择公司(选择与测试用户关联的公司:测试公司_1768346782396)
  84. await adminPage.getByTestId('company-selector-create').click();
  85. await adminPage.waitForTimeout(TIMEOUTS.SHORT);
  86. // 选择测试公司_1768346782396(与 13800001111 用户关联的公司)
  87. const companyOption = adminPage.getByRole('option', { name: TEST_COMPANY_NAME });
  88. await companyOption.click();
  89. console.debug(`[后台] 选择公司: ${TEST_COMPANY_NAME}`);
  90. // 5. 选择残疾人
  91. // 首先检查是否已经有残疾人被选择(可能在之前的测试中)
  92. // 通过检查是否存在显示残疾人详情的区域来判断
  93. const hasExistingPerson = await adminPage.getByText('残疾证号:', { exact: false }).count() > 0;
  94. if (hasExistingPerson) {
  95. console.debug('[后台] 订单中已有残疾人,跳过选择步骤');
  96. } else {
  97. // 需要选择残疾人,点击"选择残疾人"按钮
  98. await adminPage.getByTestId('select-persons-button').click();
  99. console.debug('[后台] 点击选择残疾人按钮');
  100. // 等待残疾人选择对话框出现
  101. await adminPage.waitForSelector('text=选择残疾人', { state: 'visible', timeout: TIMEOUTS.DIALOG });
  102. console.debug('[后台] 选择残疾人对话框已打开');
  103. // 等待残疾人列表加载
  104. await adminPage.waitForSelector('table tbody tr', { state: 'visible', timeout: TIMEOUTS.TABLE_LOAD });
  105. // 选择第一个残疾人 - 使用复选框选择器
  106. const firstCheckbox = adminPage.locator('[data-testid^="person-checkbox-"]').first();
  107. await firstCheckbox.click();
  108. console.debug('[后台] 已勾选第一个残疾人');
  109. // 等待确认按钮变为可用状态
  110. await adminPage.waitForSelector('[data-testid="confirm-batch-button"]:not([disabled])', { timeout: TIMEOUTS.SHORT });
  111. // 点击确认选择按钮
  112. await adminPage.getByTestId('confirm-batch-button').click();
  113. await adminPage.waitForTimeout(TIMEOUTS.MEDIUM);
  114. console.debug('[后台] 已确认选择残疾人');
  115. }
  116. // 等待 UI 稳定
  117. await adminPage.waitForTimeout(1000);
  118. // 6. 提交表单
  119. await adminPage.getByTestId('order-create-submit-button').click();
  120. await adminPage.waitForLoadState('domcontentloaded');
  121. await adminPage.waitForTimeout(TIMEOUTS.LONG);
  122. console.debug('[后台] 提交订单表单');
  123. // 7. 验证创建成功的 Toast
  124. const successToast = adminPage.locator('[data-sonner-toast][data-type="success"]');
  125. const toastCount = await successToast.count();
  126. expect(toastCount).toBeGreaterThan(0);
  127. console.debug('[后台] 订单创建成功');
  128. // 8. 验证订单出现在列表中
  129. const orderExists = adminPage.locator('table tbody tr').filter({ hasText: testOrderName }).count() > 0;
  130. expect(orderExists).toBe(true);
  131. console.debug(`[后台] 订单 "${testOrderName}" 出现在列表中`);
  132. // 9. 记录创建完成时间
  133. const endTime = Date.now();
  134. const syncTime = endTime - startTime;
  135. console.debug(`[后台] 订单创建完成,耗时: ${syncTime}ms`);
  136. });
  137. });
  138. test.describe.serial('小程序验证订单同步', () => {
  139. test.use({ storageState: undefined }); // 确保使用新的浏览器上下文
  140. test('应该在小程序中显示后台创建的订单', async ({ page: miniPage }) => {
  141. // 从模块级变量获取订单名称
  142. const orderNameForTest = testOrderName;
  143. if (!orderNameForTest) {
  144. throw new Error('未找到测试订单名称,请先运行后台创建订单测试');
  145. }
  146. console.debug(`[小程序] 查找订单: ${orderNameForTest}`);
  147. // 等待一段时间,确保数据同步完成
  148. await new Promise(resolve => setTimeout(resolve, TEST_SYNC_TIMEOUT));
  149. // 1. 小程序登录(使用辅助函数)
  150. await loginMini(miniPage);
  151. // 2. 导航到订单列表页面
  152. await miniPage.getByText('订单', { exact: true }).click();
  153. await miniPage.waitForLoadState('domcontentloaded');
  154. console.debug('[小程序] 导航到订单列表页面');
  155. // 3. 等待订单列表加载
  156. await miniPage.waitForTimeout(TIMEOUTS.LONG);
  157. // 4. 验证订单出现在小程序列表中
  158. // 使用多种方法验证订单存在
  159. const orderExistsByLocator = await miniPage.locator('text=' + orderNameForTest).count() > 0;
  160. const orderExistsByGetByText = await miniPage.getByText(orderNameForTest).count() > 0;
  161. const orderExists = orderExistsByLocator || orderExistsByGetByText;
  162. expect(orderExists).toBe(true);
  163. console.debug(`[小程序] 订单 "${orderNameForTest}" 已同步到小程序`);
  164. // 5. 点击查看详情
  165. const detailButton = miniPage.getByText('查看详情').first();
  166. await detailButton.click();
  167. await miniPage.waitForURL(/\/detail/, { timeout: TIMEOUTS.PAGE_LOAD });
  168. console.debug('[小程序] 打开订单详情');
  169. // 6. 验证订单详情信息
  170. // 验证订单名称显示
  171. const orderNameElement = miniPage.getByText(orderNameForTest);
  172. await expect(orderNameElement).toBeVisible();
  173. console.debug('[小程序] 订单详情显示正确');
  174. // 7. 记录数据同步完成时间
  175. const syncEndTime = Date.now();
  176. console.debug(`[小程序] 数据同步验证完成,时间戳: ${syncEndTime}`);
  177. });
  178. });
  179. });