test: add deterministic browse cursor helpers

This commit is contained in:
Jonathan Finley 2026-03-13 21:20:20 -04:00
parent 59c7c0a7c2
commit 36170d0fcb
2 changed files with 65 additions and 0 deletions

View file

@ -0,0 +1,22 @@
function encodeBrowseCursor(payload) {
return Buffer.from(JSON.stringify(payload)).toString('base64url')
}
function decodeBrowseCursor(cursor) {
const decoded = JSON.parse(Buffer.from(cursor, 'base64url').toString('utf8'))
if (!Array.isArray(decoded.keys) || !Array.isArray(decoded.values) || decoded.keys.length !== decoded.values.length) {
throw new Error('Cursor is missing the full ordered key set')
}
if (!decoded.keys.length || decoded.keys[decoded.keys.length - 1] !== 'id') {
throw new Error('Cursor is missing the tie-breaker value')
}
return decoded
}
module.exports = {
encodeBrowseCursor,
decodeBrowseCursor
}

View file

@ -0,0 +1,43 @@
const chai = require('chai')
const expect = chai.expect
const {
encodeBrowseCursor,
decodeBrowseCursor
} = require('../../../server/utils/queries/libraryBrowseCursor')
describe('libraryBrowseCursor', () => {
it('round-trips a deterministic title cursor with id tie-breaker', () => {
const encoded = encodeBrowseCursor({
sortBy: 'media.metadata.title',
desc: false,
keys: ['titleIgnorePrefix', 'id'],
values: ['Dune', 'item_42']
})
expect(decodeBrowseCursor(encoded)).to.deep.equal({
sortBy: 'media.metadata.title',
desc: false,
keys: ['titleIgnorePrefix', 'id'],
values: ['Dune', 'item_42']
})
})
it('rejects a cursor without the full ordered key set', () => {
expect(() => decodeBrowseCursor(encodeBrowseCursor({
sortBy: 'media.metadata.title',
desc: false,
keys: ['titleIgnorePrefix', 'id'],
values: ['Dune']
}))).to.throw('full ordered key set')
})
it('rejects a cursor without the id tie-breaker', () => {
expect(() => decodeBrowseCursor(encodeBrowseCursor({
sortBy: 'media.metadata.title',
desc: false,
keys: ['titleIgnorePrefix'],
values: ['Dune']
}))).to.throw('tie-breaker')
})
})