140 行
5.4 KiB
TypeScript
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);
|
|
});
|
|
});
|
|
});
|