Update documentation structure and enhance .gitignore
- Added generated index files and report directories to .gitignore to prevent unnecessary tracking of transient files. - Updated README links to reflect new documentation paths for better navigation. - Improved documentation organization by ensuring all links point to the correct locations, enhancing user experience and accessibility.
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
/**
|
||||
* Unit tests for authentication service
|
||||
*
|
||||
* This file demonstrates testing patterns for service functions in the API.
|
||||
* See docs/TEST_EXAMPLES.md for more examples.
|
||||
*/
|
||||
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import bcrypt from 'bcryptjs'
|
||||
import jwt from 'jsonwebtoken'
|
||||
import { login } from './auth'
|
||||
import { getDb } from '../db'
|
||||
import { AppErrors } from '../lib/errors'
|
||||
|
||||
// Mock dependencies
|
||||
vi.mock('../db')
|
||||
vi.mock('../lib/errors')
|
||||
vi.mock('bcryptjs')
|
||||
vi.mock('jsonwebtoken')
|
||||
vi.mock('../lib/secret-validation', () => ({
|
||||
requireJWTSecret: () => 'test-secret'
|
||||
}))
|
||||
|
||||
describe('auth service', () => {
|
||||
let mockDb: any
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
|
||||
mockDb = {
|
||||
query: vi.fn()
|
||||
}
|
||||
|
||||
vi.mocked(getDb).mockReturnValue(mockDb as any)
|
||||
})
|
||||
|
||||
describe('login', () => {
|
||||
it('should authenticate valid user and return token', async () => {
|
||||
// Arrange
|
||||
const mockUser = {
|
||||
id: '1',
|
||||
email: '[email protected]',
|
||||
name: 'Test User',
|
||||
password_hash: '$2a$10$hashed',
|
||||
role: 'USER',
|
||||
created_at: new Date('2024-01-01'),
|
||||
updated_at: new Date('2024-01-01'),
|
||||
}
|
||||
|
||||
mockDb.query.mockResolvedValue({
|
||||
rows: [mockUser]
|
||||
})
|
||||
|
||||
vi.mocked(bcrypt.compare).mockResolvedValue(true as never)
|
||||
vi.mocked(jwt.sign).mockReturnValue('mock-jwt-token' as any)
|
||||
|
||||
// Act
|
||||
const result = await login('[email protected]', 'password123')
|
||||
|
||||
// Assert
|
||||
expect(result).toHaveProperty('token')
|
||||
expect(result.token).toBe('mock-jwt-token')
|
||||
expect(result.user.email).toBe('[email protected]')
|
||||
expect(result.user.name).toBe('Test User')
|
||||
expect(result.user.role).toBe('USER')
|
||||
|
||||
expect(mockDb.query).toHaveBeenCalledWith(
|
||||
expect.stringContaining('SELECT'),
|
||||
['[email protected]']
|
||||
)
|
||||
expect(bcrypt.compare).toHaveBeenCalledWith('password123', mockUser.password_hash)
|
||||
expect(jwt.sign).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should throw error for invalid email', async () => {
|
||||
// Arrange
|
||||
mockDb.query.mockResolvedValue({
|
||||
rows: []
|
||||
})
|
||||
|
||||
// Act & Assert
|
||||
await expect(login('[email protected]', 'password123')).rejects.toThrow()
|
||||
|
||||
expect(bcrypt.compare).not.toHaveBeenCalled()
|
||||
expect(jwt.sign).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should throw error for invalid password', async () => {
|
||||
// Arrange
|
||||
const mockUser = {
|
||||
id: '1',
|
||||
email: '[email protected]',
|
||||
name: 'Test User',
|
||||
password_hash: '$2a$10$hashed',
|
||||
role: 'USER',
|
||||
created_at: new Date('2024-01-01'),
|
||||
updated_at: new Date('2024-01-01'),
|
||||
}
|
||||
|
||||
mockDb.query.mockResolvedValue({
|
||||
rows: [mockUser]
|
||||
})
|
||||
|
||||
vi.mocked(bcrypt.compare).mockResolvedValue(false as never)
|
||||
|
||||
// Act & Assert
|
||||
await expect(login('[email protected]', 'wrongpassword')).rejects.toThrow()
|
||||
|
||||
expect(bcrypt.compare).toHaveBeenCalledWith('wrongpassword', mockUser.password_hash)
|
||||
expect(jwt.sign).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('should include user role in JWT token', async () => {
|
||||
// Arrange
|
||||
const mockUser = {
|
||||
id: '1',
|
||||
email: '[email protected]',
|
||||
name: 'Admin User',
|
||||
password_hash: '$2a$10$hashed',
|
||||
role: 'ADMIN',
|
||||
created_at: new Date('2024-01-01'),
|
||||
updated_at: new Date('2024-01-01'),
|
||||
}
|
||||
|
||||
mockDb.query.mockResolvedValue({
|
||||
rows: [mockUser]
|
||||
})
|
||||
|
||||
vi.mocked(bcrypt.compare).mockResolvedValue(true as never)
|
||||
vi.mocked(jwt.sign).mockReturnValue('mock-jwt-token' as any)
|
||||
|
||||
// Act
|
||||
await login('[email protected]', 'password123')
|
||||
|
||||
// Assert
|
||||
expect(jwt.sign).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
id: '1',
|
||||
email: '[email protected]',
|
||||
name: 'Admin User',
|
||||
role: 'ADMIN',
|
||||
}),
|
||||
'test-secret',
|
||||
expect.objectContaining({
|
||||
expiresIn: expect.any(String)
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user