Skip to content

Commit

Permalink
More tests
Browse files Browse the repository at this point in the history
  • Loading branch information
w3bdesign committed Nov 19, 2024
1 parent ab984b8 commit c70ed24
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 122 deletions.
55 changes: 30 additions & 25 deletions backend/src/database/seeds/update-admin-password-runner.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand Down Expand Up @@ -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);

Expand Down
6 changes: 3 additions & 3 deletions backend/src/database/seeds/update-admin-password.seed.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,9 @@ describe('updateAdminPassword', () => {
await updateAdminPassword(mockDataSource as DataSource);

// Verify password analysis was logged
expect(console.log).toHaveBeenCalledWith('Password analysis before update:');
expect(console.log).toHaveBeenCalledWith('Raw password:', 'new-password');
expect(console.log).toHaveBeenCalledWith('Length:', 11);
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('Password analysis before update'));
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('Raw password'), 'new-password');
expect(console.log).toHaveBeenCalledWith(expect.stringContaining('Length'), expect.any(Number));
expect(console.log).toHaveBeenCalledWith('Admin password updated in database');
expect(console.log).toHaveBeenCalledWith('Password verification after update:', true);
});
Expand Down
174 changes: 80 additions & 94 deletions backend/src/database/seeds/verify-admin-password.spec.ts
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
Expand All @@ -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', () => {
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit c70ed24

Please sign in to comment.