import { TIMEOUTS } from '../../utils/timeouts'; 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')); /** * Story 9.5: 残疾人管理完整 CRUD 流程测试 * * 验收标准: * 1. 新增残疾人完整流程(基本信息 + 照片 + 银行卡 + 备注) * 2. 编辑残疾人信息 * 3. 删除残疾人 * 4. 查看残疾人详情 * 5. 列表查询与筛选 * 6. 数据导出(如功能可用) */ test.describe('残疾人管理 - 完整 CRUD 流程测试', () => { // 测试级别的时间戳,用于生成唯一数据 const TIMESTAMP = Date.now(); const UNIQUE_ID = `test_crud_${TIMESTAMP}`; // 用于跟踪已创建的测试数据,便于清理 const createdTestData: Array<{ name: string }> = []; // 测试数据生成函数 const generateTestPerson = (suffix: string) => ({ name: `${UNIQUE_ID}_${suffix}`, gender: '男', idCard: `42010119900101${String(TIMESTAMP + suffix.length).slice(-4)}`, disabilityId: `1234567890${TIMESTAMP + suffix.length}`, disabilityType: '肢体残疾', disabilityLevel: '一级', phone: `138${String(TIMESTAMP + suffix.length).slice(-8).padStart(8, '0')}`, idAddress: `湖北省武汉市测试街道${suffix}号`, province: '湖北省', city: '武汉市', }); test.beforeEach(async ({ adminLoginPage, disabilityPersonPage }) => { // 每次测试前重置数据存储 createdTestData.length = 0; await adminLoginPage.goto(); await adminLoginPage.login(testUsers.admin.username, testUsers.admin.password); await adminLoginPage.expectLoginSuccess(); await disabilityPersonPage.goto(); }); // 统一的测试后清理机制(优化超时保护) test.afterEach(async ({ disabilityPersonPage, page }) => { // 清理测试数据(添加超时保护以避免 afterEach 超过 60 秒) for (const data of createdTestData) { try { await disabilityPersonPage.goto().catch(() => {}); await disabilityPersonPage.searchByName(data.name); // 为每个清理操作设置较短的超时时间 const deleteButton = page.getByRole('button', { name: '删除' }).first(); if (await deleteButton.count({ timeout: TIMEOUTS.VERY_LONG }) > 0) { await deleteButton.click({ timeout: TIMEOUTS.DIALOG }); await page.getByRole('button', { name: '确认' }).click({ timeout: TIMEOUTS.DIALOG }).catch(() => {}); await page.waitForTimeout(TIMEOUTS.MEDIUM); } } catch (error) { console.debug(` ⚠ 清理数据失败: ${data.name}`, error); } } // 清空数组 createdTestData.length = 0; }); test.describe('AC1: 新增残疾人完整流程', () => { test('应该成功完成新增残疾人完整流程(基本信息 + 备注 + 银行卡)', async ({ disabilityPersonPage, page }) => { const testData = generateTestPerson('full'); createdTestData.push({ name: testData.name }); console.debug('\n========== 测试:新增残疾人完整流程(所有功能) =========='); // 1. 打开新增对话框 await disabilityPersonPage.openCreateDialog(); console.debug('✓ 对话框已打开'); // 2. 填写基本信息 await disabilityPersonPage.fillBasicForm(testData); console.debug('✓ 基本信息已填写'); // 3. 添加银行卡(使用 Page Object 方法) await disabilityPersonPage.scrollToSection('银行卡'); await disabilityPersonPage.addBankCard({ bankName: '中国工商银行', subBankName: '测试支行', cardNumber: '6222021234567890123', cardholderName: testData.name, cardType: '一类卡', isDefault: true, }); console.debug('✓ 银行卡已添加'); // 4. 添加备注 await disabilityPersonPage.scrollToSection('备注'); await disabilityPersonPage.addNote(`完整测试备注_${UNIQUE_ID}`); console.debug('✓ 备注已添加'); // 5. 提交表单 const result = await disabilityPersonPage.submitForm(); // 6. 验证提交结果 console.debug('提交结果:', { hasSuccess: result.hasSuccess, hasError: result.hasError }); if (result.hasError) { console.debug('错误消息:', result.errorMessage); } // 7. 等待对话框关闭 await disabilityPersonPage.waitForDialogClosed(); // 8. 刷新页面并搜索新创建的记录(使用重试机制修复数据持久化问题) await page.reload(); await page.waitForLoadState('networkidle'); await disabilityPersonPage.goto(); // 9. 使用带重试机制的等待方法验证记录创建成功 const personExists = await disabilityPersonPage.waitForPersonExists(testData.name, { timeout: TIMEOUTS.PAGE_LOAD }); console.debug('========== 验证结果 =========='); console.debug('数据创建成功:', personExists); expect(personExists).toBe(true); console.debug('✓ AC1 完整流程测试通过(基本信息 + 银行卡 + 备注)'); // 注意:数据清理由 test.afterEach 统一处理 }); test('应该成功完成新增残疾人完整流程(基本信息)', async ({ disabilityPersonPage, page }) => { const testData = generateTestPerson('create'); createdTestData.push({ name: testData.name }); console.debug('\n========== 测试:新增残疾人完整流程 =========='); // 1. 打开新增对话框 await disabilityPersonPage.openCreateDialog(); console.debug('✓ 对话框已打开'); // 2. 填写基本信息 await disabilityPersonPage.fillBasicForm(testData); console.debug('✓ 基本信息已填写'); // 3. 提交表单 const result = await disabilityPersonPage.submitForm(); // 4. 验证提交结果 console.debug('提交结果:', { hasSuccess: result.hasSuccess, hasError: result.hasError }); if (result.hasError) { console.debug('错误消息:', result.errorMessage); } // 5. 等待对话框关闭 await disabilityPersonPage.waitForDialogClosed(); // 6. 刷新页面并搜索新创建的记录(使用重试机制修复数据持久化问题) await page.reload(); await page.waitForLoadState('networkidle'); await disabilityPersonPage.goto(); // 7. 使用带重试机制的等待方法验证记录创建成功 const personExists = await disabilityPersonPage.waitForPersonExists(testData.name, { timeout: TIMEOUTS.PAGE_LOAD }); console.debug('========== 验证结果 =========='); console.debug('数据创建成功:', personExists); expect(personExists).toBe(true); }); test('应该成功完成新增残疾人完整流程(含备注)', async ({ disabilityPersonPage, page }) => { const testData = generateTestPerson('with_note'); createdTestData.push({ name: testData.name }); console.debug('\n========== 测试:新增残疾人(含备注) =========='); // 1. 打开新增对话框 await disabilityPersonPage.openCreateDialog(); // 2. 填写基本信息 await disabilityPersonPage.fillBasicForm(testData); // 3. 添加备注 await disabilityPersonPage.scrollToSection('备注'); await disabilityPersonPage.addNote(`测试备注_${UNIQUE_ID}`); console.debug('✓ 备注已添加'); // 4. 提交表单 const result = await disabilityPersonPage.submitForm(); // 5. 验证结果(使用重试机制修复数据持久化问题) await disabilityPersonPage.waitForDialogClosed(); await page.reload(); await page.waitForLoadState('networkidle'); await disabilityPersonPage.goto(); // 使用带重试机制的等待方法验证记录创建成功 const personExists = await disabilityPersonPage.waitForPersonExists(testData.name, { timeout: TIMEOUTS.PAGE_LOAD }); expect(personExists).toBe(true); console.debug('✓ 含备注的残疾人创建成功'); }); }); test.describe('AC2: 编辑残疾人信息', () => { test('应该成功编辑残疾人基本信息', async ({ disabilityPersonPage, page }) => { const testData = generateTestPerson('edit'); createdTestData.push({ name: testData.name }); const newName = `${UNIQUE_ID}_edited`; console.debug('\n========== 测试:编辑残疾人信息 =========='); // 1. 先创建一条记录 await disabilityPersonPage.openCreateDialog(); await disabilityPersonPage.fillBasicForm(testData); await disabilityPersonPage.submitForm(); await disabilityPersonPage.waitForDialogClosed(); // 刷新并搜索(使用重试机制修复数据持久化问题) await page.reload(); await page.waitForLoadState('networkidle'); await disabilityPersonPage.goto(); let personExists = await disabilityPersonPage.waitForPersonExists(testData.name, { timeout: TIMEOUTS.PAGE_LOAD }); expect(personExists).toBe(true); console.debug('✓ 原始记录已创建'); // 2. 打开编辑对话框 await disabilityPersonPage.openEditDialog(testData.name); console.debug('✓ 编辑对话框已打开'); // 3. 修改姓名(使用编辑表单) const form = page.locator('form#update-form'); await form.waitFor({ state: 'visible', timeout: TIMEOUTS.DIALOG }); const nameInput = form.getByLabel('姓名 *'); await nameInput.clear(); await nameInput.fill(newName); console.debug('✓ 姓名已修改为:', newName); // 4. 提交更新 const submitButton = page.getByRole('button', { name: '更新' }); await submitButton.click(); await page.waitForLoadState('networkidle', { timeout: TIMEOUTS.TABLE_LOAD }); await page.waitForTimeout(TIMEOUTS.VERY_LONG); console.debug('✓ 更新已提交'); // 5. 验证更新后的记录 await disabilityPersonPage.goto(); await disabilityPersonPage.searchByName(newName); await page.waitForTimeout(TIMEOUTS.LONG); const updatedExists = await disabilityPersonPage.personExists(newName); expect(updatedExists).toBe(true); console.debug('✓ 编辑成功:新姓名显示在列表中'); }); test('应该成功编辑并添加备注', async ({ disabilityPersonPage, page }) => { const testData = generateTestPerson('edit_note'); createdTestData.push({ name: testData.name }); console.debug('\n========== 测试:编辑并添加备注 =========='); // 1. 先创建一条记录 await disabilityPersonPage.openCreateDialog(); await disabilityPersonPage.fillBasicForm(testData); await disabilityPersonPage.submitForm(); await disabilityPersonPage.waitForDialogClosed(); await page.reload(); await page.waitForLoadState('networkidle'); await disabilityPersonPage.goto(); await disabilityPersonPage.searchByName(testData.name); // 增加等待时间以确保数据已持久化(修复稳定性问题) await page.waitForTimeout(TIMEOUTS.EXTENDED); // 2. 打开编辑对话框 await disabilityPersonPage.openEditDialog(testData.name); // 3. 添加备注 await disabilityPersonPage.scrollToSection('银行卡'); await page.waitForTimeout(TIMEOUTS.SHORT); await disabilityPersonPage.scrollToSection('备注'); await disabilityPersonPage.addNote(`编辑时添加的备注_${UNIQUE_ID}`); console.debug('✓ 编辑时添加了备注'); // 4. 提交更新 const submitButton = page.getByRole('button', { name: '更新' }); await submitButton.click(); await page.waitForLoadState('networkidle', { timeout: TIMEOUTS.TABLE_LOAD }); await page.waitForTimeout(TIMEOUTS.VERY_LONG); // 5. 验证更新成功(使用重试机制修复数据持久化问题) const stillExists = await disabilityPersonPage.waitForPersonExists(testData.name, { timeout: TIMEOUTS.TABLE_LOAD }); expect(stillExists).toBe(true); console.debug('✓ 编辑时添加备注成功'); }); }); test.describe('AC3: 删除残疾人', () => { test('应该成功删除残疾人记录', async ({ disabilityPersonPage, page }) => { const testData = generateTestPerson('delete'); createdTestData.push({ name: testData.name }); console.debug('\n========== 测试:删除残疾人记录 =========='); // 1. 先创建一条记录 await disabilityPersonPage.openCreateDialog(); await disabilityPersonPage.fillBasicForm(testData); await disabilityPersonPage.submitForm(); await disabilityPersonPage.waitForDialogClosed(); await page.reload(); await page.waitForLoadState('networkidle'); await disabilityPersonPage.goto(); // 2. 获取初始列表数量 const initialCount = await disabilityPersonPage.getListCount(); console.debug('初始记录数:', initialCount); // 搜索并验证记录存在(使用重试机制修复数据持久化问题) let personExists = await disabilityPersonPage.waitForPersonExists(testData.name, { timeout: TIMEOUTS.PAGE_LOAD }); expect(personExists).toBe(true); console.debug('✓ 记录已创建,准备删除'); // 3. 删除记录 await disabilityPersonPage.deleteDisabilityPerson(testData.name); console.debug('✓ 删除操作已执行'); // 4. 验证删除后列表数量减少 await disabilityPersonPage.goto(); await page.waitForLoadState('networkidle'); const finalCount = await disabilityPersonPage.getListCount(); console.debug('删除后记录数:', finalCount); expect(finalCount).toBeLessThanOrEqual(initialCount); // 5. 验证记录不再显示(使用重试机制修复数据持久化问题) personExists = await disabilityPersonPage.waitForPersonNotExists(testData.name, { timeout: TIMEOUTS.TABLE_LOAD }); expect(personExists).toBe(true); // 返回 true 表示确认已消失 console.debug('✓ 记录已成功删除,不再显示在列表中'); }); test('应该正确处理删除确认对话框', async ({ disabilityPersonPage, page }) => { const testData = generateTestPerson('delete_confirm'); createdTestData.push({ name: testData.name }); console.debug('\n========== 测试:删除确认对话框 =========='); // 1. 创建记录 await disabilityPersonPage.openCreateDialog(); await disabilityPersonPage.fillBasicForm(testData); await disabilityPersonPage.submitForm(); await disabilityPersonPage.waitForDialogClosed(); await page.reload(); await page.waitForLoadState('networkidle'); await disabilityPersonPage.goto(); await disabilityPersonPage.searchByName(testData.name); // 增加等待时间以确保数据已持久化(修复稳定性问题) await page.waitForTimeout(TIMEOUTS.EXTENDED); // 2. 点击删除按钮(但不确认) const row = disabilityPersonPage.personTable.locator('tbody tr').filter({ hasText: testData.name }).first(); const deleteButton = row.locator('[data-testid^="delete-person-"]').first(); await deleteButton.click(); // 3. 验证确认对话框出现 const confirmDialog = page.locator('[data-testid="delete-confirmation-dialog-title"]'); await expect(confirmDialog).toBeVisible({ timeout: TIMEOUTS.ELEMENT_VISIBLE_SHORT }); console.debug('✓ 删除确认对话框已显示'); // 4. 验证对话框内容 const dialogText = await page.locator('[role="dialog"]').textContent(); expect(dialogText).toContain('确定要删除'); expect(dialogText).toContain('此操作不可恢复'); console.debug('✓ 对话框文案正确'); // 5. 点击取消 const cancelButton = page.getByRole('button', { name: '取消' }); await cancelButton.click(); await page.waitForTimeout(TIMEOUTS.MEDIUM); // 6. 验证记录仍在列表中 const personExists = await disabilityPersonPage.personExists(testData.name); expect(personExists).toBe(true); console.debug('✓ 取消删除后记录仍存在'); // 7. 实际删除以清理测试数据 await disabilityPersonPage.deleteDisabilityPerson(testData.name); console.debug('✓ 测试数据已清理'); }); }); test.describe('AC4: 查看残疾人详情', () => { test('应该正确显示残疾人详情', async ({ disabilityPersonPage, page }) => { const testData = generateTestPerson('detail'); createdTestData.push({ name: testData.name }); console.debug('\n========== 测试:查看残疾人详情 =========='); // 1. 创建一条记录 await disabilityPersonPage.openCreateDialog(); await disabilityPersonPage.fillBasicForm(testData); await disabilityPersonPage.submitForm(); await disabilityPersonPage.waitForDialogClosed(); await page.reload(); await page.waitForLoadState('networkidle'); await disabilityPersonPage.goto(); await disabilityPersonPage.searchByName(testData.name); // 增加等待时间以确保数据已持久化(修复稳定性问题) await page.waitForTimeout(TIMEOUTS.EXTENDED); // 2. 打开详情对话框 await disabilityPersonPage.openDetailDialog(testData.name); console.debug('✓ 详情对话框已打开'); // 3. 验证详情对话框显示基本信息 const dialog = page.locator('[role="dialog"]').filter({ hasText: '残疾人详情' }); await expect(dialog).toBeVisible({ timeout: TIMEOUTS.DIALOG }); // 验证基本信息显示 const dialogText = await dialog.textContent(); expect(dialogText).toContain(testData.name); expect(dialogText).toContain(testData.idCard); expect(dialogText).toContain(testData.disabilityType); expect(dialogText).toContain(testData.disabilityLevel); expect(dialogText).toContain(testData.phone); console.debug('✓ 基本信息显示正确'); console.debug(' - 姓名:', testData.name); console.debug(' - 身份证号:', testData.idCard); console.debug(' - 残疾类型:', testData.disabilityType); console.debug(' - 残疾等级:', testData.disabilityLevel); // 4. 关闭详情对话框 const closeButton = page.getByRole('button', { name: '关闭' }); await closeButton.click(); await disabilityPersonPage.waitForDetailDialogClosed(); console.debug('✓ 详情对话框已关闭'); }); test('应该能在详情中查看完整信息', async ({ disabilityPersonPage, page }) => { const testData = generateTestPerson('full_detail'); createdTestData.push({ name: testData.name }); console.debug('\n========== 测试:查看完整详情信息 =========='); // 1. 创建带备注的记录 await disabilityPersonPage.openCreateDialog(); await disabilityPersonPage.fillBasicForm(testData); await disabilityPersonPage.scrollToSection('备注'); await disabilityPersonPage.addNote(`测试备注_${UNIQUE_ID}`); await disabilityPersonPage.submitForm(); await disabilityPersonPage.waitForDialogClosed(); await page.reload(); await page.waitForLoadState('networkidle'); await disabilityPersonPage.goto(); await disabilityPersonPage.searchByName(testData.name); // 增加等待时间以确保数据已持久化(修复稳定性问题) await page.waitForTimeout(TIMEOUTS.EXTENDED); // 2. 打开详情 await disabilityPersonPage.openDetailDialog(testData.name); // 3. 验证详情显示完整 const dialog = page.locator('[role="dialog"]').filter({ hasText: '残疾人详情' }); const dialogText = await dialog.textContent(); // 验证关键字段存在 expect(dialogText).toContain('姓名'); expect(dialogText).toContain('性别'); expect(dialogText).toContain('身份证号'); expect(dialogText).toContain('残疾证号'); expect(dialogText).toContain('联系电话'); console.debug('✓ 详情对话框显示所有基本字段'); // 4. 关闭对话框 await page.getByRole('button', { name: '关闭' }).click(); await disabilityPersonPage.waitForDetailDialogClosed(); }); }); test.describe('AC5: 列表查询与筛选', () => { test('应该支持按姓名搜索残疾人', async ({ disabilityPersonPage, page }) => { const testData = generateTestPerson('search'); createdTestData.push({ name: testData.name }); console.debug('\n========== 测试:按姓名搜索 =========='); // 1. 创建记录 await disabilityPersonPage.openCreateDialog(); await disabilityPersonPage.fillBasicForm(testData); await disabilityPersonPage.submitForm(); await disabilityPersonPage.waitForDialogClosed(); await page.reload(); await page.waitForLoadState('networkidle'); await disabilityPersonPage.goto(); // 2. 获取搜索前的列表数量 const countBeforeSearch = await disabilityPersonPage.getListCount(); console.debug('搜索前记录数:', countBeforeSearch); // 3. 执行搜索 await disabilityPersonPage.searchByName(testData.name); // 增加等待时间以确保数据已持久化(修复稳定性问题) await page.waitForTimeout(TIMEOUTS.EXTENDED); // 4. 验证搜索结果 const personExists = await disabilityPersonPage.personExists(testData.name); expect(personExists).toBe(true); console.debug('✓ 搜索成功:找到目标记录'); // 5. 验证搜索结果中只有目标记录 const searchResults = await disabilityPersonPage.getListData(); const matchingResults = searchResults.filter(r => r.name.includes(testData.name)); expect(matchingResults.length).toBeGreaterThan(0); console.debug(`✓ 搜索结果数量: ${matchingResults.length}`); }); test('应该支持按残疾类型筛选', async ({ disabilityPersonPage, page }) => { const testData = generateTestPerson('filter'); createdTestData.push({ name: testData.name }); console.debug('\n========== 测试:按残疾类型筛选 =========='); // 1. 创建记录(使用肢体残疾) await disabilityPersonPage.openCreateDialog(); await disabilityPersonPage.fillBasicForm({ ...testData, disabilityType: '肢体残疾', }); await disabilityPersonPage.submitForm(); await disabilityPersonPage.waitForDialogClosed(); await page.reload(); await page.waitForLoadState('networkidle'); await disabilityPersonPage.goto(); // 2. 获取筛选前的列表数量 await disabilityPersonPage.resetFilters(); await page.waitForTimeout(TIMEOUTS.LONG); const countBeforeFilter = await disabilityPersonPage.getListCount(); console.debug('筛选前记录数:', countBeforeFilter); // 3. 应用筛选(肢体残疾) await disabilityPersonPage.filterByDisabilityType('肢体残疾'); // 增加等待时间以确保数据已持久化(修复稳定性问题) await page.waitForTimeout(TIMEOUTS.EXTENDED); // 4. 验证筛选结果 const listData = await disabilityPersonPage.getListCount(); console.debug('筛选后记录数:', listData); // 验证结果中包含我们创建的记录 const personExists = await disabilityPersonPage.personExists(testData.name); expect(personExists).toBe(true); console.debug('✓ 筛选成功:找到目标记录'); // 5. 重置筛选 await disabilityPersonPage.resetFilters(); await page.waitForTimeout(TIMEOUTS.LONG); const countAfterReset = await disabilityPersonPage.getListCount(); console.debug('重置后记录数:', countAfterReset); }); test('应该支持重置筛选条件', async ({ disabilityPersonPage, page }) => { console.debug('\n========== 测试:重置筛选条件 =========='); // 1. 应用筛选 await disabilityPersonPage.filterByDisabilityType('肢体残疾'); await page.waitForTimeout(TIMEOUTS.LONG); const countAfterFilter = await disabilityPersonPage.getListCount(); console.debug('应用筛选后记录数:', countAfterFilter); // 2. 重置筛选 await disabilityPersonPage.resetFilters(); await page.waitForTimeout(TIMEOUTS.LONG); // 3. 验证重置后显示所有记录 const countAfterReset = await disabilityPersonPage.getListCount(); console.debug('重置后记录数:', countAfterReset); // 重置后数量应该恢复(或至少不减少) expect(countAfterReset).toBeGreaterThanOrEqual(countAfterFilter); console.debug('✓ 重置筛选成功'); }); test('应该正确获取列表数据', async ({ disabilityPersonPage, page }) => { const testData = generateTestPerson('list_data'); createdTestData.push({ name: testData.name }); console.debug('\n========== 测试:获取列表数据 =========='); // 1. 创建记录 await disabilityPersonPage.openCreateDialog(); await disabilityPersonPage.fillBasicForm(testData); await disabilityPersonPage.submitForm(); await disabilityPersonPage.waitForDialogClosed(); await page.reload(); await page.waitForLoadState('networkidle'); await disabilityPersonPage.goto(); // 2. 获取列表数据 const listData = await disabilityPersonPage.getListData(); console.debug('列表记录数:', listData.length); if (listData.length > 0) { console.debug('第一条记录:'); console.debug(' - 姓名:', listData[0].name); console.debug(' - 残疾类型:', listData[0].disabilityType); console.debug(' - 残疾等级:', listData[0].disabilityLevel); } // 3. 验证数据结构 expect(listData).toBeInstanceOf(Array); if (listData.length > 0) { expect(listData[0]).toHaveProperty('name'); expect(listData[0]).toHaveProperty('idCard'); expect(listData[0]).toHaveProperty('disabilityType'); expect(listData[0]).toHaveProperty('disabilityLevel'); expect(listData[0]).toHaveProperty('phone'); } console.debug('✓ 列表数据结构正确'); }); }); test.describe('AC6: 数据导出', () => { test('应该支持数据导出功能', async ({ disabilityPersonPage, page }) => { console.debug('\n========== 测试:数据导出功能 =========='); // 1. 检查是否存在导出按钮 const exportButton = page.getByRole('button', { name: /导出|下载|Export/i }); const exportExists = await exportButton.count() > 0; if (!exportExists) { console.debug('ℹ️ 导出按钮不存在,功能可能未实现'); // 跳过测试而非失败 test.skip(); return; } console.debug('✓ 找到导出按钮'); // 2. 使用 Page Object 的 exportData 方法执行导出 const result = await disabilityPersonPage.exportData(); // 3. 验证导出结果 if (result.success) { console.debug(`✓ 导出成功: ${result.fileName || '文件已下载'}`); expect(result.success).toBe(true); } else { console.debug('⚠️ 导出失败或未触发下载'); // 如果导出功能存在但未工作,这是需要关注的问题 expect(result.success).toBe(true); } }); test('应该验证导出文件包含正确数据', async ({ disabilityPersonPage, page }) => { console.debug('\n========== 测试:导出数据正确性 =========='); // 检查导出按钮是否存在 const exportButton = page.getByRole('button', { name: /导出|下载|Export/i }); const exportExists = await exportButton.count() > 0; if (!exportExists) { test.skip(); return; } // 1. 创建一条测试记录以便验证导出数据 const testData = generateTestPerson('export_verify'); createdTestData.push({ name: testData.name }); await disabilityPersonPage.openCreateDialog(); await disabilityPersonPage.fillBasicForm(testData); await disabilityPersonPage.submitForm(); await disabilityPersonPage.waitForDialogClosed(); await page.reload(); await page.waitForLoadState('networkidle'); await disabilityPersonPage.goto(); // 2. 执行导出 const result = await disabilityPersonPage.exportData(); // 3. 验证导出成功 expect(result.success).toBe(true); console.debug(`✓ 导出成功: ${result.fileName || '文件已下载'}`); // 注意:数据清理由 test.afterEach 统一处理 }); }); test.describe('综合测试:完整 CRUD 流程', () => { test('应该完成完整的 CRUD 生命周期', async ({ disabilityPersonPage, page }) => { const testData = generateTestPerson('lifecycle'); // 生命周期测试会在测试内部删除数据,不需要 afterEach 清理 // 但如果测试失败,afterEach 会尝试清理(此时已不存在,会安全跳过) const updatedName = `${UNIQUE_ID}_lifecycle_updated`; console.debug('\n========== 测试:完整 CRUD 生命周期 =========='); // CREATE: 创建记录 console.debug('\n[CREATE] 创建残疾人记录...'); await disabilityPersonPage.openCreateDialog(); await disabilityPersonPage.fillBasicForm(testData); await disabilityPersonPage.submitForm(); await disabilityPersonPage.waitForDialogClosed(); await page.reload(); await page.waitForLoadState('networkidle'); await disabilityPersonPage.goto(); await disabilityPersonPage.searchByName(testData.name); // 增加等待时间以确保数据已持久化(修复稳定性问题) await page.waitForTimeout(TIMEOUTS.EXTENDED); let personExists = await disabilityPersonPage.personExists(testData.name); expect(personExists).toBe(true); console.debug('✓ CREATE 成功'); // READ: 查看详情 console.debug('\n[READ] 查看残疾人详情...'); await disabilityPersonPage.openDetailDialog(testData.name); const dialog = page.locator('[role="dialog"]').filter({ hasText: '残疾人详情' }); await expect(dialog).toBeVisible(); const dialogText = await dialog.textContent(); expect(dialogText).toContain(testData.name); await page.getByRole('button', { name: '关闭' }).click(); await disabilityPersonPage.waitForDetailDialogClosed(); console.debug('✓ READ 成功'); // UPDATE: 更新记录 console.debug('\n[UPDATE] 更新残疾人记录...'); await disabilityPersonPage.openEditDialog(testData.name); const form = page.locator('form#update-form'); await form.waitFor({ state: 'visible', timeout: TIMEOUTS.DIALOG }); const nameInput = form.getByLabel('姓名 *'); await nameInput.clear(); await nameInput.fill(updatedName); const submitButton = page.getByRole('button', { name: '更新' }); await submitButton.click(); await page.waitForLoadState('networkidle', { timeout: TIMEOUTS.TABLE_LOAD }); await page.waitForTimeout(TIMEOUTS.VERY_LONG); await disabilityPersonPage.goto(); await disabilityPersonPage.searchByName(updatedName); // 增加等待时间以确保数据已持久化(修复稳定性问题) await page.waitForTimeout(TIMEOUTS.EXTENDED); const updatedExists = await disabilityPersonPage.personExists(updatedName); expect(updatedExists).toBe(true); console.debug('✓ UPDATE 成功'); // DELETE: 删除记录 console.debug('\n[DELETE] 删除残疾人记录...'); await disabilityPersonPage.deleteDisabilityPerson(updatedName); // 增加等待时间以确保数据已持久化(修复稳定性问题) await page.waitForTimeout(TIMEOUTS.EXTENDED); const deletedExists = await disabilityPersonPage.personExists(updatedName); expect(deletedExists).toBe(false); console.debug('✓ DELETE 成功'); console.debug('\n========== 完整 CRUD 生命周期测试完成 =========='); }); }); });