vendor-product-manage.spec.js 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  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. *
  23. * 运行:npx playwright test tests/e2e/vendor-product-manage.spec.js
  24. * ================================================================
  25. */
  26. const { test, expect } = require('@playwright/test');
  27. test.describe('【场景流程】供应商商品管理', () => {
  28. test.beforeEach(async ({ page }) => {
  29. // 管理员登录(admin 后台)
  30. await page.goto('http://cfc.iwintrue.com/admin/login');
  31. await page.waitForLoadState('networkidle');
  32. const adminPhone = '13701366188';
  33. const phoneInput = page.locator('input[placeholder="请输入手机号"]');
  34. await phoneInput.fill(adminPhone);
  35. await page.locator('.login-btn, button:has-text("登录")').click();
  36. await page.waitForTimeout(1500);
  37. // 验证登录成功
  38. try {
  39. await page.waitForSelector('.admin-tab, .admin-menu, .admin-layout', { timeout: 10000 });
  40. } catch (e) {
  41. if (await page.url().includes('/login')) {
  42. await page.goto('http://cfc.iwintrue.com/admin/supplier-products');
  43. await page.waitForLoadState('networkidle');
  44. }
  45. }
  46. });
  47. /**
  48. * 场景1:商品管理页面加载
  49. * 角色:管理员
  50. * 触发条件:进入供应商商品管理页面
  51. * 校验:页面加载成功,tab 切换到商品列表
  52. */
  53. test('[场景1] 商品管理页面加载 — 期望 tab 切换到商品列表', async ({ page }) => {
  54. await page.goto('http://cfc.iwintrue.com/admin/supplier-products');
  55. await page.waitForLoadState('networkidle');
  56. // 验证页面标题
  57. const title = page.locator('.el-card__header, .tab-header, h2:has-text("商品管理")');
  58. expect(await title.isVisible()).toBeTruthy();
  59. // 验证默认选中"商品列表" tab
  60. const listTab = page.locator('.nav-item.active, .el-tab-pane.is-active, text="商品列表"');
  61. expect(await listTab.isVisible()).toBeTruthy();
  62. });
  63. /**
  64. * 场景2:商品列表加载
  65. * 角色:管理员
  66. * 触发条件:进入商品管理页面
  67. * 校验:列表加载正常数据
  68. */
  69. test('[场景2] 商品列表加载 — 期望数据加载', async ({ page }) => {
  70. await page.goto('http://cfc.iwintrue.com/admin/supplier-products');
  71. await page.waitForLoadState('networkidle');
  72. // 验证列表加载
  73. const productRows = page.locator('.el-table__row, .product-row');
  74. const rowCount = await productRows.count();
  75. expect(rowCount).toBeGreaterThanOrEqual(0);
  76. // 验证列数
  77. if (rowCount > 0) {
  78. const firstRow = productRows.first();
  79. const cells = firstRow.locator('.el-table__cell');
  80. expect(await cells.count()).toBeGreaterThanOrEqual(6);
  81. }
  82. });
  83. /**
  84. * 场景3:搜索筛选商品
  85. * 角色:管理员
  86. * 触发条件:输入商品名称、供应商等筛选条件
  87. * 校验:列表刷新返回正常数据
  88. */
  89. test('[场景3] 搜索筛选商品 — 期望列表刷新', async ({ page }) => {
  90. await page.goto('http://cfc.iwintrue.com/admin/supplier-products');
  91. await page.waitForLoadState('networkidle');
  92. // 输入筛选条件
  93. const nameInput = page.locator('input[placeholder="商品名称"]');
  94. if (await nameInput.isVisible()) {
  95. await nameInput.fill('测试商品');
  96. }
  97. // 点击搜索按钮
  98. const searchBtn = page.locator('.search-btn, button:has-text("搜索")');
  99. await searchBtn.click();
  100. await page.waitForTimeout(1000);
  101. // 验证列表刷新
  102. const productRows = page.locator('.el-table__row');
  103. expect(await productRows.count()).toBeGreaterThanOrEqual(0);
  104. });
  105. /**
  106. * 场景4:查看商品详情
  107. * 角色:管理员
  108. * 触发条件:点击商品列表中的"详情"按钮
  109. * 校验:商品详情页面加载成功
  110. */
  111. test('[场景4] 查看商品详情 — 期望详情加载', async ({ page }) => {
  112. await page.goto('http://cfc.iwintrue.com/admin/supplier-products');
  113. await page.waitForLoadState('networkidle');
  114. // 查找第一个商品的详情按钮
  115. const detailBtn = page.locator('.el-table__row:first-child button:has-text("详情")');
  116. if (await detailBtn.isVisible()) {
  117. await detailBtn.click();
  118. await page.waitForTimeout(1000);
  119. // 验证详情加载
  120. const productInfo = page.locator('.product-info, .detail-card');
  121. expect(await productInfo.isVisible()).toBeTruthy();
  122. // 验证商品信息展示
  123. const productName = page.locator('.product-name, .title');
  124. expect(await productName.isVisible()).toBeTruthy();
  125. } else {
  126. // 无商品数据,跳过
  127. expect(true).toBeTruthy();
  128. }
  129. });
  130. /**
  131. * 场景5:编辑商品信息
  132. * 角色:管理员
  133. * 触发条件:点击商品列表中的"编辑"按钮
  134. * 校验:编辑表单加载成功
  135. */
  136. test('[场景5] 编辑商品信息 — 期望表单加载', async ({ page }) => {
  137. await page.goto('http://cfc.iwintrue.com/admin/supplier-products');
  138. await page.waitForLoadState('networkidle');
  139. // 查找第一个商品的编辑按钮
  140. const editBtn = page.locator('.el-table__row:first-child button:has-text("编辑")');
  141. if (await editBtn.isVisible()) {
  142. await editBtn.click();
  143. await page.waitForTimeout(1000);
  144. // 验证表单加载
  145. const formFields = page.locator('.el-form-item, .form-field');
  146. const fieldCount = await formFields.count();
  147. expect(fieldCount).toBeGreaterThanOrEqual(5);
  148. // 验证表单包含关键字段
  149. const nameInput = page.locator('input[placeholder*="名称"], input[name="name"]');
  150. expect(await nameInput.isVisible()).toBeTruthy();
  151. const priceInput = page.locator('input[placeholder*="价格"], input[name="price"]');
  152. expect(await priceInput.isVisible()).toBeTruthy();
  153. } else {
  154. // 无商品数据,跳过
  155. expect(true).toBeTruthy();
  156. }
  157. });
  158. /**
  159. * 场景6:审核商品
  160. * 角色:管理员
  161. * 触发条件:选择待审核商品,点击通过
  162. * 校验:审核成功,状态变为已上架
  163. */
  164. test('[场景6] 审核商品 — 期望通过成功', async ({ page }) => {
  165. await page.goto('http://cfc.iwintrue.com/admin/supplier-products');
  166. await page.waitForLoadState('networkidle');
  167. // 切换到审核 tab
  168. const reviewTab = page.locator('.nav-item:has-text("待审核"), .tab-item:has-text("待审核")');
  169. await reviewTab.click();
  170. await page.waitForTimeout(1000);
  171. // 查找待审核商品
  172. const pendingProducts = page.locator('.el-table__row:has-text("待审核")');
  173. const productCount = await pendingProducts.count();
  174. if (productCount > 0) {
  175. // 点击通过按钮
  176. const approveBtn = pendingProducts.first().locator('button:has-text("通过")');
  177. await approveBtn.click();
  178. await page.waitForTimeout(500);
  179. // 提交
  180. const submitBtn = page.locator('.el-dialog__footer button:has-text("确定"), button.el-button--primary');
  181. await submitBtn.click();
  182. await page.waitForTimeout(1000);
  183. // 验证提示
  184. const successTip = page.locator('.toast-success, text="审核通过"');
  185. expect(await successTip.isVisible().catch(() => false)).toBeTruthy();
  186. } else {
  187. // 无待审核商品,跳过
  188. expect(true).toBeTruthy();
  189. }
  190. });
  191. /**
  192. * 场景7:商品分类管理
  193. * 角色:管理员
  194. * 触发条件:进入商品分类页面
  195. * 校验:分类列表加载正常
  196. */
  197. test('[场景7] 商品分类管理 — 期望分类加载', async ({ page }) => {
  198. await page.goto('http://cfc.iwintrue.com/admin/category-manage');
  199. await page.waitForLoadState('networkidle');
  200. // 验证页面标题
  201. const title = page.locator('.el-card__header, .tab-header, h2:has-text("商品分类")');
  202. expect(await title.isVisible()).toBeTruthy();
  203. // 验证分类列表加载
  204. const categoryRows = page.locator('.el-table__row, .category-row');
  205. const rowCount = await categoryRows.count();
  206. expect(rowCount).toBeGreaterThanOrEqual(0);
  207. // 验证列数
  208. if (rowCount > 0) {
  209. const firstRow = categoryRows.first();
  210. const cells = firstRow.locator('.el-table__cell');
  211. expect(await cells.count()).toBeGreaterThanOrEqual(4);
  212. }
  213. });
  214. /**
  215. * 场景8:商品利润率配置
  216. * 角色:管理员
  217. * 触发条件:进入商品利润率页面
  218. * 校验:利润率配置加载正常
  219. */
  220. test('[场景8] 商品利润率配置 — 期望配置加载', async ({ page }) => {
  221. await page.goto('http://cfc.iwintrue.com/admin/product-profit-rate');
  222. await page.waitForLoadState('networkidle');
  223. // 验证页面标题
  224. const title = page.locator('.el-card__header, .tab-header, h2:has-text("利润率")');
  225. expect(await title.isVisible()).toBeTruthy();
  226. // 验证配置加载
  227. const profitRows = page.locator('.el-table__row, .profit-row');
  228. const rowCount = await profitRows.count();
  229. expect(rowCount).toBeGreaterThanOrEqual(0);
  230. // 验证列数
  231. if (rowCount > 0) {
  232. const firstRow = profitRows.first();
  233. const cells = firstRow.locator('.el-table__cell');
  234. expect(await cells.count()).toBeGreaterThanOrEqual(5);
  235. }
  236. });
  237. });