machine.spec.ts 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. import { test, expect, type Page } from '@playwright/test'
  2. // 测试账号配置
  3. const TEST_USERNAME = process.env.TEST_USERNAME || 'admin'
  4. const TEST_PASSWORD = process.env.TEST_PASSWORD || '123456'
  5. // 生成唯一的测试机器ID
  6. const generateMachineId = () => `TEST_${Date.now()}`
  7. // data-id 选择器辅助函数
  8. const byDataId = (id: string) => `[data-id="${id}"]`
  9. test.describe('机器管理 CRUD 测试', () => {
  10. // 登录辅助函数
  11. async function login(page: Page) {
  12. await page.goto('/login')
  13. await page.evaluate(() => {
  14. localStorage.clear()
  15. document.cookie.split(';').forEach((c) => {
  16. document.cookie = c.replace(/^ +/, '').replace(/=.*/, '=;expires=' + new Date().toUTCString() + ';path=/')
  17. })
  18. })
  19. await page.reload()
  20. await page.getByPlaceholder('用户名').fill(TEST_USERNAME)
  21. await page.getByPlaceholder('密码').fill(TEST_PASSWORD)
  22. await page.getByRole('button', { name: '登录' }).click()
  23. await expect(page).not.toHaveURL(/\/login/, { timeout: 15000 })
  24. }
  25. test('机器管理页面正确显示', async ({ page }) => {
  26. await login(page)
  27. await page.goto('/machine')
  28. // 验证页面元素
  29. await expect(page.locator(byDataId('btn-add-machine'))).toBeVisible()
  30. await expect(page.locator(byDataId('btn-search'))).toBeVisible()
  31. await expect(page.locator(byDataId('btn-reset'))).toBeVisible()
  32. await expect(page.locator(byDataId('machine-table'))).toBeVisible()
  33. // 验证表头 - 使用 thead 来区分表单标签和表头
  34. await expect(page.locator('thead').getByText('机器ID')).toBeVisible()
  35. await expect(page.locator('thead').getByText('名称')).toBeVisible()
  36. await expect(page.locator('thead').getByText('位置')).toBeVisible()
  37. })
  38. test('查询和重置功能', async ({ page }) => {
  39. await login(page)
  40. await page.goto('/machine')
  41. // 等待表格加载
  42. await expect(page.locator(byDataId('machine-table'))).toBeVisible()
  43. // 点击查询按钮
  44. await page.locator(byDataId('btn-search')).click()
  45. await page.waitForTimeout(500)
  46. // 表格应该仍然可见
  47. await expect(page.locator(byDataId('machine-table'))).toBeVisible()
  48. // 点击重置按钮
  49. await page.locator(byDataId('btn-reset')).click()
  50. await page.waitForTimeout(500)
  51. // 表格应该仍然可见
  52. await expect(page.locator(byDataId('machine-table'))).toBeVisible()
  53. })
  54. test('新增机器完整流程', async ({ page }) => {
  55. await login(page)
  56. await page.goto('/machine')
  57. const machineId = generateMachineId()
  58. const machineName = `测试机器_${Date.now()}`
  59. // 点击新增按钮
  60. await page.locator(byDataId('btn-add-machine')).click()
  61. // 验证弹窗打开
  62. const dialog = page.locator(byDataId('dialog-machine'))
  63. await expect(dialog).toBeVisible()
  64. await expect(page.locator('.el-dialog__title')).toContainText('新增机器')
  65. // 填写表单 - 使用 dialog 作为容器来定位输入框
  66. await dialog.locator(byDataId('input-machine-id')).fill(machineId)
  67. await dialog.locator(byDataId('input-name')).fill(machineName)
  68. await dialog.locator(byDataId('input-location')).fill('测试位置')
  69. await dialog.locator(byDataId('input-description')).fill('E2E测试创建的机器')
  70. // 等待提交按钮可用后点击
  71. const submitBtn = page.locator(byDataId('btn-submit'))
  72. await expect(submitBtn).toBeEnabled()
  73. await submitBtn.click()
  74. // 等待成功消息或弹窗关闭(API成功或失败都会关闭弹窗)
  75. const successPromise = page
  76. .locator('.el-message--success')
  77. .waitFor({ timeout: 10000 })
  78. .catch(() => null)
  79. const dialogClosePromise = expect(dialog).not.toBeVisible({ timeout: 10000 })
  80. await Promise.race([successPromise, dialogClosePromise])
  81. // 如果弹窗关闭了,说明操作已完成
  82. await expect(dialog).not.toBeVisible({ timeout: 5000 })
  83. })
  84. test('编辑机器功能', async ({ page }) => {
  85. await login(page)
  86. await page.goto('/machine')
  87. // 等待表格加载
  88. await expect(page.locator(byDataId('machine-table'))).toBeVisible()
  89. await page.waitForTimeout(1000)
  90. // 点击第一行的名称链接
  91. const firstNameLink = page.locator('[data-id^="link-edit-"]').first()
  92. // 等待数据加载,确保有可编辑的数据
  93. await expect(firstNameLink).toBeVisible({ timeout: 10000 })
  94. await firstNameLink.click()
  95. // 验证弹窗打开
  96. const dialog = page.locator(byDataId('dialog-machine'))
  97. await expect(dialog).toBeVisible()
  98. await expect(page.locator('.el-dialog__title')).toContainText('编辑机器')
  99. // 修改名称 - 使用 data-id 定位输入框
  100. const nameInput = dialog.locator(byDataId('input-name'))
  101. await nameInput.clear()
  102. await nameInput.fill(`编辑测试_${Date.now()}`)
  103. // 等待提交按钮可用后点击
  104. const submitBtn = page.locator(byDataId('btn-submit'))
  105. await expect(submitBtn).toBeEnabled()
  106. await submitBtn.click()
  107. // 验证弹窗关闭
  108. await expect(dialog).not.toBeVisible({ timeout: 15000 })
  109. })
  110. test('删除机器功能', async ({ page }) => {
  111. await login(page)
  112. await page.goto('/machine')
  113. // 等待表格加载
  114. await expect(page.locator(byDataId('machine-table'))).toBeVisible()
  115. await page.waitForTimeout(1000)
  116. // 找到第一个删除按钮并点击
  117. const deleteBtn = page.locator('[data-id^="btn-delete-"]').first()
  118. // 确保有数据可以删除
  119. await expect(deleteBtn).toBeVisible({ timeout: 10000 })
  120. await deleteBtn.click()
  121. // 确认删除对话框出现
  122. await expect(page.locator('.el-message-box')).toBeVisible()
  123. await page.locator('.el-message-box').getByRole('button', { name: '确定' }).click()
  124. // 等待确认对话框关闭(删除操作已执行)
  125. await expect(page.locator('.el-message-box')).not.toBeVisible({ timeout: 10000 })
  126. // 验证表格仍然可见(删除后页面正常)
  127. await expect(page.locator(byDataId('machine-table'))).toBeVisible()
  128. })
  129. test('新增机器表单验证', async ({ page }) => {
  130. await login(page)
  131. await page.goto('/machine')
  132. // 点击新增按钮
  133. await page.locator(byDataId('btn-add-machine')).click()
  134. await expect(page.locator(byDataId('dialog-machine'))).toBeVisible()
  135. // 直接点击确定,不填写任何内容
  136. await page.locator(byDataId('btn-submit')).click()
  137. // 验证显示验证错误 - 使用 dialog 容器来定位错误消息
  138. const dialog = page.locator(byDataId('dialog-machine'))
  139. await expect(dialog.getByText('请输入机器ID')).toBeVisible()
  140. await expect(dialog.getByText('请输入名称')).toBeVisible()
  141. })
  142. test('取消新增机器', async ({ page }) => {
  143. await login(page)
  144. await page.goto('/machine')
  145. // 点击新增按钮
  146. await page.locator(byDataId('btn-add-machine')).click()
  147. const dialog = page.locator(byDataId('dialog-machine'))
  148. await expect(dialog).toBeVisible()
  149. // 填写部分内容
  150. await dialog.locator(byDataId('input-machine-id')).fill('TEST_CANCEL')
  151. // 点击取消
  152. await page.locator(byDataId('btn-cancel')).click()
  153. // 验证弹窗关闭
  154. await expect(dialog).not.toBeVisible()
  155. })
  156. test('从侧边栏导航到机器管理', async ({ page }) => {
  157. await login(page)
  158. // 点击侧边栏机器管理菜单项
  159. await page.getByText('机器管理').first().click()
  160. // 验证跳转到机器管理页面
  161. await expect(page).toHaveURL(/\/machine/)
  162. await expect(page.locator(byDataId('btn-add-machine'))).toBeVisible()
  163. })
  164. })