|
|
@@ -1,12 +1,48 @@
|
|
|
-import { test, expect, type Page } from '../../utils/test-setup';
|
|
|
+import { test, expect } from '../../utils/test-setup';
|
|
|
import { readFileSync } from 'fs';
|
|
|
import { join, dirname } from 'path';
|
|
|
import { fileURLToPath } from 'url';
|
|
|
+import { uploadFileToField } from '@d8d/e2e-test-utils';
|
|
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
|
const __dirname = dirname(__filename);
|
|
|
const testUsers = JSON.parse(readFileSync(join(__dirname, '../../fixtures/test-users.json'), 'utf-8'));
|
|
|
|
|
|
+// 超时配置常量
|
|
|
+const TIMEOUTS = {
|
|
|
+ SHORT: 300,
|
|
|
+ MEDIUM: 500,
|
|
|
+ LONG: 3000,
|
|
|
+ DIALOG: 5000,
|
|
|
+ UPLOAD: 5000,
|
|
|
+} as const;
|
|
|
+
|
|
|
+// 用于跟踪已创建的测试数据,便于清理
|
|
|
+const createdTestData: Array<{ name: string; idCard: string }> = [];
|
|
|
+
|
|
|
+/**
|
|
|
+ * 生成唯一的测试数据
|
|
|
+ * 使用更长的随机数部分避免并行测试冲突
|
|
|
+ */
|
|
|
+function generateUniqueTestData(suffix: string) {
|
|
|
+ const randomPart = Math.floor(Math.random() * 1000000);
|
|
|
+ const timestamp = Date.now();
|
|
|
+ return {
|
|
|
+ name: `照片${suffix}_${timestamp}_${randomPart}`,
|
|
|
+ gender: randomPart % 2 === 0 ? '男' : '女',
|
|
|
+ // 使用完整的 18 位身份证,后 4 位随机
|
|
|
+ idCard: `42010119900101${String(randomPart % 10000).padStart(4, '0')}`,
|
|
|
+ // 残疾证号也使用完整随机
|
|
|
+ disabilityId: `511001199001${String(randomPart % 10000).padStart(4, '0')}`,
|
|
|
+ disabilityType: ['视力残疾', '听力残疾', '言语残疾', '肢体残疾', '智力残疾', '精神残疾'][randomPart % 6],
|
|
|
+ disabilityLevel: ['一级', '二级', '三级', '四级'][randomPart % 4],
|
|
|
+ phone: `138${String(randomPart % 100000000).padStart(8, '0')}`,
|
|
|
+ idAddress: `湖北省武汉市测试街道${randomPart % 100}号`,
|
|
|
+ province: '湖北省',
|
|
|
+ city: '武汉市'
|
|
|
+ };
|
|
|
+}
|
|
|
+
|
|
|
test.describe.serial('残疾人管理 - 照片上传功能', () => {
|
|
|
test.beforeEach(async ({ adminLoginPage, disabilityPersonPage }) => {
|
|
|
// 以管理员身份登录后台
|
|
|
@@ -16,90 +52,197 @@ test.describe.serial('残疾人管理 - 照片上传功能', () => {
|
|
|
await disabilityPersonPage.goto();
|
|
|
});
|
|
|
|
|
|
+ test.afterEach(async ({ disabilityPersonPage, page }) => {
|
|
|
+ // 清理测试数据
|
|
|
+ for (const data of createdTestData) {
|
|
|
+ try {
|
|
|
+ await disabilityPersonPage.goto();
|
|
|
+ await disabilityPersonPage.searchByName(data.name);
|
|
|
+ // 尝试删除找到的记录
|
|
|
+ const deleteButton = page.getByRole('button', { name: '删除' }).first();
|
|
|
+ if (await deleteButton.count() > 0) {
|
|
|
+ await deleteButton.click();
|
|
|
+ await page.getByRole('button', { name: '确认' }).click().catch(() => {});
|
|
|
+ await page.waitForTimeout(TIMEOUTS.MEDIUM);
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.debug(` ⚠ 清理数据失败: ${data.name}`, error);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 清空数组
|
|
|
+ createdTestData.length = 0;
|
|
|
+ });
|
|
|
+
|
|
|
/**
|
|
|
* 辅助函数:上传照片到指定索引的照片槽
|
|
|
+ * 使用 Epic 3 的 uploadFileToField 工具进行文件上传
|
|
|
+ *
|
|
|
* @param page Playwright Page 对象
|
|
|
* @param photoIndex 照片索引 (0, 1, 2, ...)
|
|
|
- * @param filePath 文件绝对路径
|
|
|
+ * @param fileName 文件名(相对于 web/tests/fixtures 目录)
|
|
|
*/
|
|
|
- async function uploadPhotoToSlot(page: Page, photoIndex: number, filePath: string) {
|
|
|
- // 1. 点击"添加照片"按钮创建照片卡片(如果还没有添加)
|
|
|
- const addPhotoButton = page.locator('[data-testid="add-photo-button"]');
|
|
|
+ async function uploadPhotoToSlot(page: any, photoIndex: number, fileName: string) {
|
|
|
+ // 文件路径相对于 web/tests/fixtures 目录
|
|
|
+ const relativeFilePath = `images/${fileName}`;
|
|
|
+
|
|
|
+ console.debug(` 开始上传照片 [${photoIndex}]: ${fileName}`);
|
|
|
+
|
|
|
+ // 0. 首先滚动到照片上传区域
|
|
|
+ const photoSectionLabel = page.getByText('照片上传');
|
|
|
+ await photoSectionLabel.scrollIntoViewIfNeeded();
|
|
|
+ await page.waitForTimeout(TIMEOUTS.SHORT);
|
|
|
+
|
|
|
+ // 1. 点击"添加照片"按钮创建照片卡片(如果还没有添加足够的卡片)
|
|
|
const photoCardCount = await page.locator('[data-testid^="remove-photo-button-"]').count();
|
|
|
+ console.debug(` 当前照片卡片数量: ${photoCardCount}, 目标索引: ${photoIndex}`);
|
|
|
+
|
|
|
if (photoCardCount <= photoIndex) {
|
|
|
+ // 需要添加照片卡片
|
|
|
for (let i = photoCardCount; i <= photoIndex; i++) {
|
|
|
- await addPhotoButton.first().click();
|
|
|
- await page.waitForTimeout(300);
|
|
|
+ // 查找"添加照片"按钮或"添加第一张照片"按钮
|
|
|
+ const addPhotoButton = page.getByRole('button', { name: /添加.*照片/ }).first();
|
|
|
+ await addPhotoButton.click();
|
|
|
+ console.debug(` ✓ 点击添加照片按钮 #${i}`);
|
|
|
+ await page.waitForTimeout(TIMEOUTS.MEDIUM);
|
|
|
+
|
|
|
+ // 等待新的照片卡片出现
|
|
|
+ const currentCount = await page.locator('[data-testid^="remove-photo-button-"]').count();
|
|
|
+ console.debug(` 点击后照片卡片数量: ${currentCount}`);
|
|
|
+ if (currentCount <= i) {
|
|
|
+ // 如果卡片还没出现,再等待一下
|
|
|
+ await page.waitForTimeout(TIMEOUTS.LONG);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// 2. 滚动到目标照片卡片
|
|
|
- const photoCard = page.locator('[data-testid^="remove-photo-button-"]').nth(photoIndex);
|
|
|
+ const photoCard = page.locator(`[data-testid="remove-photo-button-${photoIndex}"]`);
|
|
|
await photoCard.scrollIntoViewIfNeeded();
|
|
|
- await page.waitForTimeout(200);
|
|
|
-
|
|
|
- // 3. 点击"选择或上传照片"按钮打开文件选择对话框
|
|
|
- const selectButton = photoCard.locator('button').filter({ hasText: /选择或上传照片/ }).or(
|
|
|
- photoCard.locator('[data-testid="file-selector-button"]')
|
|
|
- );
|
|
|
- await selectButton.click();
|
|
|
- await page.waitForTimeout(500);
|
|
|
+ await page.waitForTimeout(TIMEOUTS.SHORT);
|
|
|
+
|
|
|
+ // 确认照片卡片可见
|
|
|
+ await expect(photoCard).toBeVisible({ timeout: TIMEOUTS.UPLOAD });
|
|
|
+ console.debug(` ✓ 照片卡片 ${photoIndex} 已可见`);
|
|
|
+
|
|
|
+ // 3. 点击 FileSelector 按钮打开文件选择对话框
|
|
|
+ // 先检查有多少个文件选择按钮
|
|
|
+ const allFileSelectorButtons = page.locator('[data-testid="file-selector-button"]');
|
|
|
+ const allButtonCount = await allFileSelectorButtons.count();
|
|
|
+ console.debug(` 页面上文件选择按钮总数: ${allButtonCount}`);
|
|
|
+
|
|
|
+ // 查找照片卡片内的文件选择按钮
|
|
|
+ const fileSelectorButton = photoCard.locator('[data-testid="file-selector-button"]');
|
|
|
+ const buttonCount = await fileSelectorButton.count();
|
|
|
+ console.debug(` 照片卡片内文件选择按钮数量: ${buttonCount}`);
|
|
|
+
|
|
|
+ if (buttonCount === 0) {
|
|
|
+ // 按钮不在照片卡片内,尝试在整个页面上查找
|
|
|
+ // 通过文本查找(备用方案) - 需要根据索引找到对应的按钮
|
|
|
+ const textButton = page.getByRole('button', { name: /更换文件|选择或上传照片/ });
|
|
|
+ const textCount = await textButton.count();
|
|
|
+ console.debug(` 全页面文本按钮数量: ${textCount}`);
|
|
|
+
|
|
|
+ if (textCount > 0) {
|
|
|
+ // 直接按索引点击按钮(按钮和照片卡片一一对应)
|
|
|
+ // 按钮可能是"选择或上传照片"或"更换文件",我们直接用索引
|
|
|
+ if (textCount > photoIndex) {
|
|
|
+ // 在点击前获取文本(点击后按钮状态可能改变导致超时)
|
|
|
+ const buttonText = await textButton.nth(photoIndex).textContent().catch(() => '未知按钮');
|
|
|
+ await textButton.nth(photoIndex).click();
|
|
|
+ console.debug(` ✓ 点击第 ${photoIndex} 个按钮: "${buttonText}"`);
|
|
|
+ } else {
|
|
|
+ // 备用方案:点击第一个按钮
|
|
|
+ console.debug(` ⚠ 按钮数量不足 (${textCount} < ${photoIndex + 1}),使用第一个`);
|
|
|
+ await textButton.first().click();
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ throw new Error('找不到文件选择按钮');
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ await fileSelectorButton.click();
|
|
|
+ }
|
|
|
+ console.debug(` ✓ 点击文件选择器按钮`);
|
|
|
+ await page.waitForTimeout(TIMEOUTS.MEDIUM);
|
|
|
|
|
|
// 4. 等待文件选择对话框出现
|
|
|
const fileDialog = page.locator('[data-testid="file-selector-dialog"]');
|
|
|
- await expect(fileDialog).toBeVisible({ timeout: 5000 });
|
|
|
+ await expect(fileDialog).toBeVisible({ timeout: TIMEOUTS.DIALOG });
|
|
|
+ console.debug(` ✓ 文件选择对话框已打开`);
|
|
|
|
|
|
- // 5. 找到上传区域的文件输入框(MinioUploader)
|
|
|
- const fileInput = fileDialog.locator(`[data-testid="photo-upload-${photoIndex}"][type="file"]`);
|
|
|
- const inputCount = await fileInput.count();
|
|
|
+ // 5. 使用 Epic 3 的 uploadFileToField 工具上传文件
|
|
|
+ // 查找文件输入框的选择器(MinioUploader 组件)
|
|
|
+ const fileInputSelector = `[data-testid="photo-upload-${photoIndex}"][type="file"]`;
|
|
|
+ const inputCount = await page.locator(fileInputSelector).count();
|
|
|
|
|
|
if (inputCount === 0) {
|
|
|
- // 如果找不到特定 testId 的输入框,尝试查找通用的 minio-uploader-input
|
|
|
- const fallbackInput = fileDialog.locator('[data-testid="minio-uploader-input"][type="file"]');
|
|
|
- await fallbackInput.setInputFiles(filePath);
|
|
|
- console.debug(` ✓ 使用 fallback 选择器上传文件 [${photoIndex}]`);
|
|
|
+ // 备用:查找通用的 minio-uploader-input
|
|
|
+ const fallbackSelector = '[data-testid="minio-uploader-input"][type="file"]';
|
|
|
+ const fallbackCount = await page.locator(fallbackSelector).count();
|
|
|
+
|
|
|
+ if (fallbackCount === 0) {
|
|
|
+ // 最后的备用方案:查找任何 type="file" 的输入框
|
|
|
+ const anyFileSelector = 'input[type="file"]';
|
|
|
+ await uploadFileToField(page, anyFileSelector, relativeFilePath, {
|
|
|
+ fixturesDir: 'tests/fixtures',
|
|
|
+ timeout: TIMEOUTS.UPLOAD
|
|
|
+ });
|
|
|
+ console.debug(` ✓ 使用 uploadFileToField 上传 [${photoIndex}]: ${relativeFilePath}`);
|
|
|
+ } else {
|
|
|
+ await uploadFileToField(page, fallbackSelector, relativeFilePath, {
|
|
|
+ fixturesDir: 'tests/fixtures',
|
|
|
+ timeout: TIMEOUTS.UPLOAD
|
|
|
+ });
|
|
|
+ console.debug(` ✓ 使用 uploadFileToField (fallback) 上传 [${photoIndex}]: ${relativeFilePath}`);
|
|
|
+ }
|
|
|
} else {
|
|
|
- await fileInput.setInputFiles(filePath);
|
|
|
- console.debug(` ✓ 上传文件到 photo-upload-${photoIndex}`);
|
|
|
+ await uploadFileToField(page, fileInputSelector, relativeFilePath, {
|
|
|
+ fixturesDir: 'tests/fixtures',
|
|
|
+ timeout: TIMEOUTS.UPLOAD
|
|
|
+ });
|
|
|
+ console.debug(` ✓ 使用 uploadFileToField 上传 [${photoIndex}]: ${relativeFilePath}`);
|
|
|
}
|
|
|
|
|
|
- // 6. 等待上传完成(等待上传成功提示或列表刷新)
|
|
|
- await page.waitForTimeout(3000);
|
|
|
+ // 6. 等待上传完成
|
|
|
+ await page.waitForTimeout(TIMEOUTS.LONG);
|
|
|
|
|
|
// 7. 点击上传后的文件进行选择(查找第一个可点击的文件)
|
|
|
const uploadedFile = fileDialog.locator('.border-primary').or(
|
|
|
fileDialog.locator('img').first()
|
|
|
);
|
|
|
const fileExists = await uploadedFile.count() > 0;
|
|
|
+ console.debug(` 上传文件选择器找到文件: ${fileExists}`);
|
|
|
|
|
|
if (fileExists) {
|
|
|
await uploadedFile.first().click();
|
|
|
- await page.waitForTimeout(300);
|
|
|
+ await page.waitForTimeout(TIMEOUTS.SHORT);
|
|
|
+ console.debug(` ✓ 点击已上传文件`);
|
|
|
+ } else {
|
|
|
+ // 如果没找到,尝试查看对话框内容
|
|
|
+ const allImages = fileDialog.locator('img');
|
|
|
+ const imgCount = await allImages.count();
|
|
|
+ console.debug(` 对话框中图片数量: ${imgCount}`);
|
|
|
+
|
|
|
+ // 尝试点击任何图片
|
|
|
+ if (imgCount > 0) {
|
|
|
+ await allImages.first().click();
|
|
|
+ console.debug(` ✓ 点击第一张图片`);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
// 8. 点击"确认选择"按钮
|
|
|
- const confirmButton = fileDialog.locator('button').filter({ hasText: /确认选择/ });
|
|
|
+ const confirmButton = fileDialog.getByRole('button', { name: '确认选择' });
|
|
|
await confirmButton.click();
|
|
|
- await page.waitForTimeout(500);
|
|
|
+ await page.waitForTimeout(TIMEOUTS.MEDIUM);
|
|
|
+ console.debug(` ✓ 确认选择`);
|
|
|
|
|
|
// 9. 等待对话框关闭
|
|
|
- await expect(fileDialog).toBeHidden({ timeout: 5000 }).catch(() => {});
|
|
|
+ await expect(fileDialog).toBeHidden({ timeout: TIMEOUTS.DIALOG }).catch(() => {});
|
|
|
+ console.debug(` ✓ 照片 [${photoIndex}] 上传完成`);
|
|
|
}
|
|
|
|
|
|
test('应该成功上传单张照片 - 身份证正面', async ({ disabilityPersonPage, page }) => {
|
|
|
- const timestamp = Date.now();
|
|
|
- const testData = {
|
|
|
- name: `照片单张测试_${timestamp}`,
|
|
|
- gender: '男',
|
|
|
- idCard: `42010119900101123${timestamp % 10}`,
|
|
|
- disabilityId: `5110011990010${timestamp % 10}`,
|
|
|
- disabilityType: '视力残疾',
|
|
|
- disabilityLevel: '一级',
|
|
|
- phone: `1380013800${timestamp % 10}`,
|
|
|
- idAddress: '湖北省武汉市测试街道1号',
|
|
|
- province: '湖北省',
|
|
|
- city: '武汉市'
|
|
|
- };
|
|
|
+ const testData = generateUniqueTestData('单张上传');
|
|
|
+ createdTestData.push({ name: testData.name, idCard: testData.idCard });
|
|
|
|
|
|
console.log('\n========== 单张照片上传测试 ==========');
|
|
|
|
|
|
@@ -108,32 +251,47 @@ test.describe.serial('残疾人管理 - 照片上传功能', () => {
|
|
|
await disabilityPersonPage.fillBasicForm(testData);
|
|
|
|
|
|
// 上传身份证正面照片
|
|
|
- await uploadPhotoToSlot(page, 0, '/mnt/code/188-179-template-6/web/tests/fixtures/images/id-card-front.jpg');
|
|
|
+ await uploadPhotoToSlot(page, 0, 'id-card-front.jpg');
|
|
|
|
|
|
- // 等待预览显示
|
|
|
- await page.waitForTimeout(1000);
|
|
|
+ // 等待并验证预览图片显示
|
|
|
+ await page.waitForTimeout(TIMEOUTS.MEDIUM);
|
|
|
|
|
|
- // 验证预览图片存在(通过查找删除按钮来确认照片卡片存在)
|
|
|
+ // 验证:照片卡片存在
|
|
|
const photoCard = page.locator('[data-testid="remove-photo-button-0"]');
|
|
|
- await expect(photoCard).toBeVisible({ timeout: 5000 });
|
|
|
+ await expect(photoCard).toBeVisible({ timeout: TIMEOUTS.UPLOAD });
|
|
|
+
|
|
|
+ // 验证预览图片存在(可能在 FileSelector 组件中,不在 photoCard 内)
|
|
|
+ // 尝试多种方式查找预览图片
|
|
|
+ const previewImage1 = page.locator('[data-testid="file-selector-button"]').first().locator('img');
|
|
|
+ const previewImage2 = page.locator('button:has-text("选择或上传照片")').locator('img');
|
|
|
+ const previewImage3 = page.locator('[data-testid="area-select"] img').first();
|
|
|
+
|
|
|
+ const hasPreview1 = await previewImage1.count() > 0;
|
|
|
+ const hasPreview2 = await previewImage2.count() > 0;
|
|
|
+ const hasPreview3 = await previewImage3.count() > 0;
|
|
|
+
|
|
|
+ console.debug(` 预览图片 (方式1): ${hasPreview1}`);
|
|
|
+ console.debug(` 预览图片 (方式2): ${hasPreview2}`);
|
|
|
+ console.debug(` 预览图片 (方式3): ${hasPreview3}`);
|
|
|
+
|
|
|
+ // 如果找不到预览,至少验证照片卡片存在
|
|
|
+ if (hasPreview1) {
|
|
|
+ await expect(previewImage1).toBeVisible({ timeout: TIMEOUTS.UPLOAD });
|
|
|
+ console.debug(' ✓ 预览图片已显示');
|
|
|
+ } else if (hasPreview2) {
|
|
|
+ await expect(previewImage2).toBeVisible({ timeout: TIMEOUTS.UPLOAD });
|
|
|
+ console.debug(' ✓ 预览图片已显示');
|
|
|
+ } else {
|
|
|
+ // 至少验证照片卡片存在
|
|
|
+ console.debug(' ✓ 照片卡片已创建(预览图片未显示,可能需要等待或刷新)');
|
|
|
+ }
|
|
|
|
|
|
console.log('✅ 单张照片上传测试通过');
|
|
|
});
|
|
|
|
|
|
test('应该成功上传多张照片 - 身份证正反面', async ({ disabilityPersonPage, page }) => {
|
|
|
- const timestamp = Date.now();
|
|
|
- const testData = {
|
|
|
- name: `多张照片测试_${timestamp}`,
|
|
|
- gender: '女',
|
|
|
- idCard: `42010119900101123${timestamp % 10}`,
|
|
|
- disabilityId: `5110011990010${timestamp % 10}`,
|
|
|
- disabilityType: '听力残疾',
|
|
|
- disabilityLevel: '二级',
|
|
|
- phone: `1380013800${timestamp % 10}`,
|
|
|
- idAddress: '湖北省武汉市测试街道2号',
|
|
|
- province: '湖北省',
|
|
|
- city: '武汉市'
|
|
|
- };
|
|
|
+ const testData = generateUniqueTestData('多张上传');
|
|
|
+ createdTestData.push({ name: testData.name, idCard: testData.idCard });
|
|
|
|
|
|
console.log('\n========== 多张照片上传测试 ==========');
|
|
|
|
|
|
@@ -142,116 +300,173 @@ test.describe.serial('残疾人管理 - 照片上传功能', () => {
|
|
|
await disabilityPersonPage.fillBasicForm(testData);
|
|
|
|
|
|
// 上传身份证正面和反面
|
|
|
- await uploadPhotoToSlot(page, 0, '/mnt/code/188-179-template-6/web/tests/fixtures/images/id-card-front.jpg');
|
|
|
- await uploadPhotoToSlot(page, 1, '/mnt/code/188-179-template-6/web/tests/fixtures/images/id-card-back.jpg');
|
|
|
+ await uploadPhotoToSlot(page, 0, 'id-card-front.jpg');
|
|
|
+ await uploadPhotoToSlot(page, 1, 'id-card-back.jpg');
|
|
|
|
|
|
// 验证两个照片卡片都存在
|
|
|
const photoCard0 = page.locator('[data-testid="remove-photo-button-0"]');
|
|
|
const photoCard1 = page.locator('[data-testid="remove-photo-button-1"]');
|
|
|
- await expect(photoCard0).toBeVisible({ timeout: 5000 });
|
|
|
- await expect(photoCard1).toBeVisible({ timeout: 5000 });
|
|
|
+ await expect(photoCard0).toBeVisible({ timeout: TIMEOUTS.UPLOAD });
|
|
|
+ await expect(photoCard1).toBeVisible({ timeout: TIMEOUTS.UPLOAD });
|
|
|
+ console.debug(' ✓ 两个照片卡片都已创建');
|
|
|
+
|
|
|
+ // 验证预览图片(使用多种方式查找)
|
|
|
+ // 方式1: FileSelector 组件内的图片
|
|
|
+ const previewImage1_0 = page.locator('[data-testid="file-selector-button"]').nth(0).locator('img');
|
|
|
+ const previewImage1_1 = page.locator('[data-testid="file-selector-button"]').nth(1).locator('img');
|
|
|
+ // 方式2: 通过文本查找的按钮内的图片
|
|
|
+ const previewImage2_0 = page.getByRole('button', { name: /更换文件|选择或上传照片/ }).nth(0).locator('img');
|
|
|
+ const previewImage2_1 = page.getByRole('button', { name: /更换文件|选择或上传照片/ }).nth(1).locator('img');
|
|
|
+ // 方式3: 区域选择内的图片
|
|
|
+ const previewImage3_0 = page.locator('[data-testid="area-select"] img').nth(0);
|
|
|
+ const previewImage3_1 = page.locator('[data-testid="area-select"] img').nth(1);
|
|
|
+
|
|
|
+ const hasPreview1_0 = await previewImage1_0.count() > 0;
|
|
|
+ const hasPreview1_1 = await previewImage1_1.count() > 0;
|
|
|
+ const hasPreview2_0 = await previewImage2_0.count() > 0;
|
|
|
+ const hasPreview2_1 = await previewImage2_1.count() > 0;
|
|
|
+ const hasPreview3_0 = await previewImage3_0.count() > 0;
|
|
|
+ const hasPreview3_1 = await previewImage3_1.count() > 0;
|
|
|
+
|
|
|
+ console.debug(` 照片0预览 (方式1): ${hasPreview1_0}, (方式2): ${hasPreview2_0}, (方式3): ${hasPreview3_0}`);
|
|
|
+ console.debug(` 照片1预览 (方式1): ${hasPreview1_1}, (方式2): ${hasPreview2_1}, (方式3): ${hasPreview3_1}`);
|
|
|
+
|
|
|
+ // 验证第一张照片预览
|
|
|
+ if (hasPreview1_0) {
|
|
|
+ await expect(previewImage1_0).toBeVisible({ timeout: TIMEOUTS.UPLOAD });
|
|
|
+ console.debug(' ✓ 照片0预览已显示 (方式1)');
|
|
|
+ } else if (hasPreview2_0) {
|
|
|
+ await expect(previewImage2_0).toBeVisible({ timeout: TIMEOUTS.UPLOAD });
|
|
|
+ console.debug(' ✓ 照片0预览已显示 (方式2)');
|
|
|
+ } else if (hasPreview3_0) {
|
|
|
+ await expect(previewImage3_0).toBeVisible({ timeout: TIMEOUTS.UPLOAD });
|
|
|
+ console.debug(' ✓ 照片0预览已显示 (方式3)');
|
|
|
+ } else {
|
|
|
+ console.debug(' ✓ 照片0卡片已创建(预览图片未找到)');
|
|
|
+ }
|
|
|
+
|
|
|
+ // 验证第二张照片预览
|
|
|
+ if (hasPreview1_1) {
|
|
|
+ await expect(previewImage1_1).toBeVisible({ timeout: TIMEOUTS.UPLOAD });
|
|
|
+ console.debug(' ✓ 照片1预览已显示 (方式1)');
|
|
|
+ } else if (hasPreview2_1) {
|
|
|
+ await expect(previewImage2_1).toBeVisible({ timeout: TIMEOUTS.UPLOAD });
|
|
|
+ console.debug(' ✓ 照片1预览已显示 (方式2)');
|
|
|
+ } else if (hasPreview3_1) {
|
|
|
+ await expect(previewImage3_1).toBeVisible({ timeout: TIMEOUTS.UPLOAD });
|
|
|
+ console.debug(' ✓ 照片1预览已显示 (方式3)');
|
|
|
+ } else {
|
|
|
+ console.debug(' ✓ 照片1卡片已创建(预览图片未找到)');
|
|
|
+ }
|
|
|
|
|
|
console.log('✅ 多张照片上传测试通过');
|
|
|
});
|
|
|
|
|
|
test('应该支持 JPG 格式上传', async ({ disabilityPersonPage, page }) => {
|
|
|
- const timestamp = Date.now();
|
|
|
- const testData = {
|
|
|
- name: `JPG格式测试_${timestamp}`,
|
|
|
- gender: '男',
|
|
|
- idCard: `42010119900101123${timestamp % 10}`,
|
|
|
- disabilityId: `5110011990010${timestamp % 10}`,
|
|
|
- disabilityType: '肢体残疾',
|
|
|
- disabilityLevel: '三级',
|
|
|
- phone: `1380013800${timestamp % 10}`,
|
|
|
- idAddress: '湖北省武汉市测试街道3号',
|
|
|
- province: '湖北省',
|
|
|
- city: '武汉市'
|
|
|
- };
|
|
|
+ const testData = generateUniqueTestData('JPG格式');
|
|
|
+ createdTestData.push({ name: testData.name, idCard: testData.idCard });
|
|
|
|
|
|
console.log('\n========== JPG 格式支持测试 ==========');
|
|
|
|
|
|
await disabilityPersonPage.openCreateDialog();
|
|
|
await disabilityPersonPage.fillBasicForm(testData);
|
|
|
|
|
|
- await uploadPhotoToSlot(page, 0, '/mnt/code/188-179-template-6/web/tests/fixtures/images/photo.jpg');
|
|
|
+ await uploadPhotoToSlot(page, 0, 'photo.jpg');
|
|
|
|
|
|
const photoCard = page.locator('[data-testid="remove-photo-button-0"]');
|
|
|
- await expect(photoCard).toBeVisible({ timeout: 5000 });
|
|
|
+ await expect(photoCard).toBeVisible({ timeout: TIMEOUTS.UPLOAD });
|
|
|
+
|
|
|
+ // 使用多种方式查找预览图片
|
|
|
+ const previewImage1 = page.locator('[data-testid="file-selector-button"]').first().locator('img');
|
|
|
+ const previewImage2 = page.getByRole('button', { name: /更换文件|选择或上传照片/ }).first().locator('img');
|
|
|
+ const previewImage3 = page.locator('[data-testid="area-select"] img').first();
|
|
|
+
|
|
|
+ const hasPreview1 = await previewImage1.count() > 0;
|
|
|
+ const hasPreview2 = await previewImage2.count() > 0;
|
|
|
+ const hasPreview3 = await previewImage3.count() > 0;
|
|
|
+
|
|
|
+ if (hasPreview1) {
|
|
|
+ await expect(previewImage1).toBeVisible({ timeout: TIMEOUTS.UPLOAD });
|
|
|
+ } else if (hasPreview2) {
|
|
|
+ await expect(previewImage2).toBeVisible({ timeout: TIMEOUTS.UPLOAD });
|
|
|
+ } else {
|
|
|
+ console.debug(' ✓ 照片卡片已创建(预览图片未显示)');
|
|
|
+ }
|
|
|
|
|
|
console.log('✅ JPG 格式支持测试通过');
|
|
|
});
|
|
|
|
|
|
test('应该支持 PNG 格式上传', async ({ disabilityPersonPage, page }) => {
|
|
|
- const timestamp = Date.now();
|
|
|
- const testData = {
|
|
|
- name: `PNG格式测试_${timestamp}`,
|
|
|
- gender: '女',
|
|
|
- idCard: `42010119900101123${timestamp % 10}`,
|
|
|
- disabilityId: `5110011990010${timestamp % 10}`,
|
|
|
- disabilityType: '言语残疾',
|
|
|
- disabilityLevel: '四级',
|
|
|
- phone: `1380013800${timestamp % 10}`,
|
|
|
- idAddress: '湖北省武汉市测试街道4号',
|
|
|
- province: '湖北省',
|
|
|
- city: '武汉市'
|
|
|
- };
|
|
|
+ const testData = generateUniqueTestData('PNG格式');
|
|
|
+ createdTestData.push({ name: testData.name, idCard: testData.idCard });
|
|
|
|
|
|
console.log('\n========== PNG 格式支持测试 ==========');
|
|
|
|
|
|
await disabilityPersonPage.openCreateDialog();
|
|
|
await disabilityPersonPage.fillBasicForm(testData);
|
|
|
|
|
|
- await uploadPhotoToSlot(page, 0, '/mnt/code/188-179-template-6/web/tests/fixtures/images/photo.png');
|
|
|
+ await uploadPhotoToSlot(page, 0, 'photo.png');
|
|
|
|
|
|
const photoCard = page.locator('[data-testid="remove-photo-button-0"]');
|
|
|
- await expect(photoCard).toBeVisible({ timeout: 5000 });
|
|
|
+ await expect(photoCard).toBeVisible({ timeout: TIMEOUTS.UPLOAD });
|
|
|
+
|
|
|
+ // 使用多种方式查找预览图片
|
|
|
+ const previewImage1 = page.locator('[data-testid="file-selector-button"]').first().locator('img');
|
|
|
+ const previewImage2 = page.getByRole('button', { name: /更换文件|选择或上传照片/ }).first().locator('img');
|
|
|
+ const previewImage3 = page.locator('[data-testid="area-select"] img').first();
|
|
|
+
|
|
|
+ const hasPreview1 = await previewImage1.count() > 0;
|
|
|
+ const hasPreview2 = await previewImage2.count() > 0;
|
|
|
+ const hasPreview3 = await previewImage3.count() > 0;
|
|
|
+
|
|
|
+ if (hasPreview1) {
|
|
|
+ await expect(previewImage1).toBeVisible({ timeout: TIMEOUTS.UPLOAD });
|
|
|
+ } else if (hasPreview2) {
|
|
|
+ await expect(previewImage2).toBeVisible({ timeout: TIMEOUTS.UPLOAD });
|
|
|
+ } else {
|
|
|
+ console.debug(' ✓ 照片卡片已创建(预览图片未显示)');
|
|
|
+ }
|
|
|
|
|
|
console.log('✅ PNG 格式支持测试通过');
|
|
|
});
|
|
|
|
|
|
test('应该支持 WEBP 格式上传', async ({ disabilityPersonPage, page }) => {
|
|
|
- const timestamp = Date.now();
|
|
|
- const testData = {
|
|
|
- name: `WEBP格式测试_${timestamp}`,
|
|
|
- gender: '男',
|
|
|
- idCard: `42010119900101123${timestamp % 10}`,
|
|
|
- disabilityId: `5110011990010${timestamp % 10}`,
|
|
|
- disabilityType: '智力残疾',
|
|
|
- disabilityLevel: '二级',
|
|
|
- phone: `1380013800${timestamp % 10}`,
|
|
|
- idAddress: '湖北省武汉市测试街道5号',
|
|
|
- province: '湖北省',
|
|
|
- city: '武汉市'
|
|
|
- };
|
|
|
+ const testData = generateUniqueTestData('WEBP格式');
|
|
|
+ createdTestData.push({ name: testData.name, idCard: testData.idCard });
|
|
|
|
|
|
console.log('\n========== WEBP 格式支持测试 ==========');
|
|
|
|
|
|
await disabilityPersonPage.openCreateDialog();
|
|
|
await disabilityPersonPage.fillBasicForm(testData);
|
|
|
|
|
|
- await uploadPhotoToSlot(page, 0, '/mnt/code/188-179-template-6/web/tests/fixtures/images/photo.webp');
|
|
|
+ await uploadPhotoToSlot(page, 0, 'photo.webp');
|
|
|
|
|
|
const photoCard = page.locator('[data-testid="remove-photo-button-0"]');
|
|
|
- await expect(photoCard).toBeVisible({ timeout: 5000 });
|
|
|
+ await expect(photoCard).toBeVisible({ timeout: TIMEOUTS.UPLOAD });
|
|
|
+
|
|
|
+ // 使用多种方式查找预览图片
|
|
|
+ const previewImage1 = page.locator('[data-testid="file-selector-button"]').first().locator('img');
|
|
|
+ const previewImage2 = page.getByRole('button', { name: /更换文件|选择或上传照片/ }).first().locator('img');
|
|
|
+ const previewImage3 = page.locator('[data-testid="area-select"] img').first();
|
|
|
+
|
|
|
+ const hasPreview1 = await previewImage1.count() > 0;
|
|
|
+ const hasPreview2 = await previewImage2.count() > 0;
|
|
|
+ const hasPreview3 = await previewImage3.count() > 0;
|
|
|
+
|
|
|
+ if (hasPreview1) {
|
|
|
+ await expect(previewImage1).toBeVisible({ timeout: TIMEOUTS.UPLOAD });
|
|
|
+ } else if (hasPreview2) {
|
|
|
+ await expect(previewImage2).toBeVisible({ timeout: TIMEOUTS.UPLOAD });
|
|
|
+ } else {
|
|
|
+ console.debug(' ✓ 照片卡片已创建(预览图片未显示)');
|
|
|
+ }
|
|
|
|
|
|
console.log('✅ WEBP 格式支持测试通过');
|
|
|
});
|
|
|
|
|
|
test('应该能够删除已上传的照片', async ({ disabilityPersonPage, page }) => {
|
|
|
- const timestamp = Date.now();
|
|
|
- const testData = {
|
|
|
- name: `删除照片测试_${timestamp}`,
|
|
|
- gender: '女',
|
|
|
- idCard: `42010119900101123${timestamp % 10}`,
|
|
|
- disabilityId: `5110011990010${timestamp % 10}`,
|
|
|
- disabilityType: '精神残疾',
|
|
|
- disabilityLevel: '一级',
|
|
|
- phone: `1380013800${timestamp % 10}`,
|
|
|
- idAddress: '湖北省武汉市测试街道6号',
|
|
|
- province: '湖北省',
|
|
|
- city: '武汉市'
|
|
|
- };
|
|
|
+ const testData = generateUniqueTestData('删除照片');
|
|
|
+ createdTestData.push({ name: testData.name, idCard: testData.idCard });
|
|
|
|
|
|
console.log('\n========== 删除照片测试 ==========');
|
|
|
|
|
|
@@ -259,21 +474,23 @@ test.describe.serial('残疾人管理 - 照片上传功能', () => {
|
|
|
await disabilityPersonPage.fillBasicForm(testData);
|
|
|
|
|
|
// 上传照片
|
|
|
- await uploadPhotoToSlot(page, 0, '/mnt/code/188-179-template-6/web/tests/fixtures/images/id-card-front.jpg');
|
|
|
+ await uploadPhotoToSlot(page, 0, 'id-card-front.jpg');
|
|
|
|
|
|
// 验证照片卡片存在
|
|
|
let photoCard = page.locator('[data-testid="remove-photo-button-0"]');
|
|
|
- await expect(photoCard).toBeVisible({ timeout: 5000 });
|
|
|
- console.debug(' ✓ 预览显示确认');
|
|
|
+ await expect(photoCard).toBeVisible({ timeout: TIMEOUTS.UPLOAD });
|
|
|
+ console.debug(' ✓ 照片卡片已创建');
|
|
|
|
|
|
// 点击删除按钮
|
|
|
await photoCard.click();
|
|
|
console.debug(' ✓ 点击删除按钮');
|
|
|
|
|
|
- await page.waitForTimeout(500);
|
|
|
+ await page.waitForTimeout(TIMEOUTS.MEDIUM);
|
|
|
|
|
|
- // 验证照片卡片已被删除
|
|
|
+ // 验证照片卡片已被删除(使用 waitForElementState 等待元素消失)
|
|
|
photoCard = page.locator('[data-testid="remove-photo-button-0"]');
|
|
|
+ await photoCard.waitFor({ state: 'hidden', timeout: TIMEOUTS.DIALOG }).catch(() => {});
|
|
|
+
|
|
|
const isVisible = await photoCard.count() > 0;
|
|
|
expect(isVisible).toBe(false);
|
|
|
|
|
|
@@ -281,19 +498,8 @@ test.describe.serial('残疾人管理 - 照片上传功能', () => {
|
|
|
});
|
|
|
|
|
|
test('超大文件应该有合理处理', async ({ disabilityPersonPage, page }) => {
|
|
|
- const timestamp = Date.now();
|
|
|
- const testData = {
|
|
|
- name: `超大文件测试_${timestamp}`,
|
|
|
- gender: '男',
|
|
|
- idCard: `42010119900101123${timestamp % 10}`,
|
|
|
- disabilityId: `5110011990010${timestamp % 10}`,
|
|
|
- disabilityType: '视力残疾',
|
|
|
- disabilityLevel: '二级',
|
|
|
- phone: `1380013800${timestamp % 10}`,
|
|
|
- idAddress: '湖北省武汉市测试街道7号',
|
|
|
- province: '湖北省',
|
|
|
- city: '武汉市'
|
|
|
- };
|
|
|
+ const testData = generateUniqueTestData('超大文件');
|
|
|
+ createdTestData.push({ name: testData.name, idCard: testData.idCard });
|
|
|
|
|
|
console.log('\n========== 超大文件处理测试 ==========');
|
|
|
|
|
|
@@ -302,7 +508,7 @@ test.describe.serial('残疾人管理 - 照片上传功能', () => {
|
|
|
|
|
|
// 尝试上传超大文件
|
|
|
try {
|
|
|
- await uploadPhotoToSlot(page, 0, '/mnt/code/188-179-template-6/web/tests/fixtures/images/large-file.jpg');
|
|
|
+ await uploadPhotoToSlot(page, 0, 'large-file.jpg');
|
|
|
|
|
|
// 验证:检查是否有错误提示或预览显示
|
|
|
const errorToast = page.locator('[data-sonner-toast][data-type="error"]');
|
|
|
@@ -326,19 +532,8 @@ test.describe.serial('残疾人管理 - 照片上传功能', () => {
|
|
|
});
|
|
|
|
|
|
test('完整流程:上传多种格式照片并提交', async ({ disabilityPersonPage, page }) => {
|
|
|
- const timestamp = Date.now();
|
|
|
- const testData = {
|
|
|
- name: `完整照片流程测试_${timestamp}`,
|
|
|
- gender: '男',
|
|
|
- idCard: `42010119900101123${timestamp % 10}`,
|
|
|
- disabilityId: `5110011990010${timestamp % 10}`,
|
|
|
- disabilityType: '肢体残疾',
|
|
|
- disabilityLevel: '四级',
|
|
|
- phone: `1380013800${timestamp % 10}`,
|
|
|
- idAddress: '湖北省武汉市测试街道9号',
|
|
|
- province: '湖北省',
|
|
|
- city: '武汉市'
|
|
|
- };
|
|
|
+ const testData = generateUniqueTestData('完整流程');
|
|
|
+ createdTestData.push({ name: testData.name, idCard: testData.idCard });
|
|
|
|
|
|
console.log('\n========== 完整照片上传流程测试 ==========');
|
|
|
|
|
|
@@ -347,24 +542,31 @@ test.describe.serial('残疾人管理 - 照片上传功能', () => {
|
|
|
await disabilityPersonPage.fillBasicForm(testData);
|
|
|
|
|
|
// 上传多种格式的照片
|
|
|
- await uploadPhotoToSlot(page, 0, '/mnt/code/188-179-template-6/web/tests/fixtures/images/id-card-front.jpg');
|
|
|
+ await uploadPhotoToSlot(page, 0, 'id-card-front.jpg');
|
|
|
console.debug(' ✓ 上传 JPG 格式:身份证正面');
|
|
|
|
|
|
- await uploadPhotoToSlot(page, 1, '/mnt/code/188-179-template-6/web/tests/fixtures/images/id-card-back.jpg');
|
|
|
+ await uploadPhotoToSlot(page, 1, 'id-card-back.jpg');
|
|
|
console.debug(' ✓ 上传 JPG 格式:身份证反面');
|
|
|
|
|
|
- await uploadPhotoToSlot(page, 2, '/mnt/code/188-179-template-6/web/tests/fixtures/images/disability-card.jpg');
|
|
|
+ await uploadPhotoToSlot(page, 2, 'disability-card.jpg');
|
|
|
console.debug(' ✓ 上传 JPG 格式:残疾证');
|
|
|
|
|
|
- await uploadPhotoToSlot(page, 3, '/mnt/code/188-179-template-6/web/tests/fixtures/images/photo.png');
|
|
|
+ await uploadPhotoToSlot(page, 3, 'photo.png');
|
|
|
console.debug(' ✓ 上传 PNG 格式:个人照片');
|
|
|
|
|
|
- // 验证至少有4个照片卡片
|
|
|
+ // 验证至少有4个照片卡片存在
|
|
|
const photoCards = page.locator('[data-testid^="remove-photo-button-"]');
|
|
|
const cardCount = await photoCards.count();
|
|
|
console.debug(` 照片卡片数量: ${cardCount}`);
|
|
|
expect(cardCount).toBeGreaterThanOrEqual(4);
|
|
|
|
|
|
+ // 验证每个照片卡片都存在(预览图片验证使用容错逻辑)
|
|
|
+ for (let i = 0; i < Math.min(cardCount, 4); i++) {
|
|
|
+ const card = photoCards.nth(i);
|
|
|
+ await expect(card).toBeVisible({ timeout: TIMEOUTS.UPLOAD });
|
|
|
+ console.debug(` ✓ 照片卡片 ${i} 已创建`);
|
|
|
+ }
|
|
|
+
|
|
|
// 提交表单
|
|
|
const result = await disabilityPersonPage.submitForm();
|
|
|
|