241 lines
7.0 KiB
TypeScript
241 lines
7.0 KiB
TypeScript
/**
|
|
* 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();
|
|
});
|
|
});
|
|
}); |