feat(spotify): implement milestone M3 api commands

This commit is contained in:
2026-04-12 01:52:18 -05:00
parent c8c0876b7c
commit d8570edcf0
8 changed files with 842 additions and 9 deletions

View File

@@ -0,0 +1,97 @@
import assert from "node:assert/strict";
import { test } from "node:test";
import { mapPlaylist, mapTrack, runListPlaylistsCommand, runSearchCommand } from "../src/search.js";
import type { CliDeps } from "../src/cli.js";
import type { SpotifyPlaylist, SpotifyTrack } from "../src/types.js";
function createDeps(): { deps: CliDeps; stdout: () => string; stderr: () => string } {
let stdout = "";
let stderr = "";
return {
deps: {
stdout: { write: (chunk: string) => { stdout += chunk; return true; } },
stderr: { write: (chunk: string) => { stderr += chunk; return true; } }
},
stdout: () => stdout,
stderr: () => stderr
};
}
const track: SpotifyTrack = {
id: "track-id",
uri: "spotify:track:track-id",
name: "Karma Police",
artists: [{ name: "Radiohead" }],
album: { name: "OK Computer" },
external_urls: { spotify: "https://open.spotify.com/track/track-id" }
};
const playlist: SpotifyPlaylist = {
id: "playlist-id",
uri: "spotify:playlist:playlist-id",
name: "Private Mix",
public: false,
owner: { id: "owner-id", display_name: "Owner" },
external_urls: { spotify: "https://open.spotify.com/playlist/playlist-id" }
};
test("maps raw track to flattened output DTO", () => {
assert.deepEqual(mapTrack(track), {
id: "track-id",
uri: "spotify:track:track-id",
name: "Karma Police",
artists: ["Radiohead"],
album: "OK Computer",
externalUrl: "https://open.spotify.com/track/track-id"
});
});
test("search command clamps limit and writes JSON", async () => {
const io = createDeps();
let observedLimit = 0;
const code = await runSearchCommand(
{ command: "search", positional: ["Karma", "Police"], json: true, public: false, limit: "99" },
io.deps,
{
searchTracks: async (_query, limit) => {
observedLimit = limit;
return [track];
}
}
);
assert.equal(code, 0);
assert.equal(observedLimit, 10);
assert.equal(JSON.parse(io.stdout()).tracks[0].externalUrl, "https://open.spotify.com/track/track-id");
assert.equal(io.stderr(), "");
});
test("maps playlist to flattened output DTO", () => {
assert.deepEqual(mapPlaylist(playlist), {
id: "playlist-id",
name: "Private Mix",
public: false,
owner: "Owner",
externalUrl: "https://open.spotify.com/playlist/playlist-id"
});
});
test("list playlists command clamps limit and writes human output", async () => {
const io = createDeps();
let observed = { limit: 0, offset: -1 };
const code = await runListPlaylistsCommand(
{ command: "list-playlists", positional: [], json: false, public: false, limit: "200", offset: "-5" },
io.deps,
{
listPlaylists: async (limit, offset) => {
observed = { limit, offset };
return [playlist];
}
}
);
assert.equal(code, 0);
assert.deepEqual(observed, { limit: 50, offset: 0 });
assert.match(io.stdout(), /playlist-id \\| private \\| Owner \\| Private Mix/);
});