import assert from "node:assert/strict"; import { mkdtemp, writeFile } from "node:fs/promises"; import { join } from "node:path"; import { tmpdir } from "node:os"; import { test } from "node:test"; import { importTracks, readImportSource, runImportCommand } from "../src/importers/index.js"; import type { CliDeps } from "../src/cli.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 }; } test("auto-detects text imports by extension fallback", async () => { const root = await mkdtemp(join(tmpdir(), "spotify-import-")); const path = join(root, "tracks.csv"); await writeFile(path, "Radiohead - Karma Police\n"); const refs = await readImportSource(path); assert.equal(refs[0].artist, "Radiohead"); assert.equal(refs[0].title, "Karma Police"); }); test("import creates a new private playlist for --playlist and records misses", async () => { const root = await mkdtemp(join(tmpdir(), "spotify-import-")); const path = join(root, "tracks.txt"); await writeFile(path, "Radiohead - Karma Police\nMissing Song\n"); let createdPublic: boolean | undefined; let addedUris: string[] = []; const result = await importTracks(path, { playlist: "New Mix", delayMs: 0 }, { createPlaylist: async (_name, options) => { createdPublic = options?.public; return { id: "playlist-id", uri: "spotify:playlist:playlist-id", name: "New Mix", public: false, owner: { id: "owner" } }; }, searchTracks: async (query) => query.includes("Missing") ? [] : [{ id: "track-id", uri: "spotify:track:track-id", name: "Karma Police", artists: [{ name: "Radiohead" }] }], addItemsToPlaylist: async (_playlistId, uris) => { addedUris = uris; return [{ snapshot_id: "snap" }]; } }); assert.equal(createdPublic, false); assert.deepEqual(addedUris, ["spotify:track:track-id"]); assert.equal(result.found.length, 1); assert.equal(result.missed.length, 1); assert.deepEqual(result.added, { playlistId: "playlist-id", count: 1, snapshotIds: ["snap"] }); }); test("import updates explicit playlist id without creating a new playlist", async () => { const root = await mkdtemp(join(tmpdir(), "spotify-import-")); const path = join(root, "tracks.txt"); await writeFile(path, "Radiohead - Karma Police\n"); let created = false; const result = await importTracks(path, { playlistId: "existing", delayMs: 0 }, { createPlaylist: async () => { created = true; throw new Error("should not create"); }, searchTracks: async () => [{ id: "track-id", uri: "spotify:track:track-id", name: "Karma Police", artists: [{ name: "Radiohead" }] }], addItemsToPlaylist: async () => [{ snapshot_id: "snap" }] }); assert.equal(created, false); assert.equal(result.added?.playlistId, "existing"); }); test("import command writes JSON result", async () => { const root = await mkdtemp(join(tmpdir(), "spotify-import-")); const path = join(root, "tracks.txt"); await writeFile(path, "Radiohead - Karma Police\n"); const io = createDeps(); await runImportCommand( { command: "import", positional: [path], playlistId: "existing", json: true }, io.deps, { createPlaylist: async () => { throw new Error("should not create"); }, searchTracks: async () => [{ id: "track-id", uri: "spotify:track:track-id", name: "Karma Police", artists: [{ name: "Radiohead" }] }], addItemsToPlaylist: async () => [{ snapshot_id: "snap" }] } ); assert.equal(JSON.parse(io.stdout()).added.playlistId, "existing"); });