98 lines
2.9 KiB
TypeScript
98 lines
2.9 KiB
TypeScript
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/);
|
|
});
|