Files
gridpilot.gg/core/ports/media/MediaResolverPort.comprehensive.test.ts
2026-01-22 18:05:30 +01:00

502 lines
17 KiB
TypeScript

/**
* Comprehensive Tests for MediaResolverPort
*
* Tests cover:
* - Interface contract compliance
* - ResolutionStrategies for all reference types
* - resolveWithDefaults helper function
* - isMediaResolverPort type guard
* - Edge cases and error handling
* - Business logic decisions
*/
import { MediaReference } from '@core/domain/media/MediaReference';
import { describe, expect, it } from 'vitest';
import {
MediaResolverPort,
ResolutionStrategies,
resolveWithDefaults,
isMediaResolverPort,
} from './MediaResolverPort';
describe('MediaResolverPort - Comprehensive Tests', () => {
describe('Interface Contract Compliance', () => {
it('should define resolve method signature correctly', () => {
// Verify the interface has the correct method signature
const testInterface: MediaResolverPort = {
resolve: async (ref: MediaReference): Promise<string | null> => {
return null;
},
};
expect(testInterface).toBeDefined();
expect(typeof testInterface.resolve).toBe('function');
});
it('should accept MediaReference and return Promise<string | null>', async () => {
const mockResolver: MediaResolverPort = {
resolve: async (ref: MediaReference): Promise<string | null> => {
// Verify ref is a MediaReference instance
expect(ref).toBeInstanceOf(MediaReference);
return '/test/path';
},
};
const ref = MediaReference.createSystemDefault('avatar');
const result = await mockResolver.resolve(ref);
expect(result).toBe('/test/path');
});
});
describe('ResolutionStrategies - System Default', () => {
it('should resolve system-default avatar without variant', () => {
const ref = MediaReference.createSystemDefault('avatar');
const result = ResolutionStrategies.systemDefault(ref);
expect(result).toBe('/media/default/neutral-default-avatar.png');
});
it('should resolve system-default avatar with male variant', () => {
const ref = MediaReference.createSystemDefault('avatar', 'male');
const result = ResolutionStrategies.systemDefault(ref);
expect(result).toBe('/media/default/male-default-avatar.png');
});
it('should resolve system-default avatar with female variant', () => {
const ref = MediaReference.createSystemDefault('avatar', 'female');
const result = ResolutionStrategies.systemDefault(ref);
expect(result).toBe('/media/default/female-default-avatar.png');
});
it('should resolve system-default avatar with neutral variant', () => {
const ref = MediaReference.createSystemDefault('avatar', 'neutral');
const result = ResolutionStrategies.systemDefault(ref);
expect(result).toBe('/media/default/neutral-default-avatar.png');
});
it('should resolve system-default logo', () => {
const ref = MediaReference.createSystemDefault('logo');
const result = ResolutionStrategies.systemDefault(ref);
expect(result).toBe('/media/default/logo.png');
});
it('should return null for non-system-default reference', () => {
const ref = MediaReference.createGenerated('team-123');
const result = ResolutionStrategies.systemDefault(ref);
expect(result).toBeNull();
});
});
describe('ResolutionStrategies - Generated', () => {
it('should resolve generated reference for team', () => {
const ref = MediaReference.createGenerated('team-123');
const result = ResolutionStrategies.generated(ref);
expect(result).toBe('/media/teams/123/logo');
});
it('should resolve generated reference for league', () => {
const ref = MediaReference.createGenerated('league-456');
const result = ResolutionStrategies.generated(ref);
expect(result).toBe('/media/leagues/456/logo');
});
it('should resolve generated reference for driver', () => {
const ref = MediaReference.createGenerated('driver-789');
const result = ResolutionStrategies.generated(ref);
expect(result).toBe('/media/avatar/789');
});
it('should resolve generated reference for unknown type', () => {
const ref = MediaReference.createGenerated('unknown-999');
const result = ResolutionStrategies.generated(ref);
expect(result).toBe('/media/generated/unknown/999');
});
it('should return null for generated reference without generationRequestId', () => {
// Create a reference with missing generationRequestId
const ref = MediaReference.createGenerated('valid-id');
// Manually create an invalid reference
const invalidRef = { type: 'generated' } as MediaReference;
const result = ResolutionStrategies.generated(invalidRef);
expect(result).toBeNull();
});
it('should return null for non-generated reference', () => {
const ref = MediaReference.createSystemDefault('avatar');
const result = ResolutionStrategies.generated(ref);
expect(result).toBeNull();
});
it('should handle generated reference with special characters in ID', () => {
const ref = MediaReference.createGenerated('team-abc-123_XYZ');
const result = ResolutionStrategies.generated(ref);
expect(result).toBe('/media/teams/abc-123_XYZ/logo');
});
it('should handle generated reference with multiple hyphens', () => {
const ref = MediaReference.createGenerated('team-abc-def-123');
const result = ResolutionStrategies.generated(ref);
expect(result).toBe('/media/teams/abc-def-123/logo');
});
});
describe('ResolutionStrategies - Uploaded', () => {
it('should resolve uploaded reference', () => {
const ref = MediaReference.createUploaded('media-456');
const result = ResolutionStrategies.uploaded(ref);
expect(result).toBe('/media/uploaded/media-456');
});
it('should return null for uploaded reference without mediaId', () => {
// Create a reference with missing mediaId
const ref = MediaReference.createUploaded('valid-id');
// Manually create an invalid reference
const invalidRef = { type: 'uploaded' } as MediaReference;
const result = ResolutionStrategies.uploaded(invalidRef);
expect(result).toBeNull();
});
it('should return null for non-uploaded reference', () => {
const ref = MediaReference.createSystemDefault('avatar');
const result = ResolutionStrategies.uploaded(ref);
expect(result).toBeNull();
});
it('should handle uploaded reference with special characters', () => {
const ref = MediaReference.createUploaded('media-abc-123_XYZ');
const result = ResolutionStrategies.uploaded(ref);
expect(result).toBe('/media/uploaded/media-abc-123_XYZ');
});
it('should handle uploaded reference with very long ID', () => {
const longId = 'a'.repeat(1000);
const ref = MediaReference.createUploaded(longId);
const result = ResolutionStrategies.uploaded(ref);
expect(result).toBe(`/media/uploaded/${longId}`);
});
});
describe('ResolutionStrategies - None', () => {
it('should return null for none reference', () => {
const ref = MediaReference.createNone();
const result = ResolutionStrategies.none(ref);
expect(result).toBeNull();
});
it('should return null for any reference passed to none strategy', () => {
const ref = MediaReference.createSystemDefault('avatar');
const result = ResolutionStrategies.none(ref);
expect(result).toBeNull();
});
});
describe('resolveWithDefaults - Integration Tests', () => {
it('should resolve system-default reference using resolveWithDefaults', () => {
const ref = MediaReference.createSystemDefault('avatar');
const result = resolveWithDefaults(ref);
expect(result).toBe('/media/default/neutral-default-avatar.png');
});
it('should resolve system-default avatar with male variant using resolveWithDefaults', () => {
const ref = MediaReference.createSystemDefault('avatar', 'male');
const result = resolveWithDefaults(ref);
expect(result).toBe('/media/default/male-default-avatar.png');
});
it('should resolve system-default logo using resolveWithDefaults', () => {
const ref = MediaReference.createSystemDefault('logo');
const result = resolveWithDefaults(ref);
expect(result).toBe('/media/default/logo.png');
});
it('should resolve generated reference using resolveWithDefaults', () => {
const ref = MediaReference.createGenerated('team-123');
const result = resolveWithDefaults(ref);
expect(result).toBe('/media/teams/123/logo');
});
it('should resolve uploaded reference using resolveWithDefaults', () => {
const ref = MediaReference.createUploaded('media-456');
const result = resolveWithDefaults(ref);
expect(result).toBe('/media/uploaded/media-456');
});
it('should resolve none reference using resolveWithDefaults', () => {
const ref = MediaReference.createNone();
const result = resolveWithDefaults(ref);
expect(result).toBeNull();
});
it('should handle all reference types in sequence', () => {
const refs = [
MediaReference.createSystemDefault('avatar'),
MediaReference.createSystemDefault('avatar', 'male'),
MediaReference.createSystemDefault('logo'),
MediaReference.createGenerated('team-123'),
MediaReference.createGenerated('league-456'),
MediaReference.createGenerated('driver-789'),
MediaReference.createUploaded('media-456'),
MediaReference.createNone(),
];
const results = refs.map(ref => resolveWithDefaults(ref));
expect(results).toEqual([
'/media/default/neutral-default-avatar.png',
'/media/default/male-default-avatar.png',
'/media/default/logo.png',
'/media/teams/123/logo',
'/media/leagues/456/logo',
'/media/avatar/789',
'/media/uploaded/media-456',
null,
]);
});
});
describe('isMediaResolverPort Type Guard', () => {
it('should return true for valid MediaResolverPort implementation', () => {
const validResolver: MediaResolverPort = {
resolve: async (ref: MediaReference): Promise<string | null> => {
return '/test/path';
},
};
expect(isMediaResolverPort(validResolver)).toBe(true);
});
it('should return false for null', () => {
expect(isMediaResolverPort(null)).toBe(false);
});
it('should return false for undefined', () => {
expect(isMediaResolverPort(undefined)).toBe(false);
});
it('should return false for non-object', () => {
expect(isMediaResolverPort('string')).toBe(false);
expect(isMediaResolverPort(123)).toBe(false);
expect(isMediaResolverPort(true)).toBe(false);
});
it('should return false for object without resolve method', () => {
const invalidResolver = {
someOtherMethod: () => {},
};
expect(isMediaResolverPort(invalidResolver)).toBe(false);
});
it('should return false for object with resolve property but not a function', () => {
const invalidResolver = {
resolve: 'not a function',
};
expect(isMediaResolverPort(invalidResolver)).toBe(false);
});
it('should return false for object with resolve as non-function property', () => {
const invalidResolver = {
resolve: 123,
};
expect(isMediaResolverPort(invalidResolver)).toBe(false);
});
it('should return true for object with resolve method and other properties', () => {
const validResolver = {
resolve: async (ref: MediaReference): Promise<string | null> => {
return '/test/path';
},
extraProperty: 'value',
anotherMethod: () => {},
};
expect(isMediaResolverPort(validResolver)).toBe(true);
});
});
describe('Business Logic Decisions', () => {
it('should make correct decision for system-default avatar without variant', () => {
const ref = MediaReference.createSystemDefault('avatar');
const result = resolveWithDefaults(ref);
// Decision: Should use neutral default avatar
expect(result).toBe('/media/default/neutral-default-avatar.png');
});
it('should make correct decision for system-default avatar with specific variant', () => {
const ref = MediaReference.createSystemDefault('avatar', 'female');
const result = resolveWithDefaults(ref);
// Decision: Should use the specified variant
expect(result).toBe('/media/default/female-default-avatar.png');
});
it('should make correct decision for generated team reference', () => {
const ref = MediaReference.createGenerated('team-123');
const result = resolveWithDefaults(ref);
// Decision: Should resolve to team logo path
expect(result).toBe('/media/teams/123/logo');
});
it('should make correct decision for generated league reference', () => {
const ref = MediaReference.createGenerated('league-456');
const result = resolveWithDefaults(ref);
// Decision: Should resolve to league logo path
expect(result).toBe('/media/leagues/456/logo');
});
it('should make correct decision for generated driver reference', () => {
const ref = MediaReference.createGenerated('driver-789');
const result = resolveWithDefaults(ref);
// Decision: Should resolve to avatar path
expect(result).toBe('/media/avatar/789');
});
it('should make correct decision for uploaded reference', () => {
const ref = MediaReference.createUploaded('media-456');
const result = resolveWithDefaults(ref);
// Decision: Should resolve to uploaded media path
expect(result).toBe('/media/uploaded/media-456');
});
it('should make correct decision for none reference', () => {
const ref = MediaReference.createNone();
const result = resolveWithDefaults(ref);
// Decision: Should return null (no media)
expect(result).toBeNull();
});
it('should make correct decision for unknown generated type', () => {
const ref = MediaReference.createGenerated('unknown-999');
const result = resolveWithDefaults(ref);
// Decision: Should fall back to generic generated path
expect(result).toBe('/media/generated/unknown/999');
});
});
describe('Edge Cases and Error Handling', () => {
it('should handle empty string IDs gracefully', () => {
// MediaReference factory methods throw on empty strings
// This tests that the strategies handle invalid refs gracefully
const invalidRef = { type: 'generated' } as MediaReference;
const result = ResolutionStrategies.generated(invalidRef);
expect(result).toBeNull();
});
it('should handle references with missing properties', () => {
const invalidRef = { type: 'uploaded' } as MediaReference;
const result = ResolutionStrategies.uploaded(invalidRef);
expect(result).toBeNull();
});
it('should handle very long IDs without performance issues', () => {
const longId = 'a'.repeat(10000);
const ref = MediaReference.createUploaded(longId);
const result = resolveWithDefaults(ref);
expect(result).toBe(`/media/uploaded/${longId}`);
});
it('should handle Unicode characters in IDs', () => {
const ref = MediaReference.createUploaded('media-日本語-123');
const result = resolveWithDefaults(ref);
expect(result).toBe('/media/uploaded/media-日本語-123');
});
it('should handle special characters in generated IDs', () => {
const ref = MediaReference.createGenerated('team-abc_def-123');
const result = resolveWithDefaults(ref);
expect(result).toBe('/media/teams/abc_def-123/logo');
});
});
describe('Path Format Consistency', () => {
it('should maintain consistent path format for system-default', () => {
const ref = MediaReference.createSystemDefault('avatar');
const result = resolveWithDefaults(ref);
// Should start with /media/default/
expect(result).toMatch(/^\/media\/default\//);
});
it('should maintain consistent path format for generated team', () => {
const ref = MediaReference.createGenerated('team-123');
const result = resolveWithDefaults(ref);
// Should start with /media/teams/
expect(result).toMatch(/^\/media\/teams\//);
});
it('should maintain consistent path format for generated league', () => {
const ref = MediaReference.createGenerated('league-456');
const result = resolveWithDefaults(ref);
// Should start with /media/leagues/
expect(result).toMatch(/^\/media\/leagues\//);
});
it('should maintain consistent path format for generated driver', () => {
const ref = MediaReference.createGenerated('driver-789');
const result = resolveWithDefaults(ref);
// Should start with /media/avatar/
expect(result).toMatch(/^\/media\/avatar\//);
});
it('should maintain consistent path format for uploaded', () => {
const ref = MediaReference.createUploaded('media-456');
const result = resolveWithDefaults(ref);
// Should start with /media/uploaded/
expect(result).toMatch(/^\/media\/uploaded\//);
});
it('should maintain consistent path format for unknown generated type', () => {
const ref = MediaReference.createGenerated('unknown-999');
const result = resolveWithDefaults(ref);
// Should start with /media/generated/
expect(result).toMatch(/^\/media\/generated\//);
});
});
});