530 lines
16 KiB
TypeScript
530 lines
16 KiB
TypeScript
/**
|
|
* TDD Tests for MediaReference value object
|
|
*
|
|
* Tests cover:
|
|
* - Discriminated union validation
|
|
* - Type-specific validation
|
|
* - Serialization/deserialization
|
|
* - Equality comparison
|
|
* - Hash generation
|
|
*/
|
|
|
|
import { MediaReference } from '@core/domain/media/MediaReference';
|
|
|
|
describe('MediaReference', () => {
|
|
describe('System Default Type', () => {
|
|
it('should create system-default reference', () => {
|
|
const ref = MediaReference.createSystemDefault();
|
|
|
|
expect(ref.type).toBe('system-default');
|
|
expect(ref.variant).toBe('avatar'); // default
|
|
});
|
|
|
|
it('should create system-default with custom variant', () => {
|
|
const ref = MediaReference.createSystemDefault('logo');
|
|
|
|
expect(ref.type).toBe('system-default');
|
|
expect(ref.variant).toBe('logo');
|
|
});
|
|
|
|
it('should create system-default with avatar variant', () => {
|
|
const ref = MediaReference.createSystemDefault('avatar', 'male');
|
|
|
|
expect(ref.type).toBe('system-default');
|
|
expect(ref.variant).toBe('avatar');
|
|
expect(ref.avatarVariant).toBe('male');
|
|
});
|
|
|
|
it('should create system-default without avatar variant for logo', () => {
|
|
const ref = MediaReference.createSystemDefault('logo', 'male');
|
|
|
|
expect(ref.type).toBe('system-default');
|
|
expect(ref.variant).toBe('logo');
|
|
expect(ref.avatarVariant).toBeUndefined();
|
|
});
|
|
|
|
it('should validate system-default type', () => {
|
|
const ref = MediaReference.fromJSON({
|
|
type: 'system-default',
|
|
variant: 'avatar'
|
|
});
|
|
|
|
expect(ref.type).toBe('system-default');
|
|
expect(ref.variant).toBe('avatar');
|
|
});
|
|
|
|
it('should validate system-default with avatar variant', () => {
|
|
const ref = MediaReference.fromJSON({
|
|
type: 'system-default',
|
|
variant: 'avatar',
|
|
avatarVariant: 'female'
|
|
});
|
|
|
|
expect(ref.type).toBe('system-default');
|
|
expect(ref.variant).toBe('avatar');
|
|
expect(ref.avatarVariant).toBe('female');
|
|
});
|
|
|
|
it('should reject system-default with invalid variant', () => {
|
|
expect(() => {
|
|
MediaReference.fromJSON({
|
|
type: 'system-default',
|
|
variant: 'invalid' as any
|
|
});
|
|
}).toThrow('Invalid variant');
|
|
});
|
|
|
|
it('should reject system-default with invalid avatar variant', () => {
|
|
expect(() => {
|
|
MediaReference.fromJSON({
|
|
type: 'system-default',
|
|
variant: 'avatar',
|
|
avatarVariant: 'invalid' as any
|
|
});
|
|
}).toThrow();
|
|
});
|
|
});
|
|
|
|
describe('New Static Methods', () => {
|
|
it('should create system-default using systemDefault method', () => {
|
|
const ref = MediaReference.systemDefault('avatar');
|
|
|
|
expect(ref.type).toBe('system-default');
|
|
expect(ref.variant).toBe('avatar');
|
|
});
|
|
|
|
it('should create system-default with avatar variant using systemDefault method', () => {
|
|
const ref = MediaReference.systemDefault('male');
|
|
|
|
expect(ref.type).toBe('system-default');
|
|
expect(ref.variant).toBe('avatar');
|
|
expect(ref.avatarVariant).toBe('male');
|
|
});
|
|
|
|
it('should create generated using generated method', () => {
|
|
const ref = MediaReference.generated('team', 'team-123');
|
|
|
|
expect(ref.type).toBe('generated');
|
|
expect(ref.generationRequestId).toBe('team-team-123');
|
|
});
|
|
});
|
|
|
|
describe('Generated Type', () => {
|
|
it('should create generated reference with request ID', () => {
|
|
const ref = MediaReference.createGenerated('req-123');
|
|
|
|
expect(ref.type).toBe('generated');
|
|
expect(ref.generationRequestId).toBe('req-123');
|
|
});
|
|
|
|
it('should validate generated type', () => {
|
|
const ref = MediaReference.fromJSON({
|
|
type: 'generated',
|
|
generationRequestId: 'req-456'
|
|
});
|
|
|
|
expect(ref.type).toBe('generated');
|
|
expect(ref.generationRequestId).toBe('req-456');
|
|
});
|
|
|
|
it('should reject generated without request ID', () => {
|
|
expect(() => {
|
|
MediaReference.fromJSON({
|
|
type: 'generated'
|
|
} as any);
|
|
}).toThrow('Generation request ID is required');
|
|
});
|
|
|
|
it('should reject generated with empty request ID', () => {
|
|
expect(() => {
|
|
MediaReference.fromJSON({
|
|
type: 'generated',
|
|
generationRequestId: ''
|
|
});
|
|
}).toThrow('Generation request ID is required');
|
|
});
|
|
});
|
|
|
|
describe('Uploaded Type', () => {
|
|
it('should create uploaded reference with media ID', () => {
|
|
const ref = MediaReference.createUploaded('media-789');
|
|
|
|
expect(ref.type).toBe('uploaded');
|
|
expect(ref.mediaId).toBe('media-789');
|
|
});
|
|
|
|
it('should validate uploaded type', () => {
|
|
const ref = MediaReference.fromJSON({
|
|
type: 'uploaded',
|
|
mediaId: 'media-abc'
|
|
});
|
|
|
|
expect(ref.type).toBe('uploaded');
|
|
expect(ref.mediaId).toBe('media-abc');
|
|
});
|
|
|
|
it('should reject uploaded without media ID', () => {
|
|
expect(() => {
|
|
MediaReference.fromJSON({
|
|
type: 'uploaded'
|
|
} as any);
|
|
}).toThrow('Media ID is required');
|
|
});
|
|
|
|
it('should reject uploaded with empty media ID', () => {
|
|
expect(() => {
|
|
MediaReference.fromJSON({
|
|
type: 'uploaded',
|
|
mediaId: ''
|
|
});
|
|
}).toThrow('Media ID is required');
|
|
});
|
|
});
|
|
|
|
describe('None Type', () => {
|
|
it('should create none reference', () => {
|
|
const ref = MediaReference.createNone();
|
|
|
|
expect(ref.type).toBe('none');
|
|
});
|
|
|
|
it('should validate none type', () => {
|
|
const ref = MediaReference.fromJSON({
|
|
type: 'none'
|
|
});
|
|
|
|
expect(ref.type).toBe('none');
|
|
});
|
|
|
|
it('should reject none with extra properties', () => {
|
|
expect(() => {
|
|
MediaReference.fromJSON({
|
|
type: 'none',
|
|
mediaId: 'should-not-exist'
|
|
} as any);
|
|
}).toThrow('None type should not have additional properties');
|
|
});
|
|
});
|
|
|
|
describe('Invalid Types', () => {
|
|
it('should reject unknown type', () => {
|
|
expect(() => {
|
|
MediaReference.fromJSON({
|
|
type: 'unknown'
|
|
} as any);
|
|
}).toThrow('Invalid type');
|
|
});
|
|
|
|
it('should reject missing type', () => {
|
|
expect(() => {
|
|
MediaReference.fromJSON({} as any);
|
|
}).toThrow('Type is required');
|
|
});
|
|
});
|
|
|
|
describe('Serialization', () => {
|
|
it('should serialize system-default to JSON', () => {
|
|
const ref = MediaReference.createSystemDefault('logo');
|
|
const json = ref.toJSON();
|
|
|
|
expect(json).toEqual({
|
|
type: 'system-default',
|
|
variant: 'logo'
|
|
});
|
|
});
|
|
|
|
it('should serialize system-default with avatar variant to JSON', () => {
|
|
const ref = MediaReference.createSystemDefault('avatar', 'female');
|
|
const json = ref.toJSON();
|
|
|
|
expect(json).toEqual({
|
|
type: 'system-default',
|
|
variant: 'avatar',
|
|
avatarVariant: 'female'
|
|
});
|
|
});
|
|
|
|
it('should deserialize system-default with avatar variant from JSON', () => {
|
|
const json = {
|
|
type: 'system-default',
|
|
variant: 'avatar',
|
|
avatarVariant: 'neutral'
|
|
};
|
|
const ref = MediaReference.fromJSON(json as unknown as Record<string, unknown>);
|
|
|
|
expect(ref.type).toBe('system-default');
|
|
expect(ref.variant).toBe('avatar');
|
|
expect(ref.avatarVariant).toBe('neutral');
|
|
});
|
|
|
|
it('should serialize generated to JSON', () => {
|
|
const ref = MediaReference.createGenerated('req-123');
|
|
const json = ref.toJSON();
|
|
|
|
expect(json).toEqual({
|
|
type: 'generated',
|
|
generationRequestId: 'req-123'
|
|
});
|
|
});
|
|
|
|
it('should serialize uploaded to JSON', () => {
|
|
const ref = MediaReference.createUploaded('media-456');
|
|
const json = ref.toJSON();
|
|
|
|
expect(json).toEqual({
|
|
type: 'uploaded',
|
|
mediaId: 'media-456'
|
|
});
|
|
});
|
|
|
|
it('should serialize none to JSON', () => {
|
|
const ref = MediaReference.createNone();
|
|
const json = ref.toJSON();
|
|
|
|
expect(json).toEqual({
|
|
type: 'none'
|
|
});
|
|
});
|
|
|
|
it('should deserialize from JSON', () => {
|
|
const json = {
|
|
type: 'uploaded',
|
|
mediaId: 'media-789'
|
|
};
|
|
const ref = MediaReference.fromJSON(json);
|
|
|
|
expect(ref.type).toBe('uploaded');
|
|
expect(ref.mediaId).toBe('media-789');
|
|
});
|
|
});
|
|
|
|
describe('Equality', () => {
|
|
it('should be equal for same system-default with same variant', () => {
|
|
const ref1 = MediaReference.createSystemDefault('avatar');
|
|
const ref2 = MediaReference.createSystemDefault('avatar');
|
|
|
|
expect(ref1.equals(ref2)).toBe(true);
|
|
});
|
|
|
|
it('should not be equal for system-default with different variants', () => {
|
|
const ref1 = MediaReference.createSystemDefault('avatar');
|
|
const ref2 = MediaReference.createSystemDefault('logo');
|
|
|
|
expect(ref1.equals(ref2)).toBe(false);
|
|
});
|
|
|
|
it('should not be equal for system-default with different avatar variants', () => {
|
|
const ref1 = MediaReference.createSystemDefault('avatar', 'male');
|
|
const ref2 = MediaReference.createSystemDefault('avatar', 'female');
|
|
|
|
expect(ref1.equals(ref2)).toBe(false);
|
|
});
|
|
|
|
it('should be equal for system-default with same avatar variant', () => {
|
|
const ref1 = MediaReference.createSystemDefault('avatar', 'male');
|
|
const ref2 = MediaReference.createSystemDefault('avatar', 'male');
|
|
|
|
expect(ref1.equals(ref2)).toBe(true);
|
|
});
|
|
|
|
it('should not be equal for system-default with and without avatar variant', () => {
|
|
const ref1 = MediaReference.createSystemDefault('avatar', 'male');
|
|
const ref2 = MediaReference.createSystemDefault('avatar');
|
|
|
|
expect(ref1.equals(ref2)).toBe(false);
|
|
});
|
|
|
|
it('should be equal for same generated with same request ID', () => {
|
|
const ref1 = MediaReference.createGenerated('req-123');
|
|
const ref2 = MediaReference.createGenerated('req-123');
|
|
|
|
expect(ref1.equals(ref2)).toBe(true);
|
|
});
|
|
|
|
it('should not be equal for generated with different request IDs', () => {
|
|
const ref1 = MediaReference.createGenerated('req-123');
|
|
const ref2 = MediaReference.createGenerated('req-456');
|
|
|
|
expect(ref1.equals(ref2)).toBe(false);
|
|
});
|
|
|
|
it('should be equal for same uploaded with same media ID', () => {
|
|
const ref1 = MediaReference.createUploaded('media-123');
|
|
const ref2 = MediaReference.createUploaded('media-123');
|
|
|
|
expect(ref1.equals(ref2)).toBe(true);
|
|
});
|
|
|
|
it('should not be equal for uploaded with different media IDs', () => {
|
|
const ref1 = MediaReference.createUploaded('media-123');
|
|
const ref2 = MediaReference.createUploaded('media-456');
|
|
|
|
expect(ref1.equals(ref2)).toBe(false);
|
|
});
|
|
|
|
it('should be equal for none references', () => {
|
|
const ref1 = MediaReference.createNone();
|
|
const ref2 = MediaReference.createNone();
|
|
|
|
expect(ref1.equals(ref2)).toBe(true);
|
|
});
|
|
|
|
it('should not be equal for different types', () => {
|
|
const ref1 = MediaReference.createSystemDefault();
|
|
const ref2 = MediaReference.createNone();
|
|
|
|
expect(ref1.equals(ref2)).toBe(false);
|
|
});
|
|
|
|
it('should not be equal to non-MediaReference', () => {
|
|
const ref = MediaReference.createSystemDefault();
|
|
|
|
expect(ref.equals({} as any)).toBe(false);
|
|
expect(ref.equals(null as any)).toBe(false);
|
|
expect(ref.equals(undefined as any)).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('Hash', () => {
|
|
it('should generate consistent hash for same system-default', () => {
|
|
const ref1 = MediaReference.createSystemDefault('avatar');
|
|
const ref2 = MediaReference.createSystemDefault('avatar');
|
|
|
|
expect(ref1.hash()).toBe(ref2.hash());
|
|
});
|
|
|
|
it('should generate different hash for different variants', () => {
|
|
const ref1 = MediaReference.createSystemDefault('avatar');
|
|
const ref2 = MediaReference.createSystemDefault('logo');
|
|
|
|
expect(ref1.hash()).not.toBe(ref2.hash());
|
|
});
|
|
|
|
it('should generate different hash for different avatar variants', () => {
|
|
const ref1 = MediaReference.createSystemDefault('avatar', 'male');
|
|
const ref2 = MediaReference.createSystemDefault('avatar', 'female');
|
|
|
|
expect(ref1.hash()).not.toBe(ref2.hash());
|
|
});
|
|
|
|
it('should generate same hash for same avatar variant', () => {
|
|
const ref1 = MediaReference.createSystemDefault('avatar', 'male');
|
|
const ref2 = MediaReference.createSystemDefault('avatar', 'male');
|
|
|
|
expect(ref1.hash()).toBe(ref2.hash());
|
|
});
|
|
|
|
it('should generate different hash for system-default with and without avatar variant', () => {
|
|
const ref1 = MediaReference.createSystemDefault('avatar', 'male');
|
|
const ref2 = MediaReference.createSystemDefault('avatar');
|
|
|
|
expect(ref1.hash()).not.toBe(ref2.hash());
|
|
});
|
|
|
|
it('should generate consistent hash for same generated', () => {
|
|
const ref1 = MediaReference.createGenerated('req-123');
|
|
const ref2 = MediaReference.createGenerated('req-123');
|
|
|
|
expect(ref1.hash()).toBe(ref2.hash());
|
|
});
|
|
|
|
it('should generate different hash for different request IDs', () => {
|
|
const ref1 = MediaReference.createGenerated('req-123');
|
|
const ref2 = MediaReference.createGenerated('req-456');
|
|
|
|
expect(ref1.hash()).not.toBe(ref2.hash());
|
|
});
|
|
|
|
it('should generate consistent hash for same uploaded', () => {
|
|
const ref1 = MediaReference.createUploaded('media-123');
|
|
const ref2 = MediaReference.createUploaded('media-123');
|
|
|
|
expect(ref1.hash()).toBe(ref2.hash());
|
|
});
|
|
|
|
it('should generate different hash for different media IDs', () => {
|
|
const ref1 = MediaReference.createUploaded('media-123');
|
|
const ref2 = MediaReference.createUploaded('media-456');
|
|
|
|
expect(ref1.hash()).not.toBe(ref2.hash());
|
|
});
|
|
|
|
it('should generate same hash for none references', () => {
|
|
const ref1 = MediaReference.createNone();
|
|
const ref2 = MediaReference.createNone();
|
|
|
|
expect(ref1.hash()).toBe(ref2.hash());
|
|
});
|
|
|
|
it('should generate different hash for different types', () => {
|
|
const ref1 = MediaReference.createSystemDefault();
|
|
const ref2 = MediaReference.createNone();
|
|
|
|
expect(ref1.hash()).not.toBe(ref2.hash());
|
|
});
|
|
});
|
|
|
|
describe('Type Guards', () => {
|
|
it('should correctly identify system-default type', () => {
|
|
const ref = MediaReference.createSystemDefault();
|
|
|
|
expect(ref.type).toBe('system-default');
|
|
expect(ref.generationRequestId).toBeUndefined();
|
|
expect(ref.mediaId).toBeUndefined();
|
|
});
|
|
|
|
it('should correctly identify generated type', () => {
|
|
const ref = MediaReference.createGenerated('req-123');
|
|
|
|
expect(ref.type).toBe('generated');
|
|
expect(ref.generationRequestId).toBe('req-123');
|
|
expect(ref.mediaId).toBeUndefined();
|
|
});
|
|
|
|
it('should correctly identify uploaded type', () => {
|
|
const ref = MediaReference.createUploaded('media-123');
|
|
|
|
expect(ref.type).toBe('uploaded');
|
|
expect(ref.mediaId).toBe('media-123');
|
|
expect(ref.generationRequestId).toBeUndefined();
|
|
});
|
|
|
|
it('should correctly identify none type', () => {
|
|
const ref = MediaReference.createNone();
|
|
|
|
expect(ref.type).toBe('none');
|
|
expect(ref.generationRequestId).toBeUndefined();
|
|
expect(ref.mediaId).toBeUndefined();
|
|
expect(ref.variant).toBeUndefined();
|
|
});
|
|
});
|
|
|
|
describe('Edge Cases', () => {
|
|
it('should handle whitespace in IDs', () => {
|
|
const ref = MediaReference.createGenerated(' req-123 ');
|
|
|
|
expect(ref.generationRequestId).toBe('req-123');
|
|
});
|
|
|
|
it('should handle special characters in IDs', () => {
|
|
const ref = MediaReference.createUploaded('media-abc-123_XYZ');
|
|
|
|
expect(ref.mediaId).toBe('media-abc-123_XYZ');
|
|
});
|
|
|
|
it('should preserve exact string values', () => {
|
|
const id = 'CaseSensitive-ID_123';
|
|
const ref = MediaReference.createUploaded(id);
|
|
|
|
expect(ref.mediaId).toBe(id);
|
|
});
|
|
|
|
it('should handle JSON round-trip', () => {
|
|
const original = MediaReference.createGenerated('req-999');
|
|
const json = original.toJSON();
|
|
const restored = MediaReference.fromJSON(json as unknown as Record<string, unknown>);
|
|
|
|
expect(restored.equals(original)).toBe(true);
|
|
});
|
|
});
|
|
}); |