assessment-order-flow.spec.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. /**
  2. * ================================================================
  3. * 场景:测评订单全流程 E2E 测试
  4. * ================================================================
  5. * 用户故事:作为家长,我希望为孩子购买专业测评服务,
  6. * 以便了解孩子的认知发展状况并获得成长建议。
  7. *
  8. * 流程步骤:
  9. * 1. 家长选择规划师和测评套餐,进入测评申请页面
  10. * 2. 家长填写孩子信息,提交测评申请
  11. * 3. 家长完成支付,订单状态变更为"已支付"
  12. * 4. 系统自动确认预约,预约状态变更为"待测评"
  13. * 5. 规划师确认预约,查看孩子的基本信息(快照)
  14. * 6. 规划师完成测评,录入认知评估结果
  15. * 7. 家长/孩子查看测评报告
  16. *
  17. * 关键里程碑:
  18. * - [Milestone-1] 订单创建成功,获得订单号
  19. * - [Milestone-2] 支付成功,预约自动创建
  20. * - [Milestone-3] 规划师确认预约
  21. * - [Milestone-4] 测评结果录入完成
  22. * - [Milestone-5] 家长可查询到孩子的最新报告
  23. * ================================================================
  24. *
  25. * 运行:npx playwright test tests/e2e/assessment-order-flow.spec.js
  26. */
  27. const { test, expect } = require('@playwright/test');
  28. test.describe('【场景流程】测评订单全流程', () => {
  29. // ===== 场景1:家长选购测评套餐 =====
  30. /**
  31. * 场景:家长选择规划师并购买测评套餐
  32. * 角色:家长
  33. * 触发条件:家长选择了具体的规划师和测评套餐
  34. */
  35. test('[场景1] 家长购买测评套餐并完成支付 - 期望全流程成功', async ({ page }) => {
  36. // ========== Given:家长进入测评申请页面 ==========
  37. await page.goto('/#/pages/assessment/apply');
  38. await page.waitForLoadState('networkidle');
  39. // 验证页面加载成功
  40. await expect(page.locator('.assessment-apply-page')).toBeVisible({ timeout: 10000 });
  41. // ========== Step 1:选择孩子 ==========
  42. const childSelector = page.locator('.child-picker');
  43. if (await childSelector.isVisible()) {
  44. await childSelector.click();
  45. await page.waitForSelector('.child-option', { timeout: 5000 });
  46. await page.click('.child-option:first-child');
  47. }
  48. // ========== Step 2:选择规划师(可选)==========
  49. const guideSelector = page.locator('.guide-picker');
  50. if (await guideSelector.isVisible()) {
  51. await guideSelector.click();
  52. await page.waitForSelector('.guide-option', { timeout: 5000 });
  53. await page.click('.guide-option:first-child');
  54. }
  55. // ========== Step 3:选择测评套餐 ==========
  56. await page.click('.package-option:first-child');
  57. // ========== When:提交申请 ==========
  58. await page.click('.submit-btn');
  59. // ========== Then:Milestone-1 - 订单创建成功 ========
  60. // 等待订单确认弹窗或跳转
  61. await page.waitForSelector('.order-confirm-modal, .order-success-tip', { timeout: 10000 });
  62. // 验证订单号生成(订单号应该在页面某处显示)
  63. const orderSuccessTip = page.locator('.order-success-tip, .order-no');
  64. if (await orderSuccessTip.isVisible()) {
  65. const orderText = await orderSuccessTip.textContent();
  66. expect(orderText).toMatch(/订单|ASR|成功/);
  67. }
  68. // ========== Step 4:点击去支付 ==========
  69. await page.click('.go-pay-btn');
  70. // ========== Then:Milestone-2 - 支付成功 ========
  71. // 选择支付方式
  72. const wechatPayOption = page.locator('.pay-method:has-text("微信支付")');
  73. if (await wechatPayOption.isVisible()) {
  74. await wechatPayOption.click();
  75. }
  76. // 确认支付
  77. await page.click('.confirm-pay-btn');
  78. // 等待支付成功提示
  79. await page.waitForSelector('.pay-success-tip, .payment-success', { timeout: 15000 });
  80. // 验证支付状态
  81. const successTip = page.locator('.pay-success-tip, .payment-success');
  82. expect(await successTip.isVisible()).toBeTruthy();
  83. });
  84. // ===== 场景2:自动分配规划师流程 =====
  85. /**
  86. * 场景:家长未指定规划师,系统自动分配家庭绑定的规划师
  87. * 角色:家长
  88. * 触发条件:家长未指定 guideId,但家庭已绑定规划师
  89. */
  90. test('[场景2] 未指定规划师时系统自动分配 - 期望使用家庭绑定的规划师', async ({ page }) => {
  91. // ========== Given:家庭已绑定规划师 ==========
  92. await page.goto('/#/pages/assessment/apply');
  93. await page.waitForLoadState('networkidle');
  94. // ========== Step 1:选择孩子 ==========
  95. const childSelector = page.locator('.child-picker');
  96. if (await childSelector.isVisible()) {
  97. await childSelector.click();
  98. await page.waitForSelector('.child-option', { timeout: 5000 });
  99. await page.click('.child-option:first-child');
  100. }
  101. // ========== Step 2:直接选择套餐(不选规划师)==========
  102. await page.click('.package-option:first-child');
  103. // ========== When:提交申请 ==========
  104. await page.click('.submit-btn');
  105. // ========== Then:系统自动使用家庭绑定的规划师 ========
  106. // 应该显示自动分配提示或规划师名称
  107. await page.waitForSelector('.auto-assign-tip, .guide-name', { timeout: 10000 });
  108. const guideName = page.locator('.guide-name, .guide-info');
  109. if (await guideName.isVisible()) {
  110. const nameText = await guideName.textContent();
  111. expect(nameText.length).toBeGreaterThan(0);
  112. }
  113. });
  114. // ===== 场景3:规划师录入测评结果 =====
  115. /**
  116. * 场景:规划师完成测评后,录入孩子的认知评估结果
  117. * 角色:成长规划师
  118. * 触发条件:预约已完成,规划师完成了一对一测评
  119. */
  120. test('[场景3] 规划师录入测评结果 - 期望结果保存并可查询', async ({ page }) => {
  121. // ========== Given:规划师进入测评结果录入页面 ==========
  122. await page.goto('/#/pages/guide/assessment/record');
  123. await page.waitForLoadState('networkidle');
  124. // ========== Step 1:选择要录入的预约 ==========
  125. await page.waitForSelector('.appointment-item', { timeout: 10000 });
  126. await page.click('.appointment-item:first-child');
  127. // ========== Step 2:填写测评结果 ==========
  128. // 输入各项分数
  129. const scoreInputs = page.locator('.score-input');
  130. const scoreCount = await scoreInputs.count();
  131. for (let i = 0; i < scoreCount; i++) {
  132. await scoreInputs.nth(i).fill(String(Math.floor(Math.random() * 20) + 80));
  133. }
  134. // 输入综合评语
  135. const reportTextarea = page.locator('.analysis-report textarea, .report-textarea');
  136. if (await reportTextarea.isVisible()) {
  137. await reportTextarea.fill('孩子整体认知发展良好,在注意力和逻辑思维方面表现突出...');
  138. }
  139. // ========== When:提交测评结果 ==========
  140. await page.click('.submit-result-btn');
  141. // ========== Then:Milestone-4 - 测评结果保存成功 ========
  142. await page.waitForSelector('.submit-success-tip, .result-saved', { timeout: 10000 });
  143. const successTip = page.locator('.submit-success-tip, .result-saved');
  144. expect(await successTip.isVisible()).toBeTruthy();
  145. });
  146. // ===== 场景4:家长查询孩子测评报告 =====
  147. /**
  148. * 场景:家长为孩子购买测评后,查看孩子的最新认知评估报告
  149. * 角色:家长
  150. * 触发条件:规划师已完成测评并录入结果
  151. */
  152. test('[场景4] 家长查询孩子最新报告 - 期望返回完整报告内容', async ({ page }) => {
  153. // ========== Given:进入测评报告页面 ==========
  154. await page.goto('/#/pages/assessment/results');
  155. await page.waitForLoadState('networkidle');
  156. // ========== Step 1:选择孩子 ==========
  157. const childSelector = page.locator('.child-picker');
  158. if (await childSelector.isVisible()) {
  159. await childSelector.click();
  160. await page.waitForSelector('.child-option', { timeout: 5000 });
  161. await page.click('.child-option:first-child');
  162. }
  163. // ========== When:查看报告 ==========
  164. await page.click('.view-report-btn');
  165. // ========== Then:Milestone-5 - 返回完整报告内容 ========
  166. await page.waitForSelector('.report-detail, .result-card', { timeout: 10000 });
  167. // 验证报告包含必要内容
  168. const reportDetail = page.locator('.report-detail, .result-content');
  169. expect(await reportDetail.isVisible()).toBeTruthy();
  170. // 验证分数显示
  171. const scoreDisplay = page.locator('.overall-score, .score-value');
  172. if (await scoreDisplay.isVisible()) {
  173. const scoreText = await scoreDisplay.textContent();
  174. expect(scoreText).toMatch(/\d+/);
  175. }
  176. });
  177. // ===== 场景5:取消未支付订单 =====
  178. /**
  179. * 场景:家长创建订单后决定取消,选择关闭交易
  180. * 角色:家长
  181. * 触发条件:订单状态为"待支付"
  182. */
  183. test('[场景5] 家长取消未支付订单 - 期望订单关闭成功', async ({ page }) => {
  184. // ========== Given:进入我的订单页面 ==========
  185. await page.goto('/#/pages/assessment/orders');
  186. await page.waitForLoadState('networkidle');
  187. // ========== Step 1:找到待支付订单 ==========
  188. await page.waitForSelector('.order-item', { timeout: 10000 });
  189. const pendingOrder = page.locator('.order-item:has-text("待支付"), .order-item:has-text("待付款")').first();
  190. await pendingOrder.click();
  191. // ========== When:点击取消订单 ==========
  192. await page.click('.cancel-order-btn');
  193. // 确认取消
  194. const confirmBtn = page.locator('.confirm-cancel-btn, .van-dialog__confirm');
  195. if (await confirmBtn.isVisible()) {
  196. await confirmBtn.click();
  197. }
  198. // ========== Then:订单成功取消 ========
  199. await page.waitForSelector('.cancel-success-tip, .order-closed', { timeout: 10000 });
  200. // 订单状态应变为"已取消"
  201. const orderStatus = page.locator('.order-status');
  202. if (await orderStatus.isVisible()) {
  203. const statusText = await orderStatus.textContent();
  204. expect(statusText).toMatch(/已取消|已关闭/);
  205. }
  206. });
  207. // ===== 场景6:已支付订单退款 =====
  208. /**
  209. * 场景:家长支付后因故需要退款
  210. * 角色:家长(发起退款)→ 系统处理
  211. * 触发条件:订单状态为"已支付"
  212. */
  213. test('[场景6] 已支付订单申请退款 - 期望退款成功', async ({ page }) => {
  214. // ========== Given:进入订单详情 ==========
  215. await page.goto('/#/pages/assessment/order-detail?orderNo=ASR20260628001');
  216. await page.waitForLoadState('networkidle');
  217. // ========== When:申请退款 ==========
  218. await page.click('.apply-refund-btn');
  219. // 填写退款原因
  220. const reasonInput = page.locator('.refund-reason textarea, .reason-input');
  221. if (await reasonInput.isVisible()) {
  222. await reasonInput.fill('因计划变更,需要退款');
  223. }
  224. // 确认提交
  225. await page.click('.submit-refund-btn');
  226. // ========== Then:退款申请提交成功 ========
  227. await page.waitForSelector('.refund-submitted, .refund-success', { timeout: 10000 });
  228. const refundTip = page.locator('.refund-submitted, .refund-success');
  229. expect(await refundTip.isVisible()).toBeTruthy();
  230. });
  231. // ===== 场景7:完整测评流程(端到端)=====
  232. test('[场景7] 完整测评生命周期 - 期望全流程成功', async ({ page }) => {
  233. // ========== Step 1:申请测评 ==========
  234. await page.goto('/#/pages/assessment/apply');
  235. await page.waitForLoadState('networkidle');
  236. // 选择孩子
  237. const childSelector = page.locator('.child-picker');
  238. if (await childSelector.isVisible()) {
  239. await childSelector.click();
  240. await page.waitForSelector('.child-option', { timeout: 5000 });
  241. await page.click('.child-option:first-child');
  242. }
  243. // 选择套餐并提交
  244. await page.click('.package-option:first-child');
  245. await page.click('.submit-btn');
  246. // 等待订单创建
  247. await page.waitForSelector('.order-no, .go-pay-btn', { timeout: 10000 });
  248. // ========== Step 2:支付订单 ==========
  249. const goPayBtn = page.locator('.go-pay-btn');
  250. if (await goPayBtn.isVisible()) {
  251. await goPayBtn.click();
  252. // 选择微信支付并确认
  253. const wechatPay = page.locator('.pay-method:has-text("微信")');
  254. if (await wechatPay.isVisible()) {
  255. await wechatPay.click();
  256. }
  257. await page.click('.confirm-pay-btn');
  258. await page.waitForSelector('.pay-success-tip', { timeout: 15000 });
  259. }
  260. // ========== Step 3:规划师确认预约 ==========
  261. await page.goto('/#/pages/guide/assessment/list');
  262. await page.waitForLoadState('networkidle');
  263. const appointmentItem = page.locator('.appointment-item').first();
  264. if (await appointmentItem.isVisible()) {
  265. await appointmentItem.click();
  266. await page.click('.confirm-appointment-btn');
  267. }
  268. // ========== Step 4:规划师录入结果 ==========
  269. await page.goto('/#/pages/guide/assessment/record');
  270. await page.waitForLoadState('networkidle');
  271. const pendingRecord = page.locator('.pending-record-item').first();
  272. if (await pendingRecord.isVisible()) {
  273. await pendingRecord.click();
  274. // 填写分数
  275. const scoreInputs = page.locator('.score-input');
  276. for (let i = 0; i < await scoreInputs.count(); i++) {
  277. await scoreInputs.nth(i).fill('85');
  278. }
  279. await page.click('.submit-result-btn');
  280. await page.waitForSelector('.result-saved', { timeout: 10000 });
  281. }
  282. // ========== Step 5:家长查看报告 ==========
  283. await page.goto('/#/pages/assessment/results');
  284. await page.waitForLoadState('networkidle');
  285. // 选择孩子
  286. const childPicker = page.locator('.child-picker');
  287. if (await childPicker.isVisible()) {
  288. await childPicker.click();
  289. await page.waitForSelector('.child-option', { timeout: 5000 });
  290. await page.click('.child-option:first-child');
  291. }
  292. // 验证报告存在
  293. await page.waitForSelector('.report-card, .result-item', { timeout: 10000 });
  294. });
  295. });