|
@@ -0,0 +1,472 @@
|
|
|
|
|
+/**
|
|
|
|
|
+ * ================================================================
|
|
|
|
|
+ * 场景:心愿兑换审批全流程 E2E 测试
|
|
|
|
|
+ * ================================================================
|
|
|
|
|
+ * 用户故事:作为孩子,我希望创建心愿并通过积累积分兑换,
|
|
|
|
|
+ * 以获得家长的认可和实际的奖励物品。
|
|
|
|
|
+ *
|
|
|
|
|
+ * 流程步骤:
|
|
|
|
|
+ * 1. 孩子创建心愿(如"想要一套科学实验套装")
|
|
|
|
|
+ * 2. 家长查看心愿并设定所需积分(如 500 积分)
|
|
|
|
|
+ * 3. 孩子通过完成任务积累积分后,申请兑换心愿
|
|
|
|
|
+ * 4. 家长审批通过,系统自动扣除积分
|
|
|
|
|
+ * 5. 家长购买物品后标记"已购买"
|
|
|
|
|
+ * 6. 孩子确认收货,心愿流程完成
|
|
|
|
|
+ *
|
|
|
|
|
+ * 关键里程碑:
|
|
|
|
|
+ * - [Milestone-1] 心愿创建成功,获得心愿ID
|
|
|
|
|
+ * - [Milestone-2] 家长定价成功,心愿状态变更为"已定价"
|
|
|
|
|
+ * - [Milestone-3] 兑换申请提交,状态变更为"兑换中"
|
|
|
|
|
+ * - [Milestone-4] 家长审批通过,积分立即扣减
|
|
|
|
|
+ * - [Milestone-5] 标记已购买,等待孩子确认
|
|
|
|
|
+ * - [Milestone-6] 孩子确认收货,心愿完成
|
|
|
|
|
+ * ================================================================
|
|
|
|
|
+ *
|
|
|
|
|
+ * 运行:npx playwright test tests/e2e/wish-exchange-flow.spec.js
|
|
|
|
|
+ */
|
|
|
|
|
+
|
|
|
|
|
+const { test, expect } = require('@playwright/test');
|
|
|
|
|
+
|
|
|
|
|
+test.describe('【场景流程】心愿兑换审批全流程', () => {
|
|
|
|
|
+
|
|
|
|
|
+ // ===== 场景1:孩子创建心愿 =====
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 场景:孩子创建一个新的心愿
|
|
|
|
|
+ * 角色:孩子
|
|
|
|
|
+ * 触发条件:孩子点击"创建心愿"并填写表单
|
|
|
|
|
+ */
|
|
|
|
|
+ test('[场景1] 孩子创建心愿 - 期望心愿创建成功', async ({ page }) => {
|
|
|
|
|
+ // ========== Given:进入创建心愿页面 ==========
|
|
|
|
|
+ await page.goto('/#/pages/wishes/create');
|
|
|
|
|
+ await page.waitForLoadState('networkidle');
|
|
|
|
|
+
|
|
|
|
|
+ // ========== When:填写心愿信息 ==========
|
|
|
|
|
+ // 输入心愿标题
|
|
|
|
|
+ const titleInput = page.locator('input[placeholder*="心愿"], .wish-title-input, input[name="title"]');
|
|
|
|
|
+ if (await titleInput.isVisible()) {
|
|
|
|
|
+ await titleInput.fill('科学实验套装');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 输入心愿描述
|
|
|
|
|
+ const descInput = page.locator('textarea[placeholder*="描述"], .wish-desc-input');
|
|
|
|
|
+ if (await descInput.isVisible()) {
|
|
|
|
|
+ await descInput.fill('包含50个实验的科学实验套装,寓教于乐');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 输入预估价格
|
|
|
|
|
+ const priceInput = page.locator('input[placeholder*="价格"], .wish-price-input, input[name="estimatedPrice"]');
|
|
|
|
|
+ if (await priceInput.isVisible()) {
|
|
|
|
|
+ await priceInput.fill('299');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ========== Then:提交创建 ==========
|
|
|
|
|
+ await page.click('.submit-btn, .create-btn');
|
|
|
|
|
+
|
|
|
|
|
+ // ========== Then:Milestone-1 - 心愿创建成功 ========
|
|
|
|
|
+ await page.waitForSelector('.success-tip, .wish-created, .create-success', { timeout: 10000 });
|
|
|
|
|
+
|
|
|
|
|
+ // 验证心愿创建成功
|
|
|
|
|
+ const successTip = page.locator('.success-tip, .wish-created, .create-success');
|
|
|
|
|
+ expect(await successTip.isVisible()).toBeTruthy();
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // ===== 场景2:家长定价 =====
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 场景:家长为孩子的心愿设定所需积分
|
|
|
|
|
+ * 角色:家长
|
|
|
|
|
+ * 触发条件:家长打开心愿详情,决定设定多少积分可兑换
|
|
|
|
|
+ */
|
|
|
|
|
+ test('[场景2] 家长设定心愿积分 - 期望积分设定成功且状态更新', async ({ page }) => {
|
|
|
|
|
+ // ========== Given:进入待定价心愿列表 ==========
|
|
|
|
|
+ await page.goto('/#/pages/wishes/pending');
|
|
|
|
|
+ await page.waitForLoadState('networkidle');
|
|
|
|
|
+
|
|
|
|
|
+ // ========== Step 1:找到待定价心愿 ==========
|
|
|
|
|
+ await page.waitForSelector('.wish-item', { timeout: 10000 });
|
|
|
|
|
+ const pendingWish = page.locator('.wish-item:has-text("待定价"), .wish-item:has-text("待设置")').first();
|
|
|
|
|
+ await pendingWish.click();
|
|
|
|
|
+
|
|
|
|
|
+ // ========== Step 2:设定积分值 ==========
|
|
|
|
|
+ await page.waitForSelector('.price-input, .points-input', { timeout: 5000 });
|
|
|
|
|
+ const priceInput = page.locator('.price-input, .points-input, input[name="pointsRequired"]');
|
|
|
|
|
+ await priceInput.fill('500');
|
|
|
|
|
+
|
|
|
|
|
+ // ========== When:提交定价 ==========
|
|
|
|
|
+ await page.click('.set-price-btn, .confirm-price-btn, .submit-btn');
|
|
|
|
|
+
|
|
|
|
|
+ // ========== Then:Milestone-2 - 定价成功 ========
|
|
|
|
|
+ await page.waitForSelector('.success-tip, .price-set, .set-success', { timeout: 10000 });
|
|
|
|
|
+
|
|
|
|
|
+ // 验证状态变更
|
|
|
|
|
+ const wishStatus = page.locator('.wish-status, .status-tag');
|
|
|
|
|
+ if (await wishStatus.isVisible()) {
|
|
|
|
|
+ const statusText = await wishStatus.textContent();
|
|
|
|
|
+ expect(statusText).toMatch(/已定价|待兑换/);
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 场景:家长设定的积分值为负数或零
|
|
|
|
|
+ * 角色:家长
|
|
|
|
|
+ * 触发条件:表单校验未通过
|
|
|
|
|
+ */
|
|
|
|
|
+ test('[场景2b] 家长设定无效积分值 - 期望返回错误提示', async ({ page }) => {
|
|
|
|
|
+ // ========== Given:进入心愿编辑页面 ==========
|
|
|
|
|
+ await page.goto('/#/pages/wishes/edit/1');
|
|
|
|
|
+ await page.waitForLoadState('networkidle');
|
|
|
|
|
+
|
|
|
|
|
+ // ========== When:设定无效积分值 ==========
|
|
|
|
|
+ const priceInput = page.locator('.price-input, .points-input, input[name="pointsRequired"]');
|
|
|
|
|
+ if (await priceInput.isVisible()) {
|
|
|
|
|
+ await priceInput.fill('0');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ await page.click('.submit-btn');
|
|
|
|
|
+
|
|
|
|
|
+ // ========== Then:返回错误提示 ========
|
|
|
|
|
+ await page.waitForSelector('.error-tip, .van-field__error, .form-error', { timeout: 5000 });
|
|
|
|
|
+
|
|
|
|
|
+ const errorTip = page.locator('.error-tip, .van-field__error, .form-error');
|
|
|
|
|
+ expect(await errorTip.isVisible()).toBeTruthy();
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // ===== 场景3:孩子申请兑换 =====
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 场景:孩子积累足够积分后,申请兑换心愿
|
|
|
|
|
+ * 角色:孩子
|
|
|
|
|
+ * 触发条件:孩子点击心愿的"申请兑换"按钮
|
|
|
|
|
+ */
|
|
|
|
|
+ test('[场景3] 孩子申请兑换心愿 - 期望兑换申请提交成功', async ({ page }) => {
|
|
|
|
|
+ // ========== Given:进入我的心愿列表 ==========
|
|
|
|
|
+ await page.goto('/#/pages/wishes/my');
|
|
|
|
|
+ await page.waitForLoadState('networkidle');
|
|
|
|
|
+
|
|
|
|
|
+ // ========== Step 1:找到已定价心愿 ==========
|
|
|
|
|
+ await page.waitForSelector('.wish-item', { timeout: 10000 });
|
|
|
|
|
+ const pricedWish = page.locator('.wish-item:has-text("已定价"), .wish-item:has-text("可兑换")').first();
|
|
|
|
|
+ await pricedWish.click();
|
|
|
|
|
+
|
|
|
|
|
+ // ========== Step 2:点击兑换按钮 ==========
|
|
|
|
|
+ await page.waitForSelector('.exchange-btn, .apply-exchange-btn', { timeout: 5000 });
|
|
|
|
|
+ await page.click('.exchange-btn, .apply-exchange-btn');
|
|
|
|
|
+
|
|
|
|
|
+ // ========== Then:Milestone-3 - 兑换申请提交成功 ========
|
|
|
|
|
+ await page.waitForSelector('.success-tip, .exchange-applied, .apply-success', { timeout: 10000 });
|
|
|
|
|
+
|
|
|
|
|
+ const successTip = page.locator('.success-tip, .exchange-applied, .apply-success');
|
|
|
|
|
+ expect(await successTip.isVisible()).toBeTruthy();
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 场景:孩子积分不足时尝试兑换
|
|
|
|
|
+ * 角色:孩子
|
|
|
|
|
+ * 触发条件:孩子积分不足以兑换该心愿
|
|
|
|
|
+ */
|
|
|
|
|
+ test('[场景3b] 积分不足时申请兑换 - 期望返回错误提示', async ({ page }) => {
|
|
|
|
|
+ // ========== Given:进入心愿详情 ==========
|
|
|
|
|
+ await page.goto('/#/pages/wishes/detail/1');
|
|
|
|
|
+ await page.waitForLoadState('networkidle');
|
|
|
|
|
+
|
|
|
|
|
+ // ========== When:点击兑换 ==========
|
|
|
|
|
+ const exchangeBtn = page.locator('.exchange-btn, .apply-exchange-btn');
|
|
|
|
|
+ if (await exchangeBtn.isVisible()) {
|
|
|
|
|
+ await exchangeBtn.click();
|
|
|
|
|
+
|
|
|
|
|
+ // ========== Then:返回积分不足提示 ========
|
|
|
|
|
+ await page.waitForSelector('.error-tip, .insufficient-points, .points-error', { timeout: 5000 });
|
|
|
|
|
+
|
|
|
|
|
+ const errorTip = page.locator('.error-tip, .insufficient-points, .points-error');
|
|
|
|
|
+ expect(await errorTip.isVisible()).toBeTruthy();
|
|
|
|
|
+
|
|
|
|
|
+ // 验证错误信息包含积分相关字样
|
|
|
|
|
+ const errorText = await errorTip.textContent();
|
|
|
|
|
+ expect(errorText).toMatch(/积分|不足/);
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // ===== 场景4:家长审批兑换 =====
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 场景:家长审批通过孩子的兑换申请,积分立即扣除
|
|
|
|
|
+ * 角色:家长
|
|
|
|
|
+ * 触发条件:家长查看兑换申请并点击"批准"
|
|
|
|
|
+ */
|
|
|
|
|
+ test('[场景4] 家长审批通过兑换 - 期望审批成功且积分扣除', async ({ page }) => {
|
|
|
|
|
+ // ========== Given:进入待审批兑换列表 ==========
|
|
|
|
|
+ await page.goto('/#/pages/wishes/pending-approval');
|
|
|
|
|
+ await page.waitForLoadState('networkidle');
|
|
|
|
|
+
|
|
|
|
|
+ // ========== Step 1:找到待审批的兑换申请 ==========
|
|
|
|
|
+ await page.waitForSelector('.exchange-item, .approval-item', { timeout: 10000 });
|
|
|
|
|
+ const pendingApproval = page.locator('.exchange-item:has-text("申请中"), .approval-item:has-text("待审批")').first();
|
|
|
|
|
+ await pendingApproval.click();
|
|
|
|
|
+
|
|
|
|
|
+ // ========== Step 2:查看积分信息 ==========
|
|
|
|
|
+ await page.waitForSelector('.points-required, .wish-points', { timeout: 5000 });
|
|
|
|
|
+
|
|
|
|
|
+ // ========== When:点击批准 ==========
|
|
|
|
|
+ await page.click('.approve-btn, .confirm-btn, .approve-exchange-btn');
|
|
|
|
|
+
|
|
|
|
|
+ // ========== Then:Milestone-4 - 审批通过 + 积分扣减 ========
|
|
|
|
|
+ await page.waitForSelector('.success-tip, .approved, .approve-success', { timeout: 10000 });
|
|
|
|
|
+
|
|
|
|
|
+ // 验证积分已扣减(如果有显示)
|
|
|
|
|
+ const remainingPoints = page.locator('.remaining-points, .current-points');
|
|
|
|
|
+ if (await remainingPoints.isVisible()) {
|
|
|
|
|
+ const pointsText = await remainingPoints.textContent();
|
|
|
|
|
+ expect(pointsText).toMatch(/\d+/);
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 场景:家长拒绝孩子的兑换申请
|
|
|
|
|
+ * 角色:家长
|
|
|
|
|
+ * 触发条件:家长认为该心愿不合适,点击"拒绝"
|
|
|
|
|
+ */
|
|
|
|
|
+ test('[场景4b] 家长拒绝兑换申请 - 期望心愿状态回退', async ({ page }) => {
|
|
|
|
|
+ // ========== Given:进入待审批兑换详情 ==========
|
|
|
|
|
+ await page.goto('/#/pages/wishes/approval/1');
|
|
|
|
|
+ await page.waitForLoadState('networkidle');
|
|
|
|
|
+
|
|
|
|
|
+ // ========== When:点击拒绝 ==========
|
|
|
|
|
+ await page.click('.reject-btn, .reject-exchange-btn');
|
|
|
|
|
+
|
|
|
|
|
+ // 填写拒绝原因
|
|
|
|
|
+ const reasonInput = page.locator('textarea[placeholder*="原因"], .reject-reason-input');
|
|
|
|
|
+ if (await reasonInput.isVisible()) {
|
|
|
|
|
+ await reasonInput.fill('本月预算已用完,下个月再兑换好吗?');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 确认拒绝
|
|
|
|
|
+ await page.click('.confirm-reject-btn, .submit-btn');
|
|
|
|
|
+
|
|
|
|
|
+ // ========== Then:拒绝成功,心愿状态回退 ========
|
|
|
|
|
+ await page.waitForSelector('.rejected, .reject-success', { timeout: 10000 });
|
|
|
|
|
+
|
|
|
|
|
+ // 验证心愿状态回退到"已定价"
|
|
|
|
|
+ const wishStatus = page.locator('.wish-status, .status-tag');
|
|
|
|
|
+ if (await wishStatus.isVisible()) {
|
|
|
|
|
+ const statusText = await wishStatus.textContent();
|
|
|
|
|
+ expect(statusText).toMatch(/已定价|待兑换/);
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // ===== 场景5:标记已购买 =====
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 场景:家长购买物品后标记心愿为"已购买"
|
|
|
|
|
+ * 角色:家长
|
|
|
|
|
+ * 触发条件:家长完成购买操作
|
|
|
|
|
+ */
|
|
|
|
|
+ test('[场景5] 家长标记心愿已购买 - 期望状态变更为待收货', async ({ page }) => {
|
|
|
|
|
+ // ========== Given:进入已批准兑换列表 ==========
|
|
|
|
|
+ await page.goto('/#/pages/wishes/approved');
|
|
|
|
|
+ await page.waitForLoadState('networkidle');
|
|
|
|
|
+
|
|
|
|
|
+ // ========== Step 1:找到已批准的兑换 ==========
|
|
|
|
|
+ await page.waitForSelector('.exchange-item, .approved-item', { timeout: 10000 });
|
|
|
|
|
+ const approvedItem = page.locator('.exchange-item:has-text("已批准"), .approved-item').first();
|
|
|
|
|
+ await approvedItem.click();
|
|
|
|
|
+
|
|
|
|
|
+ // ========== When:点击"已购买" ==========
|
|
|
|
|
+ await page.click('.mark-purchased-btn, .fulfill-btn');
|
|
|
|
|
+
|
|
|
|
|
+ // ========== Then:Milestone-5 - 标记成功 ========
|
|
|
|
|
+ await page.waitForSelector('.success-tip, .purchased, .fulfill-success', { timeout: 10000 });
|
|
|
|
|
+
|
|
|
|
|
+ // 验证状态变更为"待收货"
|
|
|
|
|
+ const wishStatus = page.locator('.wish-status, .status-tag');
|
|
|
|
|
+ if (await wishStatus.isVisible()) {
|
|
|
|
|
+ const statusText = await wishStatus.textContent();
|
|
|
|
|
+ expect(statusText).toMatch(/待收货|已购买/);
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // ===== 场景6:孩子确认收货 =====
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 场景:孩子收到物品后确认收货,心愿流程完成
|
|
|
|
|
+ * 角色:孩子
|
|
|
|
|
+ * 触发条件:孩子收到实物并确认无误
|
|
|
|
|
+ */
|
|
|
|
|
+ test('[场景6] 孩子确认收货 - 期望心愿流程完成', async ({ page }) => {
|
|
|
|
|
+ // ========== Given:进入待确认收货列表 ==========
|
|
|
|
|
+ await page.goto('/#/pages/wishes/to-confirm');
|
|
|
|
|
+ await page.waitForLoadState('networkidle');
|
|
|
|
|
+
|
|
|
|
|
+ // ========== Step 1:找到待确认的心愿 ==========
|
|
|
|
|
+ await page.waitForSelector('.wish-item', { timeout: 10000 });
|
|
|
|
|
+ const toConfirm = page.locator('.wish-item:has-text("待收货"), .wish-item:has-text("已购买")').first();
|
|
|
|
|
+ await toConfirm.click();
|
|
|
|
|
+
|
|
|
|
|
+ // ========== When:点击"确认收货" ==========
|
|
|
|
|
+ await page.click('.confirm-receive-btn, .confirm-btn');
|
|
|
|
|
+
|
|
|
|
|
+ // ========== Then:Milestone-6 - 心愿完成 ========
|
|
|
|
|
+ await page.waitForSelector('.success-tip, .completed, .confirm-success', { timeout: 10000 });
|
|
|
|
|
+
|
|
|
|
|
+ // 验证状态变更为"已完成"
|
|
|
|
|
+ const wishStatus = page.locator('.wish-status, .status-tag');
|
|
|
|
|
+ if (await wishStatus.isVisible()) {
|
|
|
|
|
+ const statusText = await wishStatus.textContent();
|
|
|
|
|
+ expect(statusText).toMatch(/已完成|已收货/);
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // ===== 场景7:完整心愿流程(端到端)=====
|
|
|
|
|
+
|
|
|
|
|
+ test('[场景7] 完整心愿生命周期 - 期望全流程成功', async ({ page }) => {
|
|
|
|
|
+ // ========== Step 1:孩子创建心愿 ==========
|
|
|
|
|
+ await page.goto('/#/pages/wishes/create');
|
|
|
|
|
+ await page.waitForLoadState('networkidle');
|
|
|
|
|
+
|
|
|
|
|
+ const titleInput = page.locator('input[name="title"], .wish-title-input');
|
|
|
|
|
+ if (await titleInput.isVisible()) {
|
|
|
|
|
+ await titleInput.fill('科学杂志订阅_' + Date.now());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const descInput = page.locator('textarea[name="description"], .wish-desc-input');
|
|
|
|
|
+ if (await descInput.isVisible()) {
|
|
|
|
|
+ await descInput.fill('儿童科学爱好者订阅一年');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ await page.click('.submit-btn');
|
|
|
|
|
+ await page.waitForSelector('.success-tip, .wish-created', { timeout: 10000 });
|
|
|
|
|
+
|
|
|
|
|
+ // ========== Step 2:家长定价 ==========
|
|
|
|
|
+ await page.goto('/#/pages/wishes/pending');
|
|
|
|
|
+ await page.waitForLoadState('networkidle');
|
|
|
|
|
+ await page.waitForSelector('.wish-item', { timeout: 10000 });
|
|
|
|
|
+
|
|
|
|
|
+ const wishItem = page.locator('.wish-item').first();
|
|
|
|
|
+ const editBtn = wishItem.locator('.edit-btn, .price-btn');
|
|
|
|
|
+ if (await editBtn.isVisible()) {
|
|
|
|
|
+ await editBtn.click();
|
|
|
|
|
+ await page.waitForSelector('.price-input', { timeout: 5000 });
|
|
|
|
|
+ const priceInput = page.locator('.price-input, input[name="pointsRequired"]');
|
|
|
|
|
+ await priceInput.fill('100');
|
|
|
|
|
+ await page.click('.set-price-btn');
|
|
|
|
|
+ await page.waitForSelector('.success-tip', { timeout: 10000 });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ========== Step 3:孩子申请兑换 ==========
|
|
|
|
|
+ await page.goto('/#/pages/wishes/my');
|
|
|
|
|
+ await page.waitForLoadState('networkidle');
|
|
|
|
|
+ await page.waitForSelector('.wish-item', { timeout: 10000 });
|
|
|
|
|
+
|
|
|
|
|
+ const exchangeBtn = page.locator('.exchange-btn').first();
|
|
|
|
|
+ if (await exchangeBtn.isVisible()) {
|
|
|
|
|
+ await exchangeBtn.click();
|
|
|
|
|
+ await page.waitForSelector('.success-tip, .exchange-applied', { timeout: 10000 });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ========== Step 4:家长审批通过 ==========
|
|
|
|
|
+ await page.goto('/#/pages/wishes/pending-approval');
|
|
|
|
|
+ await page.waitForLoadState('networkidle');
|
|
|
|
|
+
|
|
|
|
|
+ const approvalItem = page.locator('.exchange-item, .approval-item').first();
|
|
|
|
|
+ if (await approvalItem.isVisible()) {
|
|
|
|
|
+ await approvalItem.click();
|
|
|
|
|
+ await page.waitForSelector('.approve-btn', { timeout: 5000 });
|
|
|
|
|
+ await page.click('.approve-btn');
|
|
|
|
|
+ await page.waitForSelector('.success-tip, .approved', { timeout: 10000 });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ========== Step 5:家长标记已购买 ==========
|
|
|
|
|
+ await page.goto('/#/pages/wishes/approved');
|
|
|
|
|
+ await page.waitForLoadState('networkidle');
|
|
|
|
|
+
|
|
|
|
|
+ const purchasedBtn = page.locator('.mark-purchased-btn, .fulfill-btn').first();
|
|
|
|
|
+ if (await purchasedBtn.isVisible()) {
|
|
|
|
|
+ await purchasedBtn.click();
|
|
|
|
|
+ await page.waitForSelector('.success-tip, .purchased', { timeout: 10000 });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ========== Step 6:孩子确认收货 ==========
|
|
|
|
|
+ await page.goto('/#/pages/wishes/to-confirm');
|
|
|
|
|
+ await page.waitForLoadState('networkidle');
|
|
|
|
|
+
|
|
|
|
|
+ const confirmBtn = page.locator('.confirm-receive-btn').first();
|
|
|
|
|
+ if (await confirmBtn.isVisible()) {
|
|
|
|
|
+ await confirmBtn.click();
|
|
|
|
|
+ await page.waitForSelector('.success-tip, .completed', { timeout: 10000 });
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 验证最终状态
|
|
|
|
|
+ const finalStatus = page.locator('.wish-status');
|
|
|
|
|
+ if (await finalStatus.isVisible()) {
|
|
|
|
|
+ const statusText = await finalStatus.textContent();
|
|
|
|
|
+ expect(statusText).toMatch(/已完成/);
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // ===== 场景8:家长拒绝心愿 =====
|
|
|
|
|
+
|
|
|
|
|
+ test('[场景8] 家长直接拒绝心愿 - 期望心愿被关闭', async ({ page }) => {
|
|
|
|
|
+ // ========== Given:进入待处理心愿 ==========
|
|
|
|
|
+ await page.goto('/#/pages/wishes/pending');
|
|
|
|
|
+ await page.waitForLoadState('networkidle');
|
|
|
|
|
+
|
|
|
|
|
+ // ========== Step 1:选择心愿 ==========
|
|
|
|
|
+ await page.waitForSelector('.wish-item', { timeout: 10000 });
|
|
|
|
|
+ const wishItem = page.locator('.wish-item').first();
|
|
|
|
|
+ await wishItem.click();
|
|
|
|
|
+
|
|
|
|
|
+ // ========== When:点击拒绝 ==========
|
|
|
|
|
+ await page.waitForSelector('.reject-btn, .refuse-btn', { timeout: 5000 });
|
|
|
|
|
+ await page.click('.reject-btn');
|
|
|
|
|
+
|
|
|
|
|
+ // 填写原因
|
|
|
|
|
+ const reasonInput = page.locator('textarea[name="reason"], .reject-reason-input');
|
|
|
|
|
+ if (await reasonInput.isVisible()) {
|
|
|
|
|
+ await reasonInput.fill('这套书家里已经有了,换个其他的吧');
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ await page.click('.confirm-reject-btn');
|
|
|
|
|
+
|
|
|
|
|
+ // ========== Then:心愿被关闭 ========
|
|
|
|
|
+ await page.waitForSelector('.rejected, .reject-success', { timeout: 10000 });
|
|
|
|
|
+
|
|
|
|
|
+ const wishStatus = page.locator('.wish-status, .status-tag');
|
|
|
|
|
+ if (await wishStatus.isVisible()) {
|
|
|
|
|
+ const statusText = await wishStatus.textContent();
|
|
|
|
|
+ expect(statusText).toMatch(/已拒绝|已关闭/);
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ // ===== 场景9:孩子取消心愿 =====
|
|
|
|
|
+
|
|
|
|
|
+ test('[场景9] 孩子取消心愿 - 期望心愿被取消', async ({ page }) => {
|
|
|
|
|
+ // ========== Given:进入我的心愿 ==========
|
|
|
|
|
+ await page.goto('/#/pages/wishes/my');
|
|
|
|
|
+ await page.waitForLoadState('networkidle');
|
|
|
|
|
+
|
|
|
|
|
+ // ========== Step 1:选择心愿 ==========
|
|
|
|
|
+ await page.waitForSelector('.wish-item', { timeout: 10000 });
|
|
|
|
|
+ const wishItem = page.locator('.wish-item').first();
|
|
|
|
|
+
|
|
|
|
|
+ // 点击取消按钮
|
|
|
|
|
+ const cancelBtn = wishItem.locator('.cancel-btn, .cancel-wish-btn');
|
|
|
|
|
+ if (await cancelBtn.isVisible()) {
|
|
|
|
|
+ await cancelBtn.click();
|
|
|
|
|
+
|
|
|
|
|
+ // 确认取消
|
|
|
|
|
+ await page.waitForSelector('.confirm-dialog, .van-dialog', { timeout: 5000 });
|
|
|
|
|
+ await page.click('.confirm-dialog .van-button--primary, .confirm-cancel-btn');
|
|
|
|
|
+
|
|
|
|
|
+ // ========== Then:心愿被取消 ========
|
|
|
|
|
+ await page.waitForTimeout(1000);
|
|
|
|
|
+
|
|
|
|
|
+ // 验证心愿不在列表中或状态变更
|
|
|
|
|
+ const statusTag = wishItem.locator('.status-tag');
|
|
|
|
|
+ if (await statusTag.isVisible()) {
|
|
|
|
|
+ const statusText = await statusTag.textContent();
|
|
|
|
|
+ expect(statusText).toMatch(/已取消|已关闭/);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+});
|