← back to Jill Website

src/__tests__/Inquiry.test.ts

352 lines

import { InquiryModel, Inquiry } from '../models/Inquiry';
import { getTestPool } from './setup';

describe('InquiryModel Integration Tests', () => {
  let inquiryModel: InquiryModel;

  beforeEach(() => {
    // Override the pool in InquiryModel to use test pool
    inquiryModel = new InquiryModel();
    (inquiryModel as any).pool = getTestPool();
  });

  describe('create', () => {
    it('should create a new inquiry with valid data', async () => {
      const inquiryData = {
        name: 'John Doe',
        email: 'john@example.com',
        phone: '+1-555-1234',
        check_in_date: new Date('2026-06-01'),
        check_out_date: new Date('2026-06-07'),
        guest_count: 4,
        message: 'Looking forward to staying at your property!',
      };

      const inquiry = await inquiryModel.create(inquiryData);

      expect(inquiry).toBeDefined();
      expect(inquiry.id).toBeDefined();
      expect(inquiry.name).toBe('John Doe');
      expect(inquiry.email).toBe('john@example.com');
      expect(inquiry.phone).toBe('+1-555-1234');
      expect(inquiry.guest_count).toBe(4);
      expect(inquiry.message).toBe('Looking forward to staying at your property!');
      expect(inquiry.created_at).toBeDefined();
      expect(inquiry.updated_at).toBeDefined();
    });

    it('should normalize email to lowercase', async () => {
      const inquiryData = {
        name: 'Jane Smith',
        email: 'JANE@EXAMPLE.COM',
        phone: '+1-555-5678',
        check_in_date: new Date('2026-07-01'),
        check_out_date: new Date('2026-07-07'),
        guest_count: 2,
        message: 'Interested in booking',
      };

      const inquiry = await inquiryModel.create(inquiryData);
      expect(inquiry.email).toBe('jane@example.com');
    });

    it('should trim whitespace from fields', async () => {
      const inquiryData = {
        name: '  John Doe  ',
        email: '  john@example.com  ',
        phone: '  +1-555-1234  ',
        check_in_date: new Date('2026-06-01'),
        check_out_date: new Date('2026-06-07'),
        guest_count: 4,
        message: '  Looking forward to staying!  ',
      };

      const inquiry = await inquiryModel.create(inquiryData);
      expect(inquiry.name).toBe('John Doe');
      expect(inquiry.email).toBe('john@example.com');
      expect(inquiry.phone).toBe('+1-555-1234');
      expect(inquiry.message).toBe('Looking forward to staying!');
    });

    it('should reject inquiry with missing name', async () => {
      const inquiryData = {
        name: '',
        email: 'john@example.com',
        phone: '+1-555-1234',
        check_in_date: new Date('2026-06-01'),
        check_out_date: new Date('2026-06-07'),
        guest_count: 4,
        message: 'Looking forward to staying!',
      };

      await expect(inquiryModel.create(inquiryData)).rejects.toThrow('Name is required');
    });

    it('should reject inquiry with invalid email', async () => {
      const inquiryData = {
        name: 'John Doe',
        email: 'invalid-email',
        phone: '+1-555-1234',
        check_in_date: new Date('2026-06-01'),
        check_out_date: new Date('2026-06-07'),
        guest_count: 4,
        message: 'Looking forward to staying!',
      };

      await expect(inquiryModel.create(inquiryData)).rejects.toThrow('Valid email is required');
    });

    it('should reject inquiry with missing phone', async () => {
      const inquiryData = {
        name: 'John Doe',
        email: 'john@example.com',
        phone: '',
        check_in_date: new Date('2026-06-01'),
        check_out_date: new Date('2026-06-07'),
        guest_count: 4,
        message: 'Looking forward to staying!',
      };

      await expect(inquiryModel.create(inquiryData)).rejects.toThrow('Phone number is required');
    });

    it('should reject inquiry with check-out date before check-in date', async () => {
      const inquiryData = {
        name: 'John Doe',
        email: 'john@example.com',
        phone: '+1-555-1234',
        check_in_date: new Date('2026-06-07'),
        check_out_date: new Date('2026-06-01'),
        guest_count: 4,
        message: 'Looking forward to staying!',
      };

      await expect(inquiryModel.create(inquiryData)).rejects.toThrow('Check-out date must be after check-in date');
    });

    it('should reject inquiry with guest count less than 1', async () => {
      const inquiryData = {
        name: 'John Doe',
        email: 'john@example.com',
        phone: '+1-555-1234',
        check_in_date: new Date('2026-06-01'),
        check_out_date: new Date('2026-06-07'),
        guest_count: 0,
        message: 'Looking forward to staying!',
      };

      await expect(inquiryModel.create(inquiryData)).rejects.toThrow('Guest count must be at least 1');
    });

    it('should reject inquiry with empty message', async () => {
      const inquiryData = {
        name: 'John Doe',
        email: 'john@example.com',
        phone: '+1-555-1234',
        check_in_date: new Date('2026-06-01'),
        check_out_date: new Date('2026-06-07'),
        guest_count: 4,
        message: '',
      };

      await expect(inquiryModel.create(inquiryData)).rejects.toThrow('Message is required');
    });
  });

  describe('findById', () => {
    it('should retrieve inquiry by ID', async () => {
      const inquiryData = {
        name: 'John Doe',
        email: 'john@example.com',
        phone: '+1-555-1234',
        check_in_date: new Date('2026-06-01'),
        check_out_date: new Date('2026-06-07'),
        guest_count: 4,
        message: 'Looking forward to staying!',
      };

      const created = await inquiryModel.create(inquiryData);
      const found = await inquiryModel.findById(created.id!);

      expect(found).toBeDefined();
      expect(found!.id).toBe(created.id);
      expect(found!.name).toBe('John Doe');
      expect(found!.email).toBe('john@example.com');
    });

    it('should return null for non-existent ID', async () => {
      const found = await inquiryModel.findById(99999);
      expect(found).toBeNull();
    });
  });

  describe('findAll', () => {
    it('should retrieve all inquiries', async () => {
      const inquiry1 = {
        name: 'John Doe',
        email: 'john@example.com',
        phone: '+1-555-1234',
        check_in_date: new Date('2026-06-01'),
        check_out_date: new Date('2026-06-07'),
        guest_count: 4,
        message: 'First inquiry',
      };

      const inquiry2 = {
        name: 'Jane Smith',
        email: 'jane@example.com',
        phone: '+1-555-5678',
        check_in_date: new Date('2026-07-01'),
        check_out_date: new Date('2026-07-07'),
        guest_count: 2,
        message: 'Second inquiry',
      };

      await inquiryModel.create(inquiry1);
      await inquiryModel.create(inquiry2);

      const inquiries = await inquiryModel.findAll();

      expect(inquiries).toHaveLength(2);
      expect(inquiries[0].name).toBe('Jane Smith'); // Most recent first
      expect(inquiries[1].name).toBe('John Doe');
    });

    it('should respect limit parameter', async () => {
      const inquiry1 = {
        name: 'John Doe',
        email: 'john@example.com',
        phone: '+1-555-1234',
        check_in_date: new Date('2026-06-01'),
        check_out_date: new Date('2026-06-07'),
        guest_count: 4,
        message: 'First inquiry',
      };

      const inquiry2 = {
        name: 'Jane Smith',
        email: 'jane@example.com',
        phone: '+1-555-5678',
        check_in_date: new Date('2026-07-01'),
        check_out_date: new Date('2026-07-07'),
        guest_count: 2,
        message: 'Second inquiry',
      };

      await inquiryModel.create(inquiry1);
      await inquiryModel.create(inquiry2);

      const inquiries = await inquiryModel.findAll(1);
      expect(inquiries).toHaveLength(1);
    });

    it('should return empty array when no inquiries exist', async () => {
      const inquiries = await inquiryModel.findAll();
      expect(inquiries).toEqual([]);
    });
  });

  describe('update', () => {
    it('should update inquiry with valid data', async () => {
      const inquiryData = {
        name: 'John Doe',
        email: 'john@example.com',
        phone: '+1-555-1234',
        check_in_date: new Date('2026-06-01'),
        check_out_date: new Date('2026-06-07'),
        guest_count: 4,
        message: 'Original message',
      };

      const created = await inquiryModel.create(inquiryData);

      const updateData = {
        name: 'John Updated',
        email: 'john.updated@example.com',
        phone: '+1-555-9999',
        check_in_date: new Date('2026-08-01'),
        check_out_date: new Date('2026-08-07'),
        guest_count: 6,
        message: 'Updated message',
      };

      const updated = await inquiryModel.update(created.id!, updateData);

      expect(updated).toBeDefined();
      expect(updated!.id).toBe(created.id);
      expect(updated!.name).toBe('John Updated');
      expect(updated!.email).toBe('john.updated@example.com');
      expect(updated!.guest_count).toBe(6);
      expect(updated!.message).toBe('Updated message');
    });

    it('should return null when updating non-existent inquiry', async () => {
      const updateData = {
        name: 'John Updated',
        email: 'john@example.com',
        phone: '+1-555-1234',
        check_in_date: new Date('2026-06-01'),
        check_out_date: new Date('2026-06-07'),
        guest_count: 4,
        message: 'Updated message',
      };

      const updated = await inquiryModel.update(99999, updateData);
      expect(updated).toBeNull();
    });

    it('should reject update with invalid data', async () => {
      const inquiryData = {
        name: 'John Doe',
        email: 'john@example.com',
        phone: '+1-555-1234',
        check_in_date: new Date('2026-06-01'),
        check_out_date: new Date('2026-06-07'),
        guest_count: 4,
        message: 'Original message',
      };

      const created = await inquiryModel.create(inquiryData);

      const invalidUpdate = {
        name: '',
        email: 'john@example.com',
        phone: '+1-555-1234',
        check_in_date: new Date('2026-06-01'),
        check_out_date: new Date('2026-06-07'),
        guest_count: 4,
        message: 'Updated message',
      };

      await expect(inquiryModel.update(created.id!, invalidUpdate)).rejects.toThrow('Name is required');
    });
  });

  describe('delete', () => {
    it('should delete inquiry by ID', async () => {
      const inquiryData = {
        name: 'John Doe',
        email: 'john@example.com',
        phone: '+1-555-1234',
        check_in_date: new Date('2026-06-01'),
        check_out_date: new Date('2026-06-07'),
        guest_count: 4,
        message: 'Looking forward to staying!',
      };

      const created = await inquiryModel.create(inquiryData);
      const deleted = await inquiryModel.delete(created.id!);

      expect(deleted).toBe(true);

      const found = await inquiryModel.findById(created.id!);
      expect(found).toBeNull();
    });

    it('should return false when deleting non-existent inquiry', async () => {
      const deleted = await inquiryModel.delete(99999);
      expect(deleted).toBe(false);
    });
  });
});