- Add comprehensive tests for MailgunService (439 lines) * Email sending functionality with template generation * Configuration status validation * Error handling and edge cases * Mock setup for fetch API and FormData - Add DatabaseService tests (451 lines) * Strategy pattern testing (Mock vs Production) * All CRUD operations for users, medications, settings * Legacy compatibility method testing * Proper TypeScript typing - Add MockDatabaseStrategy tests (434 lines) * Complete coverage of mock database implementation * User operations, medication management * Settings and custom reminders functionality * Data persistence and error handling - Add React hooks tests * useLocalStorage hook with comprehensive edge cases (340 lines) * useSettings hook with fetch operations and error handling (78 lines) - Fix auth integration tests * Update mocking to use new database service instead of legacy couchdb.factory * Fix service variable references and expectations - Simplify mailgun config tests * Remove redundant edge case testing * Focus on core functionality validation - Fix all TypeScript and ESLint issues * Proper FormData mock typing * Correct database entity type usage * Remove non-existent property references Test Results: - 184 total tests passing - Comprehensive coverage of core services - Zero TypeScript compilation errors - Full ESLint compliance
452 lines
13 KiB
TypeScript
452 lines
13 KiB
TypeScript
import { MockDatabaseStrategy } from '../MockDatabaseStrategy';
|
|
import { AccountStatus } from '../../auth/auth.constants';
|
|
import { Frequency } from '../../../types';
|
|
|
|
describe('MockDatabaseStrategy', () => {
|
|
let strategy: MockDatabaseStrategy;
|
|
|
|
beforeEach(() => {
|
|
strategy = new MockDatabaseStrategy();
|
|
});
|
|
|
|
describe('user operations', () => {
|
|
test('should create user with auto-generated ID', async () => {
|
|
const userData = {
|
|
username: 'testuser',
|
|
email: 'test@example.com',
|
|
};
|
|
|
|
const user = await strategy.createUser(userData);
|
|
|
|
expect(user._id).toBeDefined();
|
|
expect(user._rev).toBeDefined();
|
|
expect(user.username).toBe('testuser');
|
|
expect(user.email).toBe('test@example.com');
|
|
expect(user.createdAt).toBeInstanceOf(Date);
|
|
});
|
|
|
|
test('should create user with password', async () => {
|
|
const user = await strategy.createUserWithPassword(
|
|
'test@example.com',
|
|
'hashedpassword',
|
|
'testuser'
|
|
);
|
|
|
|
expect(user.email).toBe('test@example.com');
|
|
expect(user.password).toBe('hashedpassword');
|
|
expect(user.username).toBe('testuser');
|
|
expect(user.status).toBe(AccountStatus.PENDING);
|
|
expect(user.emailVerified).toBe(false);
|
|
});
|
|
|
|
test('should create OAuth user', async () => {
|
|
const user = await strategy.createUserFromOAuth(
|
|
'oauth@example.com',
|
|
'OAuth User',
|
|
'google'
|
|
);
|
|
|
|
expect(user.email).toBe('oauth@example.com');
|
|
expect(user.username).toBe('OAuth User');
|
|
expect(user.status).toBe(AccountStatus.ACTIVE);
|
|
expect(user.emailVerified).toBe(true);
|
|
});
|
|
|
|
test('should find user by email', async () => {
|
|
const createdUser = await strategy.createUserWithPassword(
|
|
'findme@example.com',
|
|
'password',
|
|
'finduser'
|
|
);
|
|
|
|
const foundUser = await strategy.findUserByEmail('findme@example.com');
|
|
|
|
expect(foundUser?._id).toBe(createdUser._id);
|
|
expect(foundUser?.email).toBe(createdUser.email);
|
|
expect(foundUser?.username).toBe(createdUser.username);
|
|
});
|
|
|
|
test('should return null when user not found by email', async () => {
|
|
const user = await strategy.findUserByEmail('notfound@example.com');
|
|
expect(user).toBeNull();
|
|
});
|
|
|
|
test('should get user by ID', async () => {
|
|
const createdUser = await strategy.createUser({
|
|
username: 'testuser',
|
|
email: 'test@example.com',
|
|
});
|
|
|
|
const foundUser = await strategy.getUserById(createdUser._id);
|
|
|
|
expect(foundUser?._id).toBe(createdUser._id);
|
|
expect(foundUser?.email).toBe(createdUser.email);
|
|
expect(foundUser?.username).toBe(createdUser.username);
|
|
});
|
|
|
|
test('should return null when user not found by ID', async () => {
|
|
const user = await strategy.getUserById('nonexistent-id');
|
|
expect(user).toBeNull();
|
|
});
|
|
|
|
test('should update user', async () => {
|
|
const createdUser = await strategy.createUser({
|
|
username: 'original',
|
|
email: 'original@example.com',
|
|
});
|
|
|
|
const updatedUser = await strategy.updateUser({
|
|
...createdUser,
|
|
username: 'updated',
|
|
});
|
|
|
|
expect(updatedUser.username).toBe('updated');
|
|
expect(updatedUser._id).toBe(createdUser._id);
|
|
expect(updatedUser._rev).not.toBe(createdUser._rev);
|
|
});
|
|
|
|
test('should delete user', async () => {
|
|
const createdUser = await strategy.createUser({
|
|
username: 'tobedeleted',
|
|
email: 'delete@example.com',
|
|
});
|
|
|
|
const result = await strategy.deleteUser(createdUser._id);
|
|
expect(result).toBe(true);
|
|
|
|
const deletedUser = await strategy.getUserById(createdUser._id);
|
|
expect(deletedUser).toBeNull();
|
|
});
|
|
|
|
test('should get all users', async () => {
|
|
await strategy.createUser({
|
|
username: 'user1',
|
|
email: 'user1@example.com',
|
|
});
|
|
await strategy.createUser({
|
|
username: 'user2',
|
|
email: 'user2@example.com',
|
|
});
|
|
|
|
const users = await strategy.getAllUsers();
|
|
|
|
expect(users).toHaveLength(2);
|
|
expect(users[0].username).toBe('user1');
|
|
expect(users[1].username).toBe('user2');
|
|
});
|
|
});
|
|
|
|
describe('medication operations', () => {
|
|
let userId: string;
|
|
|
|
beforeEach(async () => {
|
|
const user = await strategy.createUser({
|
|
username: 'meduser',
|
|
email: 'med@example.com',
|
|
});
|
|
userId = user._id;
|
|
});
|
|
|
|
test('should create medication', async () => {
|
|
const medicationData = {
|
|
name: 'Aspirin',
|
|
dosage: '100mg',
|
|
frequency: Frequency.Daily,
|
|
startTime: '08:00',
|
|
notes: 'Take with food',
|
|
};
|
|
|
|
const medication = await strategy.createMedication(
|
|
userId,
|
|
medicationData
|
|
);
|
|
|
|
expect(medication._id).toBeDefined();
|
|
expect(medication._rev).toBeDefined();
|
|
expect(medication.name).toBe('Aspirin');
|
|
expect(medication.dosage).toBe('100mg');
|
|
expect(medication.frequency).toBe(Frequency.Daily);
|
|
});
|
|
|
|
test('should get medications for user', async () => {
|
|
await strategy.createMedication(userId, {
|
|
name: 'Med1',
|
|
dosage: '10mg',
|
|
frequency: Frequency.Daily,
|
|
startTime: '08:00',
|
|
notes: '',
|
|
});
|
|
|
|
await strategy.createMedication(userId, {
|
|
name: 'Med2',
|
|
dosage: '20mg',
|
|
frequency: Frequency.TwiceADay,
|
|
startTime: '12:00',
|
|
notes: '',
|
|
});
|
|
|
|
const medications = await strategy.getMedications(userId);
|
|
|
|
expect(medications).toHaveLength(2);
|
|
expect(medications[0].name).toBe('Med1');
|
|
expect(medications[1].name).toBe('Med2');
|
|
});
|
|
|
|
test('should update medication', async () => {
|
|
const created = await strategy.createMedication(userId, {
|
|
name: 'Original',
|
|
dosage: '10mg',
|
|
frequency: Frequency.Daily,
|
|
startTime: '08:00',
|
|
notes: '',
|
|
});
|
|
|
|
const updated = await strategy.updateMedication({
|
|
...created,
|
|
name: 'Updated',
|
|
dosage: '20mg',
|
|
});
|
|
|
|
expect(updated.name).toBe('Updated');
|
|
expect(updated.dosage).toBe('20mg');
|
|
expect(updated._rev).not.toBe(created._rev);
|
|
});
|
|
|
|
test('should delete medication', async () => {
|
|
const created = await strategy.createMedication(userId, {
|
|
name: 'ToDelete',
|
|
dosage: '10mg',
|
|
frequency: Frequency.Daily,
|
|
startTime: '08:00',
|
|
notes: '',
|
|
});
|
|
|
|
const result = await strategy.deleteMedication(created._id);
|
|
expect(result).toBe(true);
|
|
|
|
const medications = await strategy.getMedications(userId);
|
|
expect(medications).toHaveLength(0);
|
|
});
|
|
});
|
|
|
|
describe('user settings operations', () => {
|
|
let userId: string;
|
|
|
|
beforeEach(async () => {
|
|
const user = await strategy.createUser({
|
|
username: 'settingsuser',
|
|
email: 'settings@example.com',
|
|
});
|
|
userId = user._id;
|
|
});
|
|
|
|
test('should get default user settings', async () => {
|
|
const settings = await strategy.getUserSettings(userId);
|
|
|
|
expect(settings._id).toBe(userId);
|
|
expect(settings._rev).toBeDefined();
|
|
expect(settings.notificationsEnabled).toBe(true);
|
|
expect(settings.hasCompletedOnboarding).toBe(false);
|
|
});
|
|
|
|
test('should update user settings', async () => {
|
|
const currentSettings = await strategy.getUserSettings(userId);
|
|
|
|
const updatedSettings = await strategy.updateUserSettings({
|
|
...currentSettings,
|
|
notificationsEnabled: false,
|
|
hasCompletedOnboarding: true,
|
|
});
|
|
|
|
expect(updatedSettings.notificationsEnabled).toBe(false);
|
|
expect(updatedSettings.hasCompletedOnboarding).toBe(true);
|
|
expect(updatedSettings._rev).not.toBe(currentSettings._rev);
|
|
});
|
|
});
|
|
|
|
describe('taken doses operations', () => {
|
|
let userId: string;
|
|
|
|
beforeEach(async () => {
|
|
const user = await strategy.createUser({
|
|
username: 'dosesuser',
|
|
email: 'doses@example.com',
|
|
});
|
|
userId = user._id;
|
|
});
|
|
|
|
test('should get default taken doses', async () => {
|
|
const takenDoses = await strategy.getTakenDoses(userId);
|
|
|
|
expect(takenDoses._id).toBe(userId);
|
|
expect(takenDoses._rev).toBeDefined();
|
|
expect(takenDoses.doses).toEqual({});
|
|
});
|
|
|
|
test('should update taken doses', async () => {
|
|
const currentDoses = await strategy.getTakenDoses(userId);
|
|
|
|
const updatedDoses = await strategy.updateTakenDoses({
|
|
...currentDoses,
|
|
doses: {
|
|
'med1-2024-01-01': new Date().toISOString(),
|
|
},
|
|
});
|
|
|
|
expect(Object.keys(updatedDoses.doses)).toHaveLength(1);
|
|
expect(updatedDoses.doses['med1-2024-01-01']).toBeTruthy();
|
|
});
|
|
});
|
|
|
|
describe('custom reminders operations', () => {
|
|
let userId: string;
|
|
|
|
beforeEach(async () => {
|
|
const user = await strategy.createUser({
|
|
username: 'reminderuser',
|
|
email: 'reminder@example.com',
|
|
});
|
|
userId = user._id;
|
|
});
|
|
|
|
test('should create custom reminder', async () => {
|
|
const reminderData = {
|
|
title: 'Drink Water',
|
|
icon: '💧',
|
|
startTime: '08:00',
|
|
endTime: '20:00',
|
|
frequencyMinutes: 60,
|
|
};
|
|
|
|
const reminder = await strategy.createCustomReminder(
|
|
userId,
|
|
reminderData
|
|
);
|
|
|
|
expect(reminder._id).toBeDefined();
|
|
expect(reminder._rev).toBeDefined();
|
|
expect(reminder.title).toBe('Drink Water');
|
|
expect(reminder.icon).toBe('💧');
|
|
expect(reminder.frequencyMinutes).toBe(60);
|
|
});
|
|
|
|
test('should get custom reminders for user', async () => {
|
|
await strategy.createCustomReminder(userId, {
|
|
title: 'Reminder 1',
|
|
icon: '⏰',
|
|
startTime: '09:00',
|
|
endTime: '17:00',
|
|
frequencyMinutes: 30,
|
|
});
|
|
|
|
const reminders = await strategy.getCustomReminders(userId);
|
|
|
|
expect(reminders).toHaveLength(1);
|
|
expect(reminders[0].title).toBe('Reminder 1');
|
|
});
|
|
|
|
test('should update custom reminder', async () => {
|
|
const created = await strategy.createCustomReminder(userId, {
|
|
title: 'Original',
|
|
icon: '⏰',
|
|
startTime: '09:00',
|
|
endTime: '17:00',
|
|
frequencyMinutes: 30,
|
|
});
|
|
|
|
const updated = await strategy.updateCustomReminder({
|
|
...created,
|
|
title: 'Updated',
|
|
frequencyMinutes: 60,
|
|
});
|
|
|
|
expect(updated.title).toBe('Updated');
|
|
expect(updated.frequencyMinutes).toBe(60);
|
|
expect(updated._rev).not.toBe(created._rev);
|
|
});
|
|
|
|
test('should delete custom reminder', async () => {
|
|
const created = await strategy.createCustomReminder(userId, {
|
|
title: 'ToDelete',
|
|
icon: '⏰',
|
|
startTime: '09:00',
|
|
endTime: '17:00',
|
|
frequencyMinutes: 30,
|
|
});
|
|
|
|
const result = await strategy.deleteCustomReminder(created._id);
|
|
expect(result).toBe(true);
|
|
|
|
const reminders = await strategy.getCustomReminders(userId);
|
|
expect(reminders).toHaveLength(0);
|
|
});
|
|
});
|
|
|
|
describe('error handling', () => {
|
|
test('should create new document when updating non-existent user', async () => {
|
|
const result = await strategy.updateUser({
|
|
_id: 'nonexistent',
|
|
_rev: 'rev',
|
|
username: 'test',
|
|
});
|
|
|
|
expect(result._id).toBe('nonexistent');
|
|
expect(result.username).toBe('test');
|
|
});
|
|
|
|
test('should create new document when updating non-existent medication', async () => {
|
|
const result = await strategy.updateMedication({
|
|
_id: 'nonexistent',
|
|
_rev: 'rev',
|
|
name: 'test',
|
|
dosage: '10mg',
|
|
frequency: Frequency.Daily,
|
|
startTime: '08:00',
|
|
notes: '',
|
|
});
|
|
|
|
expect(result._id).toBe('nonexistent');
|
|
expect(result.name).toBe('test');
|
|
});
|
|
|
|
test('should return false when deleting non-existent user', async () => {
|
|
const result = await strategy.deleteUser('nonexistent');
|
|
expect(result).toBe(false);
|
|
});
|
|
|
|
test('should return false when deleting non-existent medication', async () => {
|
|
const result = await strategy.deleteMedication('nonexistent');
|
|
expect(result).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('data persistence', () => {
|
|
test('should maintain data across multiple operations', async () => {
|
|
// Create user
|
|
const user = await strategy.createUser({
|
|
username: 'persistent',
|
|
email: 'persistent@example.com',
|
|
});
|
|
|
|
// Create medication
|
|
const medication = await strategy.createMedication(user._id, {
|
|
name: 'Persistent Med',
|
|
dosage: '10mg',
|
|
frequency: Frequency.Daily,
|
|
startTime: '08:00',
|
|
notes: '',
|
|
});
|
|
|
|
// Verify data persists
|
|
const retrievedUser = await strategy.getUserById(user._id);
|
|
const medications = await strategy.getMedications(user._id);
|
|
|
|
expect(retrievedUser?._id).toBe(user._id);
|
|
expect(retrievedUser?.username).toBe(user.username);
|
|
expect(medications).toHaveLength(1);
|
|
expect(medications[0]._id).toBe(medication._id);
|
|
expect(medications[0].name).toBe(medication.name);
|
|
});
|
|
});
|
|
});
|