文件
shanghaipeiwan/server/tests/companion-category.spec.ts

128 行
4.8 KiB
TypeScript

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);
});
});
});