locations.e2e.test.ts 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. import { test, expect } from '@playwright/test';
  2. test.describe('地点管理E2E测试', () => {
  3. test.beforeEach(async ({ page }) => {
  4. // 登录到管理后台
  5. await page.goto('/admin/login');
  6. await page.fill('input[name="username"]', 'admin');
  7. await page.fill('input[name="password"]', 'admin');
  8. await page.click('button[type="submit"]');
  9. // 等待登录完成并跳转到仪表板
  10. await page.waitForURL('/admin/dashboard');
  11. // 导航到地点管理页面
  12. await page.goto('/admin/locations');
  13. await page.waitForLoadState('networkidle');
  14. });
  15. test('应该正确显示地点管理页面', async ({ page }) => {
  16. // 验证页面标题
  17. await expect(page.getByRole('heading', { name: '地点管理' })).toBeVisible();
  18. // 验证新建地点按钮
  19. await expect(page.getByRole('button', { name: '新建地点' })).toBeVisible();
  20. // 验证搜索框
  21. await expect(page.getByPlaceholder('搜索地点名称或地址...')).toBeVisible();
  22. // 验证筛选器
  23. await expect(page.getByPlaceholder('选择区域')).toBeVisible();
  24. await expect(page.getByPlaceholder('状态筛选')).toBeVisible();
  25. // 验证表格列标题
  26. await expect(page.getByText('地点名称')).toBeVisible();
  27. await expect(page.getByText('地址')).toBeVisible();
  28. await expect(page.getByText('所属区域')).toBeVisible();
  29. await expect(page.getByText('坐标')).toBeVisible();
  30. await expect(page.getByText('状态')).toBeVisible();
  31. await expect(page.getByText('创建时间')).toBeVisible();
  32. await expect(page.getByText('操作')).toBeVisible();
  33. });
  34. test('应该能够搜索地点', async ({ page }) => {
  35. // 在搜索框中输入关键词
  36. const searchInput = page.getByPlaceholder('搜索地点名称或地址...');
  37. await searchInput.fill('北京');
  38. // 等待搜索结果加载
  39. await page.waitForTimeout(500);
  40. // 验证搜索结果包含相关地点
  41. await expect(page.getByText('北京')).toBeVisible();
  42. });
  43. test('应该能够按区域筛选地点', async ({ page }) => {
  44. // 点击区域筛选器
  45. const areaFilter = page.getByPlaceholder('选择区域');
  46. await areaFilter.click();
  47. // 等待选项加载
  48. await page.waitForTimeout(500);
  49. // 验证区域选项存在
  50. await expect(page.getByText('全部区域')).toBeVisible();
  51. // 选择第一个区域选项
  52. const firstAreaOption = page.locator('[role="option"]').first();
  53. if (await firstAreaOption.isVisible()) {
  54. await firstAreaOption.click();
  55. // 等待筛选结果加载
  56. await page.waitForTimeout(500);
  57. // 验证筛选后的结果
  58. await expect(page.locator('tbody tr')).toBeVisible();
  59. }
  60. });
  61. test('应该能够按状态筛选地点', async ({ page }) => {
  62. // 点击状态筛选器
  63. const statusFilter = page.getByPlaceholder('状态筛选');
  64. await statusFilter.click();
  65. // 等待选项加载
  66. await page.waitForTimeout(500);
  67. // 验证状态选项存在
  68. await expect(page.getByText('全部状态')).toBeVisible();
  69. await expect(page.getByText('启用')).toBeVisible();
  70. await expect(page.getByText('禁用')).toBeVisible();
  71. // 选择"启用"状态
  72. await page.getByText('启用').click();
  73. // 等待筛选结果加载
  74. await page.waitForTimeout(500);
  75. // 验证筛选后的结果
  76. await expect(page.locator('tbody tr')).toBeVisible();
  77. });
  78. test('应该能够打开新建地点模态框', async ({ page }) => {
  79. // 点击新建地点按钮
  80. await page.getByRole('button', { name: '新建地点' }).click();
  81. // 验证模态框显示
  82. await expect(page.getByRole('heading', { name: '新建地点' })).toBeVisible();
  83. // 验证表单字段存在
  84. await expect(page.getByLabel('地点名称')).toBeVisible();
  85. await expect(page.getByLabel('地址')).toBeVisible();
  86. await expect(page.getByLabel('经度')).toBeVisible();
  87. await expect(page.getByLabel('纬度')).toBeVisible();
  88. // 关闭模态框
  89. await page.keyboard.press('Escape');
  90. // 验证模态框关闭
  91. await expect(page.getByRole('heading', { name: '新建地点' })).not.toBeVisible();
  92. });
  93. test('应该能够查看地点详情', async ({ page }) => {
  94. // 等待地点列表加载
  95. await page.waitForSelector('tbody tr');
  96. // 获取第一个地点的名称
  97. const firstLocationName = page.locator('tbody tr td').first();
  98. const locationName = await firstLocationName.textContent();
  99. // 验证地点名称显示
  100. expect(locationName).toBeTruthy();
  101. // 验证地址显示
  102. const addressCell = page.locator('tbody tr td:nth-child(2)').first();
  103. const address = await addressCell.textContent();
  104. expect(address).toBeTruthy();
  105. // 验证区域信息显示
  106. const areaCell = page.locator('tbody tr td:nth-child(3)').first();
  107. await expect(areaCell.locator('[data-radix-collection-item]')).toBeVisible();
  108. // 验证状态显示
  109. const statusCell = page.locator('tbody tr td:nth-child(5)').first();
  110. await expect(statusCell.getByText(/启用|禁用/)).toBeVisible();
  111. });
  112. test('应该能够分页浏览地点', async ({ page }) => {
  113. // 等待分页控件加载
  114. await page.waitForSelector('button:has-text("上一页"), button:has-text("下一页")');
  115. // 验证分页信息显示
  116. await expect(page.getByText(/显示第.*条,共.*条记录/)).toBeVisible();
  117. // 尝试点击下一页(如果可用)
  118. const nextButton = page.getByRole('button', { name: '下一页' });
  119. if (await nextButton.isEnabled()) {
  120. await nextButton.click();
  121. // 等待下一页数据加载
  122. await page.waitForTimeout(500);
  123. // 验证页面更新
  124. await expect(page.locator('tbody tr')).toBeVisible();
  125. }
  126. });
  127. test('应该能够编辑地点', async ({ page }) => {
  128. // 等待地点列表加载
  129. await page.waitForSelector('tbody tr');
  130. // 查找编辑按钮并点击
  131. const editButtons = page.locator('button').filter({ has: page.locator('svg[data-lucide="edit"]') });
  132. if (await editButtons.first().isVisible()) {
  133. await editButtons.first().click();
  134. // 验证编辑模态框显示
  135. await expect(page.getByRole('heading', { name: '编辑地点' })).toBeVisible();
  136. // 关闭模态框
  137. await page.keyboard.press('Escape');
  138. }
  139. });
  140. test('应该能够切换地点状态', async ({ page }) => {
  141. // 等待地点列表加载
  142. await page.waitForSelector('tbody tr');
  143. // 查找启用/禁用按钮
  144. const toggleButtons = page.getByRole('button').filter({ hasText: /禁用|启用/ });
  145. if (await toggleButtons.first().isVisible()) {
  146. // 点击切换状态按钮
  147. await toggleButtons.first().click();
  148. // 处理确认对话框
  149. page.on('dialog', dialog => dialog.accept());
  150. // 等待状态更新
  151. await page.waitForTimeout(500);
  152. // 验证状态可能已更新(按钮文本可能改变)
  153. const newButtonText = await toggleButtons.first().textContent();
  154. expect(newButtonText).toBeTruthy();
  155. }
  156. });
  157. test('应该能够删除地点', async ({ page }) => {
  158. // 等待地点列表加载
  159. await page.waitForSelector('tbody tr');
  160. // 查找删除按钮
  161. const deleteButtons = page.locator('button').filter({ has: page.locator('svg[data-lucide="trash-2"]') });
  162. if (await deleteButtons.first().isVisible()) {
  163. // 设置对话框处理
  164. page.on('dialog', dialog => dialog.accept());
  165. // 点击删除按钮
  166. await deleteButtons.first().click();
  167. // 等待删除操作完成
  168. await page.waitForTimeout(500);
  169. // 验证删除成功(可能显示成功消息)
  170. await expect(page.getByText('地点已成功删除')).toBeVisible();
  171. }
  172. });
  173. test('应该显示空状态当没有地点时', async ({ page }) => {
  174. // 使用一个不存在的搜索词来模拟空状态
  175. const searchInput = page.getByPlaceholder('搜索地点名称或地址...');
  176. await searchInput.fill('不存在的搜索词');
  177. // 等待搜索结果
  178. await page.waitForTimeout(500);
  179. // 验证可能显示空状态或"暂无地点数据"
  180. const emptyState = page.getByText('暂无地点数据');
  181. if (await emptyState.isVisible()) {
  182. await expect(emptyState).toBeVisible();
  183. }
  184. });
  185. test('应该处理网络错误场景', async ({ page }) => {
  186. // 模拟网络错误 - 通过无效搜索触发
  187. const searchInput = page.getByPlaceholder('搜索地点名称或地址...');
  188. await searchInput.fill('error-test');
  189. // 等待可能的错误处理
  190. await page.waitForTimeout(500);
  191. // 验证页面仍然可用
  192. await expect(page.getByRole('heading', { name: '地点管理' })).toBeVisible();
  193. await expect(page.getByRole('button', { name: '新建地点' })).toBeVisible();
  194. });
  195. });