99 lines
2.7 KiB
TypeScript
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 }
|
|
)
|
|
})
|
|
})
|