// Unit tests for the optional Odesli (song.link) enrichment client (run with `node --test`). // Zero-dep, hermetic: parseOdesli runs against a REAL captured response (odesli.fixture.json — // Blood Incantation "Hidden History of the Human Race", a Spotify ALBUM url that Odesli resolves // to a direct Bandcamp page), and getLinks runs against an injected fake fetch (no network). import { test } from "node:test"; import assert from "node:assert/strict"; import { readFileSync } from "node:fs"; import { parseOdesli, makeOdesli, shouldEnrich } from "./odesli.js"; // The captured live response. Its linksByPlatform has bandcamp (+ many other stores) but no // appleMusic / youtube — exactly the real-world underground-album case the linker targets. const fixture = JSON.parse(readFileSync(new URL("./odesli.fixture.json", import.meta.url), "utf8")); test("parseOdesli: extracts the direct Bandcamp url from the real captured response", () => { const out = parseOdesli(fixture); assert.equal( out.bandcamp, "https://darkdescentrecords.bandcamp.com/album/hidden-history-of-the-human-race", "the real bandcamp url is pulled from linksByPlatform.bandcamp.url", ); }); test("parseOdesli: a platform absent from the response is OMITTED (not null/undefined keys)", () => { const out = parseOdesli(fixture); // This album has no appleMusic / youtube on Odesli — those fields must be absent, not present. assert.ok(!("appleMusic" in out), "absent appleMusic -> field omitted"); assert.ok(!("youtube" in out), "absent youtube -> field omitted"); assert.deepEqual(Object.keys(out).sort(), ["bandcamp"], "only the present platform appears"); }); test("parseOdesli: extracts bandcamp + appleMusic + youtube when all three are present", () => { // Odesli's live Apple/YouTube enrichment can be empty for a given album (as in the fixture), so a // shape-complete case proves all three extract correctly when the platform IS present. const all = { linksByPlatform: { bandcamp: { url: "https://artist.bandcamp.com/album/x" }, appleMusic: { url: "https://music.apple.com/us/album/x/123" }, youtube: { url: "https://www.youtube.com/watch?v=abc" }, tidal: { url: "https://tidal.com/album/999" }, // a platform we don't surface -> ignored }, }; assert.deepEqual(parseOdesli(all), { bandcamp: "https://artist.bandcamp.com/album/x", appleMusic: "https://music.apple.com/us/album/x/123", youtube: "https://www.youtube.com/watch?v=abc", }); }); test("parseOdesli: junk / empty / missing linksByPlatform -> {}", () => { assert.deepEqual(parseOdesli(null), {}, "null body"); assert.deepEqual(parseOdesli(undefined), {}, "undefined body"); assert.deepEqual(parseOdesli({}), {}, "no linksByPlatform key"); assert.deepEqual(parseOdesli({ linksByPlatform: null }), {}, "null linksByPlatform"); assert.deepEqual(parseOdesli({ linksByPlatform: "nope" }), {}, "non-object linksByPlatform"); assert.deepEqual(parseOdesli({ linksByPlatform: {} }), {}, "empty linksByPlatform"); assert.deepEqual(parseOdesli("garbage"), {}, "string body"); assert.deepEqual( parseOdesli({ linksByPlatform: { bandcamp: {} } }), {}, "platform entry with no url -> omitted", ); assert.deepEqual( parseOdesli({ linksByPlatform: { bandcamp: { url: 42 } } }), {}, "non-string url -> omitted", ); }); // --- shouldEnrich gate (album-only) -------------------------------------------- test("shouldEnrich: TRUE only for an album result with a direct Spotify url", () => { const sp = "https://open.spotify.com/album/0SdKqbCAKdkEFPW5NyzK7R"; assert.equal(shouldEnrich({ kind: "album", spotify: sp }), true, "album + spotify url -> enrich"); // Artist results are skipped — Odesli 405s on artist urls, so calling it would be a wasted trip. assert.equal(shouldEnrich({ kind: "artist", spotify: sp }), false, "artist -> skip"); // A Google-fallback result (no spotify url) is never enriched, regardless of kind. assert.equal(shouldEnrich({ kind: "album", google: "https://www.google.com/search?q=x" }), false, "no spotify url -> skip"); assert.equal(shouldEnrich({ kind: "album", spotify: null }), false, "null spotify -> skip"); assert.equal(shouldEnrich(null), false, "null result -> skip"); assert.equal(shouldEnrich({ spotify: sp }), false, "missing kind (defaults artist-ish) -> skip"); }); test("enrichment gate: an artist result makes ZERO Odesli calls; an album result makes one", async () => { // A getLinks counter standing in for the resolver's enrichWithOdesli, which guards on shouldEnrich. const state = { calls: 0 }; const getLinks = async () => { state.calls += 1; return { bandcamp: "https://x.bandcamp.com/album/y" }; }; const enrich = async (result) => { if (!shouldEnrich(result)) return result; // the real guard const links = await getLinks(result.spotify); // only album+spotify reaches here if (typeof links.bandcamp === "string") result.bandcamp = links.bandcamp; return result; }; const sp = "https://open.spotify.com/album/0SdKqbCAKdkEFPW5NyzK7R"; const artist = await enrich({ name: "Carcass", kind: "artist", spotify: sp }); assert.equal(state.calls, 0, "artist result -> Odesli NOT called (no wasted 405)"); assert.ok(!("bandcamp" in artist), "artist result is left unenriched"); const album = await enrich({ name: "Heartwork", kind: "album", spotify: sp }); assert.equal(state.calls, 1, "album result -> exactly one Odesli call"); assert.equal(album.bandcamp, "https://x.bandcamp.com/album/y", "album result is enriched"); }); // --- getLinks (injected fetch) ------------------------------------------------- // A fetch fake that records the requested url and returns a scripted response (or throws). function fakeFetch({ ok = true, status = 200, body = {}, throws = null } = {}) { const state = { calls: 0, url: null, hadSignal: false }; const fetch = async (url, opts) => { state.calls += 1; state.url = url; state.hadSignal = Boolean(opts && opts.signal); if (throws) throw throws; return { ok, status, json: async () => body }; }; return { fetch, state }; } test("getLinks: a 200 is parsed; the request hits the right endpoint with a timeout signal", async () => { const { fetch, state } = fakeFetch({ body: fixture }); const od = makeOdesli({ fetch }); const spUrl = "https://open.spotify.com/album/0SdKqbCAKdkEFPW5NyzK7R"; const out = await od.getLinks(spUrl); assert.equal(out.bandcamp, "https://darkdescentrecords.bandcamp.com/album/hidden-history-of-the-human-race"); assert.equal(state.calls, 1); assert.ok( state.url === `https://api.song.link/v1-alpha.1/links?url=${encodeURIComponent(spUrl)}`, "GET /links?url= against the default base", ); assert.ok(state.hadSignal, "an AbortSignal.timeout is passed (bounded like the other calls)"); }); test("getLinks: a non-200 returns {} (graceful — e.g. 405 on a non-entity url)", async () => { const { fetch } = fakeFetch({ ok: false, status: 405, body: { code: "UNSUPPORTED_URL" } }); const od = makeOdesli({ fetch }); assert.deepEqual(await od.getLinks("https://open.spotify.com/artist/xyz"), {}); }); test("getLinks: a network/timeout throw returns {} (no crash)", async () => { const { fetch } = fakeFetch({ throws: new Error("AbortError: timed out") }); const od = makeOdesli({ fetch }); assert.deepEqual(await od.getLinks("https://open.spotify.com/album/abc"), {}); }); test("getLinks: a JSON parse error returns {} (graceful)", async () => { const fetch = async () => ({ ok: true, status: 200, json: async () => { throw new SyntaxError("bad json"); } }); const od = makeOdesli({ fetch }); assert.deepEqual(await od.getLinks("https://open.spotify.com/album/abc"), {}); }); test("getLinks: baseUrl override is honored", async () => { const { fetch, state } = fakeFetch({ body: { linksByPlatform: {} } }); const od = makeOdesli({ fetch, baseUrl: "http://localhost:9999/v1" }); await od.getLinks("https://open.spotify.com/album/abc"); assert.ok(state.url.startsWith("http://localhost:9999/v1/links?url="), "uses the injected baseUrl"); });