-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
113 additions
and
122 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,38 +11,53 @@ jest.mock('dotenv'); | |
jest.mock('path'); | ||
|
||
describe('update-admin-password-runner', () => { | ||
let mockDataSource: Partial<DataSource>; | ||
const originalEnv = process.env; | ||
|
||
beforeEach(() => { | ||
// Mock DataSource | ||
mockDataSource = { | ||
initialize: jest.fn().mockResolvedValue(undefined), | ||
}; | ||
|
||
// Mock updateAdminPassword | ||
(updateAdminPassword as jest.Mock).mockResolvedValue(undefined); | ||
|
||
// Mock path.resolve | ||
(path.resolve as jest.Mock).mockReturnValue('/fake/path/.env'); | ||
|
||
// Mock fs.readFileSync | ||
(fs.readFileSync as jest.Mock).mockReturnValue('mock env file content'); | ||
|
||
// Mock dotenv.parse | ||
(dotenv.parse as jest.Mock).mockReturnValue({ | ||
DATABASE_URL: 'postgres://user:pass@localhost:5432/db', | ||
ADMIN_EMAIL: '[email protected]', | ||
ADMIN_PASSWORD: 'password123', | ||
}); | ||
|
||
// Mock console methods | ||
jest.spyOn(console, 'log').mockImplementation(() => {}); | ||
jest.spyOn(console, 'error').mockImplementation(() => {}); | ||
}); | ||
|
||
afterEach(() => { | ||
process.env = originalEnv; | ||
jest.clearAllMocks(); | ||
}); | ||
|
||
describe('loadEnvConfig', () => { | ||
it('should load and parse environment configuration', () => { | ||
// Mock path.resolve | ||
(path.resolve as jest.Mock).mockReturnValue('/fake/path/.env'); | ||
|
||
// Mock fs.readFileSync | ||
(fs.readFileSync as jest.Mock).mockReturnValue('mock env file content'); | ||
|
||
// Mock dotenv.parse | ||
const mockEnvConfig = { | ||
DATABASE_URL: 'postgres://user:pass@localhost:5432/db', | ||
ADMIN_EMAIL: '[email protected]', | ||
ADMIN_PASSWORD: 'password123', | ||
}; | ||
(dotenv.parse as jest.Mock).mockReturnValue(mockEnvConfig); | ||
|
||
const result = loadEnvConfig(); | ||
|
||
expect(path.resolve).toHaveBeenCalledWith(expect.any(String), '.env'); | ||
expect(fs.readFileSync).toHaveBeenCalledWith('/fake/path/.env'); | ||
expect(dotenv.parse).toHaveBeenCalledWith('mock env file content'); | ||
expect(result).toEqual(mockEnvConfig); | ||
expect(result).toEqual({ | ||
DATABASE_URL: 'postgres://user:pass@localhost:5432/db', | ||
ADMIN_EMAIL: '[email protected]', | ||
ADMIN_PASSWORD: 'password123', | ||
}); | ||
}); | ||
|
||
it('should handle errors when loading env file', () => { | ||
|
@@ -77,16 +92,6 @@ describe('update-admin-password-runner', () => { | |
}); | ||
|
||
describe('runPasswordUpdate', () => { | ||
let mockDataSource: Partial<DataSource>; | ||
|
||
beforeEach(() => { | ||
mockDataSource = { | ||
initialize: jest.fn().mockResolvedValue(undefined), | ||
}; | ||
|
||
(updateAdminPassword as jest.Mock).mockResolvedValue(undefined); | ||
}); | ||
|
||
it('should initialize database and run password update', async () => { | ||
const result = await runPasswordUpdate(mockDataSource as DataSource); | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,29 @@ | ||
import { DataSource, Repository } from 'typeorm'; | ||
import { User } from '../../users/entities/user.entity'; | ||
import { loadEnvConfig, createDataSource, verifyAdminPassword, runVerification } from './verify-admin-password'; | ||
import * as bcrypt from 'bcrypt'; | ||
import * as fs from 'fs'; | ||
import * as dotenv from 'dotenv'; | ||
import * as path from 'path'; | ||
|
||
// Mock User entity | ||
const mockUserEntity = { | ||
id: 'user-1', | ||
email: '[email protected]', | ||
password: 'hashed-password', | ||
}; | ||
|
||
jest.mock('../../users/entities/user.entity', () => ({ | ||
User: jest.fn(), | ||
})); | ||
jest.mock('bcrypt'); | ||
jest.mock('fs'); | ||
jest.mock('dotenv'); | ||
jest.mock('path'); | ||
|
||
describe('verify-admin-password', () => { | ||
let mockDataSource: Partial<DataSource>; | ||
let mockUserRepository: Partial<Repository<User>>; | ||
let mockUserRepository: Partial<Repository<typeof mockUserEntity>>; | ||
const originalEnv = process.env; | ||
|
||
beforeEach(() => { | ||
// Mock repository | ||
|
@@ -27,37 +37,45 @@ describe('verify-admin-password', () => { | |
getRepository: jest.fn().mockReturnValue(mockUserRepository), | ||
}; | ||
|
||
// Mock bcrypt | ||
(bcrypt.compare as jest.Mock).mockResolvedValue(true); | ||
(bcrypt.hash as jest.Mock).mockResolvedValue('new-hash'); | ||
|
||
// Mock path.resolve | ||
(path.resolve as jest.Mock).mockReturnValue('/fake/path/.env'); | ||
|
||
// Mock fs.readFileSync | ||
(fs.readFileSync as jest.Mock).mockReturnValue('mock env file content'); | ||
|
||
// Mock dotenv.parse | ||
(dotenv.parse as jest.Mock).mockReturnValue({ | ||
DATABASE_URL: 'postgres://user:pass@localhost:5432/db', | ||
ADMIN_EMAIL: '[email protected]', | ||
ADMIN_PASSWORD: 'password123', | ||
}); | ||
|
||
// Mock console methods | ||
jest.spyOn(console, 'log').mockImplementation(() => {}); | ||
jest.spyOn(console, 'error').mockImplementation(() => {}); | ||
}); | ||
|
||
afterEach(() => { | ||
process.env = originalEnv; | ||
jest.clearAllMocks(); | ||
}); | ||
|
||
describe('loadEnvConfig', () => { | ||
it('should load and parse environment configuration', () => { | ||
// Mock path.resolve | ||
(path.resolve as jest.Mock).mockReturnValue('/fake/path/.env'); | ||
|
||
// Mock fs.readFileSync | ||
(fs.readFileSync as jest.Mock).mockReturnValue('mock env file content'); | ||
|
||
// Mock dotenv.parse | ||
const mockEnvConfig = { | ||
DATABASE_URL: 'postgres://user:pass@localhost:5432/db', | ||
ADMIN_EMAIL: '[email protected]', | ||
ADMIN_PASSWORD: 'password123', | ||
}; | ||
(dotenv.parse as jest.Mock).mockReturnValue(mockEnvConfig); | ||
|
||
const result = loadEnvConfig(); | ||
|
||
expect(path.resolve).toHaveBeenCalledWith(expect.any(String), '.env'); | ||
expect(fs.readFileSync).toHaveBeenCalledWith('/fake/path/.env'); | ||
expect(dotenv.parse).toHaveBeenCalledWith('mock env file content'); | ||
expect(result).toEqual(mockEnvConfig); | ||
expect(result).toEqual({ | ||
DATABASE_URL: 'postgres://user:pass@localhost:5432/db', | ||
ADMIN_EMAIL: '[email protected]', | ||
ADMIN_PASSWORD: 'password123', | ||
}); | ||
}); | ||
|
||
it('should handle errors when loading env file', () => { | ||
|
@@ -92,136 +110,104 @@ describe('verify-admin-password', () => { | |
}); | ||
|
||
describe('verifyAdminPassword', () => { | ||
const adminEmail = '[email protected]'; | ||
const adminPassword = 'password123'; | ||
const storedHash = 'hashed-password'; | ||
|
||
beforeEach(() => { | ||
// Mock bcrypt methods | ||
(bcrypt.compare as jest.Mock) | ||
.mockResolvedValueOnce(true) // For stored password | ||
.mockResolvedValueOnce(true); // For new hash | ||
(bcrypt.hash as jest.Mock).mockResolvedValue('new-hash'); | ||
}); | ||
|
||
it('should verify password successfully', async () => { | ||
const mockUser = { | ||
id: 'user-1', | ||
email: adminEmail, | ||
password: storedHash, | ||
}; | ||
(mockUserRepository.findOne as jest.Mock).mockResolvedValue(mockUser); | ||
|
||
const result = await verifyAdminPassword(mockDataSource as DataSource, adminEmail, adminPassword); | ||
|
||
expect(result).toEqual({ | ||
isValid: true, | ||
newHashValid: true, | ||
storedHash, | ||
newHash: 'new-hash', | ||
(mockUserRepository.findOne as jest.Mock).mockResolvedValue({ | ||
...mockUserEntity, | ||
}); | ||
|
||
expect(bcrypt.compare).toHaveBeenCalledWith(adminPassword, storedHash); | ||
expect(bcrypt.hash).toHaveBeenCalledWith(adminPassword, 10); | ||
expect(console.log).toHaveBeenCalledWith('Password verification result:', true); | ||
const result = await verifyAdminPassword( | ||
mockDataSource as DataSource, | ||
'[email protected]', | ||
'password123' | ||
); | ||
|
||
expect(result.isValid).toBe(true); | ||
expect(result.newHashValid).toBe(true); | ||
expect(result.storedHash).toBe('hashed-password'); | ||
expect(result.newHash).toBe('new-hash'); | ||
expect(bcrypt.compare).toHaveBeenCalledWith('password123', 'hashed-password'); | ||
}); | ||
|
||
it('should handle case when admin user is not found', async () => { | ||
(mockUserRepository.findOne as jest.Mock).mockResolvedValue(null); | ||
|
||
await expect( | ||
verifyAdminPassword(mockDataSource as DataSource, adminEmail, adminPassword) | ||
verifyAdminPassword(mockDataSource as DataSource, '[email protected]', 'password123') | ||
).rejects.toThrow('Admin user not found'); | ||
}); | ||
|
||
it('should handle invalid password', async () => { | ||
const mockUser = { | ||
id: 'user-1', | ||
email: adminEmail, | ||
password: storedHash, | ||
}; | ||
(mockUserRepository.findOne as jest.Mock).mockResolvedValue(mockUser); | ||
(mockUserRepository.findOne as jest.Mock).mockResolvedValue({ | ||
...mockUserEntity, | ||
}); | ||
(bcrypt.compare as jest.Mock) | ||
.mockResolvedValueOnce(false) // For stored password | ||
.mockResolvedValueOnce(true); // For new hash | ||
.mockResolvedValueOnce(false) // Original password check fails | ||
.mockResolvedValueOnce(true); // New hash verification succeeds | ||
|
||
const result = await verifyAdminPassword(mockDataSource as DataSource, adminEmail, adminPassword); | ||
const result = await verifyAdminPassword( | ||
mockDataSource as DataSource, | ||
'[email protected]', | ||
'wrong-password' | ||
); | ||
|
||
expect(result.isValid).toBe(false); | ||
expect(console.log).toHaveBeenCalledWith('Password verification result:', false); | ||
expect(result.newHashValid).toBe(true); | ||
}); | ||
|
||
it('should handle bcrypt errors', async () => { | ||
const mockUser = { | ||
id: 'user-1', | ||
email: adminEmail, | ||
password: storedHash, | ||
}; | ||
(mockUserRepository.findOne as jest.Mock).mockResolvedValue(mockUser); | ||
|
||
(mockUserRepository.findOne as jest.Mock).mockResolvedValue({ | ||
...mockUserEntity, | ||
}); | ||
const bcryptError = new Error('Bcrypt error'); | ||
(bcrypt.compare as jest.Mock).mockRejectedValue(bcryptError); | ||
|
||
await expect( | ||
verifyAdminPassword(mockDataSource as DataSource, adminEmail, adminPassword) | ||
verifyAdminPassword(mockDataSource as DataSource, '[email protected]', 'password123') | ||
).rejects.toThrow(bcryptError); | ||
}); | ||
}); | ||
|
||
describe('runVerification', () => { | ||
const mockEnvConfig = { | ||
ADMIN_EMAIL: '[email protected]', | ||
ADMIN_PASSWORD: 'password123', | ||
}; | ||
|
||
it('should run verification successfully', async () => { | ||
const verificationResult = { | ||
isValid: true, | ||
newHashValid: true, | ||
storedHash: 'stored-hash', | ||
newHash: 'new-hash', | ||
}; | ||
(mockUserRepository.findOne as jest.Mock).mockResolvedValue({ | ||
id: 'user-1', | ||
email: mockEnvConfig.ADMIN_EMAIL, | ||
password: 'stored-hash', | ||
...mockUserEntity, | ||
}); | ||
(bcrypt.compare as jest.Mock).mockResolvedValue(true); | ||
(bcrypt.hash as jest.Mock).mockResolvedValue('new-hash'); | ||
|
||
const result = await runVerification(mockDataSource as DataSource, mockEnvConfig); | ||
const result = await runVerification(mockDataSource as DataSource, { | ||
ADMIN_EMAIL: '[email protected]', | ||
ADMIN_PASSWORD: 'password123', | ||
}); | ||
|
||
expect(result).toEqual(verificationResult); | ||
expect(result.isValid).toBe(true); | ||
expect(mockDataSource.initialize).toHaveBeenCalled(); | ||
expect(console.log).toHaveBeenCalledWith('Connected to database'); | ||
}); | ||
|
||
it('should throw error when admin email is missing', async () => { | ||
const invalidConfig = { ADMIN_PASSWORD: 'password123' }; | ||
|
||
await expect( | ||
runVerification(mockDataSource as DataSource, invalidConfig) | ||
runVerification(mockDataSource as DataSource, { | ||
ADMIN_PASSWORD: 'password123', | ||
}) | ||
).rejects.toThrow('Admin email and password must be set in environment variables'); | ||
|
||
expect(mockDataSource.initialize).toHaveBeenCalled(); | ||
}); | ||
|
||
it('should throw error when admin password is missing', async () => { | ||
const invalidConfig = { ADMIN_EMAIL: '[email protected]' }; | ||
|
||
await expect( | ||
runVerification(mockDataSource as DataSource, invalidConfig) | ||
runVerification(mockDataSource as DataSource, { | ||
ADMIN_EMAIL: '[email protected]', | ||
}) | ||
).rejects.toThrow('Admin email and password must be set in environment variables'); | ||
|
||
expect(mockDataSource.initialize).toHaveBeenCalled(); | ||
}); | ||
|
||
it('should handle database initialization errors', async () => { | ||
const dbError = new Error('Database initialization failed'); | ||
mockDataSource.initialize = jest.fn().mockRejectedValue(dbError); | ||
|
||
await expect( | ||
runVerification(mockDataSource as DataSource, mockEnvConfig) | ||
runVerification(mockDataSource as DataSource, { | ||
ADMIN_EMAIL: '[email protected]', | ||
ADMIN_PASSWORD: 'password123', | ||
}) | ||
).rejects.toThrow(dbError); | ||
|
||
expect(console.error).toHaveBeenCalledWith('Error:', dbError); | ||
|