From dfc1556cbe546366637af782e9b22987e13df430 Mon Sep 17 00:00:00 2001 From: Jonathan Finley Date: Fri, 13 Mar 2026 21:36:47 -0400 Subject: [PATCH] test: tighten browse forwarding plumbing --- .../utils/queries/libraryItemsBookFilters.js | 5 +- .../queries/libraryItemsPodcastFilters.js | 6 +- ...braryController.largeLibraryBrowse.test.js | 58 ++++++++++--------- 3 files changed, 36 insertions(+), 33 deletions(-) diff --git a/server/utils/queries/libraryItemsBookFilters.js b/server/utils/queries/libraryItemsBookFilters.js index 3497eefa4..0ef3b3fd7 100644 --- a/server/utils/queries/libraryItemsBookFilters.js +++ b/server/utils/queries/libraryItemsBookFilters.js @@ -393,11 +393,10 @@ module.exports = { * @param {number} limit * @param {number} offset * @param {boolean} isHomePage for home page shelves - * @param {{ cursor?: string|null, pageMode?: string, collapseseries?: boolean }} requestOptions + * @param {object} browseRequestOptions Reserved for future large-library browse plumbing * @returns {{ libraryItems: import('../../models/LibraryItem')[], count: number }} */ - async getFilteredLibraryItems(libraryId, user, filterGroup, filterValue, sortBy, sortDesc, collapseseries, include, limit, offset, isHomePage = false, requestOptions = {}) { - collapseseries = requestOptions.collapseseries ?? collapseseries + async getFilteredLibraryItems(libraryId, user, filterGroup, filterValue, sortBy, sortDesc, collapseseries, include, limit, offset, isHomePage = false, browseRequestOptions = null) { // TODO: Handle collapse sub-series if (filterGroup === 'series' && collapseseries) { collapseseries = false diff --git a/server/utils/queries/libraryItemsPodcastFilters.js b/server/utils/queries/libraryItemsPodcastFilters.js index 4ba779480..1a7ad834e 100644 --- a/server/utils/queries/libraryItemsPodcastFilters.js +++ b/server/utils/queries/libraryItemsPodcastFilters.js @@ -141,12 +141,10 @@ module.exports = { * @param {string[]} include * @param {number} limit * @param {number} offset - * @param {{ cursor?: string|null, pageMode?: string, collapseseries?: boolean }} requestOptions + * @param {object} browseRequestOptions Reserved for future large-library browse plumbing * @returns {Promise<{ libraryItems: import('../../models/LibraryItem')[], count: number }>} */ - async getFilteredLibraryItems(libraryId, user, filterGroup, filterValue, sortBy, sortDesc, include, limit, offset, requestOptions = {}) { - requestOptions.cursor = requestOptions.cursor || null - requestOptions.pageMode = requestOptions.pageMode || 'paged' + async getFilteredLibraryItems(libraryId, user, filterGroup, filterValue, sortBy, sortDesc, include, limit, offset, browseRequestOptions = null) { const includeRSSFeed = include.includes('rssfeed') const includeNumEpisodesIncomplete = include.includes('numepisodesincomplete') diff --git a/test/server/controllers/LibraryController.largeLibraryBrowse.test.js b/test/server/controllers/LibraryController.largeLibraryBrowse.test.js index 798cd4799..f12518138 100644 --- a/test/server/controllers/LibraryController.largeLibraryBrowse.test.js +++ b/test/server/controllers/LibraryController.largeLibraryBrowse.test.js @@ -4,6 +4,7 @@ const sinon = require('sinon') const Database = require('../../../server/Database') const LibraryController = require('../../../server/controllers/LibraryController') +const libraryFilters = require('../../../server/utils/queries/libraryFilters') const libraryItemsBookFilters = require('../../../server/utils/queries/libraryItemsBookFilters') const libraryItemsPodcastFilters = require('../../../server/utils/queries/libraryItemsPodcastFilters') @@ -81,32 +82,40 @@ describe('LibraryController large-library browse contract', () => { }) }) - it('uses forwarded browse request options inside the book query helper', async () => { - const getOrderStub = sinon.stub(libraryItemsBookFilters, 'getOrder').returns([]) - sinon.stub(libraryItemsBookFilters, 'getMediaGroupQuery').returns({ mediaWhere: {}, replacements: {} }) - sinon.stub(libraryItemsBookFilters, 'getUserPermissionBookWhereQuery').returns({ bookWhere: [], replacements: {} }) - sinon.stub(Database.bookModel, 'findAndCountAll').resolves({ rows: [], count: 0 }) + it('forwards cursor and pageMode through LibraryItem.getByFilterAndSort into libraryFilters', async () => { + const getFilteredLibraryItemsStub = sinon.stub(libraryFilters, 'getFilteredLibraryItems').resolves({ + libraryItems: [], + count: 0, + nextCursor: null, + paginationMode: 'offset', + countMode: 'exact-on-initial-page', + isCountDeferred: false + }) - await libraryItemsBookFilters.getFilteredLibraryItems( - 'lib_1', - { id: 'user_1', isAdminOrUp: false, canAccessExplicitContent: true, accessAllTags: true }, - null, - null, - 'media.metadata.title', - false, - false, - [], - 40, - 0, - false, - { cursor: 'cursor-1', pageMode: 'endless', collapseseries: true } + await Database.libraryItemModel.getByFilterAndSort( + { id: 'lib_1', mediaType: 'book' }, + { id: 'user_1' }, + { + sortBy: 'media.metadata.title', + limit: 40, + offset: 0, + cursor: 'cursor-1', + pageMode: 'endless', + include: [], + collapseseries: true, + mediaType: 'book' + } ) - expect(getOrderStub.firstCall.args[2]).to.equal(true) + expect(getFilteredLibraryItemsStub.firstCall.args[2]).to.include({ + cursor: 'cursor-1', + pageMode: 'endless', + collapseseries: true + }) }) - it('uses forwarded browse request options inside the podcast query helper', async () => { - const requestOptions = { cursor: 'cursor-9' } + it('does not mutate caller-owned forwarded browse options in the podcast query helper', async () => { + const forwardedBrowseOptions = { cursor: 'cursor-9' } sinon.stub(libraryItemsPodcastFilters, 'getMediaGroupQuery').returns({ mediaWhere: {}, replacements: {} }) sinon.stub(libraryItemsPodcastFilters, 'getUserPermissionPodcastWhereQuery').returns({ podcastWhere: [], replacements: {} }) sinon.stub(libraryItemsPodcastFilters, 'getOrder').returns([]) @@ -122,13 +131,10 @@ describe('LibraryController large-library browse contract', () => { [], 40, 0, - requestOptions + forwardedBrowseOptions ) - expect(requestOptions).to.deep.equal({ - cursor: 'cursor-9', - pageMode: 'paged' - }) + expect(forwardedBrowseOptions).to.deep.equal({ cursor: 'cursor-9' }) }) it('forwards cursor, pageMode, and collapseseries through libraryFilters into the book query helper', async () => {