/** * ================================================================ * 场景:商品购买支付全流程 E2E 测试 * ================================================================ * 用户故事:作为家长,我希望在商城购买孩子的用品, * 完成支付后等待商品配送到家。 * * 流程步骤: * 1. 家长浏览商品列表,选择商品 * 2. 家长创建商品订单 * 3. 家长选择支付方式并完成支付 * 4. 服务商发货,填写物流信息 * 5. 家长确认收货,订单完成 * 6. 如有问题,家长申请退款 * * 关键里程碑: * - [Milestone-1] 订单创建成功,获得订单号 * - [Milestone-2] 支付成功,订单状态变更为"已支付" * - [Milestone-3] 服务商发货,订单状态变更为"已发货" * - [Milestone-4] 家长确认收货,订单完成 * - [Milestone-5] 退款申请提交成功 * ================================================================ * * 运行:npx playwright test tests/e2e/product-purchase.spec.js */ const { test, expect } = require('@playwright/test'); test.describe('【场景流程】商品购买支付全流程', () => { // ===== 场景1:创建商品订单 ===== /** * 场景:家长选购商品后创建订单 * 角色:家长 * 触发条件:点击"立即购买"或"加入购物车结算" */ test('[场景1] 创建商品订单 - 期望订单创建成功', async ({ page }) => { // ========== Given:进入商品详情页 ========== await page.goto('/#/pages/shop/product/1'); await page.waitForLoadState('networkidle'); // ========== Step 1:选择数量 ========== const quantityInput = page.locator('.quantity-input, input[name="quantity"]'); if (await quantityInput.isVisible()) { await quantityInput.fill('1'); } else { // 尝试点击增加按钮 const increaseBtn = page.locator('.increase-btn, .btn-increase'); if (await increaseBtn.isVisible()) { await increaseBtn.click(); } } // ========== Step 2:选择收货地址 ========== const addressPicker = page.locator('.address-picker, .select-address'); if (await addressPicker.isVisible()) { await addressPicker.click(); await page.waitForSelector('.address-option, .address-item', { timeout: 5000 }); await page.click('.address-option:first-child, .address-item:first-child'); } // ========== When:点击立即购买 ========== await page.click('.buy-now-btn, .purchase-btn'); // ========== Then:Milestone-1 - 订单创建成功 ======== await page.waitForSelector('.order-created, .order-success, .order-no', { timeout: 10000 }); // 验证订单号显示 const orderNo = page.locator('.order-no, .order-number'); expect(await orderNo.isVisible()).toBeTruthy(); const orderNoText = await orderNo.textContent(); expect(orderNoText).toMatch(/ORD|PRD|\d+/); }); // ===== 场景2:支付订单 ===== /** * 场景:家长选择微信支付完成订单支付 * 角色:家长 * 触发条件:点击"去支付"并选择支付方式 */ test('[场景2] 支付商品订单 - 期望支付成功', async ({ page }) => { // ========== Given:进入订单支付页面 ========== await page.goto('/#/pages/shop/pay?orderNo=ORD20260628001'); await page.waitForLoadState('networkidle'); // ========== Step 1:选择支付方式 ========== const wechatPayOption = page.locator('.pay-method:has-text("微信支付"), .wechat-pay'); if (await wechatPayOption.isVisible()) { await wechatPayOption.click(); } // ========== When:确认支付 ========== await page.click('.confirm-pay-btn, .pay-now-btn'); // ========== Then:Milestone-2 - 支付成功 ======== await page.waitForSelector('.pay-success, .payment-success, .success-tip', { timeout: 30000 }); // 验证支付成功提示 const successTip = page.locator('.pay-success, .payment-success'); expect(await successTip.isVisible()).toBeTruthy(); }); // ===== 场景3:服务商发货 ===== /** * 场景:服务商收到订单后发货,填写物流信息 * 角色:服务商/供应商 * 触发条件:商家点击"发货"并填写物流单号 */ test('[场景3] 服务商发货 - 期望订单状态更新为已发货', async ({ page }) => { // ========== Given:进入商家订单管理 ========== await page.goto('/#/pages/vendor/orders'); await page.waitForLoadState('networkidle'); // ========== Step 1:找到待发货订单 ========== await page.waitForSelector('.order-item', { timeout: 10000 }); const paidOrder = page.locator('.order-item:has-text("已支付"), .order-item:has-text("待发货")').first(); await paidOrder.click(); // ========== Step 2:点击发货按钮 ========== await page.waitForSelector('.ship-btn, .deliver-btn', { timeout: 5000 }); await page.click('.ship-btn'); // ========== Step 3:填写物流信息 ========== await page.waitForSelector('.express-company, .tracking-company', { timeout: 5000 }); // 选择快递公司 const companyPicker = page.locator('.express-company, .tracking-company'); if (await companyPicker.isVisible()) { await companyPicker.click(); await page.waitForSelector('.company-option', { timeout: 5000 }); await page.click('.company-option:first-child'); } // 输入运单号 const trackingInput = page.locator('input[name="trackingNumber"], .tracking-input'); if (await trackingInput.isVisible()) { await trackingInput.fill('SF' + Date.now()); } // ========== When:确认发货 ========== await page.click('.confirm-ship-btn, .submit-btn'); // ========== Then:Milestone-3 - 发货成功 ======== await page.waitForSelector('.ship-success, .shipped', { timeout: 10000 }); // 验证订单状态变更为"已发货" const orderStatus = page.locator('.order-status, .status-tag'); if (await orderStatus.isVisible()) { const statusText = await orderStatus.textContent(); expect(statusText).toMatch(/已发货|待收货/); } // 验证运单号显示 const trackingNo = page.locator('.tracking-number, .tracking-no'); if (await trackingNo.isVisible()) { const trackingText = await trackingNo.textContent(); expect(trackingText).toMatch(/SF|\d{10,}/); } }); // ===== 场景4:家长确认收货 ===== /** * 场景:家长收到商品后确认收货 * 角色:家长 * 触发条件:确认收到商品无误 */ test('[场景4] 家长确认收货 - 期望订单完成', async ({ page }) => { // ========== Given:进入待收货订单 ========== await page.goto('/#/pages/shop/orders?to=received'); await page.waitForLoadState('networkidle'); // ========== Step 1:找到待收货订单 ========== await page.waitForSelector('.order-item', { timeout: 10000 }); const shippedOrder = page.locator('.order-item:has-text("已发货"), .order-item:has-text("待收货")').first(); await shippedOrder.click(); // ========== When:点击确认收货 ========== await page.waitForSelector('.confirm-receive-btn, .receive-btn', { timeout: 5000 }); await page.click('.confirm-receive-btn, .receive-btn'); // ========== Then:Milestone-4 - 订单完成 ======== await page.waitForSelector('.receive-success, .completed', { timeout: 10000 }); // 验证订单状态变更为"已完成" const orderStatus = page.locator('.order-status, .status-tag'); if (await orderStatus.isVisible()) { const statusText = await orderStatus.textContent(); expect(statusText).toMatch(/已完成|已收货/); } }); // ===== 场景5:申请退款 ===== /** * 场景:家长发现问题,申请退款 * 角色:家长 * 触发条件:点击"申请退款"并填写原因 */ test('[场景5] 申请退款 - 期望退款申请提交成功', async ({ page }) => { // ========== Given:进入订单详情 ========== await page.goto('/#/pages/shop/order-detail?orderNo=ORD20260628002'); await page.waitForLoadState('networkidle'); // ========== Step 1:点击申请退款 ========== await page.waitForSelector('.refund-btn, .apply-refund-btn', { timeout: 10000 }); await page.click('.refund-btn'); // ========== Step 2:填写退款原因 ========== await page.waitForSelector('.refund-reason-input, .reason-textarea', { timeout: 5000 }); const reasonInput = page.locator('.refund-reason-input textarea, .reason-textarea'); if (await reasonInput.isVisible()) { await reasonInput.fill('商品与描述不符,收到后发现质量问题'); } // ========== When:提交退款申请 ========== await page.click('.submit-refund-btn, .confirm-refund-btn'); // ========== Then:Milestone-5 - 退款申请成功 ======== await page.waitForSelector('.refund-submitted, .refund-success', { timeout: 10000 }); // 验证退款状态 const refundStatus = page.locator('.refund-status, .status-tag'); if (await refundStatus.isVisible()) { const statusText = await refundStatus.textContent(); expect(statusText).toMatch(/退款|审核中/); } }); // ===== 场景6:取消未支付订单 ===== /** * 场景:家长改变主意,取消未支付的订单 * 角色:家长 * 触发条件:点击"取消订单" */ test('[场景6] 取消未支付订单 - 期望订单关闭', async ({ page }) => { // ========== Given:进入我的订单 ========== await page.goto('/#/pages/shop/orders'); await page.waitForLoadState('networkidle'); // ========== Step 1:找到待支付订单 ========== await page.waitForSelector('.order-item', { timeout: 10000 }); const pendingOrder = page.locator('.order-item:has-text("待支付"), .order-item:has-text("待付款")').first(); // 点击进入订单详情 await pendingOrder.click(); // ========== Step 2:点击取消订单 ========== await page.waitForSelector('.cancel-order-btn', { timeout: 5000 }); await page.click('.cancel-order-btn'); // 确认取消 await page.waitForSelector('.confirm-dialog, .van-dialog', { timeout: 5000 }); await page.click('.confirm-dialog .van-button--primary, .confirm-cancel'); // ========== Then:订单关闭 ======== await page.waitForSelector('.cancel-success, .order-closed', { timeout: 10000 }); const orderStatus = page.locator('.order-status, .status-tag'); if (await orderStatus.isVisible()) { const statusText = await orderStatus.textContent(); expect(statusText).toMatch(/已取消|已关闭/); } }); // ===== 场景7:查看我的订单列表 ===== /** * 场景:家长查看自己的订单列表 * 角色:家长 * 触发条件:进入"我的订单"页面 */ test('[场景7] 查看我的订单列表 - 期望返回订单列表', async ({ page }) => { // ========== Given:进入我的订单页面 ========== await page.goto('/#/pages/shop/orders'); await page.waitForLoadState('networkidle'); // ========== When:查看订单列表 ========== await page.waitForSelector('.order-item', { timeout: 10000 }); // ========== Then:返回订单列表 ======== const orderItems = page.locator('.order-item'); const count = await orderItems.count(); expect(count).toBeGreaterThan(0); // 验证订单状态显示 const firstOrder = orderItems.first(); const statusTag = firstOrder.locator('.status-tag, .order-status'); expect(await statusTag.isVisible()).toBeTruthy(); }); // ===== 场景8:查看订单详情 ===== /** * 场景:家长查看具体订单的详细信息 * 角色:家长 * 触发条件:点击某个订单查看详情 */ test('[场景8] 查看订单详情 - 期望返回完整订单信息', async ({ page }) => { // ========== Given:进入订单详情 ========== await page.goto('/#/pages/shop/order-detail?orderNo=ORD20260628001'); await page.waitForLoadState('networkidle'); // ========== When:查看订单详情 ========== await page.waitForSelector('.order-detail, .detail-container', { timeout: 10000 }); // ========== Then:返回完整订单信息 ======== // 验证订单号显示 const orderNo = page.locator('.order-no, .order-number'); expect(await orderNo.isVisible()).toBeTruthy(); // 验证商品信息显示 const productInfo = page.locator('.product-info, .product-name'); expect(await productInfo.isVisible()).toBeTruthy(); // 验证金额显示 const amountInfo = page.locator('.total-amount, .order-amount'); expect(await amountInfo.isVisible()).toBeTruthy(); // 验证物流信息(如果有) const logisticsInfo = page.locator('.logistics-info, .tracking-info'); // 物流信息可能不显示(未发货时),但不应该报错 }); // ===== 场景9:完整商品购买流程(端到端)===== test('[场景9] 完整商品购买流程 - 期望全流程成功', async ({ page }) => { // ========== Step 1:浏览商品 ========== await page.goto('/#/pages/shop/list'); await page.waitForLoadState('networkidle'); await page.waitForSelector('.product-item', { timeout: 10000 }); // 点击第一个商品 await page.locator('.product-item').first().click(); await page.waitForLoadState('networkidle'); // ========== Step 2:创建订单 ========== const buyBtn = page.locator('.buy-now-btn, .purchase-btn'); if (await buyBtn.isVisible()) { await buyBtn.click(); await page.waitForSelector('.order-no, .order-created', { timeout: 10000 }); } // 获取订单号 let orderNo = ''; const orderNoEl = page.locator('.order-no'); if (await orderNoEl.isVisible()) { orderNo = await orderNoEl.textContent(); } // ========== Step 3:支付订单 ========== const payBtn = page.locator('.go-pay-btn, .pay-now-btn'); if (await payBtn.isVisible()) { await payBtn.click(); // 选择微信支付 const wechatPay = page.locator('.pay-method:has-text("微信")'); if (await wechatPay.isVisible()) { await wechatPay.click(); } await page.click('.confirm-pay-btn'); await page.waitForSelector('.pay-success, .payment-success', { timeout: 30000 }); } // ========== Step 4:查看我的订单 ========== await page.goto('/#/pages/shop/orders'); await page.waitForLoadState('networkidle'); await page.waitForSelector('.order-item', { timeout: 10000 }); // 验证订单存在 const orderItems = page.locator('.order-item'); const count = await orderItems.count(); expect(count).toBeGreaterThan(0); // 如果有已发货的订单,确认收货 const shippedOrder = page.locator('.order-item:has-text("已发货")').first(); if (await shippedOrder.isVisible()) { await shippedOrder.click(); const receiveBtn = page.locator('.confirm-receive-btn'); if (await receiveBtn.isVisible()) { await receiveBtn.click(); await page.waitForSelector('.receive-success', { timeout: 10000 }); } } }); });