Files
Todo/lib/__tests__/auth-actions.test.ts

223 lines
6.2 KiB
TypeScript

/**
* Tests for user registration functionality
* This file tests the core registration logic without session creation
*/
import { describe, it, expect, afterEach, vi } from 'vitest'
import { prisma } from '../db'
import bcrypt from 'bcryptjs'
import { z } from 'zod'
// Mock the auth module to avoid Next.js dependencies in tests
vi.mock('@/auth', () => ({
signIn: vi.fn(),
}))
// Import after mocking
import { registerUser, loginUser } from '../auth-actions'
import { signIn } from 'next-auth/react'
describe('registerUser', () => {
// Clean up test users after each test
afterEach(async () => {
await prisma.user.deleteMany({
where: {
email: {
contains: 'test-',
},
},
})
})
it('should create a new user with valid credentials', async () => {
const email = `test-${Date.now()}@example.com`
const password = 'password123'
const name = 'Test User'
const result = await registerUser(email, password, name)
expect(result.success).toBe(true)
if (result.success) {
expect(result.userId).toBeDefined()
expect(typeof result.userId).toBe('string')
// Verify user was created in database
const user = await prisma.user.findUnique({
where: { email },
})
expect(user).toBeDefined()
expect(user?.email).toBe(email)
expect(user?.name).toBe(name)
expect(user?.passwordHash).toBeDefined()
expect(user?.passwordHash).not.toBe(password) // Password should be hashed
}
})
it('should reject registration with duplicate email', async () => {
const email = `test-${Date.now()}@example.com`
const password = 'password123'
// Create first user
const result1 = await registerUser(email, password)
expect(result1.success).toBe(true)
// Try to create second user with same email
const result2 = await registerUser(email, password)
expect(result2.success).toBe(false)
if (!result2.success) {
expect(result2.error).toContain('already registered')
}
})
it('should hash the password before storing', async () => {
const email = `test-${Date.now()}@example.com`
const password = 'password123'
const result = await registerUser(email, password)
expect(result.success).toBe(true)
const user = await prisma.user.findUnique({
where: { email },
})
expect(user?.passwordHash).toBeDefined()
expect(user?.passwordHash).not.toBe(password)
// Verify the hash is valid
const isValid = await bcrypt.compare(password, user!.passwordHash)
expect(isValid).toBe(true)
})
it('should reject password shorter than 8 characters', async () => {
const email = `test-${Date.now()}@example.com`
const password = 'short'
const result = await registerUser(email, password)
expect(result.success).toBe(false)
if (!result.success) {
expect(result.error).toContain('at least 8 characters')
}
})
it('should reject invalid email format', async () => {
const email = 'invalid-email'
const password = 'password123'
const result = await registerUser(email, password)
expect(result.success).toBe(false)
if (!result.success) {
expect(result.error).toContain('Invalid email')
}
})
it('should create user without name (optional field)', async () => {
const email = `test-${Date.now()}@example.com`
const password = 'password123'
const result = await registerUser(email, password)
expect(result.success).toBe(true)
const user = await prisma.user.findUnique({
where: { email },
})
expect(user).toBeDefined()
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')
}
})
})