81 lines
2.7 KiB
TypeScript
81 lines
2.7 KiB
TypeScript
import { describe, it, expect } from 'vitest';
|
|
import { UserProfileViewModel } from './UserProfileViewModel';
|
|
|
|
describe('UserProfileViewModel', () => {
|
|
it('maps required properties from the DTO', () => {
|
|
const dto = {
|
|
id: 'user-1',
|
|
name: 'Roo Racer',
|
|
};
|
|
|
|
const viewModel = new UserProfileViewModel(dto);
|
|
|
|
expect(viewModel.id).toBe('user-1');
|
|
expect(viewModel.name).toBe('Roo Racer');
|
|
expect(viewModel.avatarUrl).toBeUndefined();
|
|
expect(viewModel.iracingId).toBeUndefined();
|
|
expect(viewModel.rating).toBeUndefined();
|
|
});
|
|
|
|
it('maps optional properties only when provided', () => {
|
|
const dto = {
|
|
id: 'user-2',
|
|
name: 'Rated Driver',
|
|
avatarUrl: 'https://example.com/avatar.jpg',
|
|
iracingId: '12345',
|
|
rating: 2734,
|
|
};
|
|
|
|
const viewModel = new UserProfileViewModel(dto);
|
|
|
|
expect(viewModel.avatarUrl).toBe('https://example.com/avatar.jpg');
|
|
expect(viewModel.iracingId).toBe('12345');
|
|
expect(viewModel.rating).toBe(2734);
|
|
});
|
|
|
|
it('formats rating as whole-number string when present, or Unrated otherwise', () => {
|
|
const unrated = new UserProfileViewModel({ id: 'user-1', name: 'Unrated Driver' });
|
|
const rated = new UserProfileViewModel({ id: 'user-2', name: 'Rated Driver', rating: 2734.56 });
|
|
|
|
expect(unrated.formattedRating).toBe('Unrated');
|
|
expect(rated.formattedRating).toBe('2735');
|
|
});
|
|
|
|
it('indicates whether an iRacing ID is present', () => {
|
|
const withoutId = new UserProfileViewModel({ id: 'user-1', name: 'No ID' });
|
|
const withId = new UserProfileViewModel({ id: 'user-2', name: 'Has ID', iracingId: '67890' });
|
|
|
|
expect(withoutId.hasIracingId).toBe(false);
|
|
expect(withId.hasIracingId).toBe(true);
|
|
});
|
|
|
|
it('computes profile completeness based on available optional fields', () => {
|
|
const base = new UserProfileViewModel({ id: 'user-1', name: 'Base User' });
|
|
const withAvatar = new UserProfileViewModel({ id: 'user-2', name: 'Avatar User', avatarUrl: 'url' });
|
|
const withAvatarAndId = new UserProfileViewModel({
|
|
id: 'user-3',
|
|
name: 'Avatar + ID',
|
|
avatarUrl: 'url',
|
|
iracingId: '123',
|
|
});
|
|
const withAll = new UserProfileViewModel({
|
|
id: 'user-4',
|
|
name: 'Full Profile',
|
|
avatarUrl: 'url',
|
|
iracingId: '123',
|
|
rating: 2000,
|
|
});
|
|
|
|
expect(base.profileCompleteness).toBe(25);
|
|
expect(withAvatar.profileCompleteness).toBe(50);
|
|
expect(withAvatarAndId.profileCompleteness).toBe(75);
|
|
expect(withAll.profileCompleteness).toBe(100);
|
|
});
|
|
|
|
it('derives avatar initials from the name', () => {
|
|
const viewModel = new UserProfileViewModel({ id: 'user-1', name: 'Roo Racer' });
|
|
|
|
expect(viewModel.avatarInitials).toBe('RR');
|
|
});
|
|
});
|