文件
shanghaipeiwan/server/tests/marketing.spec.ts

140 行
5.4 KiB
TypeScript

// 已读取AGENTS.md
import { MarketingService } from '../src/core/marketing/marketing.service';
import * as fs from 'fs';
import * as path from 'path';
describe('Marketing Management System (TDD 充值赠送阶梯与通用优惠券管理套件)', () => {
let service: MarketingService;
const rootDir = path.resolve(__dirname, '../../');
const serverIndexPath = path.join(rootDir, 'server/src/index.ts');
const mysqlPath = path.join(rootDir, 'server/src/db/mysql.ts');
const repoPath = path.join(rootDir, 'server/src/db/repository.ts');
beforeEach(() => {
service = new MarketingService();
});
describe('1. 充值阶梯与赠送业务逻辑校验', () => {
it('默认初始加载 5 个经典充值阶梯且按 sortOrder 正序排序', () => {
const tiers = service.getActiveTiers();
expect(tiers.length).toBe(5);
expect(tiers[0].amount).toBe(50);
expect(tiers[0].bonusAmount).toBe(0);
expect(tiers[1].amount).toBe(100);
expect(tiers[1].bonusAmount).toBe(5);
expect(tiers[3].amount).toBe(500);
expect(tiers[3].bonusAmount).toBe(50);
});
it('成功创建新充值赠送阶梯', () => {
const tier = service.createTier({
amount: 2000,
bonusAmount: 300,
tag: '超级VIP',
sortOrder: 6,
status: 1
});
expect(tier.id).toBe(6);
expect(tier.amount).toBe(2000);
expect(tier.bonusAmount).toBe(300);
});
it('充值金额小于等于 0 时应被拒绝', () => {
expect(() => {
service.createTier({
amount: 0,
bonusAmount: 10
});
}).toThrow('充值金额必须大于0');
});
});
describe('2. 平台营销优惠券业务校验', () => {
it('默认加载优惠券种子且支持按品类过滤', () => {
const allCoupons = service.getActiveCoupons();
expect(allCoupons.length).toBe(3);
const mealCoupons = service.getActiveCoupons('MEAL');
// 包含 ALL 和 MEAL 专属
expect(mealCoupons.every((c) => c.categoryLimit === 'ALL' || c.categoryLimit === 'MEAL')).toBe(true);
});
it('成功创建合规优惠券', () => {
const coupon = service.createCoupon({
name: '国庆特惠同城微醺立减券',
discountAmount: 25,
minSpend: 60,
categoryLimit: 'DRINK',
description: '望京跳海酒馆微醺可用'
});
expect(coupon.id).toBe(4);
expect(coupon.discountAmount).toBe(25);
});
it('优惠券名称为空或减免金额无效时应被拒绝', () => {
expect(() => {
service.createCoupon({
name: '',
discountAmount: 20
});
}).toThrow('优惠券名称不能为空');
expect(() => {
service.createCoupon({
name: '测试券',
discountAmount: -5
});
}).toThrow('减免面额必须大于0');
});
it('优惠券名称或描述涉嫌违规敏感词应触发微信内容安全拦截', () => {
expect(() => {
service.createCoupon({
name: '私下转账免手续费优惠大促',
discountAmount: 50
});
}).toThrow();
});
});
describe('3. 数据库与 API 架构持久化门禁校验', () => {
it('MySQL 数据库必须包含 recharge_tiers 与 coupons 表定义及种子数据', () => {
const mysqlContent = fs.readFileSync(mysqlPath, 'utf-8');
expect(mysqlContent).toContain('CREATE TABLE IF NOT EXISTS recharge_tiers');
expect(mysqlContent).toContain('CREATE TABLE IF NOT EXISTS coupons');
expect(mysqlContent).toContain('INSERT INTO recharge_tiers');
expect(mysqlContent).toContain('INSERT INTO coupons');
});
it('Repository 数据仓储层必须实现完整的充值阶梯与优惠券 CRUD 方法', () => {
const repoContent = fs.readFileSync(repoPath, 'utf-8');
expect(repoContent).toContain('async getRechargeTiers(): Promise<any[]>');
expect(repoContent).toContain('async createRechargeTier(');
expect(repoContent).toContain('async updateRechargeTier(');
expect(repoContent).toContain('async deleteRechargeTier(');
expect(repoContent).toContain('async getCoupons(');
expect(repoContent).toContain('async createCoupon(');
expect(repoContent).toContain('async updateCoupon(');
expect(repoContent).toContain('async deleteCoupon(');
});
it('server/src/index.ts 必须注册完整的营销 API 路由', () => {
const indexContent = fs.readFileSync(serverIndexPath, 'utf-8');
expect(indexContent).toContain("app.get('/api/marketing/recharge-tiers'");
expect(indexContent).toContain("app.get('/api/admin/recharge-tiers'");
expect(indexContent).toContain("app.post('/api/admin/recharge-tiers'");
expect(indexContent).toContain("app.get('/api/marketing/coupons'");
expect(indexContent).toContain("app.get('/api/admin/coupons'");
expect(indexContent).toContain("app.post('/api/admin/coupons'");
});
it('代码文件必须严格遵循零 Emoji 门禁规范', () => {
const emojiRegex = /[\u{1F300}-\u{1F9FF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}]/u;
const serviceContent = fs.readFileSync(path.join(rootDir, 'server/src/core/marketing/marketing.service.ts'), 'utf-8');
const testContent = fs.readFileSync(__filename, 'utf-8');
expect(emojiRegex.test(serviceContent)).toBe(false);
expect(emojiRegex.test(testContent)).toBe(false);
});
});
});