/** * Domain Entity Tests: Company * * Tests for Company entity business rules and invariants */ import { describe, it, expect } from 'vitest'; import { Company } from './Company'; import { UserId } from '../value-objects/UserId'; describe('Company', () => { describe('Creation', () => { it('should create a company with valid properties', () => { const userId = UserId.fromString('user-123'); const company = Company.create({ name: 'Acme Racing Team', ownerUserId: userId, contactEmail: 'contact@acme.com', }); expect(company.getName()).toBe('Acme Racing Team'); expect(company.getOwnerUserId()).toEqual(userId); expect(company.getContactEmail()).toBe('contact@acme.com'); expect(company.getId()).toBeDefined(); expect(company.getCreatedAt()).toBeInstanceOf(Date); }); it('should create a company without optional contact email', () => { const userId = UserId.fromString('user-123'); const company = Company.create({ name: 'Acme Racing Team', ownerUserId: userId, }); expect(company.getContactEmail()).toBeUndefined(); }); it('should generate unique IDs for different companies', () => { const userId = UserId.fromString('user-123'); const company1 = Company.create({ name: 'Team A', ownerUserId: userId, }); const company2 = Company.create({ name: 'Team B', ownerUserId: userId, }); expect(company1.getId()).not.toBe(company2.getId()); }); }); describe('Rehydration', () => { it('should rehydrate company from stored data', () => { const userId = UserId.fromString('user-123'); const createdAt = new Date('2024-01-01'); const company = Company.rehydrate({ id: 'comp-123', name: 'Acme Racing Team', ownerUserId: 'user-123', contactEmail: 'contact@acme.com', createdAt, }); expect(company.getId()).toBe('comp-123'); expect(company.getName()).toBe('Acme Racing Team'); expect(company.getOwnerUserId()).toEqual(userId); expect(company.getContactEmail()).toBe('contact@acme.com'); expect(company.getCreatedAt()).toEqual(createdAt); }); it('should rehydrate company without contact email', () => { const createdAt = new Date('2024-01-01'); const company = Company.rehydrate({ id: 'comp-123', name: 'Acme Racing Team', ownerUserId: 'user-123', createdAt, }); expect(company.getContactEmail()).toBeUndefined(); }); }); describe('Validation', () => { it('should throw error when company name is empty', () => { const userId = UserId.fromString('user-123'); expect(() => { Company.create({ name: '', ownerUserId: userId, }); }).toThrow('Company name cannot be empty'); }); it('should throw error when company name is only whitespace', () => { const userId = UserId.fromString('user-123'); expect(() => { Company.create({ name: ' ', ownerUserId: userId, }); }).toThrow('Company name cannot be empty'); }); it('should throw error when company name is too short', () => { const userId = UserId.fromString('user-123'); expect(() => { Company.create({ name: 'A', ownerUserId: userId, }); }).toThrow('Company name must be at least 2 characters long'); }); it('should throw error when company name is too long', () => { const userId = UserId.fromString('user-123'); const longName = 'A'.repeat(101); expect(() => { Company.create({ name: longName, ownerUserId: userId, }); }).toThrow('Company name must be no more than 100 characters'); }); it('should accept company name with exactly 2 characters', () => { const userId = UserId.fromString('user-123'); const company = Company.create({ name: 'AB', ownerUserId: userId, }); expect(company.getName()).toBe('AB'); }); it('should accept company name with exactly 100 characters', () => { const userId = UserId.fromString('user-123'); const longName = 'A'.repeat(100); const company = Company.create({ name: longName, ownerUserId: userId, }); expect(company.getName()).toBe(longName); }); it('should trim whitespace from company name during validation', () => { const userId = UserId.fromString('user-123'); const company = Company.create({ name: ' Acme Racing Team ', ownerUserId: userId, }); // Note: The current implementation doesn't trim, it just validates // So this test documents the current behavior expect(company.getName()).toBe(' Acme Racing Team '); }); }); describe('Business Rules', () => { it('should maintain immutability of properties', () => { const userId = UserId.fromString('user-123'); const company = Company.create({ name: 'Acme Racing Team', ownerUserId: userId, contactEmail: 'contact@acme.com', }); const originalName = company.getName(); const originalEmail = company.getContactEmail(); // Try to modify (should not work due to readonly properties) // This is more of a TypeScript compile-time check, but we can verify runtime behavior expect(company.getName()).toBe(originalName); expect(company.getContactEmail()).toBe(originalEmail); }); it('should handle special characters in company name', () => { const userId = UserId.fromString('user-123'); const company = Company.create({ name: 'Acme & Sons Racing, LLC', ownerUserId: userId, }); expect(company.getName()).toBe('Acme & Sons Racing, LLC'); }); it('should handle unicode characters in company name', () => { const userId = UserId.fromString('user-123'); const company = Company.create({ name: 'Räcing Tëam Ñumber Øne', ownerUserId: userId, }); expect(company.getName()).toBe('Räcing Tëam Ñumber Øne'); }); }); describe('Edge Cases', () => { it('should handle rehydration with null contact email', () => { const createdAt = new Date('2024-01-01'); const company = Company.rehydrate({ id: 'comp-123', name: 'Acme Racing Team', ownerUserId: 'user-123', contactEmail: null as any, createdAt, }); // The entity stores null as null, not undefined expect(company.getContactEmail()).toBeNull(); }); it('should handle rehydration with undefined contact email', () => { const createdAt = new Date('2024-01-01'); const company = Company.rehydrate({ id: 'comp-123', name: 'Acme Racing Team', ownerUserId: 'user-123', contactEmail: undefined, createdAt, }); expect(company.getContactEmail()).toBeUndefined(); }); }); });