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 个字符'); }); }); });