From 41f6955f8840721239e53f95a6f00a4c1ede842e Mon Sep 17 00:00:00 2001 From: Alexander Wondwossen Date: Sun, 22 Mar 2026 12:50:48 -0400 Subject: [PATCH 1/3] fix: cap pagination page count to max fetchable results (#1923) --- app/pages/search.vue | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/app/pages/search.vue b/app/pages/search.vue index b306359ca7..58fac08c02 100644 --- a/app/pages/search.vue +++ b/app/pages/search.vue @@ -265,6 +265,18 @@ const effectiveTotal = computed(() => { return displayResults.value.length }) +/** + * Total items for pagination purposes. + * Capped by EAGER_LOAD_SIZE so that the page count only reflects pages we can + * actually fetch — e.g. with a 500-result cap, max pages = ceil(500 / pageSize). + * Without this cap, a search returning total=92,000 would show 3,680 pages but + * navigation beyond page 20 (at 25/page) would silently fail. + */ +const paginationTotal = computed(() => { + const cap = EAGER_LOAD_SIZE[searchProvider.value] + return Math.min(effectiveTotal.value, cap) +}) + // Handle filter chip removal function handleClearFilter(chip: FilterChip) { clearFilter(chip) @@ -878,7 +890,7 @@ onBeforeUnmount(() => { v-model:mode="paginationMode" v-model:page-size="preferredPageSize" v-model:current-page="currentPage" - :total-items="effectiveTotal" + :total-items="paginationTotal" :view-mode="viewMode" /> From 881ec052f1bb5e14c22e14b9c0f0844bea1e8a86 Mon Sep 17 00:00:00 2001 From: Alexander Wondwossen Date: Sun, 22 Mar 2026 14:43:05 -0400 Subject: [PATCH 2/3] test: add pagination total capping regression test --- test/unit/app/utils/pagination.spec.ts | 55 ++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 test/unit/app/utils/pagination.spec.ts diff --git a/test/unit/app/utils/pagination.spec.ts b/test/unit/app/utils/pagination.spec.ts new file mode 100644 index 0000000000..7994b0bd88 --- /dev/null +++ b/test/unit/app/utils/pagination.spec.ts @@ -0,0 +1,55 @@ +import { describe, expect, it } from 'vitest' + +/** + * Tests for the pagination total capping logic used in search.vue. + * + * The search page caps the displayed pagination total to EAGER_LOAD_SIZE + * so that page links only reflect pages that can actually be fetched. + * Without the cap, a search returning total=92,000 items would show 3,680 + * pages at 25 items/page, but navigation beyond page 20 silently fails. + */ + +const EAGER_LOAD_SIZE = { algolia: 500, npm: 500 } as const + +function paginationTotal( + effectiveTotal: number, + provider: keyof typeof EAGER_LOAD_SIZE, +): number { + const cap = EAGER_LOAD_SIZE[provider] + return Math.min(effectiveTotal, cap) +} + +describe('paginationTotal capping logic', () => { + it('returns the total as-is when it is below the cap', () => { + expect(paginationTotal(100, 'npm')).toBe(100) + expect(paginationTotal(100, 'algolia')).toBe(100) + }) + + it('returns the cap when the total exceeds it', () => { + expect(paginationTotal(92_000, 'npm')).toBe(500) + expect(paginationTotal(92_000, 'algolia')).toBe(500) + }) + + it('returns exactly the cap when the total equals the cap', () => { + expect(paginationTotal(500, 'npm')).toBe(500) + expect(paginationTotal(500, 'algolia')).toBe(500) + }) + + it('returns 0 when total is 0', () => { + expect(paginationTotal(0, 'npm')).toBe(0) + }) + + it('caps algolia and npm identically (both have 500 limit)', () => { + const total = 10_000 + expect(paginationTotal(total, 'algolia')).toBe(paginationTotal(total, 'npm')) + }) + + it('page count derived from capped total stays within fetchable range', () => { + const pageSize = 25 + const rawTotal = 92_000 + const cappedTotal = paginationTotal(rawTotal, 'npm') + const maxPages = Math.ceil(cappedTotal / pageSize) + // Should be 20 pages (500 / 25), not 3680 (92000 / 25) + expect(maxPages).toBe(20) + }) +}) From c16a053c589f948203ec0c1ea029f71978614ce2 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sun, 22 Mar 2026 18:44:44 +0000 Subject: [PATCH 3/3] [autofix.ci] apply automated fixes --- test/unit/app/utils/pagination.spec.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/test/unit/app/utils/pagination.spec.ts b/test/unit/app/utils/pagination.spec.ts index 7994b0bd88..64a08a6050 100644 --- a/test/unit/app/utils/pagination.spec.ts +++ b/test/unit/app/utils/pagination.spec.ts @@ -11,10 +11,7 @@ import { describe, expect, it } from 'vitest' const EAGER_LOAD_SIZE = { algolia: 500, npm: 500 } as const -function paginationTotal( - effectiveTotal: number, - provider: keyof typeof EAGER_LOAD_SIZE, -): number { +function paginationTotal(effectiveTotal: number, provider: keyof typeof EAGER_LOAD_SIZE): number { const cap = EAGER_LOAD_SIZE[provider] return Math.min(effectiveTotal, cap) }