import { MOCK_CARDS_DATA, MockCardBundle } from '../../../src/modules/card/mock/seed-cards'; import { CardPortalService } from '../../../src/modules/card/service/portal'; import { CardInfoEntity } from '../../../src/modules/card/entity/info'; import { CardBentoEntity } from '../../../src/modules/card/entity/bento'; describe('多张多媒体名片数据 (配图与配视频) 规格与集成测试', () => { it('1. 应包含至少 5 组不同国际行业的高保真名片数据包', () => { expect(Array.isArray(MOCK_CARDS_DATA)).toBe(true); expect(MOCK_CARDS_DATA.length).toBeGreaterThanOrEqual(5); const slugs = MOCK_CARDS_DATA.map(item => item.card.slug); const uniqueSlugs = new Set(slugs); expect(uniqueSlugs.size).toBe(MOCK_CARDS_DATA.length); // Slug 必须唯一 }); it('2. 每张名片的基础信息必须完整且配有高分辨率头像与国际化联系方式', () => { MOCK_CARDS_DATA.forEach((bundle: MockCardBundle) => { const { card } = bundle; expect(card.id).toBeDefined(); expect(card.name).toBeTruthy(); expect(card.title).toBeTruthy(); expect(card.company).toBeTruthy(); expect(card.slogan).toBeTruthy(); expect(card.status).toBe('published'); // 配图验证:头像必须是合法图片 URL (http/https) expect(card.avatarUrl).toMatch(/^https?:\/\/.+\.(png|jpe?g|webp|svg)(\?.*)?$/i); // 国际化联系方式 expect(card.phone).toMatch(/^\+[1-9]\d{1,14}$/); // E.164 规范 expect(card.email).toMatch(/^[^\s@]+@[^\s@]+\.[^\s@]+$/); expect(card.timezone).toBeTruthy(); }); }); it('3. 每张名片必须包含有效的视频 Bento 块,且配有可播放视频流与专属海报封面', () => { MOCK_CARDS_DATA.forEach((bundle: MockCardBundle) => { const { bentoBlocks } = bundle; expect(Array.isArray(bentoBlocks)).toBe(true); expect(bentoBlocks.length).toBeGreaterThan(0); // 必须包含至少一个 video 类型的 Bento 块 const videoBlocks = bentoBlocks.filter(b => b.type === 'video'); expect(videoBlocks.length).toBeGreaterThanOrEqual(1); videoBlocks.forEach(videoBlock => { expect(videoBlock.title).toBeTruthy(); // mediaUrl 作为视频封面海报,必须是合法图片 URL expect(videoBlock.mediaUrl).toMatch(/^https?:\/\/.+\.(png|jpe?g|webp)(\?.*)?$/i); // linkUrl 或 metaJson.videoUrl 必须是可播放的视频源 (mp4/m3u8/webm) let videoUrl = videoBlock.linkUrl; if (typeof videoBlock.metaJson === 'object' && videoBlock.metaJson !== null) { videoUrl = (videoBlock.metaJson as any).videoUrl || videoUrl; } else if (typeof videoBlock.metaJson === 'string') { const parsed = JSON.parse(videoBlock.metaJson); videoUrl = parsed.videoUrl || videoUrl; } expect(videoUrl).toMatch(/^https?:\/\/.+\.(mp4|webm|m3u8)(\?.*)?$/i); }); }); }); it('4. 每张名片必须包含图文案例与文章,且均配置了真实多媒体封面配图', () => { MOCK_CARDS_DATA.forEach((bundle: MockCardBundle) => { // 检查案例 expect(Array.isArray(bundle.cases)).toBe(true); expect(bundle.cases.length).toBeGreaterThanOrEqual(1); bundle.cases.forEach(c => { expect(c.title).toBeTruthy(); expect(c.client).toBeTruthy(); expect(c.coverImage).toMatch(/^https?:\/\/.+\.(png|jpe?g|webp)(\?.*)?$/i); }); // 检查文章 expect(Array.isArray(bundle.articles)).toBe(true); expect(bundle.articles.length).toBeGreaterThanOrEqual(1); bundle.articles.forEach(a => { expect(a.title).toBeTruthy(); expect(a.coverImage).toMatch(/^https?:\/\/.+\.(png|jpe?g|webp)(\?.*)?$/i); }); }); }); it('5. 微官网服务 (CardPortalService) 能够无缝聚合各名片详情,正确渲染视频与图文块', async () => { const cardInfoRepo: any = { findOne: jest.fn().mockImplementation(async options => { const slug = options?.where?.slug; const id = options?.where?.id; const found = MOCK_CARDS_DATA.find( b => (slug && b.card.slug === slug) || (id && b.card.id === Number(id)) ); return found ? ({ ...found.card } as CardInfoEntity) : null; }), }; const cardBentoRepo: any = { find: jest.fn().mockImplementation(async options => { const cardId = options?.where?.cardId; const found = MOCK_CARDS_DATA.find(b => b.card.id === Number(cardId)); return found ? found.bentoBlocks.map(blk => ({ ...blk } as CardBentoEntity)) : []; }), }; const portalService = new CardPortalService(); portalService.cardInfoEntity = cardInfoRepo; portalService.cardBentoEntity = cardBentoRepo; CardPortalService.clearAllCache(); for (const bundle of MOCK_CARDS_DATA) { const detail = await portalService.getPortalDetail(bundle.card.slug); expect(detail).toBeDefined(); expect(detail.name).toBe(bundle.card.name); expect(detail.avatarUrl).toBe(bundle.card.avatarUrl); // 验证视频块是否存在于公开微官网聚合结果中 const videoBlock = detail.bentoBlocks.find(b => b.type === 'video'); expect(videoBlock).toBeDefined(); expect(videoBlock?.mediaUrl).toBeTruthy(); } }); });