import { describe, expect, it } from 'vitest'; import type { components } from '$lib/api/schema'; import { toAlbum, toCount, toDatedTrack, toLikedTrack, toCoauthorInvitation, toLibraryTrack, toListeningStats, toMix, toPage, toPlaylist, toTrack } from './mappers'; const trackDto: components['schemas']['TrackApplicationResponse'] = { id: 't1', title: 'Song', artist: null, audioStatus: 'Completed', duration: '183.5', listensCount: '12', createdAt: '2026-01-02T00:00:00Z', updatedAt: '2026-01-03T00:00:00Z', ownerUserId: '42', tags: [], isExplicit: true, isPublished: true, coauthors: [{ id: 'u2', name: 'Guest' }] }; describe('toTrack', () => { it('normalizes numeric strings and renames isExplicit', () => { expect(toTrack(trackDto)).toEqual({ id: 't1', title: 'Song', artist: null, ownerUserId: '42', explicit: true, duration: 183.5, listensCount: 12, coauthors: [{ id: 'u2', name: 'Guest' }] }); }); it('falls back to 0 for invalid numbers', () => { const track = toTrack({ ...trackDto, duration: 'x', listensCount: 'y' }); expect(track.duration).toBe(0); expect(track.listensCount).toBe(0); }); }); describe('toDatedTrack and toLikedTrack', () => { it('keep the creation date', () => { expect(toDatedTrack(trackDto).date).toBe('2026-01-02T00:00:00Z'); expect(toLikedTrack(trackDto).likedAt).toBe(Date.parse('2026-01-02T00:00:00Z')); }); }); describe('toMix', () => { it('maps items into tracks', () => { const mix = toMix({ id: 'm1', kind: 'Daily', itemCount: 1, items: [{ trackId: 't1', title: 'Song', artist: 'A', durationSeconds: '60', listensCount: 3 }] }); expect(mix.title).toBe('Tu mezcla diaria'); expect(mix.tracks).toEqual([ { id: 't1', title: 'Song', artist: 'A', ownerUserId: null, explicit: false, duration: 60, listensCount: 3, coauthors: [] } ]); }); }); describe('toAlbum', () => { const dto: components['schemas']['AlbumApplicationResponse'] = { id: 'a1', title: 'Album', description: null, releaseYear: '2020', ownerUserId: '42', trackCount: '5', smallImageKeyName: null, mediumImageKeyName: null, largeImageKeyName: null, createdAt: '', updatedAt: 'u', coverTrackIds: ['t1'], type: 'Album' }; it('normalizes year and count', () => { expect(toAlbum(dto)).toMatchObject({ releaseYear: 2020, trackCount: 5, updatedAt: 'u' }); }); it('keeps a missing year as null', () => { expect(toAlbum({ ...dto, releaseYear: null }).releaseYear).toBeNull(); }); }); describe('toPlaylist', () => { const dto: components['schemas']['PlayListApplicationResponse'] = { id: 'p1', name: 'List', description: 'd', smallImageKeyName: null, mediumImageKeyName: null, largeImageKeyName: null, ownerUserId: '42', visibility: 'Public', trackCount: '7', durationSeconds: '90.5', createdAt: '', updatedAt: 'u', coverTrackIds: [] }; it('drops storage keys and normalizes totals', () => { expect(toPlaylist(dto)).toEqual({ id: 'p1', name: 'List', description: 'd', visibility: 'Public', ownerUserId: '42', trackCount: 7, durationSeconds: 90.5, coverTrackIds: [], updatedAt: 'u' }); }); }); describe('toPage', () => { it('maps items and normalizes numbers', () => { expect( toPage( { items: [1, 2], pageNumber: '2', hasNextPage: true, totalItemCount: '10' }, (n) => n * 2 ) ).toEqual({ items: [2, 4], pageNumber: 2, hasNextPage: true, totalItemCount: 10 }); }); }); describe('toCount', () => { it('normalizes numbers, numeric strings and missing values', () => { expect(toCount(4)).toBe(4); expect(toCount('12')).toBe(12); expect(toCount(undefined)).toBe(0); expect(toCount(null)).toBe(0); expect(toCount('abc')).toBe(0); }); }); describe('toListeningStats', () => { it('converts string counters to numbers', () => { expect( toListeningStats({ tracksThisWeek: '5', secondsThisWeek: 300, streakDays: '2' }) ).toEqual({ tracksThisWeek: 5, secondsThisWeek: 300, streakDays: 2 }); }); it('falls back to zeros without data', () => { expect(toListeningStats(undefined)).toEqual({ tracksThisWeek: 0, secondsThisWeek: 0, streakDays: 0 }); }); }); describe('toLibraryTrack', () => { it('keeps the coauthor invites with their status', () => { const track = toLibraryTrack({ ...trackDto, albums: [], coauthorInvites: [ { userId: 'u2', name: 'Guest', status: 'Accepted' }, { userId: 'u3', name: 'Other', status: 'Pending' } ] }); expect(track.coauthorInvites).toEqual([ { userId: 'u2', name: 'Guest', status: 'Accepted' }, { userId: 'u3', name: 'Other', status: 'Pending' } ]); expect(track.coauthors).toEqual([{ id: 'u2', name: 'Guest' }]); }); }); describe('toCoauthorInvitation', () => { it('copies the invitation fields', () => { const dto = { id: 'i1', trackId: 't1', trackTitle: 'Song', artist: null, ownerUserId: '42', invitedAt: '2026-01-02T00:00:00Z' }; expect(toCoauthorInvitation(dto)).toEqual(dto); }); });