159 行
4.7 KiB
TypeScript
159 行
4.7 KiB
TypeScript
import { ReviewAndCommentService } from '../src/core/review/review.service';
|
||
import { OrderStatus } from '../src/core/order/order-state-machine';
|
||
|
||
describe('ReviewAndCommentService (TDD 订单评价打分与动态评论测试套件)', () => {
|
||
let service: ReviewAndCommentService;
|
||
|
||
beforeEach(() => {
|
||
service = new ReviewAndCommentService();
|
||
});
|
||
|
||
describe('1. 订单评价业务规则与越权拦截', () => {
|
||
it('已完成(COMPLETED)状态的订单成功提交 5 星好评与评价标签', () => {
|
||
const review = service.submitOrderReview({
|
||
orderId: 'ord_1001',
|
||
orderStatus: OrderStatus.COMPLETED,
|
||
expertId: 101,
|
||
userId: 2001,
|
||
userNickname: '电竞小王子',
|
||
rating: 5,
|
||
tags: ['技术强', '声音好听', '带飞吃鸡'],
|
||
content: '大神非常给力,连续吃鸡3把!'
|
||
});
|
||
|
||
expect(review.id).toBeDefined();
|
||
expect(review.rating).toBe(5);
|
||
expect(review.tags).toContain('带飞吃鸡');
|
||
expect(review.orderId).toBe('ord_1001');
|
||
});
|
||
|
||
it('非 COMPLETED 状态的订单(如服务中/待付款)尝试评价应被拒绝拦截', () => {
|
||
expect(() => {
|
||
service.submitOrderReview({
|
||
orderId: 'ord_1002',
|
||
orderStatus: OrderStatus.IN_SERVICE,
|
||
expertId: 101,
|
||
userId: 2001,
|
||
userNickname: '小李',
|
||
rating: 5,
|
||
});
|
||
}).toThrow('只有已完成(COMPLETED)状态的订单才允许提交服务评价');
|
||
});
|
||
|
||
it('评分小于 1 或大于 5 时应抛出参数校验异常', () => {
|
||
expect(() => {
|
||
service.submitOrderReview({
|
||
orderId: 'ord_1003',
|
||
orderStatus: OrderStatus.COMPLETED,
|
||
expertId: 101,
|
||
userId: 2001,
|
||
userNickname: '小李',
|
||
rating: 6,
|
||
});
|
||
}).toThrow('评分必须在 1 至 5 星之间');
|
||
|
||
expect(() => {
|
||
service.submitOrderReview({
|
||
orderId: 'ord_1004',
|
||
orderStatus: OrderStatus.COMPLETED,
|
||
expertId: 101,
|
||
userId: 2001,
|
||
userNickname: '小李',
|
||
rating: 0,
|
||
});
|
||
}).toThrow('评分必须在 1 至 5 星之间');
|
||
});
|
||
|
||
it('同一订单禁止重复提交评价(防刷评)', () => {
|
||
service.submitOrderReview({
|
||
orderId: 'ord_1005',
|
||
orderStatus: OrderStatus.COMPLETED,
|
||
expertId: 101,
|
||
userId: 2001,
|
||
userNickname: '小李',
|
||
rating: 5,
|
||
});
|
||
|
||
expect(() => {
|
||
service.submitOrderReview({
|
||
orderId: 'ord_1005',
|
||
orderStatus: OrderStatus.COMPLETED,
|
||
expertId: 101,
|
||
userId: 2001,
|
||
userNickname: '小李',
|
||
rating: 4,
|
||
});
|
||
}).toThrow('该订单已评价,不可重复提交评价');
|
||
});
|
||
|
||
it('大神新增多条评价后,动态综合平均评分计算准确', () => {
|
||
service.submitOrderReview({
|
||
orderId: 'ord_201',
|
||
orderStatus: OrderStatus.COMPLETED,
|
||
expertId: 102,
|
||
userId: 301,
|
||
userNickname: '玩家A',
|
||
rating: 5,
|
||
});
|
||
|
||
service.submitOrderReview({
|
||
orderId: 'ord_202',
|
||
orderStatus: OrderStatus.COMPLETED,
|
||
expertId: 102,
|
||
userId: 302,
|
||
userNickname: '玩家B',
|
||
rating: 4,
|
||
});
|
||
|
||
const avg = service.calculateExpertAverageRating(102);
|
||
expect(avg).toBe(4.5);
|
||
});
|
||
});
|
||
|
||
describe('2. 友圈动态互动评论区规则', () => {
|
||
it('成功发表动态互动评论并支持按动态聚合查询', () => {
|
||
const c1 = service.submitPostComment({
|
||
postId: 'post_001',
|
||
userId: 2001,
|
||
author: '三里屯吃货',
|
||
content: '我也在三里屯,求组队!'
|
||
});
|
||
|
||
const c2 = service.submitPostComment({
|
||
postId: 'post_001',
|
||
userId: 2002,
|
||
author: '火锅达人',
|
||
content: '晚上几点开饭?已加微。'
|
||
});
|
||
|
||
const list = service.getCommentsByPost('post_001');
|
||
expect(list.length).toBe(2);
|
||
expect(list[0].id).toBe(c1.id);
|
||
expect(list[1].id).toBe(c2.id);
|
||
});
|
||
|
||
it('空评论或纯空格评论应被拦截', () => {
|
||
expect(() => {
|
||
service.submitPostComment({
|
||
postId: 'post_001',
|
||
userId: 2001,
|
||
author: '张三',
|
||
content: ' '
|
||
});
|
||
}).toThrow('评论内容不能为空');
|
||
});
|
||
|
||
it('超长评论(超过500字)应被安全阻断', () => {
|
||
const longText = 'a'.repeat(501);
|
||
expect(() => {
|
||
service.submitPostComment({
|
||
postId: 'post_001',
|
||
userId: 2001,
|
||
author: '张三',
|
||
content: longText
|
||
});
|
||
}).toThrow('评论内容不能超过 500 个字符');
|
||
});
|
||
});
|
||
});
|