Skip to content

Commit 657f8f3

Browse files
fix: preserve search results during preference hydration (#3109)
1 parent 0a6de95 commit 657f8f3

2 files changed

Lines changed: 93 additions & 0 deletions

File tree

app/composables/npm/useSearch.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,10 @@ export function useSearch(
228228
return
229229
}
230230

231+
if (asyncData.status.value === 'pending') {
232+
await asyncData.refresh({ dedupe: 'defer' })
233+
}
234+
231235
if (cache.value && (cache.value.query !== q || cache.value.provider !== provider)) {
232236
cache.value = null
233237
await asyncData.refresh()
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import { mockNuxtImport } from '@nuxt/test-utils/runtime'
2+
import { beforeEach, describe, expect, it, vi } from 'vitest'
3+
import { nextTick, ref } from 'vue'
4+
import type { NpmSearchResponse } from '#shared/types'
5+
import { useSearch } from '~/composables/npm/useSearch'
6+
7+
const { mockAlgoliaSearch, mockAlgoliaMultiSearch, mockUseAlgoliaSearch, mockUseNpmSearch } =
8+
vi.hoisted(() => ({
9+
mockAlgoliaSearch: vi.fn(),
10+
mockAlgoliaMultiSearch: vi.fn(),
11+
mockUseAlgoliaSearch: vi.fn(),
12+
mockUseNpmSearch: vi.fn(),
13+
}))
14+
15+
mockNuxtImport('useAlgoliaSearch', () => mockUseAlgoliaSearch)
16+
mockNuxtImport('useNpmSearch', () => mockUseNpmSearch)
17+
18+
describe('useSearch', () => {
19+
beforeEach(() => {
20+
vi.clearAllMocks()
21+
22+
mockUseAlgoliaSearch.mockReturnValue({
23+
search: mockAlgoliaSearch,
24+
searchWithSuggestions: mockAlgoliaMultiSearch,
25+
})
26+
27+
mockUseNpmSearch.mockReturnValue({
28+
search: vi.fn(),
29+
checkOrgExists: vi.fn(),
30+
checkUserExists: vi.fn(),
31+
})
32+
})
33+
34+
it('waits for a pending initial search before loading more results', async () => {
35+
const response: NpmSearchResponse = {
36+
isStale: false,
37+
objects: [
38+
{
39+
package: {
40+
name: 'nuxt',
41+
version: '4.0.0',
42+
date: '2026-01-01T00:00:00.000Z',
43+
links: {},
44+
},
45+
},
46+
],
47+
total: 1,
48+
time: '2026-01-01T00:00:00.000Z',
49+
}
50+
51+
const searchResult = {
52+
search: response,
53+
orgExists: false,
54+
userExists: false,
55+
packageExists: true,
56+
}
57+
58+
let resolveInitialSearch!: (value: typeof searchResult) => void
59+
60+
mockAlgoliaMultiSearch
61+
.mockImplementationOnce(
62+
() =>
63+
new Promise(resolve => {
64+
resolveInitialSearch = resolve
65+
}),
66+
)
67+
.mockResolvedValue(searchResult)
68+
69+
mockAlgoliaSearch.mockResolvedValue(response)
70+
71+
const size = ref(25)
72+
const result = useSearch(ref('nuxt'), ref('algolia'), () => ({ size: size.value }), {
73+
suggestions: true,
74+
})
75+
76+
await vi.waitFor(() => {
77+
expect(mockAlgoliaMultiSearch).toHaveBeenCalled()
78+
})
79+
80+
size.value = 50
81+
await nextTick()
82+
83+
resolveInitialSearch(searchResult)
84+
85+
await vi.waitFor(() => {
86+
expect(result.data.value?.objects.map(item => item.package.name)).toEqual(['nuxt'])
87+
})
88+
})
89+
})

0 commit comments

Comments
 (0)