order-list-validation.spec.ts 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725
  1. import { TIMEOUTS } from '../../utils/timeouts';
  2. import { test, expect } from '../../utils/test-setup';
  3. import { EnterpriseMiniPage } from '../../pages/mini/enterprise-mini.page';
  4. import { AdminLoginPage } from '../../pages/admin/login.page';
  5. import { ORDER_STATUS } from '../../pages/admin/order-management.page';
  6. /**
  7. * 订单列表页完整验证 E2E 测试 (Story 13.8)
  8. *
  9. * 测试目标:验证企业小程序订单列表页的完整功能
  10. *
  11. * 测试流程:
  12. * 1. 企业用户登录小程序
  13. * 2. 导航到订单列表页
  14. * 3. 验证订单列表显示
  15. * 4. 验证筛选功能
  16. * 5. 验证搜索功能
  17. * 6. 验证订单卡片交互(查看详情)
  18. *
  19. * Playwright MCP 探索结果 (2026-01-14):
  20. * - 小程序订单列表页没有 data-testid 属性
  21. * - 使用 Taro 组件 (taro-view-core, taro-text-core)
  22. * - 需要使用文本选择器和 CSS 类选择器
  23. * - 订单卡片包含:订单名称、创建日期、状态、人数、日期、统计信息
  24. * - 点击"查看详情"成功导航到订单详情页
  25. */
  26. // 测试常量
  27. const TEST_USER_PHONE = '13800001111'; // 小程序登录手机号
  28. const TEST_USER_PASSWORD = process.env.TEST_ENTERPRISE_PASSWORD || 'password123'; // 小程序登录密码
  29. // 测试用户的平台和公司信息(从数据库查询获取)
  30. // 用户 13800001111 的 company_id = 1663,对应的公司关联的 platform_id = 1545
  31. const TEST_PLATFORM_NAME = '测试平台_1768346782302'; // platform_id = 1545
  32. const TEST_COMPANY_NAME = '测试公司_1768346782396'; // company_id = 1663
  33. /**
  34. * 订单列表页常量(基于 Playwright MCP 探索)
  35. */
  36. const ORDER_LIST_SELECTORS = {
  37. // 页面
  38. pageUrl: '/mini/#/mini/pages/yongren/order/list/index',
  39. pageTitle: '订单列表',
  40. // 筛选标签(文本选择器)
  41. filterTabs: {
  42. all: '全部订单',
  43. inProgress: '进行中',
  44. completed: '已完成',
  45. cancelled: '已取消',
  46. },
  47. // 搜索
  48. searchPlaceholder: '按订单号、人才姓名搜索',
  49. searchButton: '搜索',
  50. // 订单卡片
  51. orderCard: '.bg-white', // CSS 类选择器
  52. viewDetailButton: '查看详情', // 文本选择器
  53. // 底部导航
  54. bottomNav: {
  55. home: '首页',
  56. talent: '人才',
  57. order: '订单',
  58. data: '数据',
  59. settings: '设置',
  60. },
  61. } as const;
  62. test.describe('订单列表页完整验证 - Story 13.8', () => {
  63. // 每个测试使用独立的浏览器上下文
  64. test.use({ storageState: undefined });
  65. /**
  66. * 测试场景:订单列表基础功能验证 (AC1)
  67. */
  68. test.describe.serial('订单列表基础功能测试 (AC1)', () => {
  69. test.use({ storageState: undefined });
  70. test('应该成功加载订单列表并显示订单卡片', async ({ enterpriseMiniPage: miniPage }) => {
  71. // 1. 登录小程序
  72. await miniPage.goto();
  73. await miniPage.login(TEST_USER_PHONE, TEST_USER_PASSWORD);
  74. await miniPage.expectLoginSuccess();
  75. await miniPage.page.waitForTimeout(TIMEOUTS.MEDIUM);
  76. // 2. 导航到订单列表页
  77. await miniPage.page.goto(`http://localhost:8080${ORDER_LIST_SELECTORS.pageUrl}`);
  78. await miniPage.page.waitForTimeout(TIMEOUTS.LONG);
  79. // 3. 验证页面标题
  80. const pageTitle = await miniPage.page.title();
  81. expect(pageTitle).toBe(ORDER_LIST_SELECTORS.pageTitle);
  82. // 4. 验证订单卡片显示
  83. // 注意:小程序订单列表页没有 data-testid,使用 CSS 类选择器
  84. const orderCards = miniPage.page.locator(ORDER_LIST_SELECTORS.orderCard);
  85. const cardCount = await orderCards.count();
  86. // 验证至少有一个订单卡片(排除导航栏等元素)
  87. expect(cardCount).toBeGreaterThan(0);
  88. console.debug(`[订单列表] 找到 ${cardCount} 个订单卡片`);
  89. // 5. 验证筛选区域可见
  90. const filterTabs = miniPage.page.getByText(ORDER_LIST_SELECTORS.filterTabs.all);
  91. await expect(filterTabs).toBeVisible();
  92. console.debug('[订单列表] 筛选标签可见');
  93. });
  94. test('订单卡片应该显示所有必填字段', async ({ enterpriseMiniPage: miniPage }) => {
  95. // 1. 登录并导航到订单列表
  96. await miniPage.goto();
  97. await miniPage.login(TEST_USER_PHONE, TEST_USER_PASSWORD);
  98. await miniPage.expectLoginSuccess();
  99. await miniPage.page.goto(`http://localhost:8080${ORDER_LIST_SELECTORS.pageUrl}`);
  100. await miniPage.page.waitForTimeout(TIMEOUTS.LONG);
  101. // 2. 获取页面内容验证订单信息显示
  102. // 基于实际探索,订单列表页包含订单名称、状态、人数等信息
  103. const pageText = await miniPage.page.textContent('body');
  104. // 3. 验证页面包含订单相关信息
  105. expect(pageText).toBeDefined();
  106. expect(pageText!.length).toBeGreaterThan(0);
  107. // 4. 验证包含状态关键词(基于实际探索:草稿/进行中/已完成/已取消)
  108. const hasStatus = pageText!.match(/草稿|进行中|已完成|已取消/);
  109. expect(hasStatus).toBeTruthy();
  110. // 5. 验证包含人数信息(基于实际探索:0人)
  111. expect(pageText).toContain('人');
  112. // 6. 验证包含日期信息(基于实际探索:YYYY-MM-DD 格式或 "未设置")
  113. const hasDate = pageText!.match(/\d{4}-\d{2}-\d{2}|未设置/);
  114. expect(hasDate).toBeTruthy();
  115. console.debug('[订单列表] 订单卡片字段验证通过');
  116. });
  117. test('订单状态徽章应该正确显示', async ({ enterpriseMiniPage: miniPage }) => {
  118. // 1. 登录并导航到订单列表
  119. await miniPage.goto();
  120. await miniPage.login(TEST_USER_PHONE, TEST_USER_PASSWORD);
  121. await miniPage.expectLoginSuccess();
  122. await miniPage.page.goto(`http://localhost:8080${ORDER_LIST_SELECTORS.pageUrl}`);
  123. await miniPage.page.waitForTimeout(TIMEOUTS.LONG);
  124. // 2. 验证订单状态显示
  125. // 检查页面包含至少一个订单状态
  126. const statusText = await miniPage.page.textContent('body');
  127. const hasOrderStatus = statusText?.match(/草稿|进行中|已完成|已取消/);
  128. expect(hasOrderStatus).toBeTruthy();
  129. console.debug('[订单列表] 订单状态徽章显示正确');
  130. });
  131. test('订单人数和日期信息应该正确显示', async ({ enterpriseMiniPage: miniPage }) => {
  132. // 1. 登录并导航到订单列表
  133. await miniPage.goto();
  134. await miniPage.login(TEST_USER_PHONE, TEST_USER_PASSWORD);
  135. await miniPage.expectLoginSuccess();
  136. await miniPage.page.goto(`http://localhost:8080${ORDER_LIST_SELECTORS.pageUrl}`);
  137. await miniPage.page.waitForTimeout(TIMEOUTS.LONG);
  138. // 2. 验证人数信息显示
  139. const pageText = await miniPage.page.textContent('body');
  140. expect(pageText).toContain('人');
  141. console.debug('[订单列表] 订单人数显示正确');
  142. // 3. 验证日期信息显示(格式:YYYY-MM-DD 或 "未设置")
  143. const hasDate = pageText?.match(/\d{4}-\d{2}-\d{2}|未设置/);
  144. expect(hasDate).toBeTruthy();
  145. console.debug('[订单列表] 订单日期显示正确');
  146. });
  147. });
  148. /**
  149. * 测试场景:订单列表交互功能验证 (AC7)
  150. */
  151. test.describe.serial('订单列表交互功能测试 (AC7)', () => {
  152. test.use({ storageState: undefined });
  153. test('应该点击订单卡片跳转到订单详情页', async ({ enterpriseMiniPage: miniPage }) => {
  154. // 1. 登录并导航到订单列表
  155. await miniPage.goto();
  156. await miniPage.login(TEST_USER_PHONE, TEST_USER_PASSWORD);
  157. await miniPage.expectLoginSuccess();
  158. await miniPage.page.goto(`http://localhost:8080${ORDER_LIST_SELECTORS.pageUrl}`);
  159. await miniPage.page.waitForTimeout(TIMEOUTS.LONG);
  160. // 2. 记录当前 URL
  161. const beforeUrl = miniPage.page.url();
  162. console.debug(`[详情页] 当前 URL: ${beforeUrl}`);
  163. // 3. 点击"查看详情"按钮
  164. // 使用 evaluate 直接点击,避免被其他元素阻挡
  165. await miniPage.page.evaluate((buttonText) => {
  166. const buttons = Array.from(document.querySelectorAll('*'));
  167. const targetButton = buttons.find(el =>
  168. el.textContent?.includes(buttonText) && el.textContent?.trim() === buttonText
  169. );
  170. if (targetButton) {
  171. (targetButton as HTMLElement).click();
  172. }
  173. }, ORDER_LIST_SELECTORS.viewDetailButton);
  174. // 4. 等待导航完成
  175. await miniPage.page.waitForTimeout(TIMEOUTS.MEDIUM);
  176. // 5. 验证 URL 已改变(包含订单详情页路径)
  177. const afterUrl = miniPage.page.url();
  178. console.debug(`[详情页] 导航后 URL: ${afterUrl}`);
  179. expect(afterUrl).toContain('/mini/pages/yongren/order/detail/index');
  180. expect(afterUrl).toContain('id=');
  181. console.debug('[详情页] 成功导航到订单详情页');
  182. });
  183. test('应该可以从详情页返回列表页', async ({ enterpriseMiniPage: miniPage }) => {
  184. // 1. 登录并导航到订单列表
  185. await miniPage.goto();
  186. await miniPage.login(TEST_USER_PHONE, TEST_USER_PASSWORD);
  187. await miniPage.expectLoginSuccess();
  188. await miniPage.page.goto(`http://localhost:8080${ORDER_LIST_SELECTORS.pageUrl}`);
  189. await miniPage.page.waitForTimeout(TIMEOUTS.LONG);
  190. // 2. 点击"查看详情"进入订单详情页
  191. await miniPage.page.evaluate((buttonText) => {
  192. const buttons = Array.from(document.querySelectorAll('*'));
  193. const targetButton = buttons.find(el =>
  194. el.textContent?.includes(buttonText) && el.textContent?.trim() === buttonText
  195. );
  196. if (targetButton) {
  197. (targetButton as HTMLElement).click();
  198. }
  199. }, ORDER_LIST_SELECTORS.viewDetailButton);
  200. await miniPage.page.waitForTimeout(TIMEOUTS.MEDIUM);
  201. // 3. 验证在详情页
  202. const detailUrl = miniPage.page.url();
  203. expect(detailUrl).toContain('/mini/pages/yongren/order/detail/index');
  204. // 4. 返回列表页(使用 EnterpriseMiniPage 的 clickBottomNav 方法)
  205. await miniPage.clickBottomNav('order');
  206. await miniPage.page.waitForTimeout(TIMEOUTS.MEDIUM);
  207. // 5. 验证返回到列表页
  208. const listUrl = miniPage.page.url();
  209. expect(listUrl).toContain('/mini/pages/yongren/order/list');
  210. console.debug('[详情页] 成功返回到订单列表页');
  211. });
  212. });
  213. /**
  214. * 测试场景:订单状态筛选功能验证 (AC2)
  215. */
  216. test.describe.serial('订单状态筛选功能测试 (AC2)', () => {
  217. test.use({ storageState: undefined });
  218. test('应该显示所有筛选标签', async ({ enterpriseMiniPage: miniPage }) => {
  219. // 1. 登录并导航到订单列表
  220. await miniPage.goto();
  221. await miniPage.login(TEST_USER_PHONE, TEST_USER_PASSWORD);
  222. await miniPage.expectLoginSuccess();
  223. await miniPage.page.goto(`http://localhost:8080${ORDER_LIST_SELECTORS.pageUrl}`);
  224. await miniPage.page.waitForTimeout(TIMEOUTS.LONG);
  225. // 2. 验证所有筛选标签可见
  226. const { filterTabs } = ORDER_LIST_SELECTORS;
  227. // 使用 .first() 避免 strict mode violation
  228. await expect(miniPage.page.getByText(filterTabs.all).first()).toBeVisible();
  229. await expect(miniPage.page.getByText(filterTabs.inProgress).first()).toBeVisible();
  230. await expect(miniPage.page.getByText(filterTabs.completed).first()).toBeVisible();
  231. await expect(miniPage.page.getByText(filterTabs.cancelled).first()).toBeVisible();
  232. console.debug('[筛选] 所有筛选标签可见');
  233. });
  234. test('应该可以按订单状态筛选 - 进行中', async ({ enterpriseMiniPage: miniPage }) => {
  235. // 1. 登录并导航到订单列表
  236. await miniPage.goto();
  237. await miniPage.login(TEST_USER_PHONE, TEST_USER_PASSWORD);
  238. await miniPage.expectLoginSuccess();
  239. await miniPage.page.goto(`http://localhost:8080${ORDER_LIST_SELECTORS.pageUrl}`);
  240. await miniPage.page.waitForTimeout(TIMEOUTS.LONG);
  241. // 2. 点击"进行中"筛选标签
  242. await miniPage.page.evaluate((tabText) => {
  243. const tabs = Array.from(document.querySelectorAll('*'));
  244. const targetTab = tabs.find(el =>
  245. el.textContent?.includes(tabText) && el.textContent?.trim() === tabText
  246. );
  247. if (targetTab) {
  248. (targetTab as HTMLElement).click();
  249. }
  250. }, ORDER_LIST_SELECTORS.filterTabs.inProgress);
  251. await miniPage.page.waitForTimeout(TIMEOUTS.MEDIUM);
  252. // 3. 验证筛选结果:检查页面包含"进行中"状态
  253. const pageText = await miniPage.page.textContent('body');
  254. const hasInProgressStatus = pageText?.includes('进行中');
  255. expect(hasInProgressStatus).toBe(true);
  256. // 4. 验证筛选后的订单列表
  257. const filteredCards = miniPage.page.locator(ORDER_LIST_SELECTORS.orderCard);
  258. const filteredCount = await filteredCards.count();
  259. // 验证筛选后有订单显示(至少有进行中状态的订单)
  260. expect(filteredCount).toBeGreaterThan(0);
  261. console.debug(`[筛选] 筛选后订单数量: ${filteredCount}`);
  262. // 5. 进一步验证:检查筛选结果确实包含"进行中"状态的订单
  263. let foundMatchingOrder = false;
  264. for (let i = 0; i < Math.min(filteredCount, 3); i++) {
  265. const cardText = await filteredCards.nth(i).textContent();
  266. if (cardText?.includes('进行中')) {
  267. foundMatchingOrder = true;
  268. console.debug(`[筛选] 订单 ${i + 1} 包含"进行中"状态`);
  269. break;
  270. }
  271. }
  272. expect(foundMatchingOrder).toBe(true);
  273. console.debug('[筛选] 筛选功能验证通过');
  274. });
  275. });
  276. /**
  277. * 测试场景:订单搜索功能验证 (AC4)
  278. */
  279. test.describe.serial('订单搜索功能测试 (AC4)', () => {
  280. test.use({ storageState: undefined });
  281. test('应该显示搜索框和搜索按钮', async ({ enterpriseMiniPage: miniPage }) => {
  282. // 1. 登录并导航到订单列表
  283. await miniPage.goto();
  284. await miniPage.login(TEST_USER_PHONE, TEST_USER_PASSWORD);
  285. await miniPage.expectLoginSuccess();
  286. await miniPage.page.goto(`http://localhost:8080${ORDER_LIST_SELECTORS.pageUrl}`);
  287. await miniPage.page.waitForTimeout(TIMEOUTS.LONG);
  288. // 2. 验证搜索框可见
  289. // 使用 .first() 避免 strict mode violation(有多个搜索框)
  290. const searchInput = miniPage.page.getByPlaceholder(ORDER_LIST_SELECTORS.searchPlaceholder).first();
  291. await expect(searchInput).toBeVisible();
  292. // 3. 验证搜索按钮可见
  293. const searchButton = miniPage.page.getByText(ORDER_LIST_SELECTORS.searchButton);
  294. await expect(searchButton).toBeVisible();
  295. console.debug('[搜索] 搜索框和搜索按钮可见');
  296. });
  297. test('应该可以按订单名称搜索并显示筛选结果', async ({ enterpriseMiniPage: miniPage }) => {
  298. // 1. 登录并导航到订单列表
  299. await miniPage.goto();
  300. await miniPage.login(TEST_USER_PHONE, TEST_USER_PASSWORD);
  301. await miniPage.expectLoginSuccess();
  302. await miniPage.page.goto(`http://localhost:8080${ORDER_LIST_SELECTORS.pageUrl}`);
  303. await miniPage.page.waitForTimeout(TIMEOUTS.LONG);
  304. // 2. 记录初始订单数量
  305. const initialCards = miniPage.page.locator(ORDER_LIST_SELECTORS.orderCard);
  306. const initialCount = await initialCards.count();
  307. console.debug(`[搜索] 初始订单数量: ${initialCount}`);
  308. // 3. 在搜索框输入已知存在的订单关键词
  309. // 基于实际探索:搜索 "Epic13" 应该能找到匹配的订单
  310. const searchInput = miniPage.page.getByPlaceholder(ORDER_LIST_SELECTORS.searchPlaceholder).first();
  311. const searchKeyword = 'Epic13';
  312. await searchInput.type(searchKeyword);
  313. // 4. 等待搜索自动触发(基于探索:搜索是自动触发的)
  314. await miniPage.page.waitForTimeout(TIMEOUTS.MEDIUM);
  315. // 5. 验证搜索输入成功
  316. const inputValue = await searchInput.evaluate((el: any) => el.value || el.textContent);
  317. expect(inputValue).toContain(searchKeyword);
  318. console.debug(`[搜索] 搜索关键词已输入: ${searchKeyword}`);
  319. // 6. 验证搜索结果:检查页面包含搜索关键词
  320. const pageText = await miniPage.page.textContent('body');
  321. const hasKeyword = pageText?.includes(searchKeyword);
  322. expect(hasKeyword).toBe(true);
  323. // 7. 验证搜索结果只包含匹配的订单
  324. const searchResults = miniPage.page.locator(ORDER_LIST_SELECTORS.orderCard);
  325. const resultCount = await searchResults.count();
  326. // 验证有搜索结果
  327. expect(resultCount).toBeGreaterThan(0);
  328. console.debug(`[搜索] 搜索结果数量: ${resultCount}`);
  329. // 8. 验证搜索结果确实包含搜索关键词
  330. let foundMatchingResult = false;
  331. for (let i = 0; i < Math.min(resultCount, 3); i++) {
  332. const cardText = await searchResults.nth(i).textContent();
  333. if (cardText?.includes(searchKeyword)) {
  334. foundMatchingResult = true;
  335. console.debug(`[搜索] 搜索结果 ${i + 1} 包含关键词 "${searchKeyword}"`);
  336. break;
  337. }
  338. }
  339. expect(foundMatchingResult).toBe(true);
  340. console.debug('[搜索] 搜索功能验证通过');
  341. });
  342. });
  343. /**
  344. * 测试场景:后台编辑后订单列表同步验证 (AC3, AC5)
  345. *
  346. * 测试流程:
  347. * 1. 后台登录并创建/编辑订单
  348. * 2. 小程序验证订单信息同步
  349. * 3. 验证数据同步时间(≤ 10 秒)
  350. */
  351. test.describe.serial('后台编辑后订单列表同步测试 (AC3, AC5)', () => {
  352. test.use({ storageState: undefined });
  353. // 管理员登录凭据
  354. const ADMIN_USERNAME = 'admin';
  355. const ADMIN_PASSWORD = process.env.TEST_ADMIN_PASSWORD || 'admin123';
  356. /**
  357. * 辅助函数:执行管理员登录
  358. * @param adminLoginPage 管理员登录页面对象
  359. */
  360. async function adminLogin(adminLoginPage: AdminLoginPage): Promise<void> {
  361. await adminLoginPage.goto();
  362. await adminLoginPage.login(ADMIN_USERNAME, ADMIN_PASSWORD);
  363. // 验证登录成功
  364. await adminLoginPage.page.waitForURL('/admin/dashboard', { timeout: TIMEOUTS.PAGE_LOAD });
  365. }
  366. /**
  367. * 辅助函数:等待订单在小程序列表中更新
  368. * @param miniPage 小程序页面
  369. * @param orderName 订单名称
  370. * @param timeout 超时时间(毫秒)
  371. * @returns 是否在超时时间内检测到更新
  372. */
  373. async function waitForOrderUpdate(miniPage: EnterpriseMiniPage, orderName: string, timeout: number = 10000): Promise<boolean> {
  374. const startTime = Date.now();
  375. while (Date.now() - startTime < timeout) {
  376. // 刷新页面
  377. await miniPage.page.reload({ waitUntil: 'domcontentloaded', timeout: TIMEOUTS.PAGE_LOAD });
  378. await miniPage.page.waitForTimeout(TIMEOUTS.SHORT);
  379. // 检查订单是否出现
  380. const pageText = await miniPage.page.textContent('body');
  381. if (pageText && pageText.includes(orderName)) {
  382. return true;
  383. }
  384. await miniPage.page.waitForTimeout(500);
  385. }
  386. return false;
  387. }
  388. /**
  389. * 辅助函数:在小程序订单列表中查找订单
  390. * @param miniPage 小程序页面
  391. * @param orderName 订单名称
  392. * @returns 是否找到订单
  393. */
  394. async function findOrderInList(miniPage: EnterpriseMiniPage, orderName: string): Promise<boolean> {
  395. const pageText = await miniPage.page.textContent('body');
  396. if (!pageText) return false;
  397. // 检查是否包含订单名称
  398. const hasOrderName = pageText.includes(orderName);
  399. return hasOrderName;
  400. }
  401. test('后台修改订单名称后小程序同步', async ({ enterpriseMiniPage: miniPage, orderManagementPage: adminPage, adminLoginPage }) => {
  402. // 测试数据
  403. const originalName = `E2E测试_名称同步_${Date.now()}`;
  404. const updatedName = `${originalName}_已更新`;
  405. // 1. 后台登录并创建订单(需要关联到测试用户的平台和公司)
  406. await adminLogin(adminLoginPage);
  407. await adminPage.goto();
  408. const createResult = await adminPage.createOrder({
  409. name: originalName,
  410. platformName: TEST_PLATFORM_NAME,
  411. companyName: TEST_COMPANY_NAME,
  412. expectedStartDate: '2026-02-01',
  413. });
  414. expect(createResult.success).toBe(true);
  415. console.debug(`[跨端同步] 后台创建订单成功: ${originalName}`);
  416. // 2. 小程序验证订单显示
  417. await miniPage.goto();
  418. await miniPage.login(TEST_USER_PHONE, TEST_USER_PASSWORD);
  419. await miniPage.expectLoginSuccess();
  420. await miniPage.navigateToOrderList();
  421. // 等待订单出现
  422. const found = await waitForOrderUpdate(miniPage, originalName, TIMEOUTS.OPERATION);
  423. expect(found).toBe(true);
  424. console.debug(`[跨端同步] 小程序显示订单: ${originalName}`);
  425. // 3. 后台修改订单名称
  426. await adminLogin(adminLoginPage);
  427. await adminPage.goto();
  428. const editResult = await adminPage.editOrder(originalName, {
  429. name: updatedName, // 编辑时需要提供 name
  430. });
  431. expect(editResult.success).toBe(true);
  432. console.debug(`[跨端同步] 后台修改订单名称: ${originalName} → ${updatedName}`);
  433. // 4. 小程序验证订单名称更新
  434. await miniPage.navigateToOrderList();
  435. const updated = await waitForOrderUpdate(miniPage, updatedName, TIMEOUTS.OPERATION);
  436. expect(updated).toBe(true);
  437. // 验证旧名称不再存在
  438. const oldNameExists = await findOrderInList(miniPage, originalName);
  439. expect(oldNameExists).toBe(false);
  440. console.debug(`[跨端同步] 小程序订单名称已更新: ${updatedName}`);
  441. });
  442. test('后台修改订单状态后小程序同步', async ({ enterpriseMiniPage: miniPage, orderManagementPage: adminPage, adminLoginPage }) => {
  443. // 测试数据
  444. const orderName = `E2E测试_状态同步_${Date.now()}`;
  445. // 1. 后台登录并创建订单(需要关联到测试用户的平台和公司)
  446. await adminLogin(adminLoginPage);
  447. await adminPage.goto();
  448. const createResult = await adminPage.createOrder({
  449. name: orderName,
  450. platformName: TEST_PLATFORM_NAME,
  451. companyName: TEST_COMPANY_NAME,
  452. status: ORDER_STATUS.DRAFT,
  453. expectedStartDate: '2026-02-01',
  454. });
  455. expect(createResult.success).toBe(true);
  456. console.debug(`[跨端同步] 后台创建订单: ${orderName}, 状态: 草稿`);
  457. // 2. 小程序验证订单显示
  458. await miniPage.goto();
  459. await miniPage.login(TEST_USER_PHONE, TEST_USER_PASSWORD);
  460. await miniPage.expectLoginSuccess();
  461. await miniPage.navigateToOrderList();
  462. const found = await waitForOrderUpdate(miniPage, orderName, TIMEOUTS.OPERATION);
  463. expect(found).toBe(true);
  464. console.debug(`[跨端同步] 小程序显示订单: ${orderName}`);
  465. // 3. 后台修改订单状态为"进行中"
  466. await adminLogin(adminLoginPage);
  467. await adminPage.goto();
  468. const editResult = await adminPage.editOrder(orderName, {
  469. name: orderName, // 编辑时需要提供 name
  470. status: ORDER_STATUS.IN_PROGRESS,
  471. });
  472. expect(editResult.success).toBe(true);
  473. console.debug(`[跨端同步] 后台修改订单状态: 草稿 → 进行中`);
  474. // 4. 小程序验证订单状态更新
  475. await miniPage.navigateToOrderList();
  476. await miniPage.page.waitForTimeout(TIMEOUTS.MEDIUM);
  477. // 检查页面包含"进行中"状态
  478. const pageText = await miniPage.page.textContent('body');
  479. expect(pageText).toContain('进行中');
  480. console.debug(`[跨端同步] 小程序订单状态已更新: 进行中`);
  481. });
  482. test('后台修改日期后小程序同步', async ({ enterpriseMiniPage: miniPage, orderManagementPage: adminPage, adminLoginPage }) => {
  483. // 测试数据
  484. const orderName = `E2E测试_日期同步_${Date.now()}`;
  485. const originalDate = '2026-02-01';
  486. const updatedDate = '2026-03-15';
  487. // 1. 后台登录并创建订单(需要关联到测试用户的平台和公司)
  488. await adminLogin(adminLoginPage);
  489. await adminPage.goto();
  490. const createResult = await adminPage.createOrder({
  491. name: orderName,
  492. platformName: TEST_PLATFORM_NAME,
  493. companyName: TEST_COMPANY_NAME,
  494. expectedStartDate: originalDate,
  495. });
  496. expect(createResult.success).toBe(true);
  497. console.debug(`[跨端同步] 后台创建订单: ${orderName}, 开始日期: ${originalDate}`);
  498. // 2. 小程序验证订单显示
  499. await miniPage.goto();
  500. await miniPage.login(TEST_USER_PHONE, TEST_USER_PASSWORD);
  501. await miniPage.expectLoginSuccess();
  502. await miniPage.navigateToOrderList();
  503. const found = await waitForOrderUpdate(miniPage, orderName, TIMEOUTS.OPERATION);
  504. expect(found).toBe(true);
  505. // 验证日期显示
  506. const initialPageText = await miniPage.page.textContent('body');
  507. expect(initialPageText).toContain(originalDate);
  508. console.debug(`[跨端同步] 小程序显示日期: ${originalDate}`);
  509. // 3. 后台修改预计开始日期
  510. await adminLogin(adminLoginPage);
  511. await adminPage.goto();
  512. const editResult = await adminPage.editOrder(orderName, {
  513. name: orderName, // 编辑时需要提供 name
  514. expectedStartDate: updatedDate,
  515. });
  516. expect(editResult.success).toBe(true);
  517. console.debug(`[跨端同步] 后台修改日期: ${originalDate} → ${updatedDate}`);
  518. // 4. 小程序验证日期更新
  519. await miniPage.navigateToOrderList();
  520. await miniPage.page.waitForTimeout(TIMEOUTS.MEDIUM);
  521. // 检查更新后的日期
  522. const updatedPageText = await miniPage.page.textContent('body');
  523. expect(updatedPageText).toContain(updatedDate);
  524. console.debug(`[跨端同步] 小程序日期已更新: ${updatedDate}`);
  525. });
  526. test('验证数据同步时间(≤ 10 秒)', async ({ enterpriseMiniPage: miniPage, orderManagementPage: adminPage, adminLoginPage }) => {
  527. // 测试数据
  528. const orderName = `E2E测试_同步时间_${Date.now()}`;
  529. const SYNC_TIMEOUT = 10000; // 10 秒
  530. // 1. 后台登录并创建订单(需要关联到测试用户的平台和公司)
  531. await adminLogin(adminLoginPage);
  532. await adminPage.goto();
  533. const createResult = await adminPage.createOrder({
  534. name: orderName,
  535. platformName: TEST_PLATFORM_NAME,
  536. companyName: TEST_COMPANY_NAME,
  537. expectedStartDate: '2026-02-01',
  538. });
  539. expect(createResult.success).toBe(true);
  540. console.debug(`[跨端同步] 后台创建订单: ${orderName}`);
  541. // 2. 记录开始时间并等待小程序显示
  542. const startTime = Date.now();
  543. await miniPage.goto();
  544. await miniPage.login(TEST_USER_PHONE, TEST_USER_PASSWORD);
  545. await miniPage.expectLoginSuccess();
  546. await miniPage.navigateToOrderList();
  547. // 等待订单出现,最多等待 10 秒
  548. const found = await waitForOrderUpdate(miniPage, orderName, SYNC_TIMEOUT);
  549. const syncTime = Date.now() - startTime;
  550. console.debug(`[跨端同步] 数据同步耗时: ${syncTime}ms`);
  551. // 验证订单在 10 秒内同步
  552. expect(found).toBe(true);
  553. expect(syncTime).toBeLessThanOrEqual(SYNC_TIMEOUT);
  554. console.debug(`[跨端同步] 数据同步时间验证通过: ${syncTime}ms ≤ ${SYNC_TIMEOUT}ms`);
  555. });
  556. });
  557. /**
  558. * 测试场景:底部导航验证 (AC7)
  559. */
  560. test.describe.serial('底部导航功能测试', () => {
  561. test.use({ storageState: undefined });
  562. test('应该显示底部导航栏', async ({ enterpriseMiniPage: miniPage }) => {
  563. // 1. 登录并导航到订单列表
  564. await miniPage.goto();
  565. await miniPage.login(TEST_USER_PHONE, TEST_USER_PASSWORD);
  566. await miniPage.expectLoginSuccess();
  567. await miniPage.page.goto(`http://localhost:8080${ORDER_LIST_SELECTORS.pageUrl}`);
  568. await miniPage.page.waitForTimeout(TIMEOUTS.LONG);
  569. // 2. 验证底部导航栏可见
  570. const { bottomNav } = ORDER_LIST_SELECTORS;
  571. // 使用 .nth() 或 CSS 类选择器避免 strict mode violation
  572. // 底部导航栏在页面底部,使用更具体的选择器
  573. await expect(miniPage.page.getByText(bottomNav.home)).toBeVisible();
  574. await expect(miniPage.page.getByText(bottomNav.talent)).toBeVisible();
  575. // "订单"文本出现在多个位置,使用 exact: true 精确匹配底部导航
  576. await expect(miniPage.page.getByText(bottomNav.order, { exact: true })).toBeVisible();
  577. await expect(miniPage.page.getByText(bottomNav.data, { exact: true })).toBeVisible();
  578. await expect(miniPage.page.getByText(bottomNav.settings, { exact: true })).toBeVisible();
  579. console.debug('[导航] 底部导航栏可见');
  580. });
  581. test('应该可以通过底部导航返回首页', async ({ enterpriseMiniPage: miniPage }) => {
  582. // 1. 登录并导航到订单列表
  583. await miniPage.goto();
  584. await miniPage.login(TEST_USER_PHONE, TEST_USER_PASSWORD);
  585. await miniPage.expectLoginSuccess();
  586. await miniPage.page.goto(`http://localhost:8080${ORDER_LIST_SELECTORS.pageUrl}`);
  587. await miniPage.page.waitForTimeout(TIMEOUTS.LONG);
  588. // 2. 点击"首页"导航(使用 EnterpriseMiniPage 的 clickBottomNav 方法)
  589. await miniPage.clickBottomNav('home');
  590. await miniPage.page.waitForTimeout(TIMEOUTS.MEDIUM);
  591. // 3. 验证导航到首页
  592. const currentUrl = miniPage.page.url();
  593. expect(currentUrl).toContain('/mini/pages/yongren/dashboard');
  594. console.debug('[导航] 成功返回首页');
  595. });
  596. });
  597. });