Add comprehensive test suite and update configuration
- Add Jest testing framework configuration - Add test files for services, types, and utilities - Update package.json with Jest dependencies and test scripts - Enhance pre-commit checks to include testing - Add proper environment validation and error handling in mailgun service
This commit is contained in:
308
types/__tests__/types.test.ts
Normal file
308
types/__tests__/types.test.ts
Normal file
@@ -0,0 +1,308 @@
|
||||
import { Frequency, UserRole, DoseStatus } from '../../types';
|
||||
import type {
|
||||
Medication,
|
||||
Dose,
|
||||
CustomReminder,
|
||||
ReminderInstance,
|
||||
User,
|
||||
CouchDBDocument,
|
||||
} from '../../types';
|
||||
|
||||
describe('Type Definitions and Enums', () => {
|
||||
describe('Frequency Enum', () => {
|
||||
test('should have correct string values', () => {
|
||||
expect(Frequency.Daily).toBe('Daily');
|
||||
expect(Frequency.TwiceADay).toBe('Twice a day');
|
||||
expect(Frequency.ThreeTimesADay).toBe('Three times a day');
|
||||
expect(Frequency.EveryXHours).toBe('Every X hours');
|
||||
});
|
||||
|
||||
test('should be usable as object keys', () => {
|
||||
const frequencyMap = {
|
||||
[Frequency.Daily]: 1,
|
||||
[Frequency.TwiceADay]: 2,
|
||||
[Frequency.ThreeTimesADay]: 3,
|
||||
[Frequency.EveryXHours]: 'variable',
|
||||
};
|
||||
|
||||
expect(frequencyMap[Frequency.Daily]).toBe(1);
|
||||
expect(frequencyMap[Frequency.TwiceADay]).toBe(2);
|
||||
expect(frequencyMap[Frequency.ThreeTimesADay]).toBe(3);
|
||||
expect(frequencyMap[Frequency.EveryXHours]).toBe('variable');
|
||||
});
|
||||
|
||||
test('should have all expected frequency options', () => {
|
||||
const frequencyValues = Object.values(Frequency);
|
||||
expect(frequencyValues).toHaveLength(4);
|
||||
expect(frequencyValues).toContain('Daily');
|
||||
expect(frequencyValues).toContain('Twice a day');
|
||||
expect(frequencyValues).toContain('Three times a day');
|
||||
expect(frequencyValues).toContain('Every X hours');
|
||||
});
|
||||
});
|
||||
|
||||
describe('UserRole Enum', () => {
|
||||
test('should have correct values', () => {
|
||||
expect(UserRole.USER).toBe('USER');
|
||||
expect(UserRole.ADMIN).toBe('ADMIN');
|
||||
});
|
||||
});
|
||||
|
||||
describe('DoseStatus Enum', () => {
|
||||
test('should have correct values', () => {
|
||||
expect(DoseStatus.UPCOMING).toBe('UPCOMING');
|
||||
expect(DoseStatus.TAKEN).toBe('TAKEN');
|
||||
expect(DoseStatus.MISSED).toBe('MISSED');
|
||||
expect(DoseStatus.SNOOZED).toBe('SNOOZED');
|
||||
});
|
||||
});
|
||||
|
||||
describe('CouchDBDocument Type', () => {
|
||||
test('should require _id and _rev fields', () => {
|
||||
const doc: CouchDBDocument = {
|
||||
_id: 'test-id',
|
||||
_rev: 'test-rev',
|
||||
};
|
||||
|
||||
expect(doc._id).toBe('test-id');
|
||||
expect(doc._rev).toBe('test-rev');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Medication Type', () => {
|
||||
test('should accept valid medication object', () => {
|
||||
const medication: Medication = {
|
||||
_id: 'med-123',
|
||||
_rev: 'rev-456',
|
||||
name: 'Aspirin',
|
||||
dosage: '100mg',
|
||||
frequency: Frequency.Daily,
|
||||
startTime: '08:00',
|
||||
notes: 'Take with food',
|
||||
};
|
||||
|
||||
expect(medication._id).toBe('med-123');
|
||||
expect(medication.name).toBe('Aspirin');
|
||||
expect(medication.frequency).toBe(Frequency.Daily);
|
||||
expect(medication.startTime).toBe('08:00');
|
||||
});
|
||||
|
||||
test('should accept medication with hoursBetween for EveryXHours frequency', () => {
|
||||
const medication: Medication = {
|
||||
_id: 'med-456',
|
||||
_rev: 'rev-789',
|
||||
name: 'Pain Reliever',
|
||||
dosage: '200mg',
|
||||
frequency: Frequency.EveryXHours,
|
||||
startTime: '06:00',
|
||||
hoursBetween: 6,
|
||||
notes: '',
|
||||
};
|
||||
|
||||
expect(medication.frequency).toBe(Frequency.EveryXHours);
|
||||
expect(medication.hoursBetween).toBe(6);
|
||||
});
|
||||
|
||||
test('should accept medication with optional fields undefined', () => {
|
||||
const medication: Medication = {
|
||||
_id: 'med-789',
|
||||
_rev: 'rev-012',
|
||||
name: 'Vitamin D',
|
||||
dosage: '1000 IU',
|
||||
frequency: Frequency.Daily,
|
||||
startTime: '07:00',
|
||||
hoursBetween: undefined,
|
||||
notes: '',
|
||||
};
|
||||
|
||||
expect(medication.hoursBetween).toBeUndefined();
|
||||
expect(medication.notes).toBe('');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Dose Type', () => {
|
||||
test('should accept valid dose object', () => {
|
||||
const scheduledTime = new Date('2024-01-15T08:00:00.000Z');
|
||||
const dose: Dose = {
|
||||
id: 'dose-123',
|
||||
medicationId: 'med-456',
|
||||
scheduledTime,
|
||||
};
|
||||
|
||||
expect(dose.id).toBe('dose-123');
|
||||
expect(dose.medicationId).toBe('med-456');
|
||||
expect(dose.scheduledTime).toBe(scheduledTime);
|
||||
expect(dose.scheduledTime).toBeInstanceOf(Date);
|
||||
});
|
||||
|
||||
test('should validate unique dose ID format', () => {
|
||||
const dose: Dose = {
|
||||
id: 'med-123-2024-01-15-080000',
|
||||
medicationId: 'med-123',
|
||||
scheduledTime: new Date('2024-01-15T08:00:00.000Z'),
|
||||
};
|
||||
|
||||
expect(dose.id).toContain('med-123');
|
||||
expect(dose.id).toContain('2024-01-15');
|
||||
});
|
||||
});
|
||||
|
||||
describe('CustomReminder Type', () => {
|
||||
test('should accept valid custom reminder object', () => {
|
||||
const reminder: CustomReminder = {
|
||||
_id: 'reminder-123',
|
||||
_rev: 'rev-456',
|
||||
title: 'Check Blood Pressure',
|
||||
icon: '🩺',
|
||||
startTime: '09:00',
|
||||
endTime: '17:00',
|
||||
frequencyMinutes: 60,
|
||||
};
|
||||
|
||||
expect(reminder._id).toBe('reminder-123');
|
||||
expect(reminder.title).toBe('Check Blood Pressure');
|
||||
expect(reminder.icon).toBe('🩺');
|
||||
expect(reminder.startTime).toBe('09:00');
|
||||
expect(reminder.endTime).toBe('17:00');
|
||||
expect(reminder.frequencyMinutes).toBe(60);
|
||||
});
|
||||
|
||||
test('should validate frequency minutes is a number', () => {
|
||||
const reminder: CustomReminder = {
|
||||
_id: 'reminder-789',
|
||||
_rev: 'rev-012',
|
||||
title: 'Hydrate',
|
||||
icon: '💧',
|
||||
startTime: '08:00',
|
||||
endTime: '20:00',
|
||||
frequencyMinutes: 30,
|
||||
};
|
||||
|
||||
expect(typeof reminder.frequencyMinutes).toBe('number');
|
||||
expect(reminder.frequencyMinutes).toBeGreaterThan(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('ReminderInstance Type', () => {
|
||||
test('should accept valid reminder instance object', () => {
|
||||
const scheduledTime = new Date('2024-01-15T10:00:00.000Z');
|
||||
const instance: ReminderInstance = {
|
||||
id: 'instance-123',
|
||||
reminderId: 'reminder-456',
|
||||
title: 'Take Vitamins',
|
||||
icon: '💊',
|
||||
scheduledTime,
|
||||
};
|
||||
|
||||
expect(instance.id).toBe('instance-123');
|
||||
expect(instance.reminderId).toBe('reminder-456');
|
||||
expect(instance.title).toBe('Take Vitamins');
|
||||
expect(instance.icon).toBe('💊');
|
||||
expect(instance.scheduledTime).toBe(scheduledTime);
|
||||
expect(instance.scheduledTime).toBeInstanceOf(Date);
|
||||
});
|
||||
});
|
||||
|
||||
describe('User Type', () => {
|
||||
test('should accept valid user object with required fields', () => {
|
||||
const user: User = {
|
||||
_id: 'user-123',
|
||||
_rev: 'rev-456',
|
||||
username: 'testuser',
|
||||
};
|
||||
|
||||
expect(user._id).toBe('user-123');
|
||||
expect(user._rev).toBe('rev-456');
|
||||
expect(user.username).toBe('testuser');
|
||||
});
|
||||
|
||||
test('should accept user with all optional fields', () => {
|
||||
const user: User = {
|
||||
_id: 'user-456',
|
||||
_rev: 'rev-789',
|
||||
username: 'fulluser',
|
||||
email: 'full@example.com',
|
||||
avatar: 'base64-encoded-avatar',
|
||||
password: 'hashed-password',
|
||||
emailVerified: true,
|
||||
role: UserRole.USER,
|
||||
createdAt: new Date('2024-01-01T00:00:00.000Z'),
|
||||
lastLoginAt: new Date('2024-01-15T08:00:00.000Z'),
|
||||
};
|
||||
|
||||
expect(user.email).toBe('full@example.com');
|
||||
expect(user.avatar).toBe('base64-encoded-avatar');
|
||||
expect(user.password).toBe('hashed-password');
|
||||
expect(user.emailVerified).toBe(true);
|
||||
expect(user.role).toBe(UserRole.USER);
|
||||
expect(user.createdAt).toBeInstanceOf(Date);
|
||||
expect(user.lastLoginAt).toBeInstanceOf(Date);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Type Compatibility', () => {
|
||||
test('should handle Date objects consistently', () => {
|
||||
const now = new Date();
|
||||
const dose: Dose = {
|
||||
id: 'date-test',
|
||||
medicationId: 'med-test',
|
||||
scheduledTime: now,
|
||||
};
|
||||
|
||||
expect(dose.scheduledTime).toBe(now);
|
||||
expect(dose.scheduledTime).toBeInstanceOf(Date);
|
||||
});
|
||||
|
||||
test('should handle unicode characters in string fields', () => {
|
||||
const reminder: CustomReminder = {
|
||||
_id: 'unicode-test',
|
||||
_rev: 'rev-unicode',
|
||||
title: 'Medicine with émojis 💊🏥',
|
||||
icon: '🎯',
|
||||
startTime: '08:00',
|
||||
endTime: '20:00',
|
||||
frequencyMinutes: 30,
|
||||
};
|
||||
|
||||
expect(reminder.title).toContain('émojis');
|
||||
expect(reminder.title).toContain('💊');
|
||||
expect(reminder.icon).toBe('🎯');
|
||||
});
|
||||
|
||||
test('should handle empty string values where appropriate', () => {
|
||||
const medication: Medication = {
|
||||
_id: 'empty-test',
|
||||
_rev: 'rev-empty',
|
||||
name: 'Test Med',
|
||||
dosage: '10mg',
|
||||
frequency: Frequency.Daily,
|
||||
startTime: '08:00',
|
||||
notes: '',
|
||||
};
|
||||
|
||||
expect(medication.notes).toBe('');
|
||||
expect(typeof medication.notes).toBe('string');
|
||||
});
|
||||
|
||||
test('should maintain type safety with functions', () => {
|
||||
const createDose = (medication: Medication): Dose => ({
|
||||
id: `${medication._id}-${Date.now()}`,
|
||||
medicationId: medication._id,
|
||||
scheduledTime: new Date(),
|
||||
});
|
||||
|
||||
const medication: Medication = {
|
||||
_id: 'function-test',
|
||||
_rev: 'rev-function',
|
||||
name: 'Function Med',
|
||||
dosage: '25mg',
|
||||
frequency: Frequency.TwiceADay,
|
||||
startTime: '12:00',
|
||||
notes: '',
|
||||
};
|
||||
|
||||
const dose = createDose(medication);
|
||||
expect(dose.medicationId).toBe(medication._id);
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user