'use strict'; // Unit tests for the Deezer metadata mapping/matching (backend/lib/deezer.js). // Pure logic only — no network. Run: `node --test` from backend/ (or `npm test`). // A live smoke test against api.deezer.com is included but only runs with RUN_LIVE=1. const test = require('node:test'); const assert = require('node:assert/strict'); const dz = require('../lib/deezer'); // ── Fixtures: the exact Deezer shapes the mappers consume ───────────────────── const ALBUM = { id: 302127, title: 'Discovery', cover_xl: 'https://img/cover_xl.jpg', cover_big: 'https://img/cover_big.jpg', release_date: '2001-03-07', nb_tracks: 14, record_type: 'album', genres: { data: [{ id: 113, name: 'Dance' }] }, artist: { id: 27, name: 'Daft Punk' }, }; const TRACK = { id: 3135556, title: 'Harder, Better, Faster, Stronger', duration: 224, explicit_lyrics: false, preview: 'https://img/preview.mp3', artist: { id: 27, name: 'Daft Punk' }, }; test('mapAlbumTrack: numbers by album order and inherits album-level fields', () => { const item = dz.mapAlbumTrack(TRACK, ALBUM, 3); // 4th track assert.equal(item.wrapperType, 'track'); assert.equal(item.kind, undefined); // shape has no kind here; downloadAlbumTracks doesn't read it assert.equal(item.trackNumber, 4); // index + 1 (Deezer album tracks carry no track_position) assert.equal(item.trackName, 'Harder, Better, Faster, Stronger'); assert.equal(item.collectionName, 'Discovery'); assert.equal(item.collectionArtistName, 'Daft Punk'); assert.equal(item.primaryGenreName, 'Dance'); assert.equal(item.releaseDate, '2001-03-07'); assert.equal(item.trackCount, 14); assert.equal(item.trackTimeMillis, 224000); // seconds → ms assert.equal(item.trackExplicitness, 'notExplicit'); assert.equal(item.artworkUrl100, 'https://img/cover_xl.jpg'); }); test('mapAlbumTrack: per-track artist wins over the album artist (mixed-artist albums)', () => { const feat = { ...TRACK, artist: { id: 99, name: 'MeloMance' } }; const item = dz.mapAlbumTrack(feat, ALBUM, 0); assert.equal(item.artistName, 'MeloMance'); // drives the per-track YTM search assert.equal(item.collectionArtistName, 'Daft Punk'); // album_artist stays stable → no album split }); test('mapAlbumTrack: explicit flag maps through', () => { const item = dz.mapAlbumTrack({ ...TRACK, explicit_lyrics: true }, ALBUM, 0); assert.equal(item.trackExplicitness, 'explicit'); }); test('pickTrackMatch: strict match on artist + title', () => { const results = [ { title: 'Some Other Song', artist: { name: 'Daft Punk' } }, { title: 'Harder, Better, Faster, Stronger', artist: { name: 'Daft Punk' } }, ]; const m = dz.pickTrackMatch(results, 'Daft Punk', 'Harder, Better, Faster, Stronger'); assert.equal(m, results[1]); }); test('pickTrackMatch: title-only fallback for non-Japanese when artist differs', () => { const results = [{ title: 'Levitating', artist: { name: 'Some Cover Act' } }]; const m = dz.pickTrackMatch(results, 'Dua Lipa', 'Levitating'); assert.equal(m, results[0]); // ASCII title → title-only fallback allowed }); test('pickTrackMatch: NO title-only fallback for Japanese titles', () => { const results = [{ title: '残酷な天使のテーゼ', artist: { name: 'Someone Else' } }]; const m = dz.pickTrackMatch(results, '高橋洋子', '残酷な天使のテーゼ'); assert.equal(m, null); // JP title + wrong artist must not match a same-titled cover }); test('pickTrackMatch: Japanese title DOES match when the artist matches', () => { const results = [{ title: '残酷な天使のテーゼ', artist: { name: '高橋洋子' } }]; const m = dz.pickTrackMatch(results, '高橋洋子', '残酷な天使のテーゼ'); assert.equal(m, results[0]); }); test('pickTrackMatch: leading aesthetic punctuation is ignored on the artist', () => { const results = [{ title: 'nostalgia', artist: { name: '.diedlonely' } }]; const m = dz.pickTrackMatch(results, '.diedlonely', 'nostalgia'); assert.equal(m, results[0]); }); test('pickTrackMatch: empty / no match returns null', () => { assert.equal(dz.pickTrackMatch([], 'x', 'y'), null); assert.equal(dz.pickTrackMatch([{ title: 'A', artist: { name: 'B' } }], 'C', 'D'), null); }); test('normalizeTitle: unifies variant suffixes and punctuation', () => { assert.equal(dz.normalizeTitle("don't rush - slowed"), dz.normalizeTitle("don't rush (slowed)")); assert.equal(dz.normalizeTitle('Mr. Lawrence'), dz.normalizeTitle('Mr Lawrence')); }); // ── Live smoke test (opt-in): confirms the real Deezer shape still maps ──────── test('LIVE: lookupTrackMeta returns enriched fields', { skip: process.env.RUN_LIVE !== '1' }, async () => { const meta = await dz.lookupTrackMeta('Daft Punk', 'Harder, Better, Faster, Stronger'); assert.ok(meta.album, 'album present'); assert.ok(meta.genre, 'genre present'); assert.ok(meta.year, 'year present'); assert.ok(meta.durationMs > 0, 'duration present'); });