1
0
Files
record-shop/server/test/settings.test.ts

125 lines
3.8 KiB
TypeScript

import { describe, it, expect } from 'vitest'
import { buildTestApp, setupAdmin, auth } from './helpers.js'
function subsonicStubFetch(ok: boolean): typeof fetch {
return (async (url: any) => {
if (String(url).includes('/rest/ping')) {
const body = ok
? { 'subsonic-response': { status: 'ok' } }
: {
'subsonic-response': {
status: 'failed',
error: { code: 40, message: 'Wrong username or password.' },
},
}
return new Response(JSON.stringify(body), {
status: 200,
headers: { 'content-type': 'application/json' },
})
}
return new Response('not found', { status: 404 })
}) as typeof fetch
}
describe('settings routes', () => {
it('starts empty and stores/clears tokens', async () => {
const app = await buildTestApp()
const cookie = await setupAdmin(app)
const empty = await app.inject({ method: 'GET', url: '/api/settings', ...auth(cookie) })
expect(empty.json()).toEqual({
hasDiscogsToken: false,
discogsTokenMasked: null,
subsonicUrl: null,
subsonicUsername: null,
hasSubsonicPassword: false,
})
const put = await app.inject({
method: 'PUT',
url: '/api/settings',
...auth(cookie),
payload: { discogsToken: 'abcdef0123456789' },
})
expect(put.statusCode).toBe(200)
expect(put.json()).toMatchObject({ hasDiscogsToken: true, discogsTokenMasked: '****56789' })
await app.inject({
method: 'PUT',
url: '/api/settings',
...auth(cookie),
payload: { discogsToken: '' },
})
const cleared = await app.inject({ method: 'GET', url: '/api/settings', ...auth(cookie) })
expect(cleared.json().hasDiscogsToken).toBe(false)
await app.close()
})
it('stores valid subsonic config after successful ping', async () => {
const app = await buildTestApp(subsonicStubFetch(true))
const cookie = await setupAdmin(app)
const put = await app.inject({
method: 'PUT',
url: '/api/settings',
...auth(cookie),
payload: {
subsonicUrl: 'http://navidrome.local',
subsonicUsername: 'sam',
subsonicPassword: 'pass',
},
})
expect(put.statusCode).toBe(200)
expect(put.json()).toMatchObject({
subsonicUrl: 'http://navidrome.local',
hasSubsonicPassword: true,
})
await app.close()
})
it('rejects bad subsonic credentials with 400 subsonic_auth', async () => {
const app = await buildTestApp(subsonicStubFetch(false))
const cookie = await setupAdmin(app)
const put = await app.inject({
method: 'PUT',
url: '/api/settings',
...auth(cookie),
payload: {
subsonicUrl: 'http://navidrome.local',
subsonicUsername: 'sam',
subsonicPassword: 'wrong',
},
})
expect(put.statusCode).toBe(400)
expect(put.json()).toMatchObject({ error: 'subsonic_auth' })
await app.close()
})
it('rejects unreachable subsonic with 400 subsonic_unreachable', async () => {
const failing = (async () => {
throw new TypeError('fetch failed')
}) as unknown as typeof fetch
const app = await buildTestApp(failing)
const cookie = await setupAdmin(app)
const put = await app.inject({
method: 'PUT',
url: '/api/settings',
...auth(cookie),
payload: {
subsonicUrl: 'http://nope.invalid',
subsonicUsername: 'sam',
subsonicPassword: 'pass',
},
})
expect(put.statusCode).toBe(400)
expect(put.json()).toMatchObject({ error: 'subsonic_unreachable' })
await app.close()
})
it('requires auth', async () => {
const app = await buildTestApp()
const res = await app.inject({ method: 'GET', url: '/api/settings' })
expect(res.statusCode).toBe(401)
await app.close()
})
})