import { test, expect } from '../../utils/test-setup'; import { readFileSync } from 'fs'; import { join, dirname } from 'path'; import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const testUsers = JSON.parse(readFileSync(join(__dirname, '../../fixtures/test-users.json'), 'utf-8')); /** * 生成唯一区域名称 * @param prefix - 名称前缀 * @returns 唯一的区域名称 */ function generateUniqueRegionName(prefix: string = '测试区域'): string { const timestamp = Date.now(); const random = Math.floor(Math.random() * 1000); return `${prefix}_${timestamp}_${random}`; } /** * 生成唯一区域代码 * @param level - 区域层级 * @returns 唯一的区域代码 */ function generateUniqueRegionCode(level: string): string { const timestamp = Date.now(); return `${level.toUpperCase()}_${timestamp}`; } test.describe.serial('编辑区域测试', () => { // 用于跟踪测试创建的区域,以便清理 const createdProvinces: string[] = []; test.beforeEach(async ({ adminLoginPage, regionManagementPage }) => { // 以管理员身份登录后台 await adminLoginPage.goto(); await adminLoginPage.login(testUsers.admin.username, testUsers.admin.password); await adminLoginPage.expectLoginSuccess(); await regionManagementPage.goto(); await regionManagementPage.waitForTreeLoaded(); }); test.afterEach(async ({ regionManagementPage }) => { // 清理测试创建的数据 let cleanupSuccessCount = 0; let cleanupFailCount = 0; for (const provinceName of createdProvinces) { try { // 等待树形结构就绪后检查区域是否存在 await regionManagementPage.waitForTreeLoaded(); const exists = await regionManagementPage.regionExists(provinceName); if (exists) { const deleteSuccess = await regionManagementPage.deleteRegion(provinceName); if (deleteSuccess) { cleanupSuccessCount++; console.debug(`✅ 已清理测试数据: ${provinceName}`); } else { cleanupFailCount++; console.debug(`⚠️ 删除失败(无成功提示): ${provinceName}`); } } else { console.debug(`ℹ️ 区域不存在,跳过删除: ${provinceName}`); } } catch (error) { cleanupFailCount++; console.debug(`❌ 清理异常: ${provinceName}`, error); } } // 记录清理结果摘要 console.debug(`🧹 测试数据清理: 成功 ${cleanupSuccessCount}, 失败 ${cleanupFailCount}`); // 如果有清理失败,记录警告但不阻塞测试 if (cleanupFailCount > 0) { console.debug(`⚠️ 有 ${cleanupFailCount} 个区域清理失败,可能产生脏数据`); } // 清空跟踪列表 createdProvinces.length = 0; }); test.describe('编辑区域名称', () => { test('应该成功编辑区域名称', async ({ regionManagementPage }) => { // 首先创建一个测试省份 const originalName = generateUniqueRegionName('测试省'); await regionManagementPage.createProvince({ name: originalName, code: generateUniqueRegionCode('PROV'), level: 1, }); createdProvinces.push(originalName); // 刷新树形结构以显示新创建的省份 await regionManagementPage.refreshTree(); // 编辑区域名称 const newName = generateUniqueRegionName('编辑后的省'); const result = await regionManagementPage.editRegion(originalName, { name: newName, }); // 验证编辑成功 expect(result.success).toBe(true); expect(result.hasError).toBe(false); // 等待树形结构刷新 await regionManagementPage.waitForTreeLoaded(); // 验证列表中显示新名称 const exists = await regionManagementPage.regionExists(newName); expect(exists).toBe(true); // 更新清理列表中的名称 const index = createdProvinces.indexOf(originalName); if (index > -1) { createdProvinces[index] = newName; } }); test('编辑后原名称不应存在', async ({ regionManagementPage }) => { const originalName = generateUniqueRegionName('测试省'); await regionManagementPage.createProvince({ name: originalName, code: generateUniqueRegionCode('PROV'), level: 1, }); createdProvinces.push(originalName); // 刷新树形结构以显示新创建的省份 await regionManagementPage.refreshTree(); const newName = generateUniqueRegionName('编辑后的省'); const result = await regionManagementPage.editRegion(originalName, { name: newName }); expect(result.success).toBe(true); await regionManagementPage.waitForTreeLoaded(); // 验证原名称不存在 const originalExists = await regionManagementPage.regionExists(originalName); expect(originalExists).toBe(false); // 验证新名称存在 const newExists = await regionManagementPage.regionExists(newName); expect(newExists).toBe(true); // 更新清理列表 const index = createdProvinces.indexOf(originalName); if (index > -1) { createdProvinces[index] = newName; } }); }); test.describe('修改区域代码', () => { test('应该成功修改行政区划代码', async ({ regionManagementPage }) => { const provinceName = generateUniqueRegionName('测试省'); await regionManagementPage.createProvince({ name: provinceName, code: 'OLD_CODE', level: 1, }); createdProvinces.push(provinceName); await regionManagementPage.waitForTreeLoaded(); // 修改代码 const newCode = generateUniqueRegionCode('NEW'); const result = await regionManagementPage.editRegion(provinceName, { code: newCode, }); expect(result.success).toBe(true); expect(result.hasError).toBe(false); }); test('应该能同时修改名称和代码', async ({ regionManagementPage }) => { const originalName = generateUniqueRegionName('测试省'); await regionManagementPage.createProvince({ name: originalName, code: 'OLD_CODE', level: 1, }); createdProvinces.push(originalName); await regionManagementPage.waitForTreeLoaded(); const newName = generateUniqueRegionName('新省名'); const newCode = generateUniqueRegionCode('NEW'); const result = await regionManagementPage.editRegion(originalName, { name: newName, code: newCode, }); expect(result.success).toBe(true); expect(result.hasError).toBe(false); await regionManagementPage.waitForTreeLoaded(); expect(await regionManagementPage.regionExists(newName)).toBe(true); // 更新清理列表 const index = createdProvinces.indexOf(originalName); if (index > -1) { createdProvinces[index] = newName; } }); }); test.describe('区域状态切换', () => { test('应该成功禁用已启用的区域', async ({ regionManagementPage }) => { const provinceName = generateUniqueRegionName('测试省'); console.debug(`创建省份: ${provinceName}`); await regionManagementPage.createProvince({ name: provinceName, code: generateUniqueRegionCode('PROV'), level: 1, }); createdProvinces.push(provinceName); // 等待树形结构加载完成 await regionManagementPage.waitForTreeLoaded(); // 验证区域存在并获取初始状态 const exists = await regionManagementPage.regionExists(provinceName); expect(exists).toBe(true); const initialStatus = await regionManagementPage.getRegionStatus(provinceName); expect(initialStatus).toBe('启用'); // 禁用区域 const success = await regionManagementPage.toggleRegionStatus(provinceName); expect(success).toBe(true); // 等待树形结构刷新(toggleRegionStatus 内部已等待) await regionManagementPage.waitForTreeLoaded(); // 验证状态已更新 const newStatus = await regionManagementPage.getRegionStatus(provinceName); expect(newStatus).toBe('禁用'); }); test('应该成功启用已禁用的区域', async ({ regionManagementPage }) => { const provinceName = generateUniqueRegionName('测试省'); await regionManagementPage.createProvince({ name: provinceName, code: generateUniqueRegionCode('PROV'), level: 1, }); createdProvinces.push(provinceName); await regionManagementPage.waitForTreeLoaded(); // 先禁用 await regionManagementPage.toggleRegionStatus(provinceName); await regionManagementPage.waitForTreeLoaded(); // 验证已禁用 const disabledStatus = await regionManagementPage.getRegionStatus(provinceName); expect(disabledStatus).toBe('禁用'); // 再启用 const success = await regionManagementPage.toggleRegionStatus(provinceName); expect(success).toBe(true); await regionManagementPage.waitForTreeLoaded(); // 验证状态已恢复为启用 const status = await regionManagementPage.getRegionStatus(provinceName); expect(status).toBe('启用'); }); test('取消状态切换应保持原状态', async ({ regionManagementPage }) => { const provinceName = generateUniqueRegionName('测试省'); await regionManagementPage.createProvince({ name: provinceName, code: generateUniqueRegionCode('PROV'), level: 1, }); createdProvinces.push(provinceName); await regionManagementPage.waitForTreeLoaded(); const initialStatus = await regionManagementPage.getRegionStatus(provinceName); expect(initialStatus).toBe('启用'); // 打开状态切换对话框但取消 await regionManagementPage.openToggleStatusDialog(provinceName); await regionManagementPage.cancelToggleStatus(); // 验证状态未改变(不需要刷新页面) const currentStatus = await regionManagementPage.getRegionStatus(provinceName); expect(currentStatus).toBe(initialStatus); }); }); test.describe.skip('编辑子区域 - TODO: 需要修复 createChildRegion 功能', () => { test('应该成功编辑市级区域名称', async ({ regionManagementPage, page }) => { const provinceName = generateUniqueRegionName('测试省'); const originalCityName = generateUniqueRegionName('测试市'); // 创建省和市 await regionManagementPage.createProvince({ name: provinceName, code: generateUniqueRegionCode('PROV'), level: 1, }); createdProvinces.push(provinceName); await page.goto('/admin/areas'); await regionManagementPage.waitForTreeLoaded(); // 创建市后,先展开省节点验证市已创建 const cityResult = await regionManagementPage.createChildRegion(provinceName, '市', { name: originalCityName, code: generateUniqueRegionCode('CITY'), level: 2, }); expect(cityResult.success).toBe(true); await page.goto('/admin/areas'); await regionManagementPage.waitForTreeLoaded(); // 直接展开新创建的省节点(滚动到可见区域) await regionManagementPage.expandNode(provinceName); await page.waitForTimeout(1000); // 验证市级区域可见 const cityVisible = await regionManagementPage.regionExists(originalCityName); console.debug(`市级区域 "${originalCityName}" 可见: ${cityVisible}`); expect(cityVisible).toBe(true); // 编辑城市名称 const newCityName = generateUniqueRegionName('编辑后的市'); const result = await regionManagementPage.editRegion(originalCityName, { name: newCityName, }); expect(result.success).toBe(true); expect(result.hasError).toBe(false); }); test('应该成功编辑区级区域状态', async ({ regionManagementPage, page }) => { const provinceName = generateUniqueRegionName('测试省'); const cityName = generateUniqueRegionName('测试市'); const districtName = generateUniqueRegionName('测试区'); // 创建省市区三级结构 await regionManagementPage.createProvince({ name: provinceName, code: generateUniqueRegionCode('PROV'), level: 1, }); createdProvinces.push(provinceName); await page.goto('/admin/areas'); await regionManagementPage.waitForTreeLoaded(); const cityResult = await regionManagementPage.createChildRegion(provinceName, '市', { name: cityName, code: generateUniqueRegionCode('CITY'), level: 2, }); expect(cityResult.success).toBe(true); await page.goto('/admin/areas'); await regionManagementPage.waitForTreeLoaded(); const districtResult = await regionManagementPage.createChildRegion(provinceName, '市', { name: districtName, code: generateUniqueRegionCode('DISTRICT'), level: 3, }); expect(districtResult.success).toBe(true); await page.goto('/admin/areas'); await regionManagementPage.waitForTreeLoaded(); // 展开省节点 await regionManagementPage.expandNode(provinceName); await page.waitForTimeout(1000); // 切换区的状态 const success = await regionManagementPage.toggleRegionStatus(districtName); expect(success).toBe(true); }); }); test.describe('表单验证', () => { test('清空名称时应显示错误提示', async ({ regionManagementPage }) => { const provinceName = generateUniqueRegionName('测试省'); await regionManagementPage.createProvince({ name: provinceName, code: generateUniqueRegionCode('PROV'), level: 1, }); createdProvinces.push(provinceName); await regionManagementPage.waitForTreeLoaded(); // 打开编辑对话框并清空名称 await regionManagementPage.openEditDialog(provinceName); await regionManagementPage.page.getByLabel('区域名称').fill(''); // 提交表单 const submitButton = regionManagementPage.page.getByRole('button', { name: '更新' }); await submitButton.click(); // 验证错误提示 - 可能是内联错误或 toast await regionManagementPage.page.waitForTimeout(500); // 检查内联错误 const nameError = regionManagementPage.page.getByText('区域名称不能为空'); const hasInlineError = await nameError.count() > 0; // 检查 toast 错误 const errorToast = regionManagementPage.page.locator('[data-sonner-toast][data-type="error"]'); const hasToastError = await errorToast.count() > 0; // 至少应该有一种错误提示 expect(hasInlineError || hasToastError).toBe(true); // 取消对话框 await regionManagementPage.cancelDialog(); }); test('应该支持取消编辑操作', async ({ regionManagementPage }) => { const provinceName = generateUniqueRegionName('测试省'); await regionManagementPage.createProvince({ name: provinceName, code: generateUniqueRegionCode('PROV'), level: 1, }); createdProvinces.push(provinceName); await regionManagementPage.waitForTreeLoaded(); // 打开编辑对话框 await regionManagementPage.openEditDialog(provinceName); // 修改名称 const newName = generateUniqueRegionName('修改后的省'); await regionManagementPage.page.getByLabel('区域名称').fill(newName); // 点击取消按钮 await regionManagementPage.cancelDialog(); // 验证对话框已关闭 const dialog = regionManagementPage.page.locator('[role="dialog"]'); await expect(dialog).not.toBeVisible(); // 验证数据未修改 - 原名称仍存在 await regionManagementPage.waitForTreeLoaded(); const originalExists = await regionManagementPage.regionExists(provinceName); expect(originalExists).toBe(true); }); }); test.describe('连续编辑操作', () => { test('应该能连续编辑多个区域', async ({ regionManagementPage }) => { // 创建多个省份 const province1 = generateUniqueRegionName('测试省1'); const province2 = generateUniqueRegionName('测试省2'); await regionManagementPage.createProvince({ name: province1, code: generateUniqueRegionCode('PROV1'), level: 1, }); createdProvinces.push(province1); await regionManagementPage.waitForTreeLoaded(); await regionManagementPage.createProvince({ name: province2, code: generateUniqueRegionCode('PROV2'), level: 1, }); createdProvinces.push(province2); await regionManagementPage.waitForTreeLoaded(); // 编辑第一个省份 const newProvince1Name = generateUniqueRegionName('编辑后的省1'); const result1 = await regionManagementPage.editRegion(province1, { name: newProvince1Name }); expect(result1.success).toBe(true); // 更新清理列表 const index1 = createdProvinces.indexOf(province1); if (index1 > -1) { createdProvinces[index1] = newProvince1Name; } // 编辑第二个省份 const newProvince2Name = generateUniqueRegionName('编辑后的省2'); const result2 = await regionManagementPage.editRegion(province2, { name: newProvince2Name }); expect(result2.success).toBe(true); // 更新清理列表 const index2 = createdProvinces.indexOf(province2); if (index2 > -1) { createdProvinces[index2] = newProvince2Name; } }); }); });