feat: matchedAlbum on item detail, onLoan collection filter
This commit is contained in:
@@ -212,4 +212,39 @@ describe('collection routes', () => {
|
||||
expect(list.json().items).toHaveLength(0)
|
||||
await app.close()
|
||||
})
|
||||
|
||||
it('detail includes matchedAlbum (null when unmatched)', async () => {
|
||||
const { app, cookie } = await appWithToken()
|
||||
const added = await app.inject({ method: 'POST', url: '/api/collection', ...auth(cookie), payload: { releaseId: 1001 } })
|
||||
const id = added.json().id as number
|
||||
const detail = await app.inject({ method: 'GET', url: `/api/collection/${id}`, ...auth(cookie) })
|
||||
expect(detail.json().matchedAlbum).toBeNull()
|
||||
|
||||
await app.inject({
|
||||
method: 'POST',
|
||||
url: '/api/library/albums/test-seed',
|
||||
...auth(cookie),
|
||||
payload: { albums: [{ subsonicId: 'alb-9', title: 'Motion', artist: 'The Cinematic Orchestra' }] },
|
||||
})
|
||||
const again = await app.inject({ method: 'GET', url: `/api/collection/${id}`, ...auth(cookie) })
|
||||
expect(again.json().matchedAlbum).toMatchObject({ subsonicId: 'alb-9', lastPlayedAt: null })
|
||||
await app.close()
|
||||
})
|
||||
|
||||
// KNOWN-RED handoff: the loan route arrives in Task 5 — this test turns
|
||||
// green then. Everything else in this file must pass now.
|
||||
it('list supports onLoan=true/false filter', async () => {
|
||||
const { app, cookie } = await appWithToken()
|
||||
const added = await app.inject({ method: 'POST', url: '/api/collection', ...auth(cookie), payload: { releaseId: 1001 } })
|
||||
const id = added.json().id as number
|
||||
await app.inject({ method: 'POST', url: `/api/collection/${id}/loan`, ...auth(cookie), payload: { borrower: 'Bob' } })
|
||||
|
||||
const all = await app.inject({ method: 'GET', url: '/api/collection', ...auth(cookie) })
|
||||
expect(all.json().items).toHaveLength(1)
|
||||
const onLoan = await app.inject({ method: 'GET', url: '/api/collection?onLoan=true', ...auth(cookie) })
|
||||
expect(onLoan.json().items).toHaveLength(1)
|
||||
const notOnLoan = await app.inject({ method: 'GET', url: '/api/collection?onLoan=false', ...auth(cookie) })
|
||||
expect(notOnLoan.json().items).toHaveLength(0)
|
||||
await app.close()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest'
|
||||
import { openDatabase, type DB } from '../src/db.js'
|
||||
import { resolveRipStatus } from '../src/ripstatus.js'
|
||||
import { resolveRipStatus, findMatchedAlbum } from '../src/ripstatus.js'
|
||||
|
||||
describe('resolveRipStatus', () => {
|
||||
let db: DB
|
||||
@@ -56,3 +56,42 @@ describe('resolveRipStatus', () => {
|
||||
expect(resolveRipStatus(db, 1, itemId)).toBe('ripped')
|
||||
})
|
||||
})
|
||||
|
||||
describe('findMatchedAlbum', () => {
|
||||
let db: DB
|
||||
|
||||
beforeEach(() => {
|
||||
db = openDatabase(':memory:')
|
||||
db.prepare("INSERT INTO users (id, username, password_hash, is_admin) VALUES (1, 'sam', 'x', 1)").run()
|
||||
db.prepare(
|
||||
"INSERT INTO collection_items (id, user_id, discogs_release_id, title, artist) VALUES (10, 1, 100, 'Motion', 'The Cinematic Orchestra')"
|
||||
).run()
|
||||
})
|
||||
|
||||
function addAlbum(id: number, title: string, artist: string) {
|
||||
db.prepare('INSERT INTO digital_albums (id, user_id, subsonic_id, title, artist) VALUES (?, 1, ?, ?, ?)').run(
|
||||
id,
|
||||
`sub-${id}`,
|
||||
title,
|
||||
artist
|
||||
)
|
||||
}
|
||||
|
||||
it('returns the match-linked album', () => {
|
||||
addAlbum(1, 'Motion (Remastered)', 'The Cinematic Orchestra')
|
||||
db.prepare('INSERT INTO match_links (user_id, item_id, album_id) VALUES (1, 10, 1)').run()
|
||||
const m = findMatchedAlbum(db, 1, 10)
|
||||
expect(m).toMatchObject({ subsonicId: 'sub-1', lastPlayedAt: null })
|
||||
})
|
||||
|
||||
it('falls back to the confident fuzzy match', () => {
|
||||
addAlbum(2, 'Motion!', 'Cinematic Orchestra')
|
||||
const m = findMatchedAlbum(db, 1, 10)
|
||||
expect(m).toMatchObject({ subsonicId: 'sub-2' })
|
||||
})
|
||||
|
||||
it('returns null when nothing matches or the item is missing', () => {
|
||||
expect(findMatchedAlbum(db, 1, 10)).toBeNull()
|
||||
expect(findMatchedAlbum(db, 1, 9999)).toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user