2026-06-01 17:00:05 +08:00

99 lines
2.7 KiB
TypeScript

import { NextRequest } from 'next/server'
import { POST } from '../route'
jest.mock('@/lib/auth', () => ({
authOptions: {},
}))
jest.mock('next-auth', () => ({
getServerSession: jest.fn(),
}))
jest.mock('@/lib/prisma', () => ({
prisma: {
$transaction: jest.fn(),
user: {
findUnique: jest.fn(),
update: jest.fn(),
},
},
}))
jest.mock('bcryptjs', () => ({
compare: jest.fn(),
hash: jest.fn(async (value: string) => `hashed:${value}`),
}))
jest.mock('@/lib/system-init', () => ({
isInitialAdminPasswordChangeRequired: jest.fn(),
clearInitialAdminPasswordRequirement: jest.fn(),
}))
const { getServerSession } = require('next-auth')
const { prisma } = require('@/lib/prisma')
const bcrypt = require('bcryptjs')
const {
isInitialAdminPasswordChangeRequired,
clearInitialAdminPasswordRequirement,
} = require('@/lib/system-init')
function createRequest(body: Record<string, unknown>) {
return new NextRequest('http://localhost/api/user/change-password', {
method: 'POST',
body: JSON.stringify(body),
})
}
describe('POST /api/user/change-password', () => {
beforeEach(() => {
jest.resetAllMocks()
getServerSession.mockResolvedValue({
user: {
email: 'admin@local.flnxi',
},
})
prisma.user.findUnique.mockResolvedValue({
id: 'admin-1',
email: 'admin@local.flnxi',
password: 'old-hash',
})
isInitialAdminPasswordChangeRequired.mockResolvedValue(false)
bcrypt.compare.mockResolvedValue(false)
prisma.$transaction.mockImplementation(async (callback: any) => callback({
user: prisma.user,
}))
})
test('拒绝弱新密码且不查询用户密码', async () => {
const response = await POST(createRequest({
oldPassword: 'old-password',
newPassword: '123456',
}))
const data = await response.json()
expect(response.status).toBe(400)
expect(data.error).toContain('至少')
expect(prisma.user.findUnique).not.toHaveBeenCalled()
expect(prisma.user.update).not.toHaveBeenCalled()
})
test('首次登录强制改密时允许省略旧密码,但仍要求强密码', async () => {
isInitialAdminPasswordChangeRequired.mockResolvedValue(true)
const response = await POST(createRequest({
newPassword: 'Flnxi-2026-Safe',
}))
const data = await response.json()
expect(response.status).toBe(200)
expect(data.success).toBe(true)
expect(bcrypt.hash).toHaveBeenCalledWith('Flnxi-2026-Safe', 10)
expect(prisma.user.update).toHaveBeenCalled()
expect(clearInitialAdminPasswordRequirement).toHaveBeenCalledWith(
'admin-1',
expect.objectContaining({ user: prisma.user }),
{ throwOnFailure: true }
)
})
})