Implement authentication functionality with login server action
- Created loginUser server action with credential validation - Implemented password verification using bcrypt (via NextAuth authorize) - Session creation on successful login handled by NextAuth - Invalid credentials handled with appropriate error messages - Added comprehensive unit tests for login functionality - All tests passing (11/11) Requirements: 2.1, 2.2
This commit is contained in:
@@ -14,7 +14,8 @@ vi.mock('@/auth', () => ({
|
||||
}))
|
||||
|
||||
// Import after mocking
|
||||
import { registerUser } from '../auth-actions'
|
||||
import { registerUser, loginUser } from '../auth-actions'
|
||||
import { signIn } from '@/auth'
|
||||
|
||||
describe('registerUser', () => {
|
||||
// Clean up test users after each test
|
||||
@@ -125,3 +126,97 @@ describe('registerUser', () => {
|
||||
expect(user?.name).toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
describe('loginUser', () => {
|
||||
// Clean up test users after each test
|
||||
afterEach(async () => {
|
||||
await prisma.user.deleteMany({
|
||||
where: {
|
||||
email: {
|
||||
contains: 'test-login-',
|
||||
},
|
||||
},
|
||||
})
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
it('should successfully login with valid credentials', async () => {
|
||||
const email = `test-login-${Date.now()}@example.com`
|
||||
const password = 'password123'
|
||||
|
||||
// Create a test user first
|
||||
await registerUser(email, password, 'Test User')
|
||||
|
||||
// Mock signIn to succeed
|
||||
vi.mocked(signIn).mockResolvedValueOnce(undefined as any)
|
||||
|
||||
// Attempt login
|
||||
const result = await loginUser(email, password)
|
||||
|
||||
expect(result.success).toBe(true)
|
||||
expect(signIn).toHaveBeenCalledWith('credentials', {
|
||||
email,
|
||||
password,
|
||||
redirect: false,
|
||||
})
|
||||
})
|
||||
|
||||
it('should reject login with invalid credentials', async () => {
|
||||
const email = `test-login-${Date.now()}@example.com`
|
||||
const password = 'password123'
|
||||
|
||||
// Create a test user first
|
||||
await registerUser(email, password, 'Test User')
|
||||
|
||||
// Mock signIn to throw error (invalid credentials)
|
||||
vi.mocked(signIn).mockRejectedValueOnce(new Error('Invalid credentials'))
|
||||
|
||||
// Attempt login with wrong password
|
||||
const result = await loginUser(email, 'wrongpassword')
|
||||
|
||||
expect(result.success).toBe(false)
|
||||
if (!result.success) {
|
||||
expect(result.error).toContain('Invalid email or password')
|
||||
}
|
||||
})
|
||||
|
||||
it('should reject login with non-existent email', async () => {
|
||||
const email = `test-login-nonexistent-${Date.now()}@example.com`
|
||||
const password = 'password123'
|
||||
|
||||
// Mock signIn to throw error (user not found)
|
||||
vi.mocked(signIn).mockRejectedValueOnce(new Error('User not found'))
|
||||
|
||||
// Attempt login with non-existent email
|
||||
const result = await loginUser(email, password)
|
||||
|
||||
expect(result.success).toBe(false)
|
||||
if (!result.success) {
|
||||
expect(result.error).toContain('Invalid email or password')
|
||||
}
|
||||
})
|
||||
|
||||
it('should reject login with invalid email format', async () => {
|
||||
const email = 'invalid-email'
|
||||
const password = 'password123'
|
||||
|
||||
const result = await loginUser(email, password)
|
||||
|
||||
expect(result.success).toBe(false)
|
||||
if (!result.success) {
|
||||
expect(result.error).toContain('Invalid email')
|
||||
}
|
||||
})
|
||||
|
||||
it('should reject login with empty password', async () => {
|
||||
const email = `test-login-${Date.now()}@example.com`
|
||||
const password = ''
|
||||
|
||||
const result = await loginUser(email, password)
|
||||
|
||||
expect(result.success).toBe(false)
|
||||
if (!result.success) {
|
||||
expect(result.error).toContain('Password is required')
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user