66de1dc396
- client: 全部页面接入 onShareAppMessage/onShareTimeline 分享钩子 - client: login 页增强、profile 订阅展示优化 - client/stores: 订阅字段扁平结构映射为 subInfo(plan/expiresAt/startDate) - server: auth 路由 JWT 无效/过期统一返回 401 未授权响应 - server: models/tests 同步更新
176 lines
5.1 KiB
JavaScript
Executable File
176 lines
5.1 KiB
JavaScript
Executable File
/**
|
|
* 用户模型单元测试
|
|
*/
|
|
|
|
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)
|
|
})
|
|
})
|
|
})
|