import test from 'node:test'; import assert from 'node:assert/strict'; import fs from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; const adminRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); const uploadCompDir = path.join(adminRoot, 'src/components/Upload'); const imageUploaderPath = path.join(uploadCompDir, 'ImageUploader.tsx'); const fileUploaderPath = path.join(uploadCompDir, 'FileUploader.tsx'); const uploadIndexPath = path.join(uploadCompDir, 'index.ts'); const casesPagePath = path.join(adminRoot, 'src/pages/card/cases/index.tsx'); const builderPagePath = path.join(adminRoot, 'src/pages/card/builder/index.tsx'); const articlesPagePath = path.join(adminRoot, 'src/pages/card/articles/index.tsx'); const brandKitPagePath = path.join(adminRoot, 'src/pages/team/brand-kit/index.tsx'); const userSettingHeaderPath = path.join(adminRoot, 'src/pages/user/setting/header.tsx'); test('1. components/Upload 必须存在 ImageUploader 与 FileUploader 并正确导出', () => { assert.ok(fs.existsSync(imageUploaderPath), '必须存在 ImageUploader.tsx'); assert.ok(fs.existsSync(fileUploaderPath), '必须存在 FileUploader.tsx'); assert.ok(fs.existsSync(uploadIndexPath), '必须存在 index.ts 统一导出'); const indexContent = fs.readFileSync(uploadIndexPath, 'utf-8'); assert.ok(indexContent.includes('ImageUploader'), 'index.ts 需导出 ImageUploader'); assert.ok(indexContent.includes('FileUploader'), 'index.ts 需导出 FileUploader'); }); test('2. ImageUploader 必须支持点击放大预览、删除、以及多图模式多选批量上传', () => { const content = fs.readFileSync(imageUploaderPath, 'utf-8'); assert.ok(content.includes('Upload'), '必须基于 Arco Upload'); assert.ok(content.includes('Image'), '必须使用 Arco Image 组件或 Preview 进行放大预览'); assert.ok(content.includes('multiple'), '必须支持 multiple 属性用于多选批量上传'); assert.ok(content.includes('IconEye') || content.includes('IconZoomIn') || content.includes('preview'), '必须支持点击放大预览'); assert.ok(content.includes('IconDelete') || content.includes('onRemove') || content.includes('handleDelete'), '必须支持点击删除'); assert.ok(!content.includes('any'), '严禁使用 any'); }); test('3. FileUploader 必须支持文件上传、点击预览/打开与点击删除', () => { const content = fs.readFileSync(fileUploaderPath, 'utf-8'); assert.ok(content.includes('Upload'), '必须基于 Arco Upload'); assert.ok(content.includes('IconDelete') || content.includes('onRemove') || content.includes('handleDelete'), '必须支持删除文件'); assert.ok(!content.includes('any'), '严禁使用 any'); }); test('4. cases 页面封面图与 PDF 必须接入 ImageUploader 与 FileUploader', () => { const content = fs.readFileSync(casesPagePath, 'utf-8'); assert.ok(content.includes('ImageUploader'), 'cases 必须使用 ImageUploader 上传封面图'); assert.ok(content.includes('FileUploader'), 'cases 必须使用 FileUploader 上传 PDF'); }); test('5. builder 页面必须接入 ImageUploader 管理组件 mediaUrl', () => { const content = fs.readFileSync(builderPagePath, 'utf-8'); assert.ok(content.includes('ImageUploader'), 'builder 页面 mediaUrl 必须使用 ImageUploader'); }); test('6. articles 页面必须接入 ImageUploader 管理文章封面 coverImage', () => { const content = fs.readFileSync(articlesPagePath, 'utf-8'); assert.ok(content.includes('ImageUploader'), 'articles 页面必须使用 ImageUploader'); }); test('7. team/brand-kit 页面必须接入 ImageUploader 管理品牌 logoUrl', () => { const content = fs.readFileSync(brandKitPagePath, 'utf-8'); assert.ok(content.includes('ImageUploader'), 'brand-kit 页面必须使用 ImageUploader'); }); test('8. user/setting/header 必须支持头像放大预览与删除头像', () => { const content = fs.readFileSync(userSettingHeaderPath, 'utf-8'); assert.ok(content.includes('Image') || content.includes('Modal') || content.includes('preview'), '必须支持头像放大预览'); assert.ok(content.includes('IconDelete') || content.includes('handleDelete') || content.includes('onDelete'), '必须支持头像删除'); });