|
|
@@ -179,3 +179,309 @@ test.describe('LSS管理 CRUD 测试', () => {
|
|
|
await expect(page.locator('text=LSS 管理')).toBeVisible()
|
|
|
})
|
|
|
})
|
|
|
+
|
|
|
+test.describe('LSS管理 - CodeEditor 组件测试 (JSON模式)', () => {
|
|
|
+ // 登录辅助函数
|
|
|
+ async function login(page: Page) {
|
|
|
+ await page.goto('/login')
|
|
|
+ await page.evaluate(() => {
|
|
|
+ localStorage.clear()
|
|
|
+ document.cookie.split(';').forEach((c) => {
|
|
|
+ document.cookie = c.replace(/^ +/, '').replace(/=.*/, '=;expires=' + new Date().toUTCString() + ';path=/')
|
|
|
+ })
|
|
|
+ })
|
|
|
+ await page.reload()
|
|
|
+
|
|
|
+ await page.getByPlaceholder('用户名').fill(TEST_USERNAME)
|
|
|
+ await page.getByPlaceholder('密码').fill(TEST_PASSWORD)
|
|
|
+ await page.getByRole('button', { name: '登录' }).click()
|
|
|
+ await expect(page).not.toHaveURL(/\/login/, { timeout: 15000 })
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 测试 CodeEditor JSON 模式 - 头部显示
|
|
|
+ */
|
|
|
+ test('CodeEditor JSON模式 - 验证头部显示JSON标签和按钮', async ({ page }) => {
|
|
|
+ await login(page)
|
|
|
+ await page.goto('/lss')
|
|
|
+
|
|
|
+ // 等待表格加载
|
|
|
+ await page.waitForTimeout(1000)
|
|
|
+
|
|
|
+ // 点击 Device List 按钮打开设备列表
|
|
|
+ const deviceListButton = page.locator('tbody tr').first().locator('button').first()
|
|
|
+ await expect(deviceListButton).toBeVisible({ timeout: 10000 })
|
|
|
+ await deviceListButton.click()
|
|
|
+
|
|
|
+ // 等待设备列表面板打开
|
|
|
+ const devicePanel = page.locator('.el-drawer, .el-dialog').filter({ hasText: 'Camera List' })
|
|
|
+ await expect(devicePanel).toBeVisible({ timeout: 5000 })
|
|
|
+
|
|
|
+ // 点击 Parameter Configuration 的 View 按钮
|
|
|
+ const viewButton = devicePanel.locator('tbody tr').first().locator('button:has-text("View")').first()
|
|
|
+ await expect(viewButton).toBeVisible({ timeout: 5000 })
|
|
|
+ await viewButton.click()
|
|
|
+
|
|
|
+ // 等待参数配置抽屉打开
|
|
|
+ const paramsDrawer = page.locator('.el-drawer').filter({ hasText: '参数配置' })
|
|
|
+ await expect(paramsDrawer).toBeVisible({ timeout: 5000 })
|
|
|
+
|
|
|
+ // 验证 CodeEditor 头部显示 JSON 标签
|
|
|
+ const codeEditor = paramsDrawer.locator('.code-editor')
|
|
|
+ await expect(codeEditor).toBeVisible()
|
|
|
+ await expect(codeEditor.locator('.editor-header')).toBeVisible()
|
|
|
+ await expect(codeEditor.locator('.file-type')).toContainText('JSON')
|
|
|
+
|
|
|
+ // 验证 Copy 按钮存在
|
|
|
+ await expect(codeEditor.locator('button:has-text("复制"), button:has-text("Copy")')).toBeVisible()
|
|
|
+
|
|
|
+ // 验证 格式化 按钮存在 (JSON模式特有)
|
|
|
+ await expect(codeEditor.locator('button:has-text("格式化")')).toBeVisible()
|
|
|
+ })
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 测试 CodeEditor JSON 模式 - 复制功能
|
|
|
+ */
|
|
|
+ test('CodeEditor JSON模式 - 复制按钮功能', async ({ page }) => {
|
|
|
+ await login(page)
|
|
|
+ await page.goto('/lss')
|
|
|
+
|
|
|
+ // 等待表格加载
|
|
|
+ await page.waitForTimeout(1000)
|
|
|
+
|
|
|
+ // 点击 Device List 按钮
|
|
|
+ const deviceListButton = page.locator('tbody tr').first().locator('button').first()
|
|
|
+ await deviceListButton.click()
|
|
|
+
|
|
|
+ // 等待设备列表面板打开
|
|
|
+ const devicePanel = page.locator('.el-drawer, .el-dialog').filter({ hasText: 'Camera List' })
|
|
|
+ await expect(devicePanel).toBeVisible({ timeout: 5000 })
|
|
|
+
|
|
|
+ // 点击 Parameter Configuration 的 View 按钮
|
|
|
+ const viewButton = devicePanel.locator('tbody tr').first().locator('button:has-text("View")').first()
|
|
|
+ await viewButton.click()
|
|
|
+
|
|
|
+ // 等待参数配置抽屉打开
|
|
|
+ const paramsDrawer = page.locator('.el-drawer').filter({ hasText: '参数配置' })
|
|
|
+ await expect(paramsDrawer).toBeVisible({ timeout: 5000 })
|
|
|
+
|
|
|
+ // 点击复制按钮
|
|
|
+ const copyButton = paramsDrawer.locator(
|
|
|
+ '.code-editor button:has-text("复制"), .code-editor button:has-text("Copy")'
|
|
|
+ )
|
|
|
+ await copyButton.click()
|
|
|
+
|
|
|
+ // 验证复制成功提示
|
|
|
+ await expect(page.locator('.el-message--success')).toBeVisible({ timeout: 3000 })
|
|
|
+ })
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 测试 CodeEditor JSON 模式 - 格式化功能
|
|
|
+ */
|
|
|
+ test('CodeEditor JSON模式 - 格式化按钮功能', async ({ page }) => {
|
|
|
+ await login(page)
|
|
|
+ await page.goto('/lss')
|
|
|
+
|
|
|
+ // 等待表格加载
|
|
|
+ await page.waitForTimeout(1000)
|
|
|
+
|
|
|
+ // 点击 Device List 按钮
|
|
|
+ const deviceListButton = page.locator('tbody tr').first().locator('button').first()
|
|
|
+ await deviceListButton.click()
|
|
|
+
|
|
|
+ // 等待设备列表面板打开
|
|
|
+ const devicePanel = page.locator('.el-drawer, .el-dialog').filter({ hasText: 'Camera List' })
|
|
|
+ await expect(devicePanel).toBeVisible({ timeout: 5000 })
|
|
|
+
|
|
|
+ // 点击 Parameter Configuration 的 View 按钮
|
|
|
+ const viewButton = devicePanel.locator('tbody tr').first().locator('button:has-text("View")').first()
|
|
|
+ await viewButton.click()
|
|
|
+
|
|
|
+ // 等待参数配置抽屉打开
|
|
|
+ const paramsDrawer = page.locator('.el-drawer').filter({ hasText: '参数配置' })
|
|
|
+ await expect(paramsDrawer).toBeVisible({ timeout: 5000 })
|
|
|
+
|
|
|
+ // 验证格式化按钮可用(如果内容是有效JSON)
|
|
|
+ const formatButton = paramsDrawer.locator('.code-editor button:has-text("格式化")')
|
|
|
+ await expect(formatButton).toBeVisible()
|
|
|
+
|
|
|
+ // 点击格式化按钮(如果按钮未禁用)
|
|
|
+ const isDisabled = await formatButton.isDisabled()
|
|
|
+ if (!isDisabled) {
|
|
|
+ await formatButton.click()
|
|
|
+ // 格式化后内容应该保持有效
|
|
|
+ await page.waitForTimeout(300)
|
|
|
+ }
|
|
|
+ })
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 测试 CodeEditor JSON 模式 - 无效JSON显示错误提示
|
|
|
+ */
|
|
|
+ test('CodeEditor JSON模式 - 无效JSON显示错误提示', async ({ page }) => {
|
|
|
+ await login(page)
|
|
|
+ await page.goto('/lss')
|
|
|
+
|
|
|
+ // 等待表格加载
|
|
|
+ await page.waitForTimeout(1000)
|
|
|
+
|
|
|
+ // 点击 Device List 按钮
|
|
|
+ const deviceListButton = page.locator('tbody tr').first().locator('button').first()
|
|
|
+ await deviceListButton.click()
|
|
|
+
|
|
|
+ // 等待设备列表面板打开
|
|
|
+ const devicePanel = page.locator('.el-drawer, .el-dialog').filter({ hasText: 'Camera List' })
|
|
|
+ await expect(devicePanel).toBeVisible({ timeout: 5000 })
|
|
|
+
|
|
|
+ // 点击 Parameter Configuration 的 View 按钮
|
|
|
+ const viewButton = devicePanel.locator('tbody tr').first().locator('button:has-text("View")').first()
|
|
|
+ await viewButton.click()
|
|
|
+
|
|
|
+ // 等待参数配置抽屉打开
|
|
|
+ const paramsDrawer = page.locator('.el-drawer').filter({ hasText: '参数配置' })
|
|
|
+ await expect(paramsDrawer).toBeVisible({ timeout: 5000 })
|
|
|
+
|
|
|
+ // 获取编辑器并输入无效JSON
|
|
|
+ const codeEditor = paramsDrawer.locator('.code-editor')
|
|
|
+ const editorContent = codeEditor.locator('.cm-content')
|
|
|
+
|
|
|
+ // 清空并输入无效JSON
|
|
|
+ await editorContent.click()
|
|
|
+ await page.keyboard.press('Meta+a')
|
|
|
+ await page.keyboard.type('{ invalid json }')
|
|
|
+
|
|
|
+ // 验证错误提示显示
|
|
|
+ await expect(codeEditor.locator('.validation-error')).toBeVisible({ timeout: 3000 })
|
|
|
+ await expect(codeEditor.locator('.validation-error')).toContainText('JSON 格式错误')
|
|
|
+
|
|
|
+ // 验证格式化按钮被禁用
|
|
|
+ const formatButton = codeEditor.locator('button:has-text("格式化")')
|
|
|
+ await expect(formatButton).toBeDisabled()
|
|
|
+ })
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 测试 CodeEditor JSON 模式 - 更新内容并验证保存成功
|
|
|
+ */
|
|
|
+ test('CodeEditor JSON模式 - 更新参数配置并验证保存成功', async ({ page }) => {
|
|
|
+ await login(page)
|
|
|
+ await page.goto('/lss')
|
|
|
+
|
|
|
+ // 等待表格加载
|
|
|
+ await page.waitForTimeout(1000)
|
|
|
+
|
|
|
+ // 点击 Device List 按钮
|
|
|
+ const deviceListButton = page.locator('tbody tr').first().locator('button').first()
|
|
|
+ await deviceListButton.click()
|
|
|
+
|
|
|
+ // 等待设备列表面板打开
|
|
|
+ const devicePanel = page.locator('.el-drawer, .el-dialog').filter({ hasText: 'Camera List' })
|
|
|
+ await expect(devicePanel).toBeVisible({ timeout: 5000 })
|
|
|
+
|
|
|
+ // 点击 Parameter Configuration 的 View 按钮
|
|
|
+ const viewButton = devicePanel.locator('tbody tr').first().locator('button:has-text("View")').first()
|
|
|
+ await viewButton.click()
|
|
|
+
|
|
|
+ // 等待参数配置抽屉打开
|
|
|
+ const paramsDrawer = page.locator('.el-drawer').filter({ hasText: '参数配置' })
|
|
|
+ await expect(paramsDrawer).toBeVisible({ timeout: 5000 })
|
|
|
+
|
|
|
+ // 获取当前编辑器内容
|
|
|
+ const codeEditor = paramsDrawer.locator('.code-editor')
|
|
|
+ const editorContent = codeEditor.locator('.cm-content')
|
|
|
+
|
|
|
+ // 生成唯一标识用于验证更新
|
|
|
+ const timestamp = Date.now()
|
|
|
+ const testValue = `"testUpdate": "${timestamp}"`
|
|
|
+
|
|
|
+ // 修改JSON内容 - 在现有JSON中添加测试字段
|
|
|
+ await editorContent.click()
|
|
|
+ await page.keyboard.press('Meta+a')
|
|
|
+ // 输入新的有效JSON内容
|
|
|
+ await page.keyboard.type(`{\n ${testValue},\n "ip": "192.168.0.64"\n}`)
|
|
|
+
|
|
|
+ // 点击更新按钮
|
|
|
+ const updateButton = paramsDrawer.locator('button:has-text("更新"), button:has-text("Update")')
|
|
|
+ await updateButton.click()
|
|
|
+
|
|
|
+ // 等待更新成功提示
|
|
|
+ await expect(page.locator('.el-message--success')).toBeVisible({ timeout: 5000 })
|
|
|
+
|
|
|
+ // 等待抽屉关闭
|
|
|
+ await expect(paramsDrawer).not.toBeVisible({ timeout: 5000 })
|
|
|
+
|
|
|
+ // 重新打开参数配置抽屉验证内容已保存
|
|
|
+ await page.waitForTimeout(500)
|
|
|
+ await viewButton.click()
|
|
|
+
|
|
|
+ // 等待抽屉重新打开
|
|
|
+ const paramsDrawerReopened = page.locator('.el-drawer').filter({ hasText: '参数配置' })
|
|
|
+ await expect(paramsDrawerReopened).toBeVisible({ timeout: 5000 })
|
|
|
+
|
|
|
+ // 验证内容包含我们添加的测试字段
|
|
|
+ const editorContentReopened = paramsDrawerReopened.locator('.cm-content')
|
|
|
+ await expect(editorContentReopened).toContainText(timestamp.toString())
|
|
|
+ })
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 测试 CodeEditor JSON 模式 - 运行参数更新并验证保存成功
|
|
|
+ */
|
|
|
+ test('CodeEditor JSON模式 - 更新运行参数并验证保存成功', async ({ page }) => {
|
|
|
+ await login(page)
|
|
|
+ await page.goto('/lss')
|
|
|
+
|
|
|
+ // 等待表格加载
|
|
|
+ await page.waitForTimeout(1000)
|
|
|
+
|
|
|
+ // 点击 Device List 按钮
|
|
|
+ const deviceListButton = page.locator('tbody tr').first().locator('button').first()
|
|
|
+ await deviceListButton.click()
|
|
|
+
|
|
|
+ // 等待设备列表面板打开
|
|
|
+ const devicePanel = page.locator('.el-drawer, .el-dialog').filter({ hasText: 'Camera List' })
|
|
|
+ await expect(devicePanel).toBeVisible({ timeout: 5000 })
|
|
|
+
|
|
|
+ // 点击 Run Parameters 的 View 按钮(第二个 View 按钮)
|
|
|
+ const viewButtons = devicePanel.locator('tbody tr').first().locator('button:has-text("View")')
|
|
|
+ const runParamsViewButton = viewButtons.nth(1)
|
|
|
+ await expect(runParamsViewButton).toBeVisible({ timeout: 5000 })
|
|
|
+ await runParamsViewButton.click()
|
|
|
+
|
|
|
+ // 等待运行参数抽屉打开
|
|
|
+ const paramsDrawer = page.locator('.el-drawer').filter({ hasText: '运行参数' })
|
|
|
+ await expect(paramsDrawer).toBeVisible({ timeout: 5000 })
|
|
|
+
|
|
|
+ // 获取编辑器
|
|
|
+ const codeEditor = paramsDrawer.locator('.code-editor')
|
|
|
+ const editorContent = codeEditor.locator('.cm-content')
|
|
|
+
|
|
|
+ // 生成唯一标识用于验证更新
|
|
|
+ const timestamp = Date.now()
|
|
|
+ const testValue = `"runtimeTest": "${timestamp}"`
|
|
|
+
|
|
|
+ // 修改JSON内容
|
|
|
+ await editorContent.click()
|
|
|
+ await page.keyboard.press('Meta+a')
|
|
|
+ await page.keyboard.type(`{\n ${testValue}\n}`)
|
|
|
+
|
|
|
+ // 点击更新按钮
|
|
|
+ const updateButton = paramsDrawer.locator('button:has-text("更新"), button:has-text("Update")')
|
|
|
+ await updateButton.click()
|
|
|
+
|
|
|
+ // 等待更新成功提示
|
|
|
+ await expect(page.locator('.el-message--success')).toBeVisible({ timeout: 5000 })
|
|
|
+
|
|
|
+ // 等待抽屉关闭
|
|
|
+ await expect(paramsDrawer).not.toBeVisible({ timeout: 5000 })
|
|
|
+
|
|
|
+ // 重新打开运行参数抽屉验证内容已保存
|
|
|
+ await page.waitForTimeout(500)
|
|
|
+ await runParamsViewButton.click()
|
|
|
+
|
|
|
+ // 等待抽屉重新打开
|
|
|
+ const paramsDrawerReopened = page.locator('.el-drawer').filter({ hasText: '运行参数' })
|
|
|
+ await expect(paramsDrawerReopened).toBeVisible({ timeout: 5000 })
|
|
|
+
|
|
|
+ // 验证内容包含我们添加的测试字段
|
|
|
+ const editorContentReopened = paramsDrawerReopened.locator('.cm-content')
|
|
|
+ await expect(editorContentReopened).toContainText(timestamp.toString())
|
|
|
+ })
|
|
|
+})
|