import { describe, expect, it } from 'vitest' import { BANNER_HOTSPOT_DEFAULT_HOVER_SCALE, createBannerHotspot, hasBannerImage, mergeHomeConfig, normalizeHomeBanner, } from './homeConfig' describe('normalizeHomeBanner', () => { it('把旧的扁平 image_url 结构升级为 PC / 移动两端共用同一张图', () => { const banner = normalizeHomeBanner({ title: '旧结构', eyebrow: '首页', tone: 'green', image_url: ' https://cdn.example/legacy.png ', }) expect(banner.pc.image_url).toBe('https://cdn.example/legacy.png') expect(banner.mobile.image_url).toBe('https://cdn.example/legacy.png') expect(banner.tone).toBe('green') expect(banner.enabled).toBe(true) expect(banner.pc.hotspots).toEqual([]) }) it('两端分别配图时互不覆盖', () => { const banner = normalizeHomeBanner({ title: '两端分图', pc: { image_url: 'https://cdn.example/pc.png' }, mobile: { image_url: 'https://cdn.example/mobile.png' }, }) expect(banner.pc.image_url).toBe('https://cdn.example/pc.png') expect(banner.mobile.image_url).toBe('https://cdn.example/mobile.png') }) it('只配移动图时 PC 端不会误用移动图', () => { const banner = normalizeHomeBanner({ title: '仅移动图', mobile: { image_url: 'https://cdn.example/mobile.png' }, }) expect(banner.pc.image_url).toBe('') expect(banner.mobile.image_url).toBe('https://cdn.example/mobile.png') expect(hasBannerImage(banner.pc)).toBe(false) }) it('收敛热区坐标并丢弃无效热区', () => { const banner = normalizeHomeBanner({ title: '热区', pc: { image_url: '/pc.png', hotspots: [ { id: ' h1 ', x: 90, y: 95, width: 20, height: 20, action: { type: 'route', target: '/x' }, }, { id: 'zero', y: 10, width: 0, height: 10, action: { type: 'route', target: '/x' } }, ], }, }) expect(banner.pc.hotspots).toHaveLength(1) expect(banner.pc.hotspots[0]).toMatchObject({ id: 'h1', x: 80, y: 80 }) }) it('缺失目标的跳转退化为不跳转,避免死热区', () => { const banner = normalizeHomeBanner({ title: '死区', pc: { image_url: '/pc.png', action: { type: 'route', target: ' ' } }, mobile: { image_url: '/m.png', action: { type: 'link', target: 'https://a.example' } }, }) expect(banner.pc.action).toEqual({ type: 'none', target: '', open_new_tab: false }) expect(banner.mobile.action).toEqual({ type: 'link', target: 'https://a.example', open_new_tab: false, }) }) it('热区按钮图去空格,悬浮倍数默认与收敛', () => { const banner = normalizeHomeBanner({ title: '按钮图', pc: { image_url: '/pc.png', hotspots: [ { id: 'a', width: 20, height: 20, image_url: ' https://cdn.example/btn.png ' }, { id: 'b', width: 20, height: 20, hover_scale: 9 }, { id: 'c', width: 20, height: 20, hover_scale: 0.5 }, ], }, }) expect(banner.pc.hotspots[0]?.image_url).toBe('https://cdn.example/btn.png') expect(banner.pc.hotspots[0]?.hover_scale).toBe(BANNER_HOTSPOT_DEFAULT_HOVER_SCALE) expect(banner.pc.hotspots[1]?.hover_scale).toBe(1.5) expect(banner.pc.hotspots[2]?.hover_scale).toBe(1) }) it('保留停用标记', () => { expect(normalizeHomeBanner({ title: '停用', enabled: false }).enabled).toBe(false) }) }) describe('mergeHomeConfig', () => { it('过滤掉既无文案也无图片的空轮播', () => { const config = mergeHomeConfig({ banners: [ { title: '有效' }, { title: ' ', pc: { image_url: 'https://cdn.example/pc.png' } }, { title: '' }, ], }) // 只有图片没有文案的轮播要保留,全空的条目被丢弃 expect(config.banners.map(item => item.pc.image_url)).toEqual([ '', 'https://cdn.example/pc.png', ]) }) it('全部无效时回落到默认轮播', () => { const config = mergeHomeConfig({ banners: [{ title: '' }] }) expect(config.banners.length).toBeGreaterThan(0) expect(config.banners[0]?.pc.image_url).toBe('') }) it('首页业务入口总开关缺省关闭,显式开启时透传', () => { expect(mergeHomeConfig({}).home_entries_enabled).toBe(false) expect(mergeHomeConfig({ home_entries_enabled: true }).home_entries_enabled).toBe(true) expect(mergeHomeConfig({ home_entries_enabled: false }).home_entries_enabled).toBe(false) }) }) describe('createBannerHotspot', () => { it('生成带默认行为的热区,便于后台直接框选', () => { const hotspot = createBannerHotspot({ x: 10, y: 12 }) expect(hotspot.id).toBeTruthy() expect(hotspot.action).toEqual({ type: 'none', target: '', open_new_tab: false }) expect(hotspot.image_url).toBe('') expect(hotspot.hover_scale).toBe(BANNER_HOTSPOT_DEFAULT_HOVER_SCALE) expect(hotspot).toMatchObject({ x: 10, y: 12, width: 24, height: 24 }) }) })