207 lines
4.9 KiB
TypeScript
207 lines
4.9 KiB
TypeScript
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);
|
|
});
|
|
});
|