import { CompanionTrack, ExpenseBurdenType, ServiceCategoryManager, CreateServiceItemDto } from '../src/core/companion/service-category'; describe('CompanionCategoryManager (TDD 测试套件: 陪玩·陪吃·陪喝品类与安全风控)', () => { let manager: ServiceCategoryManager; beforeEach(() => { manager = new ServiceCategoryManager(); }); describe('1. 品类赛道与元数据校验', () => { it('应正确识别并列出包含线上游戏、线下陪玩、陪吃、陪喝、陪唱的所有赛道', () => { const tracks = manager.getAllTracks(); expect(tracks).toContain(CompanionTrack.ONLINE_GAME); expect(tracks).toContain(CompanionTrack.OFFLINE_PLAY); expect(tracks).toContain(CompanionTrack.OFFLINE_MEAL); expect(tracks).toContain(CompanionTrack.OFFLINE_DRINK); expect(tracks).toContain(CompanionTrack.OFFLINE_SING); expect(tracks.length).toBe(5); }); it('线上游戏陪玩服务必须包含有效游戏名称', () => { const validGameDto: CreateServiceItemDto = { track: CompanionTrack.ONLINE_GAME, title: '王者荣耀 · 百星排位包胜率', gameName: '王者荣耀', unitPriceCents: 3500, unit: '小时', }; const item = manager.createServiceItem(validGameDto); expect(item.id).toBeDefined(); expect(item.track).toBe(CompanionTrack.ONLINE_GAME); // 缺失游戏名称应抛出异常 expect(() => { manager.createServiceItem({ track: CompanionTrack.ONLINE_GAME, title: '排位上分', unitPriceCents: 3000, unit: '小时', }); }).toThrow('线上游戏陪玩服务必须指定具体游戏品类'); }); }); describe('2. 线下陪玩、陪吃、陪喝场所安全风控校验', () => { it('线下陪吃服务必须指定服务城市与公开合法就餐场所', () => { const mealDto: CreateServiceItemDto = { track: CompanionTrack.OFFLINE_MEAL, title: '同城美食探店 · 网红火锅/西餐饭搭子', city: '北京市', venueType: '商场餐饮/品牌连锁餐厅', unitPriceCents: 6000, unit: '小时', }; const item = manager.createServiceItem(mealDto); expect(item.id).toBeDefined(); expect(item.track).toBe(CompanionTrack.OFFLINE_MEAL); }); it('线下陪喝服务必须指定服务城市与公开休闲场所', () => { const drinkDto: CreateServiceItemDto = { track: CompanionTrack.OFFLINE_DRINK, title: '下午茶手冲咖啡 · 聊天解压微醺陪伴', city: '上海市', venueType: '星巴克臻选/正规茶室/清吧', unitPriceCents: 5000, unit: '小时', }; const item = manager.createServiceItem(drinkDto); expect(item.track).toBe(CompanionTrack.OFFLINE_DRINK); }); it('线下陪唱服务必须指定服务城市与公开正规量贩KTV场所', () => { const singDto: CreateServiceItemDto = { track: CompanionTrack.OFFLINE_SING, title: '量贩KTV百首流行曲库麦霸对唱', city: '北京市', venueType: '纯K/唱吧麦颂/温莎量贩KTV', unitPriceCents: 8000, unit: '小时', }; const item = manager.createServiceItem(singDto); expect(item.track).toBe(CompanionTrack.OFFLINE_SING); expect(item.city).toBe('北京市'); }); it('线下服务未指定城市应抛出异常', () => { expect(() => { manager.createServiceItem({ track: CompanionTrack.OFFLINE_PLAY, title: '剧本杀探案组局', venueType: '正规剧本推理馆', unitPriceCents: 4500, unit: '小时', }); }).toThrow('线下陪伴服务必须指定服务城市'); }); it('安全风控规则: 严禁将私人住宅、酒店客房等非公开场所作为履约地点', () => { const unsafeDto: CreateServiceItemDto = { track: CompanionTrack.OFFLINE_MEAL, title: '居家便餐', city: '广州市', venueType: '私人公寓/私人住宅空间', unitPriceCents: 5000, unit: '小时', }; expect(() => { manager.createServiceItem(unsafeDto); }).toThrow('安全风控触发: 线下陪伴服务仅限在合法的公开商业场所履约,禁止私人住宅或私密空间'); }); }); describe('3. 消费承担方式 (AA制/客户请客/大神自理)', () => { it('应支持合法的就餐与消费承担方式', () => { const burdenTypes = manager.getExpenseBurdenTypes(); expect(burdenTypes).toContain(ExpenseBurdenType.AA_SHARE); expect(burdenTypes).toContain(ExpenseBurdenType.BUYER_TREAT); expect(burdenTypes).toContain(ExpenseBurdenType.SELF_CARE); }); }); });