/** * 用户模型单元测试 */ const mongoose = require('mongoose') const User = require('../../src/models/User') describe('User Model', () => { beforeAll(async () => { // 连接测试数据库 const mongoURI = process.env.MONGODB_URI || 'mongodb://localhost:27017/wdkj_test' await mongoose.connect(mongoURI) // 确保唯一索引已构建(dropDatabase 后 mongoose 不会自动重建) await mongoose.connection.syncIndexes() }) afterAll(async () => { // 防呆:只允许在测试库中 dropDatabase if (mongoose.connection.name === 'wdkj') { throw new Error('[安全] 不允许对生产数据库 wdkj 执行 dropDatabase') } // 清理并关闭连接 await mongoose.connection.dropDatabase() await mongoose.connection.close() }) beforeEach(async () => { // 每个测试前清空users集合 await User.deleteMany({}) }) describe('用户创建', () => { test('应该成功创建新用户', async () => { const userData = { openid: 'test_openid_123', nickName: '测试用户', avatarUrl: 'https://example.com/avatar.jpg' } const user = new User(userData) const savedUser = await user.save() expect(savedUser._id).toBeDefined() expect(savedUser.openid).toBe(userData.openid) expect(savedUser.nickName).toBe(userData.nickName) expect(savedUser.avatarUrl).toBe(userData.avatarUrl) expect(savedUser.unlockedDims).toContain(1) expect(savedUser.totalScore).toBe(0) }) test('username 必须唯一', async () => { await new User({ username: 'alice', nickName: '用户A' }).save() const duplicateUser = new User({ username: 'alice', nickName: '用户B' }) await expect(duplicateUser.save()).rejects.toThrow() }) test('openid 必须唯一', async () => { const userData = { openid: 'unique_openid', nickName: '用户1' } await new User(userData).save() const duplicateUser = new User({ openid: 'unique_openid', nickName: '用户2' }) await expect(duplicateUser.save()).rejects.toThrow() }) test('默认昵称应该是"星辰旅行者"', async () => { const user = new User({ openid: 'test_openid' }) await user.save() expect(user.nickName).toBe('星辰旅行者') }) }) describe('探索数据', () => { test('应该正确计算总分', async () => { const user = new User({ openid: 'test_openid', exploreData: { dim1: { bestScore: 100 }, dim2: { bestArea: 200 }, dim3: { bestScore: 150 } } }) await user.save() expect(user.totalScore).toBe(450) expect(user.dim1Score).toBe(100) expect(user.dim2Score).toBe(200) expect(user.dim3Score).toBe(150) }) test('未解锁维度分数应为0', async () => { const user = new User({ openid: 'test_openid', exploreData: { dim1: { bestScore: 100 } } }) await user.save() expect(user.dim2Score).toBe(0) expect(user.dim3Score).toBe(0) expect(user.dim4Score).toBe(0) expect(user.dim5Score).toBe(0) }) }) describe('虚拟字段', () => { test('isNew 应该对新用户返回 true', async () => { const user = new User({ openid: 'test_openid' }) await user.save() expect(user.isNew).toBe(true) }) test('isNew 应该对老用户返回 false', async () => { const yesterday = new Date() yesterday.setDate(yesterday.getDate() - 2) const user = new User({ openid: 'test_openid', createdAt: yesterday }) await user.save() expect(user.isNew).toBe(false) }) }) describe('静态方法', () => { test('getLeaderboard 应该返回排行榜', async () => { // 创建测试用户(分数由 exploreData 派生,保存时自动计算) await User.create([ { openid: 'user1', exploreData: { dim1: { bestScore: 300 } } }, { openid: 'user2', exploreData: { dim1: { bestScore: 500 } } }, { openid: 'user3', exploreData: { dim1: { bestScore: 400 } } } ]) const leaderboard = await User.getLeaderboard(null, 10) expect(leaderboard).toHaveLength(3) expect(leaderboard[0].totalScore).toBe(500) expect(leaderboard[1].totalScore).toBe(400) expect(leaderboard[2].totalScore).toBe(300) }) test('getLeaderboard 应该支持按维度排序', async () => { await User.create([ { openid: 'user1', exploreData: { dim1: { bestScore: 100 } } }, { openid: 'user2', exploreData: { dim1: { bestScore: 200 } } }, { openid: 'user3', exploreData: { dim1: { bestScore: 150 } } } ]) const leaderboard = await User.getLeaderboard(1, 10) expect(leaderboard[0].dim1Score).toBe(200) expect(leaderboard[1].dim1Score).toBe(150) expect(leaderboard[2].dim1Score).toBe(100) }) }) })