Files
alice-backend/test/spotify.test.mjs
T

33 lines
1.8 KiB
JavaScript

import test from 'node:test';
import assert from 'node:assert/strict';
import { mkdtempSync, readFileSync, rmSync, statSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { createHash } from 'node:crypto';
import { startSpotify, finishSpotify, spotifyStatus, searchSpotify } from '../server/spotify.mjs';
test('PKCE state is single use and token persists privately; exact artist ranks first', async () => {
const dir = mkdtempSync(join(tmpdir(), 'spotify-test-'));
process.env.DATA_DIR = dir; process.env.SPOTIFY_CLIENT_ID = 'test-client';
const original = globalThis.fetch;
let verifier;
globalThis.fetch = async (url, options) => {
if (String(url).includes('/api/token')) {
verifier = options.body.get('code_verifier');
return Response.json({ access_token: 'access', refresh_token: 'refresh', expires_in: 3600 });
}
return Response.json({ tracks: { items: [{ uri: 'spotify:track:1', name: 'Song', type: 'track' }] }, artists: { items: [{ uri: 'spotify:artist:1', name: 'Aphex Twin', type: 'artist' }] } });
};
try {
const url = new URL(startSpotify()), state = url.searchParams.get('state');
await assert.rejects(finishSpotify('wrong', 'code'));
await finishSpotify(state, 'code');
assert.equal(createHash('sha256').update(verifier).digest('base64url'), url.searchParams.get('code_challenge'));
await assert.rejects(finishSpotify(state, 'code'));
assert.equal(statSync(join(dir, 'spotify.json')).mode & 0o777, 0o600);
assert.equal(JSON.parse(readFileSync(join(dir, 'spotify.json'))).refresh_token, 'refresh');
assert.deepEqual(spotifyStatus(), { configured: true, connected: true });
assert.equal((await searchSpotify('aphex twin'))[0].type, 'artist');
} finally { globalThis.fetch = original; rmSync(dir, { recursive: true, force: true }); }
});